Skip to content

Commit 7bec0a7

Browse files
authored
Update npm package migration script to have a cutoff date (#96)
* Update .gitignore to ignore temp & tool folders * Add a .env.example file with some variables that are used in scripts * Update migrate-npm-packages-between-github-instances.sh to have a cutoff date * Update migrate-npm-packages-between-github-instances.sh allowing CUTOFF_DATE default to be empty, which in turns will migrate all versions (keeping existing behaviour)
1 parent c91fd9e commit 7bec0a7

File tree

3 files changed

+49
-20
lines changed

3 files changed

+49
-20
lines changed

.env.example

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# export $(grep -v '^#' .env | xargs)
2+
3+
SOURCE_HOST=
4+
SOURCE_ORG=
5+
GH_SOURCE_PAT=
6+
7+
TARGET_HOST=
8+
TARGET_ORG=
9+
GH_TARGET_PAT=

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@
66
node_modules*
77
test*.js
88
test*.sh
9+
temp
10+
tool
11+
.env

scripts/migrate-npm-packages-between-github-instances.sh

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,27 +11,27 @@
1111
# Example: ./migrate-npm-packages-between-github-instances.sh joshjohanning-org github.com joshjohanning-emu github.com | tee output.log
1212
#
1313
# Notes:
14-
# - Mapping the npm package to a repo is optional.
14+
# - Mapping the npm package to a repo is optional.
1515
# - If there is a repo that exists in the target with the same repo name, it will map it
1616
# - If the repo doesn't exist, the package will still import but won't be mapped to a repo
1717
# - See ./failed-packages.txt for any packages that failed to import
1818

1919
set -e
2020

21-
if [ $# -ne "4" ]; then
22-
echo "Usage: $0 <source-org> <source-host> <target-org> <target-host>"
23-
exit 1
21+
if [ $# -lt "4" ]; then
22+
echo "Usage: $0 <source-org> <source-host> <target-org> <target-host>"
23+
exit 1
2424
fi
2525

2626
# make sure env variables are defined
2727
if [ -z "$GH_SOURCE_PAT" ]; then
28-
echo "Error: set GH_SOURCE_PAT env var"
29-
exit 1
28+
echo "Error: set GH_SOURCE_PAT env var"
29+
exit 1
3030
fi
3131

3232
if [ -z "$GH_TARGET_PAT" ]; then
33-
echo "Error: set GH_TARGET_PAT env var"
34-
exit 1
33+
echo "Error: set GH_TARGET_PAT env var"
34+
exit 1
3535
fi
3636

3737
echo "..."
@@ -40,14 +40,19 @@ SOURCE_ORG=$1
4040
SOURCE_HOST=$2
4141
TARGET_ORG=$3
4242
TARGET_HOST=$4
43+
# Optional: Set CUTOFF_DATE to migrate only package versions created on or after this date.
44+
# Format: YYYY-MM-DDTHH:MM:SSZ (e.g., 2023-03-13T00:00:00Z)
45+
# Example: To migrate versions from the past year, use: $(date -u -v-1y +"%Y-%m-%dT%H:%M:%SZ")
46+
# If CUTOFF_DATE is unset or empty, all available versions will be migrated.
47+
CUTOFF_DATE=$5
4348

4449
# create temp dir
4550
mkdir -p ./temp
4651
cd ./temp
4752
temp_dir=$(pwd)
4853

4954
# set up .npmrc for target org
50-
echo @$TARGET_ORG:registry=https://npm.pkg.$TARGET_HOST/ > $temp_dir/.npmrc && echo "//npm.pkg.$TARGET_HOST/:_authToken=$GH_TARGET_PAT" >> $temp_dir/.npmrc
55+
echo @$TARGET_ORG:registry=https://npm.pkg.$TARGET_HOST/ >$temp_dir/.npmrc && echo "//npm.pkg.$TARGET_HOST/:_authToken=$GH_TARGET_PAT" >>$temp_dir/.npmrc
5156

5257
packages=$(GH_HOST="$SOURCE_HOST" GH_TOKEN=$GH_SOURCE_PAT gh api --paginate "/orgs/$SOURCE_ORG/packages?package_type=npm" -q '.[] | .name + " " + .repository.name')
5358

@@ -57,32 +62,44 @@ echo "$packages" | while IFS= read -r response; do
5762
repo_name=$(echo "$response" | cut -d ' ' -f 2)
5863

5964
echo "org: $SOURCE_ORG repo: $repo_name --> package name $package_name"
60-
61-
versions=$(GH_HOST="$SOURCE_HOST" GH_TOKEN=$GH_SOURCE_PAT gh api --paginate "/orgs/$SOURCE_ORG/packages/npm/$package_name/versions" -q '.[] | .name' | sort -V)
62-
for version in $versions
63-
do
65+
66+
# Cache package metadata to avoid multiple API calls for each version
67+
curl -H "Authorization: token $GH_SOURCE_PAT" -Ls "https://npm.pkg.github.com/@$SOURCE_ORG/$package_name" >"${temp_dir}/${package_name}.json"
68+
69+
# Fetch versions, filter by date only if CUTOFF_DATE is set
70+
if [ -n "$CUTOFF_DATE" ]; then
71+
versions=$(GH_HOST="$SOURCE_HOST" GH_TOKEN=$GH_SOURCE_PAT gh api --paginate "/orgs/$SOURCE_ORG/packages/npm/$package_name/versions" |
72+
jq -r --arg cutoff "$CUTOFF_DATE" '.[] | select(.created_at >= $cutoff) | .name' |
73+
sort -V)
74+
else
75+
versions=$(GH_HOST="$SOURCE_HOST" GH_TOKEN=$GH_SOURCE_PAT gh api --paginate "/orgs/$SOURCE_ORG/packages/npm/$package_name/versions" |
76+
jq -r '.[].name' |
77+
sort -V)
78+
fi
79+
80+
for version in $versions; do
6481
echo "$version"
6582

6683
# get url of tarball
67-
url=$(curl -H "Authorization: token $GH_SOURCE_PAT" -Ls https://npm.pkg.github.com/@$SOURCE_ORG/$package_name | jq --arg version $version -r '.versions[$version].dist.tarball')
84+
url=$(jq --arg version $version -r '.versions[$version].dist.tarball' "${temp_dir}/${package_name}.json")
6885

6986
# check for error
7087
if [ "$url" == "null" ]; then
71-
echo "ERROR: version $version not found for package $package_name"
72-
echo "NOTE: Make sure you have the proper scopes for gh; ie run this: gh auth refresh -h github.com -s read:packages"
73-
exit 1
88+
echo "ERROR: version $version not found for package $package_name"
89+
echo "NOTE: Make sure you have the proper scopes for gh; ie run this: gh auth refresh -h github.com -s read:packages"
90+
continue
7491
fi
7592

76-
# download
93+
# download
7794
curl -sS -H "Authorization: token $GH_SOURCE_PAT" -L -o $package_name-$version.tgz $url
78-
95+
7996
# untar
8097
mkdir -p ./$package_name-$version
8198
# if you run into permissions issue, add a `sudo` here
8299
tar xzf $package_name-$version.tgz -C $package_name-$version
83100
cd $package_name-$version/package
84101
perl -pi -e "s/$SOURCE_ORG/$TARGET_ORG/ig" package.json
85-
npm publish --ignore-scripts --userconfig $temp_dir/.npmrc || echo "skipped package due to failure: $package_name-$version.tgz" >> ./failed-packages.txt
102+
npm publish --ignore-scripts --userconfig $temp_dir/.npmrc || echo "skipped package due to failure: $package_name-$version.tgz" >>./failed-packages.txt
86103
cd ./../../
87104

88105
done

0 commit comments

Comments
 (0)