1- # Generated from operatorstack/intelligence-flow.
1+ # Generated by labkit (python -m labkit gen). Do not edit by hand.
2+ # Edit labs/<lab>/publish.config.json and regenerate; drift fails `labkit doctor`.
3+ # Install into operatorstack/boatstack at .github/workflows/sync-upstream.yml (bootstrap step).
24name : Sync from Intelligence Flow
35
46on :
57 schedule :
6- - cron : " 17 */6 * * *"
8+ - cron : " 2 */6 * * *"
79 workflow_dispatch :
810 inputs :
911 source_commit :
2325 sync :
2426 runs-on : ubuntu-latest
2527 steps :
26- - name : Create repository automation token
28+ - name : Create publisher token
2729 id : app-token
2830 uses : actions/create-github-app-token@v3
2931 with :
3840 - name : Check out Boatstack
3941 uses : actions/checkout@v4
4042 with :
41- path : boatstack -repo
43+ path : public -repo
4244 token : ${{ steps.app-token.outputs.token }}
4345 - name : Check out Intelligence Flow
4446 uses : actions/checkout@v4
@@ -48,20 +50,28 @@ jobs:
4850 fetch-depth : 0
4951 path : intelligence-flow
5052 token : ${{ steps.app-token.outputs.token }}
53+ - name : Set up Python
54+ uses : actions/setup-python@v5
55+ with :
56+ python-version : " 3.12"
57+ - name : Install labkit
58+ shell : bash
59+ run : python3 -m pip install --quiet ./intelligence-flow/labkit
5160 - name : Generate projection
5261 id : generate
5362 shell : bash
5463 run : |
5564 source_commit="$(git -C intelligence-flow log -1 --format=%H -- labs/12-product-engineering-loop)"
56- current_commit="$(jq -r '.source.commit // empty' boatstack -repo/UPSTREAM.json)"
65+ current_commit="$(jq -r '.source.commit // empty' public -repo/UPSTREAM.json 2>/dev/null || echo '' )"
5766 if [[ -n "$current_commit" ]] &&
5867 ! git -C intelligence-flow merge-base --is-ancestor "$current_commit" "$source_commit"; then
59- echo "Ignoring stale projection request $source_commit ; Boatstack already records $current_commit."
68+ echo "Ignoring stale request; Boatstack already records $current_commit."
6069 echo "stale=true" >> "$GITHUB_OUTPUT"
6170 exit 0
6271 fi
63- python3 intelligence-flow/labs/12-product-engineering-loop/scripts/build_boatstack.py \
64- --repo boatstack-repo \
72+ python3 -m labkit project \
73+ --config intelligence-flow/labs/12-product-engineering-loop/publish.config.json \
74+ --repo public-repo \
6575 --source-commit "$source_commit" \
6676 --write
6777 echo "source_commit=$source_commit" >> "$GITHUB_OUTPUT"
@@ -73,62 +83,49 @@ jobs:
7383 SOURCE_COMMIT : ${{ steps.generate.outputs.source_commit }}
7484 shell : bash
7585 run : |
76- cd boatstack -repo
86+ cd public -repo
7787 if [[ -z "$(git status --porcelain)" ]]; then
7888 echo "Boatstack already matches Intelligence Flow."
7989 exit 0
8090 fi
8191 git add -A
82- rewritten_notes=()
83- while IFS= read -r note; do
84- rewritten_notes+=("$note")
85- done < <(git diff --cached --name-only --diff-filter=MD --no-renames -- \
86- 'release-notes/*.md')
87- if (( ${#rewritten_notes[@]} > 0 )); then
92+ rewritten=()
93+ while IFS= read -r note; do rewritten+=("$note"); done < <(
94+ git diff --cached --name-only --diff-filter=MD --no-renames -- 'release-notes/*.md')
95+ if (( ${#rewritten[@]} > 0 )); then
8896 echo "BLOCKED: Boatstack release notes are append-only:" >&2
89- printf ' %s\n' "${rewritten_notes [@]}" >&2
97+ printf ' %s\n' "${rewritten [@]}" >&2
9098 exit 1
9199 fi
92- added_notes=()
93- while IFS= read -r note; do
94- added_notes+=("$note")
95- done < <(git diff --cached --name-only --diff-filter=A --no-renames -- \
96- 'release-notes/*.md' | LC_ALL=C sort)
97- if (( ${#added_notes[@]} == 0 )); then
98- echo "BLOCKED: projected Boatstack changes require a release message." >&2
100+ added=()
101+ while IFS= read -r note; do added+=("$note"); done < <(
102+ git diff --cached --name-only --diff-filter=A --no-renames -- 'release-notes/*.md' | LC_ALL=C sort)
103+ if (( ${#added[@]} == 0 )); then
104+ echo "BLOCKED: projected changes require a release note in release-notes/." >&2
99105 exit 1
100106 fi
101107 body_file="$(mktemp)"
102108 {
103- echo "## What this sync releases"
104- echo
105- for note in "${added_notes[@]}"; do
106- cat "$note"
107- echo
108- done
109- echo "<details>"
110- echo "<summary>Projection provenance</summary>"
111- echo
109+ echo "## What this sync releases"; echo
110+ for note in "${added[@]}"; do cat "$note"; echo; done
111+ echo "<details><summary>Projection provenance</summary>"; echo
112112 echo "Generated from \`operatorstack/intelligence-flow@$SOURCE_COMMIT\`."
113- echo "Review provenance, tests, examples, and context-cost changes before merging."
114- echo
113+ echo "Review provenance, tests, and examples before merging."; echo
115114 echo "</details>"
116115 } > "$body_file"
117116 short="${SOURCE_COMMIT:0:12}"
118117 branch="sync/intelligence-flow-$short"
119118 existing="$(gh pr list --head "$branch" --state open --json url --jq '.[0].url')"
120- if [[ -n "$existing" ]]; then
121- echo "Upstream PR already open: $existing"
122- exit 0
123- fi
124119 git config user.name "${{ steps.app-token.outputs.app-slug }}[bot]"
125120 git config user.email "${{ steps.app-token.outputs.app-slug }}[bot]@users.noreply.github.com"
126121 git switch -c "$branch"
127122 git commit -m "Sync Boatstack from Intelligence Flow Labs @ $short"
128- git push --set-upstream origin "$branch"
129- pr_url="$(gh pr create \
130- --base main \
131- --head "$branch" \
132- --title "Sync Boatstack from Intelligence Flow Labs @ $short" \
133- --body-file "$body_file")"
134- echo "Opened generated PR: $pr_url"
123+ git push --force --set-upstream origin "$branch"
124+ if [[ -z "$existing" ]]; then
125+ pr_url="$(gh pr create --base main --head "$branch" \
126+ --title "Sync Boatstack from Intelligence Flow Labs @ $short" \
127+ --body-file "$body_file")"
128+ echo "Opened generated PR: $pr_url"
129+ else
130+ echo "Updated existing PR: $existing"
131+ fi
0 commit comments