11
11
# Example: ./migrate-npm-packages-between-github-instances.sh joshjohanning-org github.com joshjohanning-emu github.com | tee output.log
12
12
#
13
13
# Notes:
14
- # - Mapping the npm package to a repo is optional.
14
+ # - Mapping the npm package to a repo is optional.
15
15
# - If there is a repo that exists in the target with the same repo name, it will map it
16
16
# - If the repo doesn't exist, the package will still import but won't be mapped to a repo
17
17
# - See ./failed-packages.txt for any packages that failed to import
18
18
19
19
set -e
20
20
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
24
24
fi
25
25
26
26
# make sure env variables are defined
27
27
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
30
30
fi
31
31
32
32
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
35
35
fi
36
36
37
37
echo " ..."
@@ -40,14 +40,19 @@ SOURCE_ORG=$1
40
40
SOURCE_HOST=$2
41
41
TARGET_ORG=$3
42
42
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
43
48
44
49
# create temp dir
45
50
mkdir -p ./temp
46
51
cd ./temp
47
52
temp_dir=$( pwd)
48
53
49
54
# 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
51
56
52
57
packages=$( GH_HOST=" $SOURCE_HOST " GH_TOKEN=$GH_SOURCE_PAT gh api --paginate " /orgs/$SOURCE_ORG /packages?package_type=npm" -q ' .[] | .name + " " + .repository.name' )
53
58
@@ -57,32 +62,44 @@ echo "$packages" | while IFS= read -r response; do
57
62
repo_name=$( echo " $response " | cut -d ' ' -f 2)
58
63
59
64
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
64
81
echo " $version "
65
82
66
83
# 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 " )
68
85
69
86
# check for error
70
87
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
74
91
fi
75
92
76
- # download
93
+ # download
77
94
curl -sS -H " Authorization: token $GH_SOURCE_PAT " -L -o $package_name -$version .tgz $url
78
-
95
+
79
96
# untar
80
97
mkdir -p ./$package_name -$version
81
98
# if you run into permissions issue, add a `sudo` here
82
99
tar xzf $package_name -$version .tgz -C $package_name -$version
83
100
cd $package_name -$version /package
84
101
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
86
103
cd ./../../
87
104
88
105
done
0 commit comments