geet-geet 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -0
- package/bin/geet.sh +150 -0
- package/docs/AUTO_PROMOTE.md +173 -0
- package/docs/CONTRIBUTING.md +142 -0
- package/docs/DEMO.md +131 -0
- package/docs/DEV_GUIDE.md +519 -0
- package/docs/FAQ.md +128 -0
- package/docs/MERGE_KEEP_OURS.md +243 -0
- package/docs/MULTI_LAYERED_TEMPLATES.md +92 -0
- package/docs/PREVENT_COMMIT_PATTERNS.md +250 -0
- package/docs/PUBLISHING_A_TEMPLATE.md +150 -0
- package/docs/UNDERSTANDING_GEET.md +68 -0
- package/docs/USING_A_TEMPLATE.md +131 -0
- package/lib/detach.sh +225 -0
- package/lib/digest-and-locate.sh +476 -0
- package/lib/doctor.sh +252 -0
- package/lib/flags.sh +52 -0
- package/lib/ghcli.sh +386 -0
- package/lib/git.sh +55 -0
- package/lib/help.sh +53 -0
- package/lib/ignored.sh +4 -0
- package/lib/include.sh +54 -0
- package/lib/init.sh +234 -0
- package/lib/install.sh +166 -0
- package/lib/logger.sh +278 -0
- package/lib/pre-commit/auto-promote-pgi.sh +20 -0
- package/lib/pre-commit/auto-promote-readme.sh +20 -0
- package/lib/pre-commit/hook.sh +66 -0
- package/lib/pre-commit/protect-patterns.sh +76 -0
- package/lib/pre-commit/unstage-soft-detached-files.sh +48 -0
- package/lib/prework.sh +181 -0
- package/lib/session.sh +111 -0
- package/lib/split.sh +120 -0
- package/lib/sync.sh +98 -0
- package/lib/template.sh +635 -0
- package/lib/tree.sh +252 -0
- package/lib/whoops.sh +37 -0
- package/package.json +15 -0
package/lib/template.sh
ADDED
|
@@ -0,0 +1,635 @@
|
|
|
1
|
+
# template.sh — sourceable template creation function
|
|
2
|
+
# Usage:
|
|
3
|
+
# source template.sh
|
|
4
|
+
# template [layer-name]
|
|
5
|
+
#
|
|
6
|
+
# Creates a new template layer in the current app.
|
|
7
|
+
|
|
8
|
+
###############################################################################
|
|
9
|
+
# template.sh — promote the CURRENT APP into a NEW TEMPLATE REPO that the owner can commit files into, and publish
|
|
10
|
+
#
|
|
11
|
+
# This script creates a NEW hidden layer folder (e.g. .MyApp2 or .sk2)
|
|
12
|
+
# and initializes a template git repo for it, WITHOUT disturbing:
|
|
13
|
+
# - the app repo (.git)
|
|
14
|
+
# - any existing layers (e.g. .geet)
|
|
15
|
+
#
|
|
16
|
+
# Think of this as:
|
|
17
|
+
# “I built something useful, and I think that SOME but not all of my code is re-usable.
|
|
18
|
+
# I want to publish some of my code for other's to use (or to re-use myself)...
|
|
19
|
+
# But I don't want to spend weeks refactoring to split apart the reusable code from the implementation specific code
|
|
20
|
+
# In fact, it may not even be possible”
|
|
21
|
+
#
|
|
22
|
+
# -----------------------------------------------------------------------------
|
|
23
|
+
# What this script does:
|
|
24
|
+
#
|
|
25
|
+
# 1) Sets up the new layer
|
|
26
|
+
# MyApp/
|
|
27
|
+
# .git <- this is your app's git dir which tracks EVERYTHING, not just template repo code, but including template repo code
|
|
28
|
+
# .mytemplate/ <<<<- THIS is what we are setting up
|
|
29
|
+
# dot-git/ <- this is the .git of the template repo, just in an odd spot with an odd name
|
|
30
|
+
# git.sh <- base git command for the template's repo
|
|
31
|
+
# geet.sh <- calls geet but specifies which template we are in
|
|
32
|
+
# .geetinclude <- to allow adding files to the template's repo
|
|
33
|
+
# .geetexclude <- this is the .gitignore used by git.sh
|
|
34
|
+
# README.md <- just helps explain stuff to you and your users
|
|
35
|
+
# ... <- the rest of your source code for both the app and the template, interleaved
|
|
36
|
+
# .gitignore <- your app's .gitignore, not to be confused with .mytemplate/.geetexclude, this file mus also exclude **/dot-git/
|
|
37
|
+
# README.md <- your app's README, not to be confused with the template's readme. this leads to some complication for developers working on both an app and a template... they have to pull a switcheroo....
|
|
38
|
+
#
|
|
39
|
+
# 2) Initialize a NEW template git repo and commits some files to it
|
|
40
|
+
# .mytemplate/dot-git/
|
|
41
|
+
#
|
|
42
|
+
# IMPORTANT:
|
|
43
|
+
# - This does have to temporarily touch .git (the app's git dir) to move it out of the way, during the init, but it puts it back immediately, unscathed
|
|
44
|
+
# - dot-git/ should NEVER be committed to any git repo
|
|
45
|
+
#
|
|
46
|
+
###############################################################################
|
|
47
|
+
|
|
48
|
+
template() {
|
|
49
|
+
debug "creating new template layer, APP_NAME=$APP_NAME"
|
|
50
|
+
|
|
51
|
+
###############################################################################
|
|
52
|
+
# ARGUMENT PARSING & VALIDATION
|
|
53
|
+
###############################################################################
|
|
54
|
+
|
|
55
|
+
# Required argument: explicit name for the new template layer
|
|
56
|
+
# Example:
|
|
57
|
+
# $GEET_ALIAS template sk2 -> creates .sk2
|
|
58
|
+
#
|
|
59
|
+
RAW_NAME="${1:-}"
|
|
60
|
+
|
|
61
|
+
# Show help if requested
|
|
62
|
+
if [[ "$RAW_NAME" == "help" || "$RAW_NAME" == "-h" || "$RAW_NAME" == "--help" ]]; then
|
|
63
|
+
cat <<EOF
|
|
64
|
+
$GEET_ALIAS template — promote the CURRENT APP into a NEW TEMPLATE REPO
|
|
65
|
+
|
|
66
|
+
This script creates a NEW hidden layer folder (e.g., .MyApp2 or .sk2)
|
|
67
|
+
and initializes a template git repo for it, WITHOUT disturbing:
|
|
68
|
+
- the app repo (.git)
|
|
69
|
+
- any existing layers (e.g., .geet)
|
|
70
|
+
|
|
71
|
+
Think of this as:
|
|
72
|
+
"I built something useful, and I think that SOME but not all of my code is re-usable.
|
|
73
|
+
I want to publish some of my code for others to use (or to re-use myself)...
|
|
74
|
+
But I don't want to spend weeks refactoring to split apart the reusable code from
|
|
75
|
+
the implementation specific code. In fact, it may not even be possible"
|
|
76
|
+
|
|
77
|
+
Usage:
|
|
78
|
+
$GEET_ALIAS template <name> [description]
|
|
79
|
+
|
|
80
|
+
Examples:
|
|
81
|
+
$GEET_ALIAS template mytemplate
|
|
82
|
+
$GEET_ALIAS template mytemplate "A React Native base project"
|
|
83
|
+
$GEET_ALIAS template sk2 "Starter kit v2 with TypeScript"
|
|
84
|
+
|
|
85
|
+
Requirements:
|
|
86
|
+
- <name> must be non-empty and different from the app name
|
|
87
|
+
- <name> cannot contain spaces
|
|
88
|
+
|
|
89
|
+
What this creates:
|
|
90
|
+
- $DD_APP_NAME/$DD_TEMPLATE_NAME/ (new layer directory)
|
|
91
|
+
- $DD_APP_NAME/$DD_TEMPLATE_NAME/dot-git/ (template's git repository)
|
|
92
|
+
- $DD_APP_NAME/$DD_TEMPLATE_NAME/geet-git.sh (git wrapper for template repo)
|
|
93
|
+
- $DD_APP_NAME/$DD_TEMPLATE_NAME/geet.sh (geet wrapper for template)
|
|
94
|
+
- $DD_APP_NAME/$DD_TEMPLATE_NAME/.geetinclude (whitelist of files to include)
|
|
95
|
+
- $DD_APP_NAME/$DD_TEMPLATE_NAME/.geetexclude (compiled excludes)
|
|
96
|
+
- $DD_APP_NAME/$DD_TEMPLATE_NAME/README.md (template documentation)
|
|
97
|
+
EOF
|
|
98
|
+
return 0
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
# Detect GH_USER lazily (only when needed for template creation)
|
|
102
|
+
if [[ "$GH_USER" == "$DEFAULT_GH_USER" ]] || [[ -z "$GH_USER" ]]; then
|
|
103
|
+
get_gh_user
|
|
104
|
+
fi
|
|
105
|
+
TEMPLATE_GH_USER=GH_USER
|
|
106
|
+
debug "GH_USER=$GH_USER"
|
|
107
|
+
# Validation: must be non-empty
|
|
108
|
+
if [[ -z "$RAW_NAME" ]]; then
|
|
109
|
+
die "template requires a name argument (e.g., '$GEET_ALIAS template mytemplate')"
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
# Normalize: remove leading dot if present
|
|
113
|
+
LAYER_NAME="${RAW_NAME#.}"
|
|
114
|
+
|
|
115
|
+
# Validation: cannot be empty after normalization
|
|
116
|
+
if [[ -z "$LAYER_NAME" ]]; then
|
|
117
|
+
die "template name cannot be empty or just a dot"
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
# Validation: cannot contain spaces
|
|
121
|
+
if [[ "$LAYER_NAME" =~ [[:space:]] ]]; then
|
|
122
|
+
die "template name cannot contain spaces: '$LAYER_NAME'"
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
# Validation: must be different from app name
|
|
126
|
+
if [[ "$LAYER_NAME" == "$APP_NAME" ]]; then
|
|
127
|
+
die "template name must be different from app name: '$APP_NAME'"
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
NEW_LAYER_DIR="$APP_DIR/.${LAYER_NAME}"
|
|
131
|
+
TEMPLATE_DIR="$NEW_LAYER_DIR"
|
|
132
|
+
|
|
133
|
+
# Optional description argument
|
|
134
|
+
NEW_TEMPLATE_DESC="${2:-}"
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
debug "new template layer will be created at: $NEW_LAYER_DIR"
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
###############################################################################
|
|
144
|
+
# SAFETY CHECKS
|
|
145
|
+
###############################################################################
|
|
146
|
+
|
|
147
|
+
# Check if we have a git repo in current directory
|
|
148
|
+
if [[ ! -d "$APP_DIR/.git" ]]; then
|
|
149
|
+
log "no git repo found at $APP_DIR/.git"
|
|
150
|
+
log "initializing new git repo..."
|
|
151
|
+
git -C "$APP_DIR" init >/dev/null
|
|
152
|
+
fi
|
|
153
|
+
|
|
154
|
+
# Idempotency check - if layer already exists, exit cleanly
|
|
155
|
+
if [[ -e "$NEW_LAYER_DIR" ]]; then
|
|
156
|
+
log "layer already exists: $NEW_LAYER_DIR"
|
|
157
|
+
log "leaving existing layer undisturbed"
|
|
158
|
+
return 0
|
|
159
|
+
fi
|
|
160
|
+
|
|
161
|
+
# We expect the base layer (TEMPLATE_DIR) to have the required files
|
|
162
|
+
if [[ ! -f "$GEET_LIB/git.sh" || ! -f "$GEET_LIB/init.sh" ]]; then
|
|
163
|
+
die "source files missing (expected at $GEET_LIB/)"
|
|
164
|
+
fi
|
|
165
|
+
|
|
166
|
+
###############################################################################
|
|
167
|
+
# CREATE NEW LAYER STRUCTURE
|
|
168
|
+
###############################################################################
|
|
169
|
+
|
|
170
|
+
log "creating new template layer: .$LAYER_NAME"
|
|
171
|
+
|
|
172
|
+
# make empty dirs
|
|
173
|
+
mkdir -p "$NEW_LAYER_DIR"
|
|
174
|
+
|
|
175
|
+
# append the layer name into the hierarchy
|
|
176
|
+
# Copy from the base template's .geethier if it exists
|
|
177
|
+
if [[ -f "$TEMPLATE_DIR/.geethier" ]]; then
|
|
178
|
+
cp "$TEMPLATE_DIR/.geethier" "$NEW_LAYER_DIR/.geethier"
|
|
179
|
+
else
|
|
180
|
+
touch "$NEW_LAYER_DIR/.geethier"
|
|
181
|
+
fi
|
|
182
|
+
echo "$LAYER_NAME" >> "$NEW_LAYER_DIR/.geethier"
|
|
183
|
+
debug "made" "$NEW_LAYER_DIR/.geethier"
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
cat > "$NEW_LAYER_DIR/README.md" <<EOFREADME
|
|
187
|
+
# Welcome to the "$LAYER_NAME" template!
|
|
188
|
+
|
|
189
|
+
> ${NEW_TEMPLATE_DESC:-a template to build from}
|
|
190
|
+
|
|
191
|
+
This template was created with [geet](https://github.com/modularizer/geet),
|
|
192
|
+
a CLI git wrapper which acts as an alternative to git submodules,
|
|
193
|
+
allowing publishing a template which controls files which are interspersed in the same working directory as your project.
|
|
194
|
+
|
|
195
|
+
## QUICKSTART
|
|
196
|
+
\`\`\`bash
|
|
197
|
+
npm install -g geet-geet
|
|
198
|
+
geet install $GH_USER/$LAYER_NAME.git $DD_APP_NAME
|
|
199
|
+
\`\`\`
|
|
200
|
+
|
|
201
|
+
### Operations
|
|
202
|
+
### 1. Pull template updates
|
|
203
|
+
\`\`\`bash
|
|
204
|
+
geet pull
|
|
205
|
+
\`\`\`
|
|
206
|
+
|
|
207
|
+
### 2. Soft-detach a file or many files
|
|
208
|
+
> "If I diverge from the template, let me"
|
|
209
|
+
|
|
210
|
+
This applies keep-ours merges to only accept ff-only updates to specific files, and configures a precommit hook to unstage these files if you accidentally stage your updates.
|
|
211
|
+
\`\`\`bash
|
|
212
|
+
geet slide app/index.tsx
|
|
213
|
+
\`\`\`
|
|
214
|
+
|
|
215
|
+
### 3. Hard-detach
|
|
216
|
+
> "I am absolutely changing this file and diverging from the template"
|
|
217
|
+
|
|
218
|
+
Done via --skip-worktree
|
|
219
|
+
|
|
220
|
+
\`\`\`bash
|
|
221
|
+
geet detach app/index.tsx
|
|
222
|
+
\`\`\`
|
|
223
|
+
|
|
224
|
+
### 4. Check what is tracked by the template
|
|
225
|
+
\`\`\`bash
|
|
226
|
+
geet tree
|
|
227
|
+
\`\`\`
|
|
228
|
+
|
|
229
|
+
### Everything else
|
|
230
|
+
Just use \`git\` for commands related to your app and \`geet\` for any git commands related to the template repo
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Things to know:
|
|
235
|
+
1. Typically, template files get double-tracked
|
|
236
|
+
- They get pulled into your working directory and tracked by YOU
|
|
237
|
+
- They ALSO are tracked by the remote template repo
|
|
238
|
+
- If and when you wish, you can pull updates from the template repo into your project and add and commit the files into your repo
|
|
239
|
+
- If you are a developer/contributor of the template repo, you can optionally push code back to the template repo using a different git command
|
|
240
|
+
2. \`$GEET_ALIAS\` is the suggested entrypoint for all your pull/push git-like commands. It protects you and adds some features. More on that later.
|
|
241
|
+
3. You can either operate your template on an **include basis (recommended)** or and exclude basis.
|
|
242
|
+
- You probably know about standard \`.gitignore\` files, but in this case since we have all the app code stuff can be a bit different.
|
|
243
|
+
- [.$LAYER_NAME/.geetinclude](.$LAYER_NAME/.geetinclude) is a whitelist that gets parsed into [.$LAYER_NAME/.geetexclude](.$LAYER_NAME/.geetexclude) which is acting as the template's \`.gitignore\`
|
|
244
|
+
- Let's say your actual full app is 80% of the code and the generic stuff you are turning into a template is only 20% of the code, it might be best to exclude everything to avoid committing implementation-specific code to the template repo, then add some generic files and folders back in, to allow commiting them to the template. This is when you would use .geetinclude for the convenience
|
|
245
|
+
- Alternatively, if your primary goal is to develop a template, and 80% of your code is reusable, but then you just have 20% of "sample" code that you don't want included, maybe just overwrite .geetexclude file entierly, **but leave \*\*/dot-git/ excluded**
|
|
246
|
+
- read the comments in .geetexclude for more info
|
|
247
|
+
- use `$GEET_ALIAS tree` to see what is currently included in the template repo
|
|
248
|
+
4. geet supports many layered templating, so if you want to extend a template and publish as a new template it is definitly possible! See .geehier to see how many levels this one has
|
|
249
|
+
|
|
250
|
+
If you're the owner of this template, feel free to overwrite or add to this README to tell users about what your project does. It's all your's from here.
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
EOFREADME
|
|
254
|
+
debug "wrote" "$NEW_LAYER_DIR/README.md"
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
cat > "$NEW_LAYER_DIR/parent.gitignore" <<EOFPGI
|
|
258
|
+
# This is a sample of your APP's gitignore, (NOT the template repo's gitignore)
|
|
259
|
+
# You can extend or overwrite it, but it NEEDS to ignore the following two things
|
|
260
|
+
**/dot-git/
|
|
261
|
+
**/untracked-template-config.env
|
|
262
|
+
EOFPGI
|
|
263
|
+
debug "wrote" "$NEW_LAYER_DIR/parent.gitignore"
|
|
264
|
+
# Helper functions to create .env files
|
|
265
|
+
#write_global_config() {
|
|
266
|
+
# local target="$GEET_LIB/../config.env"
|
|
267
|
+
# # Only create if it doesn't exist (don't overwrite user preferences)
|
|
268
|
+
# if [[ -f "$target" ]]; then
|
|
269
|
+
# debug "global config already exists at $target, skipping"
|
|
270
|
+
# return 0
|
|
271
|
+
# fi
|
|
272
|
+
#
|
|
273
|
+
# cat > "$target" <<'EOF'
|
|
274
|
+
## Geet Global User Preferences
|
|
275
|
+
## This file contains global settings that apply to all geet operations
|
|
276
|
+
## Edit these values to customize your geet experience
|
|
277
|
+
#
|
|
278
|
+
#SHOW_LEVEL=true
|
|
279
|
+
#COLOR_MODE=light
|
|
280
|
+
#COLOR_SCOPE=line
|
|
281
|
+
#EOF
|
|
282
|
+
# log "created global config at $target"
|
|
283
|
+
#}
|
|
284
|
+
extract_flag --topics TEMPLATE_TOPICS
|
|
285
|
+
extract_flag --homepage TEMPLATE_HOMEPAGE
|
|
286
|
+
write_geet_template_env() {
|
|
287
|
+
local target="$NEW_LAYER_DIR/template-config.env"
|
|
288
|
+
cat > "$target" <<EOF
|
|
289
|
+
# ______________________________________________________________________________________________________________________
|
|
290
|
+
# Basics
|
|
291
|
+
# ______________________________________________________________________________________________________________________
|
|
292
|
+
# What is your project?
|
|
293
|
+
TEMPLATE_NAME=$LAYER_NAME
|
|
294
|
+
TEMPLATE_DESC="$NEW_TEMPLATE_DESC"
|
|
295
|
+
TEMPLATE_TOPICS="geet,template,$TEMPLATE_TOPICS"
|
|
296
|
+
TEMPLATE_HOMEPAGE="$TEMPLATE_HOMEPAGE"
|
|
297
|
+
|
|
298
|
+
# ______________________________________________________________________________________________________________________
|
|
299
|
+
# REPO LOCATION
|
|
300
|
+
# ______________________________________________________________________________________________________________________
|
|
301
|
+
# Where is the repo? (this should get autopopulated when you run '$GEET_ALIAS template', but you can fix it here)
|
|
302
|
+
TEMPLATE_GH_USER=$GH_USER
|
|
303
|
+
TEMPLATE_GH_NAME=$LAYER_NAME
|
|
304
|
+
TEMPLATE_GH_URL=https://github.com/$GH_USER/$LAYER_NAME
|
|
305
|
+
TEMPLATE_GH_SSH=git@github.com:$GH_USER/$LAYER_NAME.git
|
|
306
|
+
TEMPLATE_GH_HTTPS=https://github.com/$GH_USER/$LAYER_NAME.git
|
|
307
|
+
|
|
308
|
+
# ______________________________________________________________________________________________________________________
|
|
309
|
+
# Configuring Help Text
|
|
310
|
+
# ______________________________________________________________________________________________________________________
|
|
311
|
+
# Is there an alias to your /path/to/.$TEMPLATE_NAME/geet.sh?
|
|
312
|
+
# maybe you added to package.json or something like that
|
|
313
|
+
# update it here to update the CLI docs and help text
|
|
314
|
+
GEET_ALIAS="${GEET_ALIAS}"
|
|
315
|
+
|
|
316
|
+
# also use in help text thorughout the CLI
|
|
317
|
+
DD_APP_NAME=MyApp
|
|
318
|
+
DD_TEMPLATE_NAME=$LAYER_NAME
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
# ______________________________________________________________________________________________________________________
|
|
322
|
+
# Configuring Precommit
|
|
323
|
+
# ______________________________________________________________________________________________________________________
|
|
324
|
+
PREVENT_COMMIT_FILE_PATTERNS=".*secret.*"
|
|
325
|
+
|
|
326
|
+
# Prevent committing content matching these patterns (pipe-delimited regex)
|
|
327
|
+
PREVENT_COMMIT_CONTENT_PATTERNS="API_KEY=|SECRET_KEY=|password:\\s*[\"'].*[\"']|TODO.*remove.*template|CUSTOMER_ID=|stripe_live_key"
|
|
328
|
+
EOF
|
|
329
|
+
debug "wrote $target"
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
# Create global config if it doesn't exist
|
|
334
|
+
#write_global_config
|
|
335
|
+
|
|
336
|
+
# Create template .env configuration files
|
|
337
|
+
write_geet_template_env
|
|
338
|
+
log "created template .env configuration files"
|
|
339
|
+
|
|
340
|
+
# Create or copy .geetinclude from base template
|
|
341
|
+
if [[ -f "$TEMPLATE_DIR/.geetinclude" ]]; then
|
|
342
|
+
log "copying .geetinclude template from $TEMPLATE_DIR/.geetinclude"
|
|
343
|
+
cp "$TEMPLATE_DIR/.geetinclude" "$NEW_LAYER_DIR/.geetinclude"
|
|
344
|
+
else
|
|
345
|
+
cat > "$NEW_LAYER_DIR/.geetinclude" <<'EOFGEETINCLUDE'
|
|
346
|
+
# Add your include stuff here, you can call '$GEET_ALIAS sync' to sync it to the .geetexclude if you wish, but it will also auto-sync on every geet command
|
|
347
|
+
EOFGEETINCLUDE
|
|
348
|
+
fi
|
|
349
|
+
|
|
350
|
+
# Create initial .geetexclude with base rules and markers for compiled includes
|
|
351
|
+
cat > "$NEW_LAYER_DIR/.geetexclude" <<EOFGEETEXCLUDE
|
|
352
|
+
#-----------------------------------------------------------------------------------------------------------------------
|
|
353
|
+
# FAQ SECTION (docs)
|
|
354
|
+
#-----------------------------------------------------------------------------------------------------------------------
|
|
355
|
+
# Q: Can I fully overwrite this file?
|
|
356
|
+
# A: YES BUT: you MUST ensure **/dot-git/ gets ignored/excluded
|
|
357
|
+
|
|
358
|
+
# Q: How to sync from my .$LAYER_NAME/.geetinclude?
|
|
359
|
+
# A: run \`$GEET_ALIAS sync\` or \`.$LAYER_NAME/bin/git-sync.sh\`
|
|
360
|
+
|
|
361
|
+
#-----------------------------------------------------------------------------------------------------------------------
|
|
362
|
+
# DEFAULT INCLUDE SECTION (optional)
|
|
363
|
+
# this section excludes everything, then adds back in some tools
|
|
364
|
+
#-----------------------------------------------------------------------------------------------------------------------
|
|
365
|
+
*
|
|
366
|
+
!*/
|
|
367
|
+
!.$LAYER_NAME/geet.sh
|
|
368
|
+
!.$LAYER_NAME/.geethier
|
|
369
|
+
!.$LAYER_NAME/.geetinclude
|
|
370
|
+
!.$LAYER_NAME/.geetexclude
|
|
371
|
+
!.$LAYER_NAME/template-config.env
|
|
372
|
+
!.$LAYER_NAME/parent.gitignore
|
|
373
|
+
!.$LAYER_NAME/geet-git.sh
|
|
374
|
+
!.$LAYER_NAME/README.md
|
|
375
|
+
!.$LAYER_NAME/pre-commit/*
|
|
376
|
+
|
|
377
|
+
#-----------------------------------------------------------------------------------------------------------------------
|
|
378
|
+
# AUTOGENERATED INCLUDE SECTION (optional)
|
|
379
|
+
# now add back in contents from .geetinclude, just flipped
|
|
380
|
+
#-----------------------------------------------------------------------------------------------------------------------
|
|
381
|
+
# GEETINCLUDESTART
|
|
382
|
+
|
|
383
|
+
# Whoops! either .$LAYER_NAME/.geetinclude is empty or .$LAYER_NAME/.geetinclude hasn't been synced
|
|
384
|
+
|
|
385
|
+
# GEETINCLUDEEND
|
|
386
|
+
|
|
387
|
+
#-----------------------------------------------------------------------------------------------------------------------
|
|
388
|
+
# MANUAL EXCLUDE SECTION
|
|
389
|
+
# treat this part as your standard .gitignore, if you want to operate on an exclude basis vs an include basis
|
|
390
|
+
# typically either add to this section OR use .geetinclude, not both
|
|
391
|
+
# technically you could use both this section and your .geetinclude, but why?
|
|
392
|
+
#-----------------------------------------------------------------------------------------------------------------------
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
#-----------------------------------------------------------------------------------------------------------------------
|
|
396
|
+
# MANDATORY EXCLUDE SECTION (required)
|
|
397
|
+
# we must never ever commit these files/folders
|
|
398
|
+
#-----------------------------------------------------------------------------------------------------------------------
|
|
399
|
+
**/dot-git/
|
|
400
|
+
**/untracked-template-config.env
|
|
401
|
+
EOFGEETEXCLUDE
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
###############################################################################
|
|
405
|
+
# MAKE A GIT WRAPPER
|
|
406
|
+
###############################################################################
|
|
407
|
+
cat > "$NEW_LAYER_DIR/geet-git.sh" <<EOFGIT
|
|
408
|
+
#!/usr/bin/env bash
|
|
409
|
+
|
|
410
|
+
THIS_FILE="\${BASH_SOURCE[0]}" # e.g. .$LAYER_NAME/geet-git.sh
|
|
411
|
+
THIS_DIR="\$(cd -- "\$(dirname -- "\$THIS_FILE")" && pwd)" # e.g. .$LAYER_NAME
|
|
412
|
+
PARENT_DIR="\$(dirname "\$THIS_DIR")" # e.g. # e.g. $PATH_TO/$APP_NAME
|
|
413
|
+
|
|
414
|
+
# this file behaves like git, but always specifies our correct git directory, working tree, and gitignore
|
|
415
|
+
# e.g. exec git --git-dir=".$LAYER_NAME/dot-git" --work-tree="." -c "core.excludesFile=.$LAYER_NAME/.geetexclude" "\$@"
|
|
416
|
+
exec git --git-dir="\$THIS_DIR/dot-git" --work-tree="\$PARENT_DIR" -c "core.excludesFile=\$THIS_DIR/.geetexclude" "\$@"
|
|
417
|
+
EOFGIT
|
|
418
|
+
chmod +x "$NEW_LAYER_DIR/geet-git.sh"
|
|
419
|
+
GEET_GIT="$NEW_LAYER_DIR/geet-git.sh"
|
|
420
|
+
log "created geet.sh wrapper (ensures excludesFile is always applied)"
|
|
421
|
+
|
|
422
|
+
###############################################################################
|
|
423
|
+
# MAKE A GEET WRAPPER
|
|
424
|
+
###############################################################################
|
|
425
|
+
cat > "$NEW_LAYER_DIR/geet.sh" <<EOFGEET
|
|
426
|
+
#!/usr/bin/env bash
|
|
427
|
+
# this file behaves like geet, but always specifies our correct template directory, so it can be called from anywhere
|
|
428
|
+
THIS_FILE="\${BASH_SOURCE[0]}" # e.g. .$LAYER_NAME/geet.sh
|
|
429
|
+
THIS_DIR="\$(cd -- "\$(dirname -- "\$THIS_FILE")" && pwd)" # e.g. .$LAYER_NAME
|
|
430
|
+
|
|
431
|
+
# now call geet, but tell it the absolute path of the template folder
|
|
432
|
+
# e.g. exec geet --geet-dir ".$LAYER_NAME" "\$@"
|
|
433
|
+
exec geet --geet-dir "\$THIS_DIR" "\$@"
|
|
434
|
+
EOFGEET
|
|
435
|
+
chmod +x "$NEW_LAYER_DIR/geet.sh"
|
|
436
|
+
log "created geet.sh wrapper (ensures geet sees the correct template dir)"
|
|
437
|
+
|
|
438
|
+
mkdir -p "$NEW_LAYER_DIR/pre-commit"
|
|
439
|
+
cat > "$NEW_LAYER_DIR/pre-commit/README.md" <<EOFGEET
|
|
440
|
+
# We support pre-commit hooks!
|
|
441
|
+
* Simply add .sh files to ${NEW_LAYER_DIR}/pre-commit/
|
|
442
|
+
* make certain they are executable (\`chmod +x $NEW_LAYER_DIR/pre-commit/*.sh\`)
|
|
443
|
+
* During pre-commit we will iterate through each and \`source\` each one.
|
|
444
|
+
* It's up to you which hooks you track with git or ignore, in general probably best to commit them
|
|
445
|
+
EOFGEET
|
|
446
|
+
chmod +x "$NEW_LAYER_DIR/pre-commit/README.md"
|
|
447
|
+
|
|
448
|
+
debug "added files"
|
|
449
|
+
###############################################################################
|
|
450
|
+
# INITIALIZE TEMPLATE GIT REPO FOR THE NEW LAYER
|
|
451
|
+
###############################################################################
|
|
452
|
+
NEW_DOTGIT="$NEW_LAYER_DIR/dot-git"
|
|
453
|
+
debug "NEW_DOTGIT=$NEW_DOTGIT"
|
|
454
|
+
|
|
455
|
+
if [ -d "$APP_DIR/.git" ]; then
|
|
456
|
+
log "temporarily moving $APP_DIR/.git to $APP_DIR/not-git"
|
|
457
|
+
mv "$APP_DIR/.git" "$APP_DIR/not-git"
|
|
458
|
+
fi
|
|
459
|
+
|
|
460
|
+
log "initializing template git repo for $LAYER_NAME using 'git init --separate-git-dir=$NEW_DOTGIT $APP_DIR'"
|
|
461
|
+
git init --separate-git-dir="$NEW_DOTGIT" "$APP_DIR"
|
|
462
|
+
|
|
463
|
+
log "removing the pointer file that git leaves behind when --separate-git-dir is specified"
|
|
464
|
+
rm "$APP_DIR/.git"
|
|
465
|
+
|
|
466
|
+
if [ -d "$APP_DIR/not-git" ]; then
|
|
467
|
+
log "restoring our original git dir from $APP_DIR/not-git back to $APP_DIR/.git"
|
|
468
|
+
mv "$APP_DIR/not-git" "$APP_DIR/.git"
|
|
469
|
+
fi
|
|
470
|
+
|
|
471
|
+
# log "don't worry, that file-shuffle was kinda ugly but it was a one-time thing, we don't need to do on every command"
|
|
472
|
+
# log "instead, in the future we will use something like 'git --git-dir=<somefolder> --work-tree=<somefolder> -c core.exludesFile=<somefile>'"
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
###############################################################################
|
|
476
|
+
# COMPILE WHITELIST AND CREATE INITIAL COMMIT
|
|
477
|
+
###############################################################################
|
|
478
|
+
|
|
479
|
+
# We run the NEW layer's geet.sh, not the base layer's.
|
|
480
|
+
# This ensures:
|
|
481
|
+
# - .geetinclude is compiled into .geetexclude
|
|
482
|
+
# - commands are scoped correctly to the new layer
|
|
483
|
+
#
|
|
484
|
+
# First, compile excludes by calling status (idempotent).
|
|
485
|
+
source "$GEET_LIB/sync.sh"
|
|
486
|
+
sync
|
|
487
|
+
geet_git add ".$LAYER_NAME/geet.sh"
|
|
488
|
+
geet_git add ".$LAYER_NAME/.geethier"
|
|
489
|
+
geet_git add ".$LAYER_NAME/.geetinclude"
|
|
490
|
+
geet_git add ".$LAYER_NAME/.geetexclude"
|
|
491
|
+
geet_git add ".$LAYER_NAME/template-config.env"
|
|
492
|
+
geet_git add ".$LAYER_NAME/geet-git.sh"
|
|
493
|
+
geet_git add ".$LAYER_NAME/pre-commit/README.md"
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
###############################################################################
|
|
497
|
+
# SETUP README PROMOTION
|
|
498
|
+
###############################################################################
|
|
499
|
+
# Promote .mytemplate/README.md to README.md so it shows on GitHub
|
|
500
|
+
# Uses merge=keep-ours to prevent conflicts after README files diverge
|
|
501
|
+
geet_git add ".$LAYER_NAME/README.md"
|
|
502
|
+
|
|
503
|
+
log "setting up README.md promotion (see docs/AUTO_PROMOTE.md)"
|
|
504
|
+
|
|
505
|
+
# Set up keep-ours merge driver (prevents conflicts)
|
|
506
|
+
git --git-dir="$NEW_DOTGIT" config merge.keep-ours.name "Always keep working tree version"
|
|
507
|
+
git --git-dir="$NEW_DOTGIT" config merge.keep-ours.driver "true"
|
|
508
|
+
|
|
509
|
+
# Get hash of README.md content
|
|
510
|
+
readme_hash=$(git --git-dir="$NEW_DOTGIT" hash-object -w "$NEW_LAYER_DIR/README.md")
|
|
511
|
+
|
|
512
|
+
# Stage README at promoted location (root)
|
|
513
|
+
git --git-dir="$NEW_DOTGIT" update-index --add --cacheinfo 100644 "$readme_hash" "README.md"
|
|
514
|
+
|
|
515
|
+
# Configure merge strategy for promoted README
|
|
516
|
+
mkdir -p "$NEW_DOTGIT/info"
|
|
517
|
+
echo "README.md merge=keep-ours" >> "$NEW_DOTGIT/info/attributes"
|
|
518
|
+
|
|
519
|
+
###############################################################################
|
|
520
|
+
# SETUP PARENT GITIGNORE PROMOTION
|
|
521
|
+
###############################################################################
|
|
522
|
+
# Promote .mytemplate/README.md to README.md so it shows on GitHub
|
|
523
|
+
# Uses merge=keep-ours to prevent conflicts after README files diverge
|
|
524
|
+
geet_git add ".$LAYER_NAME/parent.gitignore"
|
|
525
|
+
|
|
526
|
+
log "setting up parent.gitignore promotion (see docs/AUTO_PROMOTE.md)"
|
|
527
|
+
# Get hash of README.md content
|
|
528
|
+
pgi_hash=$(git --git-dir="$NEW_DOTGIT" hash-object -w "$NEW_LAYER_DIR/parent.gitignore")
|
|
529
|
+
|
|
530
|
+
# Stage file at promoted location (root)
|
|
531
|
+
git --git-dir="$NEW_DOTGIT" update-index --add --cacheinfo 100644 "$pgi_hash" ".gitignore"
|
|
532
|
+
|
|
533
|
+
# Configure merge strategy for promoted file
|
|
534
|
+
mkdir -p "$NEW_DOTGIT/info"
|
|
535
|
+
echo ".gitignore merge=keep-ours" >> "$NEW_DOTGIT/info/attributes"
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
debug "added files"
|
|
539
|
+
###############################################################################
|
|
540
|
+
# SETUP PRE-COMMIT HOOKS
|
|
541
|
+
###############################################################################
|
|
542
|
+
# Create pre-commit hook to auto-promote README on future commits
|
|
543
|
+
|
|
544
|
+
log "creating pre-commit hook for auto-promotion"
|
|
545
|
+
|
|
546
|
+
mkdir -p "$NEW_DOTGIT/hooks"
|
|
547
|
+
cp "$GEET_LIB/pre-commit/hook.sh" "$NEW_DOTGIT/hooks/pre-commit"
|
|
548
|
+
chmod +x "$NEW_DOTGIT/hooks/pre-commit"
|
|
549
|
+
log "pre-commit hook created:"
|
|
550
|
+
log " • Auto-promotes README.md to root"
|
|
551
|
+
log " • Checks for app-specific patterns (configure in template-config.env)"
|
|
552
|
+
|
|
553
|
+
# Commit the initial promotion
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
log "README.md will appear at root on GitHub"
|
|
557
|
+
log "future edits to .$LAYER_NAME/README.md auto-promote to README.md"
|
|
558
|
+
|
|
559
|
+
geet_git commit -m "Initial commit" || true
|
|
560
|
+
###############################################################################
|
|
561
|
+
# SETUP CUSTOM ALIAS (package.json if present)
|
|
562
|
+
###############################################################################
|
|
563
|
+
|
|
564
|
+
PACKAGE_JSON="$APP_DIR/package.json"
|
|
565
|
+
if [[ -f "$PACKAGE_JSON" ]]; then
|
|
566
|
+
# Check if jq is available for safe JSON manipulation
|
|
567
|
+
if command -v jq >/dev/null 2>&1; then
|
|
568
|
+
log "adding '$LAYER_NAME' script to package.json"
|
|
569
|
+
|
|
570
|
+
# Add script using jq
|
|
571
|
+
tmp_json=$(mktemp)
|
|
572
|
+
jq --arg name "$LAYER_NAME" --arg path ".$LAYER_NAME/geet.sh" \
|
|
573
|
+
'.scripts[$name] = $path' \
|
|
574
|
+
"$PACKAGE_JSON" > "$tmp_json"
|
|
575
|
+
mv "$tmp_json" "$PACKAGE_JSON"
|
|
576
|
+
|
|
577
|
+
log "you can now run: npm run $LAYER_NAME <command>"
|
|
578
|
+
else
|
|
579
|
+
log "tip: install jq to auto-add npm scripts"
|
|
580
|
+
log "or manually add to package.json:"
|
|
581
|
+
log " \"scripts\": { \"$LAYER_NAME\": \".$LAYER_NAME/geet.sh\" }"
|
|
582
|
+
fi
|
|
583
|
+
fi
|
|
584
|
+
|
|
585
|
+
|
|
586
|
+
# update the parents gitignore
|
|
587
|
+
debug "checking " "$APP_DIR/.gitignore"
|
|
588
|
+
touch "$APP_DIR/.gitignore"
|
|
589
|
+
grep -qxF "**/dot-git/" "$APP_DIR/.gitignore" || echo "**/dot-git/" >> "$APP_DIR/.gitignore"
|
|
590
|
+
grep -qxF "**/untracked-template-config.env" "$APP_DIR/.gitignore" || echo "**/untracked-template-config.env" >> "$APP_DIR/.gitignore"
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
###############################################################################
|
|
594
|
+
# FINAL OUTPUT
|
|
595
|
+
###############################################################################
|
|
596
|
+
log "NICE! we think it worked!"
|
|
597
|
+
log "a template repo was created which uses $APP_DIR as its working directory, but its .git lives at $NEW_DOTGIT"
|
|
598
|
+
log "\`$GEET_ALIAS\` commands will call \`git\` for the template repo, while \`git\` will continue to mean your working repo"
|
|
599
|
+
log "you can modify the template's .gitignore using $NEW_LAYER_DIR/.geetinclude or $NEW_LAYER_DIR/.geetexclude"
|
|
600
|
+
log "you can modify some tracked settings at $NEW_LAYER_DIR/.templateconfig.env or untracked ones at $NEW_LAYER_DIR/untracked-template-config.env"
|
|
601
|
+
log "you can customize your template's README at $NEW_LAYER_DIR/README.md and we will sync it to the right location to show up in project root on GitHub and clones"
|
|
602
|
+
|
|
603
|
+
local PUB_APP=""
|
|
604
|
+
local PRI_APP=""
|
|
605
|
+
local INT_APP=""
|
|
606
|
+
|
|
607
|
+
has_flag --public PUB_APP
|
|
608
|
+
has_flag --private PRI_APP
|
|
609
|
+
has_flag --internal INT_APP
|
|
610
|
+
|
|
611
|
+
# Determine publish visibility
|
|
612
|
+
local publish_visibility="none"
|
|
613
|
+
if [[ -n "$PUB_APP" ]]; then
|
|
614
|
+
publish_visibility="public"
|
|
615
|
+
elif [[ -n "$PRI_APP" ]]; then
|
|
616
|
+
publish_visibility="private"
|
|
617
|
+
elif [[ -n "$INT_APP" ]]; then
|
|
618
|
+
publish_visibility="internal"
|
|
619
|
+
fi
|
|
620
|
+
|
|
621
|
+
if [[ "$publish_visibility" != "none" ]];then
|
|
622
|
+
source "$GEET_LIB/ghcli.sh"
|
|
623
|
+
publish_template "--$publish_visibility"
|
|
624
|
+
exit 0
|
|
625
|
+
fi
|
|
626
|
+
|
|
627
|
+
|
|
628
|
+
|
|
629
|
+
log
|
|
630
|
+
log "next steps:"
|
|
631
|
+
log " 1) stage files: \`$GEET_ALIAS include \"app/index.tsx\" \"app/_layout.tsx\"\` # we use include instead of add because it will modify the .geetinclude to allow the file in"
|
|
632
|
+
log " 2) commit: \`$GEET_ALIAS commit -m \"Add the basic template\""\`
|
|
633
|
+
log " 5) publish to github: \`$GEET_ALIAS publish template\` # (or $GEET_ALIAS publish template --private)"
|
|
634
|
+
|
|
635
|
+
} # end of template()
|