Skip to content

Commit 8d9f8ab

Browse files
refactor(ci): Write AI prompts to temp files instead of GITHUB_OUTPUT
1 parent 2b537bd commit 8d9f8ab

2 files changed

Lines changed: 101 additions & 92 deletions

File tree

.github/blocks/bump-monorepo-versions/action.yaml

Lines changed: 53 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -78,17 +78,19 @@ runs:
7878
core.setOutput('sha', context.sha);
7979
}
8080
81-
- name: Gather per-package commit logs
81+
- name: Write monorepo release prompt
8282
id: commit-logs
8383
shell: bash
8484
env:
8585
CHANGED_JSON: ${{ inputs.changed-packages }}
8686
LAST_SHA: ${{ steps.last-release.outputs.sha }}
87+
SERVICE_NAME: ${{ inputs.service-name }}
88+
PRERELEASE: ${{ inputs.prerelease }}
8789
run: |
8890
set -euo pipefail
8991
9092
PKG_COUNT=$(echo "$CHANGED_JSON" | jq 'length')
91-
PROMPT_PARTS=""
93+
PROMPT_FILE="${RUNNER_TEMP}/bump-monorepo-versions-prompt.md"
9294
9395
# Resolve a valid base once: the last release if it is an ancestor of
9496
# HEAD, else the repo root. Used unguarded below so a genuine git failure
@@ -99,6 +101,33 @@ runs:
99101
BASE=$(git rev-list --max-parents=0 HEAD | tail -1)
100102
fi
101103
104+
{
105+
echo "You are a release manager for the \"${SERVICE_NAME}\" monorepo."
106+
echo "Prerelease: ${PRERELEASE}"
107+
echo
108+
cat <<'PROMPT'
109+
For each package below, determine the next semantic version. Base the
110+
decision on the ACTUAL CODE CHANGES — the commits, the changed-file
111+
list, and the diff are all provided per package. Commit messages are a
112+
hint, not the source of truth: most authors do not annotate breaking
113+
changes, so the diff is authoritative.
114+
115+
Rules (apply in order, per package, versioned independently):
116+
- MAJOR — an explicit `BREAKING CHANGE:` footer or `type!:` marker, OR a
117+
diff that is backward-incompatible even without one (a public/exported
118+
symbol or entry point removed or renamed, a schema/required field or
119+
return shape changed, default behavior or a config contract changed).
120+
You are explicitly allowed to bump the major from the diff alone.
121+
- MINOR — backward-compatible new functionality is ADDED (feat:).
122+
- PATCH — fixes, perf, refactors, docs, chores; nothing public removed
123+
or broken.
124+
Be conservative about MAJOR: purely additive changes are MINOR, and when
125+
genuinely unclear pick the lower bump. For prereleases the -rc suffix is
126+
added automatically.
127+
128+
PROMPT
129+
} > "$PROMPT_FILE"
130+
102131
for i in $(seq 0 $(( PKG_COUNT - 1 ))); do
103132
NAME=$(echo "$CHANGED_JSON" | jq -r ".[$i].name")
104133
PKG_PATH=$(echo "$CHANGED_JSON" | jq -r ".[$i].path")
@@ -113,7 +142,7 @@ runs:
113142
(diff truncated at ${CAP} chars — run: git diff $BASE..HEAD -- ${PKG_PATH} for the full diff)"
114143
fi
115144
116-
PROMPT_PARTS="${PROMPT_PARTS}
145+
cat >> "$PROMPT_FILE" <<PROMPT
117146
Package: ${NAME}
118147
Current version: ${CURRENT_VER}
119148
Path: ${PKG_PATH}
@@ -123,13 +152,28 @@ runs:
123152
${NAME_STATUS}
124153
Diff:
125154
${PKG_DIFF}
126-
---"
155+
---
156+
PROMPT
127157
done
128158
129-
EOF_MARKER=$(openssl rand -hex 16)
130-
echo "prompt<<${EOF_MARKER}" >> "$GITHUB_OUTPUT"
131-
echo "$PROMPT_PARTS" >> "$GITHUB_OUTPUT"
132-
echo "${EOF_MARKER}" >> "$GITHUB_OUTPUT"
159+
cat >> "$PROMPT_FILE" <<'PROMPT'
160+
161+
Respond in exactly this format (no extra text before or after each section):
162+
163+
VERSIONS_JSON
164+
{"package-name":"X.Y.Z", ...}
165+
END_VERSIONS_JSON
166+
167+
RELEASE_NOTES
168+
(write combined release notes for all packages below, grouped by package.
169+
Plain language, 1-2 sentences per item, 1-2 emojis max.
170+
Group by: ## New Features, ## Bug Fixes, ## Improvements as applicable.
171+
Note that we only need these groups if they are applicable. For example, do not mention a bug fixes section if there were no bug fixes
172+
Prefix each item with the package name in bold.)
173+
END_RELEASE_NOTES
174+
PROMPT
175+
176+
echo "prompt-file=${PROMPT_FILE}" >> "$GITHUB_OUTPUT"
133177
134178
- name: AI determine versions and release notes
135179
id: ai-release
@@ -138,44 +182,7 @@ runs:
138182
openai-api-key: ${{ inputs.openai-api-key }}
139183
safety-strategy: read-only
140184
effort: high
141-
prompt: |
142-
You are a release manager for the "${{ inputs.service-name }}" monorepo.
143-
Prerelease: ${{ inputs.prerelease }}
144-
145-
For each package below, determine the next semantic version. Base the
146-
decision on the ACTUAL CODE CHANGES — the commits, the changed-file
147-
list, and the diff are all provided per package. Commit messages are a
148-
hint, not the source of truth: most authors do not annotate breaking
149-
changes, so the diff is authoritative.
150-
151-
Rules (apply in order, per package, versioned independently):
152-
- MAJOR — an explicit `BREAKING CHANGE:` footer or `type!:` marker, OR a
153-
diff that is backward-incompatible even without one (a public/exported
154-
symbol or entry point removed or renamed, a schema/required field or
155-
return shape changed, default behavior or a config contract changed).
156-
You are explicitly allowed to bump the major from the diff alone.
157-
- MINOR — backward-compatible new functionality is ADDED (feat:).
158-
- PATCH — fixes, perf, refactors, docs, chores; nothing public removed
159-
or broken.
160-
Be conservative about MAJOR: purely additive changes are MINOR, and when
161-
genuinely unclear pick the lower bump. For prereleases the -rc suffix is
162-
added automatically.
163-
164-
${{ steps.commit-logs.outputs.prompt }}
165-
166-
Respond in exactly this format (no extra text before or after each section):
167-
168-
VERSIONS_JSON
169-
{"package-name":"X.Y.Z", ...}
170-
END_VERSIONS_JSON
171-
172-
RELEASE_NOTES
173-
(write combined release notes for all packages below, grouped by package.
174-
Plain language, 1-2 sentences per item, 1-2 emojis max.
175-
Group by: ## New Features, ## Bug Fixes, ## Improvements as applicable.
176-
Note that we only need these groups if they are applicable. For example, do not mention a bug fixes section if there were no bug fixes
177-
Prefix each item with the package name in bold.)
178-
END_RELEASE_NOTES
185+
prompt-file: ${{ steps.commit-logs.outputs.prompt-file }}
179186

180187
- name: Apply versions
181188
id: apply-versions

.github/blocks/determine-publish-version/action.yaml

Lines changed: 48 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,14 @@ runs:
8787
core.setOutput('stable_version', '0.0.0');
8888
}
8989
90-
- name: Gather change context
90+
- name: Write version prompt
9191
id: context
9292
shell: bash
9393
env:
9494
BASE_SHA: ${{ steps.last-release.outputs.stable_sha }}
9595
HEAD_SHA: ${{ github.sha }}
96+
STABLE_VERSION: ${{ steps.last-release.outputs.stable_version }}
97+
PRERELEASE: ${{ inputs.prerelease }}
9698
run: |
9799
set -euo pipefail
98100
# No prior stable release -> diff against the empty tree so the entire
@@ -107,9 +109,46 @@ runs:
107109
STAT=$(clip "$(git diff --stat "$DIFF_BASE" "$HEAD_SHA")" 40000)
108110
LOG=$(clip "$(git log --no-merges --format='- %s%n%b' $LOG_RANGE)" 100000)
109111
DIFF=$(clip "$(git diff "$DIFF_BASE" "$HEAD_SHA")" 400000)
110-
MARKER=$(openssl rand -hex 16)
112+
PROMPT_FILE="${RUNNER_TEMP}/determine-publish-version-prompt.md"
111113
{
112-
echo "context<<${MARKER}"
114+
echo "Determine the next semantic version after ${STABLE_VERSION}."
115+
echo "Current version: ${STABLE_VERSION}"
116+
echo "Prerelease: ${PRERELEASE}"
117+
echo
118+
cat <<'PROMPT'
119+
Base your decision on the ACTUAL CODE CHANGES below — the commit
120+
messages, the list of changed files, and the diff are all provided.
121+
Commit messages are a hint, not the source of truth: most authors do
122+
not annotate breaking changes, so the diff is authoritative. If the diff
123+
was truncated you may run `git diff` yourself (read-only) for any file.
124+
125+
How to choose the bump (apply in order):
126+
1. MAJOR — if a commit message carries an explicit `BREAKING CHANGE:`
127+
footer or a `type!:` marker, that is authoritative: bump major.
128+
ALSO bump major if the DIFF itself is backward-incompatible even when
129+
no commit said so — e.g. a public endpoint/route/exported symbol is
130+
removed or renamed, a request/response schema or required field
131+
changes shape, default behavior changes in a way that breaks existing
132+
callers, or a config/runtime contract changes. You are explicitly
133+
allowed to bump the major from the diff alone.
134+
2. MINOR — backward-COMPATIBLE new functionality: a new endpoint, flag,
135+
exported symbol, or capability is ADDED without breaking existing
136+
ones (corresponds to `feat:`).
137+
3. PATCH — bug fixes, performance, internal refactors, docs, chores, or
138+
anything else that neither adds public surface nor breaks it.
139+
140+
Be conservative about MAJOR to avoid false positives: purely additive
141+
changes are MINOR, not MAJOR. Only call it breaking if existing public
142+
behavior is actually removed or changed incompatibly. When genuinely
143+
unclear between two levels, pick the lower one (default to patch).
144+
PROMPT
145+
echo
146+
echo "A major bump of ${STABLE_VERSION} increments the first number and"
147+
echo "zeroes the rest (e.g. 0.1.5 -> 1.0.0); minor increments the"
148+
echo "second (0.1.5 -> 0.2.0); patch the third (0.1.5 -> 0.1.6)."
149+
echo "For prereleases use the same logic — the -rc suffix is added automatically."
150+
echo
151+
echo "=== CHANGES SINCE ${STABLE_VERSION} ==="
113152
echo "## Commit messages"
114153
echo "$LOG"
115154
echo
@@ -123,8 +162,11 @@ runs:
123162
echo '```diff'
124163
echo "$DIFF"
125164
echo '```'
126-
echo "${MARKER}"
127-
} >> "$GITHUB_OUTPUT"
165+
echo "=== END CHANGES ==="
166+
echo
167+
echo "Respond with ONLY X.Y.Z"
168+
} > "$PROMPT_FILE"
169+
echo "prompt-file=${PROMPT_FILE}" >> "$GITHUB_OUTPUT"
128170
129171
- name: AI Determine Version
130172
id: ai-version
@@ -133,47 +175,7 @@ runs:
133175
openai-api-key: ${{ inputs.openai-api-key }}
134176
safety-strategy: read-only
135177
effort: high
136-
prompt: |
137-
Determine the next semantic version after ${{ steps.last-release.outputs.stable_version }}.
138-
Current version: ${{ steps.last-release.outputs.stable_version }}
139-
Prerelease: ${{ inputs.prerelease }}
140-
141-
Base your decision on the ACTUAL CODE CHANGES below — the commit
142-
messages, the list of changed files, and the diff are all provided.
143-
Commit messages are a hint, not the source of truth: most authors do
144-
not annotate breaking changes, so the diff is authoritative. If the diff
145-
was truncated you may run `git diff` yourself (read-only) for any file.
146-
147-
How to choose the bump (apply in order):
148-
1. MAJOR — if a commit message carries an explicit `BREAKING CHANGE:`
149-
footer or a `type!:` marker, that is authoritative: bump major.
150-
ALSO bump major if the DIFF itself is backward-incompatible even when
151-
no commit said so — e.g. a public endpoint/route/exported symbol is
152-
removed or renamed, a request/response schema or required field
153-
changes shape, default behavior changes in a way that breaks existing
154-
callers, or a config/runtime contract changes. You are explicitly
155-
allowed to bump the major from the diff alone.
156-
2. MINOR — backward-COMPATIBLE new functionality: a new endpoint, flag,
157-
exported symbol, or capability is ADDED without breaking existing
158-
ones (corresponds to `feat:`).
159-
3. PATCH — bug fixes, performance, internal refactors, docs, chores, or
160-
anything else that neither adds public surface nor breaks it.
161-
162-
Be conservative about MAJOR to avoid false positives: purely additive
163-
changes are MINOR, not MAJOR. Only call it breaking if existing public
164-
behavior is actually removed or changed incompatibly. When genuinely
165-
unclear between two levels, pick the lower one (default to patch).
166-
167-
A major bump of ${{ steps.last-release.outputs.stable_version }} increments
168-
the first number and zeroes the rest (e.g. 0.1.5 -> 1.0.0); minor
169-
increments the second (0.1.5 -> 0.2.0); patch the third (0.1.5 -> 0.1.6).
170-
For prereleases use the same logic — the -rc suffix is added automatically.
171-
172-
=== CHANGES SINCE ${{ steps.last-release.outputs.stable_version }} ===
173-
${{ steps.context.outputs.context }}
174-
=== END CHANGES ===
175-
176-
Respond with ONLY X.Y.Z
178+
prompt-file: ${{ steps.context.outputs.prompt-file }}
177179

178180
- name: Parse Version
179181
id: version

0 commit comments

Comments
 (0)