2
2
3
3
# ## Configuration ###
4
4
5
- # This script will use local copies of the repositories to reduce network traffic
6
- MY_REPOS=" $HOME /GitHub"
7
-
8
5
# All repositories are assumed to be hosted in this GitHub org
9
6
GITHUB_ORG=" scratchfoundation"
10
7
8
+ # This is the list of repositories to merge into the monorepo
11
9
ALL_REPOS="
12
10
scratch-audio \
13
11
scratch-blocks \
@@ -27,10 +25,43 @@ ALL_REPOS="
27
25
paper.js \
28
26
"
29
27
28
+ # This is the directory where you have a copy of all the repositories you want to merge.
29
+ # This script will run `git fetch` on these repos, but otherwise will not modify them.
30
+ BUILD_CACHE=" ./monorepo.cache"
31
+
32
+ # The monorepo will be built here. Delete it to start over.
33
+ BUILD_OUT=" ./monorepo.out"
34
+
35
+ # Temporary clones will be placed here. If the script completes successfully, this directory will be deleted.
36
+ BUILD_TMP=" ./monorepo.tmp"
37
+
38
+ # Use ${BASE_COMMIT} from ${BASE_REPO} as the starting point for the monorepo.
39
+ BASE_COMMIT=" $( git rev-parse develop) "
40
+ BASE_REPO=" scratch-editor"
41
+
30
42
# ## End configuration ###
31
43
32
44
set -e
33
45
46
+ if [ ! -d " $BUILD_CACHE " ]; then
47
+ echo " Please link $BUILD_CACHE to a directory with a copy of all the repositories you want to merge."
48
+ echo " For example, if you have ~/GitHub/scratch-audio, ~/GitHub/scratch-blocks, etc., then run:"
49
+ echo " ln -s ~/GitHub $BUILD_CACHE "
50
+ exit 1
51
+ fi
52
+
53
+ if [ -d " $BUILD_TMP " ]; then
54
+ echo " Please remove $BUILD_TMP before running this script."
55
+ echo " You may want: rm -rf $BUILD_TMP $BUILD_OUT "
56
+ exit 1
57
+ fi
58
+
59
+ if [ -d " $BUILD_OUT " ]; then
60
+ echo " Please remove $BUILD_OUT before running this script."
61
+ echo " You may want: rm -rf $BUILD_TMP $BUILD_OUT "
62
+ exit 1
63
+ fi
64
+
34
65
# Thanks to https://stackoverflow.com/a/17841619
35
66
join_args () {
36
67
local d=${1-} f=${2-}
@@ -39,43 +70,49 @@ join_args () {
39
70
fi
40
71
}
41
72
73
+ init_monorepo () {
74
+ git init " $BUILD_OUT "
75
+ git -C
" $BUILD_OUT " remote add origin
" [email protected] :${GITHUB_ORG} /${BASE_REPO} .git"
76
+ git -C " $BUILD_OUT " fetch --all
77
+ git -C " $BUILD_OUT " checkout -b develop " $BASE_COMMIT "
78
+ }
79
+
42
80
add_repo_to_monorepo () {
43
81
REPO_NAME=" $1 "
44
82
ORG_AND_REPO_NAME=" ${GITHUB_ORG} /${REPO_NAME} "
45
83
echo " Working on $ORG_AND_REPO_NAME "
46
- mkdir -p tmp
47
84
48
85
#
49
86
# Clone
50
87
#
51
88
52
89
# refresh the cache
53
- git -C " ${MY_REPOS } /${REPO_NAME} " fetch --all
90
+ git -C " ${BUILD_CACHE } /${REPO_NAME} " fetch --all
54
91
# reference = go faster
55
- git -C
tmp clone --single-branch --reference
" $MY_REPOS " / " $ REPO_NAME" " [email protected] :${ORG_AND_REPO_NAME} .git"
92
+ git -C
" $BUILD_TMP " clone --single-branch --reference
" $( realpath " $BUILD_CACHE " ) / ${ REPO_NAME} " " [email protected] :${ORG_AND_REPO_NAME} .git"
56
93
# get ready to disconnect reference repo
57
- git -C " tmp /${REPO_NAME} " repack -a
94
+ git -C " ${BUILD_TMP} /${REPO_NAME} " repack -a
58
95
# actually disconnect the reference repo
59
- rm -f " tmp /${REPO_NAME} /.git/objects/info/alternates"
96
+ rm -f " ${BUILD_TMP} /${REPO_NAME} /.git/objects/info/alternates"
60
97
61
98
#
62
99
# Move to subdirectory
63
100
#
64
101
65
102
# make filter-repo accept this as a fresh clone
66
- git -C " tmp /${REPO_NAME} " gc
103
+ git -C " ${BUILD_TMP} /${REPO_NAME} " gc
67
104
68
105
# rewrite history as if all this work happened in a subdirectory
69
106
# "git mv" is simpler but makes history less visible unless you explicitly use "--follow"
70
- if [ ! -f " tmp /${REPO_NAME} /.gitmodules" ]; then
107
+ if [ ! -f " ${BUILD_TMP} /${REPO_NAME} /.gitmodules" ]; then
71
108
# this is significantly faster than the special case below
72
- git -C " tmp /${REPO_NAME} " filter-repo --to-subdirectory-filter " workspaces/$REPO_NAME "
109
+ git -C " ${BUILD_TMP} /${REPO_NAME} " filter-repo --to-subdirectory-filter " workspaces/$REPO_NAME "
73
110
else
74
111
# the .gitmodules file must stay in the repository root, but the paths inside it must be rewritten
75
112
# this is complicated for the reasons described here: https://github.com/newren/git-filter-repo/issues/158
76
113
# this is also slower, so we only do it for repositories that have submodules
77
114
# if we have more than one, this will cause merge conflicts
78
- git -C " tmp /${REPO_NAME} " filter-repo \
115
+ git -C " ${BUILD_TMP} /${REPO_NAME} " filter-repo \
79
116
--filename-callback " return filename if filename == b'.gitmodules' else b'workspaces/${REPO_NAME} /'+filename" \
80
117
--blob-callback " if blob.data.startswith(b'[submodule '): blob.data = blob.data.replace(b'path = ', b'path = workspaces/${REPO_NAME} /')"
81
118
fi
@@ -84,26 +121,26 @@ add_repo_to_monorepo () {
84
121
# Merge it in
85
122
#
86
123
87
- BRANCH=" $( git -C " tmp /${REPO_NAME} " branch --format=" %(refname:short)" ) "
124
+ BRANCH=" $( git -C " ${BUILD_TMP} /${REPO_NAME} " branch --format=" %(refname:short)" ) "
88
125
89
- git remote add " temp-$REPO_NAME " " tmp /${REPO_NAME} "
90
- git fetch --no-tags " temp-$REPO_NAME "
91
- git merge --allow-unrelated-histories --no-verify -m " chore(deps): add workspaces/$REPO_NAME " " temp-$REPO_NAME /$BRANCH "
92
- git remote remove " temp-$REPO_NAME "
93
- rm -rf " tmp /${REPO_NAME} "
126
+ git -C " $BUILD_OUT " remote add " temp-$REPO_NAME " " $( realpath " ${BUILD_TMP} " ) /${REPO_NAME} "
127
+ git -C " $BUILD_OUT " fetch --no-tags " temp-$REPO_NAME "
128
+ git -C " $BUILD_OUT " merge --allow-unrelated-histories --no-verify -m " chore(deps): add workspaces/$REPO_NAME " " temp-$REPO_NAME /$BRANCH "
129
+ git -C " $BUILD_OUT " remote remove " temp-$REPO_NAME "
130
+ rm -rf " ${BUILD_TMP} /${REPO_NAME} "
94
131
}
95
132
96
133
fixup_current_branch () {
97
134
# submodules could be necessary for build/test scripts
98
- git submodule update --init --recursive
135
+ git -C " $BUILD_OUT " submodule update --init --recursive
99
136
100
137
# remove repository-level configuration and dependencies, like commitlint
101
138
# do not remove configuration and dependencies that could vary between packages, like semantic-release
102
139
# some of these files only make sense in the root of the repository
103
140
# others could be in subdirectories, like .editorconfig, but centralizing them makes consistency easier
104
141
# it would be nice to merge all the package-lock.json files into one but it's not clear how to do that
105
142
# just remove the package-lock.json files for now, and build a new one with "npm i" later
106
- rm -rf workspaces/* /{.circleci,.editorconfig,.gitattributes,.github,.husky,package-lock.json,renovate.json* }
143
+ rm -rf " $BUILD_OUT " / workspaces/* /{.circleci,.editorconfig,.gitattributes,.github,.husky,package-lock.json,renovate.json* }
107
144
for REPO in $ALL_REPOS ; do
108
145
jq -f <( join_args ' | ' \
109
146
' if .scripts.prepare == "husky install" then del(.scripts.prepare) else . end' \
@@ -116,14 +153,14 @@ fixup_current_branch () {
116
153
' del(.devDependencies."cz-conventional-changelog")' \
117
154
' del(.devDependencies."husky")' \
118
155
' if .devDependencies == {} then del(.devDependencies) else . end' \
119
- ) " workspaces/${REPO} /package.json" | sponge " workspaces/${REPO} /package.json"
156
+ ) " ${BUILD_OUT} / workspaces/${REPO} /package.json" | sponge " ${BUILD_OUT} / workspaces/${REPO} /package.json"
120
157
done
121
- git commit -m " chore: remove repo-level configuration and deps from workspaces/*" \
158
+ git -C " $BUILD_OUT " commit -m " chore: remove repo-level configuration and deps from workspaces/*" \
122
159
workspaces
123
160
124
- npm i
125
- npm i --package-lock-only # sometimes this is necessary to get a consistent package-lock.json
126
- git commit -m " chore(deps): build initial real package-lock.json" \
161
+ npm -C " $BUILD_OUT " i
162
+ npm -C " $BUILD_OUT " i --package-lock-only # sometimes this is necessary to get a consistent package-lock.json
163
+ git -C " $BUILD_OUT " commit -m " chore(deps): build initial real package-lock.json" \
127
164
package.json package-lock.json
128
165
129
166
for REPO in $ALL_REPOS ; do
@@ -133,50 +170,56 @@ fixup_current_branch () {
133
170
OPTDEPS=" "
134
171
PEERDEPS=" "
135
172
for DEP in $ALL_REPOS ; do
136
- if jq -e .dependencies.\" $DEP \" " workspaces/${REPO} /package.json" > /dev/null; then
173
+ if jq -e .dependencies.\" $DEP \" " ${BUILD_OUT} / workspaces/${REPO} /package.json" > /dev/null; then
137
174
REMOVEDEPS=" $REMOVEDEPS $DEP "
138
175
DEPS=" $DEPS $DEP @*"
139
176
fi
140
- if jq -e .devDependencies.\" $DEP \" " workspaces/${REPO} /package.json" > /dev/null; then
177
+ if jq -e .devDependencies.\" $DEP \" " ${BUILD_OUT} / workspaces/${REPO} /package.json" > /dev/null; then
141
178
REMOVEDEPS=" $REMOVEDEPS $DEP "
142
179
DEVDEPS=" $DEVDEPS $DEP @*"
143
180
fi
144
- if jq -e .optionalDependencies.\" $DEP \" " workspaces/${REPO} /package.json" > /dev/null; then
181
+ if jq -e .optionalDependencies.\" $DEP \" " ${BUILD_OUT} / workspaces/${REPO} /package.json" > /dev/null; then
145
182
REMOVEDEPS=" $REMOVEDEPS $DEP "
146
183
OPTDEPS=" $OPTDEPS $DEP @*"
147
184
fi
148
- if jq -e .peerDependencies.\" $DEP \" " workspaces/${REPO} /package.json" > /dev/null; then
185
+ if jq -e .peerDependencies.\" $DEP \" " ${BUILD_OUT} / workspaces/${REPO} /package.json" > /dev/null; then
149
186
REMOVEDEPS=" $REMOVEDEPS $DEP "
150
187
PEERDEPS=" $PEERDEPS $DEP @*"
151
188
fi
152
189
done
153
190
if [ -n " $REMOVEDEPS " ]; then
154
- npm uninstall $REMOVEDEPS -w $REPO
191
+ npm -C $BUILD_OUT uninstall $REMOVEDEPS -w " $REPO "
155
192
if [ -n " $DEPS " ]; then
156
- npm i --save --save-exact $DEPS -w $REPO
193
+ npm -C " $BUILD_OUT " i --save --save-exact $DEPS -w " $REPO "
157
194
fi
158
195
if [ -n " $DEVDEPS " ]; then
159
- npm i --save-dev --save-exact $DEVDEPS -w $REPO
196
+ npm -C " $BUILD_OUT " i --save-dev --save-exact $DEVDEPS -w " $REPO "
160
197
fi
161
198
if [ -n " $OPTDEPS " ]; then
162
- npm i --save-optional --save-exact $OPTDEPS -w $REPO
199
+ npm -C " $BUILD_OUT " i --save-optional --save-exact $OPTDEPS -w " $REPO "
163
200
fi
164
201
if [ -n " $PEERDEPS " ]; then
165
- npm i --save-peer --save-exact $PEERDEPS -w $REPO
202
+ npm -C " $BUILD_OUT " i --save-peer --save-exact $PEERDEPS -w " $REPO "
166
203
fi
167
204
fi
168
205
done
169
206
170
- git commit -m " chore(deps): use workspace versions of all local packages" \
207
+ git -C " $BUILD_OUT " commit -m " chore(deps): use workspace versions of all local packages" \
171
208
package.json package-lock.json workspaces/* /package.json
172
209
}
173
210
174
211
# ## Do the things! ###
175
212
213
+ init_monorepo
214
+
215
+ mkdir -p " $BUILD_TMP "
216
+
176
217
for REPO in $ALL_REPOS ; do
177
218
add_repo_to_monorepo " $REPO "
178
219
done
179
220
180
- ( rmdir tmp || true) 2> /dev/null
221
+ rmdir " $BUILD_TMP "
181
222
182
223
fixup_current_branch
224
+
225
+ echo " All done!"
0 commit comments