-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathbootstrap.sh
More file actions
executable file
·238 lines (215 loc) · 9.49 KB
/
Copy pathbootstrap.sh
File metadata and controls
executable file
·238 lines (215 loc) · 9.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
#!/usr/bin/env bash
# bootstrap.sh — fork zava-* repos into your org and rewrite refs
# Usage: ./bin/bootstrap.sh --org=YOUR_ORG [--source-org=DevExpGbb] [--dry-run] [--force]
set -euo pipefail
ORG=""
SOURCE_ORG="DevExpGbb"
SKIP_TEMPLATE=true # trainees use "Use this template" instead
DRY_RUN=false
FORCE=false
for a in "$@"; do
case "$a" in
--org=*) ORG="${a#--org=}" ;;
--source-org=*) SOURCE_ORG="${a#--source-org=}" ;;
--include-template) SKIP_TEMPLATE=false ;;
--dry-run) DRY_RUN=true ;;
--force) FORCE=true ;;
*) echo "unknown arg: $a"; exit 2 ;;
esac
done
[[ -z "$ORG" ]] && { echo "usage: $0 --org=<github-org> [--source-org=DevExpGbb] [--dry-run] [--force]"; exit 2; }
# Refuse to bootstrap into the source org — this would re-fork DevExpGbb back
# into itself, rewrite refs to itself, and overwrite the live apm-policy.yml
# with the template (a v1.2.0 → v1.2.0 no-op only if templates are in sync).
if [[ "$ORG" == "$SOURCE_ORG" ]]; then
echo "❌ Refusing to bootstrap into source org '$SOURCE_ORG'."
echo " Pass --org=<a-different-org> (the consumer org) and keep --source-org=$SOURCE_ORG."
exit 2
fi
if $DRY_RUN; then
echo "🔍 DRY-RUN MODE — no GitHub state will be modified."
echo
fi
# Helper: echo command in dry-run mode, execute otherwise.
run() {
if $DRY_RUN; then
echo " [DRYRUN] $*"
else
"$@"
fi
}
# Capture KIT_DIR before any cd — BASH_SOURCE[0] may be relative (e.g.
# "./bin/bootstrap.sh"), which would no longer resolve after we cd into $WORK
# or $WORK/.github later in the script.
KIT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
WORK="${WORK:-/tmp/zava-bootstrap-$ORG}"
mkdir -p "$WORK" && cd "$WORK"
REPOS=(zava-agent-config zava-storefront poisoned-tracing-skill)
$SKIP_TEMPLATE || REPOS+=(zava-skills-workshop-template)
echo "=== bootstrap → $ORG (source=$SOURCE_ORG) ==="
# 1. Fork each repo (idempotent: gh repo fork is no-op if exists)
for r in "${REPOS[@]}"; do
echo
echo "--- $r ---"
if gh api "repos/$ORG/$r" >/dev/null 2>&1; then
echo " ✅ $ORG/$r already exists, skipping fork"
else
echo " → forking $SOURCE_ORG/$r → $ORG/$r"
run gh repo fork "$SOURCE_ORG/$r" --org "$ORG" --default-branch-only --clone=false
$DRY_RUN || sleep 5 # let GitHub finish the fork
fi
# Forks have GitHub Actions disabled until the user clicks "I understand my
# workflows, go ahead and enable them" in the UI. Enable them via API so that
# tag-push triggers (release.yml) and label-triggers (pr-review-panel) fire
# on the fork without manual intervention.
if ! $DRY_RUN; then
echo '{"enabled":true,"allowed_actions":"all"}' \
| gh api -X PUT "repos/$ORG/$r/actions/permissions" --input - >/dev/null 2>&1 \
|| echo " ⚠️ could not enable Actions on $ORG/$r — enable manually via repo Settings → Actions"
fi
done
# 2. Rewrite refs in each fork: $SOURCE_ORG/ → $ORG/
$DRY_RUN && { echo; echo "🔍 DRY-RUN: skipping ref-rewrite phase (would clone+sed each fork)"; }
$DRY_RUN || for r in "${REPOS[@]}"; do
echo
echo "--- rewriting refs in $ORG/$r ---"
rm -rf "$WORK/$r"
gh repo clone "$ORG/$r" "$WORK/$r" -- --quiet
cd "$WORK/$r"
# Find files containing the source org slug in apm.yml or workflow files
hits=$(grep -rl "$SOURCE_ORG/" --include="*.yml" --include="*.yaml" --include="*.md" --include="*.json" . 2>/dev/null | grep -v "^./.git/" || true)
if [[ -z "$hits" ]]; then
echo " ✅ no $SOURCE_ORG/ refs found, skipping"
cd "$WORK"
continue
fi
echo " → rewriting in:"
echo "$hits" | sed 's/^/ /'
echo "$hits" | xargs sed -i.bak "s|$SOURCE_ORG/|$ORG/|g"
find . -name "*.bak" -delete
if git diff --quiet; then
echo " ✅ no diff after rewrite (already clean)"
else
git -c user.name="Zava Workshop Kit" -c user.email="zava-kit@example.com" \
commit -am "chore: rewrite source-org refs $SOURCE_ORG → $ORG
Generated by zava-workshop-kit/bin/bootstrap.sh.
Repinning marketplace + workflow imports to your org."
echo " ✅ committed rewrites (push deferred until lockfile regen)"
fi
# Regenerate APM lockfile if apm.yml exists. Cross-org tag tarballs hash
# differently even at the same version (each release.yml run produces a
# fresh tarball), so the inherited lockfile would trip apm audit's
# supply-chain check. apm CLI is required only when consumer repos pin
# marketplace plugins.
if [[ -f apm.yml ]] && command -v apm >/dev/null 2>&1; then
echo " → regenerating apm.lock.yaml against $ORG content"
if apm install --update >/dev/null 2>&1; then
# Marketplace-publisher repos (zava-agent-config) declare apm.yml for
# plugin metadata but pin no dependencies — no apm.lock.yaml is produced.
# Only attempt to commit the lockfile when it actually exists.
if [[ -f apm.lock.yaml ]] && ! git diff --quiet apm.lock.yaml 2>/dev/null; then
git -c user.name="Zava Workshop Kit" -c user.email="zava-kit@example.com" \
commit -m "chore(apm): regenerate lockfile against $ORG plugins" apm.lock.yaml
echo " ✅ lockfile regenerated"
elif [[ -f apm.lock.yaml ]]; then
echo " ✅ lockfile already current"
else
echo " ✅ no apm dependencies — lockfile not needed"
fi
else
echo " ⚠️ apm install --update failed — push and regenerate manually"
fi
elif [[ -f apm.yml ]]; then
echo " ⚠️ apm.yml present but 'apm' CLI not on PATH — skipping lockfile regen"
echo " install apm and rerun: cd $WORK/$r && apm install --update && git commit -am 'chore(apm): lockfile' && git push"
fi
if ! git diff --quiet origin/HEAD HEAD 2>/dev/null; then
git push origin HEAD
echo " ✅ pushed"
fi
cd "$WORK"
done
# 3. Org .github repo + apm-policy.yml
echo
echo "--- org policy: $ORG/.github ---"
if ! gh api "repos/$ORG/.github" >/dev/null 2>&1; then
echo " → creating $ORG/.github"
run gh repo create "$ORG/.github" --public --description "Org defaults for $ORG" --add-readme
$DRY_RUN || sleep 3
fi
if $DRY_RUN; then
echo " [DRYRUN] would clone $ORG/.github, template apm-policy.yml (YOUR_ORG → $ORG), back up any existing policy, commit + push"
else
rm -rf "$WORK/.github"
gh repo clone "$ORG/.github" "$WORK/.github" -- --quiet
cd "$WORK/.github"
# Back up existing policy before overwriting (safety net for orgs that already
# have a curated apm-policy.yml — avoids silent loss of governance config).
if [[ -f apm-policy.yml ]] && ! $FORCE; then
backup="apm-policy.yml.bak.$(date +%Y%m%d-%H%M%S)"
cp apm-policy.yml "$backup"
echo " ⚠️ existing apm-policy.yml found — backed up to $backup"
echo " diff after templating below; if it doesn't look right, restore from $backup or rerun with --force to skip backup"
fi
# Template YOUR_ORG → $ORG via sed (the previous bare `cp` left placeholders
# in the deployed policy, which is a runtime failure).
sed "s|YOUR_ORG|$ORG|g" "$KIT_DIR/templates/apm-policy.yml" > apm-policy.yml
if [[ -f "${backup:-/dev/null}" ]] && diff -q apm-policy.yml "$backup" >/dev/null 2>&1; then
echo " ✅ apm-policy.yml unchanged after template"
rm -f "$backup"
else
# Stage first, then check for diff against HEAD. Plain `git diff --quiet
# apm-policy.yml` returns 0 (silently) when the file is untracked — which
# incorrectly classified a brand-new policy file as "already in place" and
# silently skipped the commit, leaving $ORG/.github with no policy at all.
git add apm-policy.yml
if git diff --cached --quiet; then
echo " ✅ apm-policy.yml already in place"
else
git -c user.name="Zava Workshop Kit" -c user.email="zava-kit@example.com" \
commit -m "chore: org-level apm-policy.yml from zava-workshop-kit"
git push origin HEAD || true
echo " ✅ apm-policy.yml committed"
fi
fi
cd "$WORK"
fi
# 4. Trigger marketplace release on the fork (so your org has its own v5.0.1 release)
echo
echo "--- triggering release on $ORG/zava-agent-config ---"
if $DRY_RUN; then
echo " [DRYRUN] would push the latest upstream tag and trigger release.yml on $ORG/zava-agent-config"
else
LATEST_TAG=$(gh api "repos/$SOURCE_ORG/zava-agent-config/releases/latest" --jq .tag_name 2>/dev/null || echo "")
if [[ -z "$LATEST_TAG" ]]; then
echo " ⚠️ could not read latest tag from source — skipping release trigger"
elif gh api "repos/$ORG/zava-agent-config/releases/tags/$LATEST_TAG" >/dev/null 2>&1; then
echo " ✅ release $LATEST_TAG already published in $ORG"
else
cd "$WORK/zava-agent-config"
if ! git tag | grep -q "^$LATEST_TAG$"; then
echo " → fetching tags"
git fetch --tags origin || true
fi
if git tag | grep -q "^$LATEST_TAG$"; then
git push origin "$LATEST_TAG" 2>/dev/null || echo " (tag push: may already exist)"
echo " → triggering release.yml workflow"
gh workflow run release.yml --repo "$ORG/zava-agent-config" --ref "$LATEST_TAG" 2>/dev/null \
|| echo " ⚠️ workflow_dispatch failed — push tag manually or trigger from UI"
else
echo " ⚠️ tag $LATEST_TAG not in local clone — fork may not have inherited tags"
echo " run: git fetch upstream --tags && git push origin --tags"
fi
cd "$WORK"
fi
fi
echo
if $DRY_RUN; then
echo "=== 🔍 dry-run complete (no state modified) ==="
echo " re-run without --dry-run to apply"
else
echo "=== ✅ bootstrap complete ==="
echo " workspace: $WORK"
echo " next: ./bin/smoke.sh --org=$ORG"
echo " undo: ./bin/teardown.sh --org=$ORG"
fi