project-auto-wizard 0.14.0 → 0.15.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.ja.md +2 -0
- package/README.ko.md +2 -0
- package/README.md +3 -1
- package/README.zh-CN.md +2 -0
- package/package.json +1 -1
- package/payload/scripts/changelog_manager.py +8 -8
- package/payload/scripts/messages.py +306 -0
- package/payload/scripts/version_manager.py +46 -46
- package/payload/workflows/common/PROJECT-COMMON-AI-PR-SUMMARY.yaml +6 -4
- package/payload/workflows/common/PROJECT-COMMON-AUTO-CHANGELOG-CONTROL.yaml +47 -29
- package/payload/workflows/common/PROJECT-COMMON-README-VERSION-UPDATE.yaml +38 -35
- package/payload/workflows/common/PROJECT-COMMON-RELEASE-PUBLISH.yaml +36 -28
- package/payload/workflows/common/PROJECT-COMMON-VERSION-CONTROL.yaml +35 -28
- package/src/commands/doctor.js +5 -0
- package/src/commands/dry-run.js +1 -0
- package/src/core/copy/readme.js +58 -2
- package/src/i18n/catalog/en/commands.js +1 -0
- package/src/i18n/catalog/en/copy.js +1 -0
- package/src/i18n/catalog/ko/commands.js +1 -0
- package/src/i18n/catalog/ko/copy.js +1 -0
- package/src/index.js +4 -3
- package/src/ui/summary.js +1 -1
|
@@ -86,22 +86,24 @@ jobs:
|
|
|
86
86
|
- name: Check README.md exists
|
|
87
87
|
id: precheck
|
|
88
88
|
run: |
|
|
89
|
+
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
89
90
|
if [ -f README.md ]; then
|
|
90
91
|
echo "readme_exists=true" >> $GITHUB_OUTPUT
|
|
91
92
|
else
|
|
92
93
|
echo "readme_exists=false" >> $GITHUB_OUTPUT
|
|
93
|
-
echo "
|
|
94
|
+
echo "$(m wf_readme.not_found)"
|
|
94
95
|
fi
|
|
95
96
|
|
|
96
97
|
- name: Read latest version via version_manager.py
|
|
97
98
|
id: version_info
|
|
98
99
|
if: steps.precheck.outputs.readme_exists == 'true'
|
|
99
100
|
run: |
|
|
101
|
+
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
100
102
|
LATEST_VERSION=$(python3 .github/scripts/version_manager.py get | tail -n 1)
|
|
101
103
|
# Guard: an empty version must never reach the README rewrite —
|
|
102
104
|
# it would commit a corrupted "v (date)" line.
|
|
103
105
|
if [ -z "$LATEST_VERSION" ]; then
|
|
104
|
-
echo "
|
|
106
|
+
echo "$(m wf_readme.read_version_failed)"
|
|
105
107
|
exit 1
|
|
106
108
|
fi
|
|
107
109
|
RELEASE_DATE=$(date '+%Y-%m-%d')
|
|
@@ -130,28 +132,28 @@ jobs:
|
|
|
130
132
|
local version_text="$4"
|
|
131
133
|
|
|
132
134
|
echo ""
|
|
133
|
-
echo "
|
|
134
|
-
echo "
|
|
135
|
-
echo "
|
|
136
|
-
echo "
|
|
137
|
-
echo "
|
|
135
|
+
echo "$(m wf_readme.update_failed)"
|
|
136
|
+
echo "$(m wf_readme.err_type error_type="$error_type")"
|
|
137
|
+
echo "$(m wf_readme.err_current_line version_line="$version_line")"
|
|
138
|
+
echo "$(m wf_readme.err_header header_part="$header_part")"
|
|
139
|
+
echo "$(m wf_readme.err_new_text version_text="$version_text")"
|
|
138
140
|
echo ""
|
|
139
|
-
echo "
|
|
141
|
+
echo "$(m wf_readme.hint_formats)"
|
|
140
142
|
echo " $(m wf_readme.hint_first_example)"
|
|
141
143
|
echo " ## Current Version : v1.0.0"
|
|
142
144
|
echo " ## Version : v1.0.0"
|
|
143
|
-
echo "
|
|
144
|
-
echo "
|
|
145
|
-
echo "
|
|
146
|
-
echo "
|
|
145
|
+
echo "$(m wf_readme.hint_notes)"
|
|
146
|
+
echo "$(m wf_readme.hint_no_bold)"
|
|
147
|
+
echo "$(m wf_readme.hint_no_regex)"
|
|
148
|
+
echo "$(m wf_readme.hint_after_colon)"
|
|
147
149
|
}
|
|
148
150
|
|
|
149
151
|
if [ "$SHOW_DATE" = "true" ]; then
|
|
150
152
|
VERSION_TEXT="v${LATEST_VERSION} (${RELEASE_DATE})"
|
|
151
|
-
echo "
|
|
153
|
+
echo "$(m wf_readme.text_with_date version_text="$VERSION_TEXT")"
|
|
152
154
|
else
|
|
153
155
|
VERSION_TEXT="v${LATEST_VERSION}"
|
|
154
|
-
echo "
|
|
156
|
+
echo "$(m wf_readme.text version_text="$VERSION_TEXT")"
|
|
155
157
|
fi
|
|
156
158
|
|
|
157
159
|
# Patterns for recognized version lines (case-insensitive, flexible spacing)
|
|
@@ -172,14 +174,14 @@ jobs:
|
|
|
172
174
|
if grep -qi "$pattern" README.md; then
|
|
173
175
|
VERSION_LINE=$(grep -i "$pattern" README.md | head -n 1)
|
|
174
176
|
PATTERN_FOUND="$pattern"
|
|
175
|
-
echo "
|
|
177
|
+
echo "$(m wf_readme.line_found version_line="$VERSION_LINE")"
|
|
176
178
|
break
|
|
177
179
|
fi
|
|
178
180
|
done
|
|
179
181
|
|
|
180
182
|
# No version line yet — insert a default one
|
|
181
183
|
if [ -z "$VERSION_LINE" ]; then
|
|
182
|
-
echo "
|
|
184
|
+
echo "$(m wf_readme.line_inserting)"
|
|
183
185
|
# Heading wording follows the configured language; an existing line keeps its own wording
|
|
184
186
|
DEFAULT_HEADING=$(m wf_readme.default_heading)
|
|
185
187
|
|
|
@@ -190,16 +192,16 @@ jobs:
|
|
|
190
192
|
# at the very top of the file
|
|
191
193
|
sed -i '1i\<!-- AUTO-VERSION-SECTION: DO NOT EDIT MANUALLY -->\n## '"$DEFAULT_HEADING"' : '"$VERSION_TEXT"'\n' README.md
|
|
192
194
|
fi
|
|
193
|
-
echo "
|
|
195
|
+
echo "$(m wf_readme.line_inserted version_text="$VERSION_TEXT")"
|
|
194
196
|
else
|
|
195
197
|
# Update the existing version line
|
|
196
198
|
|
|
197
199
|
# Validate the line format
|
|
198
200
|
if [[ "$VERSION_LINE" =~ \*\* ]]; then
|
|
199
201
|
echo ""
|
|
200
|
-
echo "
|
|
201
|
-
echo "
|
|
202
|
-
echo "
|
|
202
|
+
echo "$(m wf_readme.warn_bold)"
|
|
203
|
+
echo "$(m wf_readme.warn_current_line version_line="$VERSION_LINE")"
|
|
204
|
+
echo "$(m wf_readme.warn_may_break)"
|
|
203
205
|
echo ""
|
|
204
206
|
fi
|
|
205
207
|
|
|
@@ -211,12 +213,12 @@ jobs:
|
|
|
211
213
|
PREV_LINE=$(sed -n "${PREV_LINE_NUMBER}p" README.md)
|
|
212
214
|
if [[ "$PREV_LINE" != *"AUTO-VERSION-SECTION"* ]]; then
|
|
213
215
|
sed -i "${PREV_LINE_NUMBER}a\\<!-- AUTO-VERSION-SECTION: DO NOT EDIT MANUALLY -->" README.md
|
|
214
|
-
echo "
|
|
216
|
+
echo "$(m wf_readme.marker_added)"
|
|
215
217
|
LINE_NUMBER=$((LINE_NUMBER + 1))
|
|
216
218
|
fi
|
|
217
219
|
else
|
|
218
220
|
sed -i '1i\<!-- AUTO-VERSION-SECTION: DO NOT EDIT MANUALLY -->' README.md
|
|
219
|
-
echo "
|
|
221
|
+
echo "$(m wf_readme.marker_added)"
|
|
220
222
|
LINE_NUMBER=$((LINE_NUMBER + 1))
|
|
221
223
|
fi
|
|
222
224
|
|
|
@@ -224,7 +226,7 @@ jobs:
|
|
|
224
226
|
HEADER_PART=$(printf '%s\n' "$VERSION_LINE" | sed 's/\(.*:\).*/\1 /')
|
|
225
227
|
|
|
226
228
|
if [ -z "$HEADER_PART" ] || [[ "$HEADER_PART" == "$VERSION_LINE" ]]; then
|
|
227
|
-
print_error_message "
|
|
229
|
+
print_error_message "$(m wf_readme.err_no_colon)" "$VERSION_LINE" "$HEADER_PART" "$VERSION_TEXT"
|
|
228
230
|
exit 1
|
|
229
231
|
fi
|
|
230
232
|
|
|
@@ -237,29 +239,30 @@ jobs:
|
|
|
237
239
|
ESCAPED_LINE=$(printf '%s' "$NEW_LINE" | sed 's/[&\\|]/\\&/g')
|
|
238
240
|
|
|
239
241
|
if ! sed -i "${LINE_NUMBER}s|.*|${ESCAPED_LINE}|" README.md 2>/tmp/sed_error.log; then
|
|
240
|
-
SED_ERROR=$(cat /tmp/sed_error.log 2>/dev/null ||
|
|
241
|
-
print_error_message "
|
|
242
|
+
SED_ERROR=$(cat /tmp/sed_error.log 2>/dev/null || m wf_readme.err_sed_unknown)
|
|
243
|
+
print_error_message "$(m wf_readme.err_sed error="$SED_ERROR")" "$VERSION_LINE" "$HEADER_PART" "$VERSION_TEXT"
|
|
242
244
|
exit 1
|
|
243
245
|
fi
|
|
244
246
|
|
|
245
247
|
# Verify the replacement
|
|
246
248
|
UPDATED_LINE=$(sed -n "${LINE_NUMBER}p" README.md)
|
|
247
249
|
if [[ "$UPDATED_LINE" != *"$VERSION_TEXT"* ]]; then
|
|
248
|
-
print_error_message "
|
|
249
|
-
echo "
|
|
250
|
+
print_error_message "$(m wf_readme.err_verify)" "$VERSION_LINE" "$HEADER_PART" "$VERSION_TEXT"
|
|
251
|
+
echo "$(m wf_readme.updated_line_detail updated_line="$UPDATED_LINE")"
|
|
250
252
|
exit 1
|
|
251
253
|
fi
|
|
252
254
|
|
|
253
|
-
echo "
|
|
255
|
+
echo "$(m wf_readme.line_updated version_text="$VERSION_TEXT")"
|
|
254
256
|
fi
|
|
255
257
|
|
|
256
258
|
- name: Commit and push changes
|
|
257
259
|
if: steps.precheck.outputs.readme_exists == 'true'
|
|
258
260
|
run: |
|
|
261
|
+
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
259
262
|
git add README.md
|
|
260
263
|
|
|
261
264
|
if git diff --staged --quiet; then
|
|
262
|
-
echo "
|
|
265
|
+
echo "$(m wf_readme.no_changes)"
|
|
263
266
|
else
|
|
264
267
|
VERSION="${{ steps.version_info.outputs.latest_version }}"
|
|
265
268
|
|
|
@@ -272,19 +275,19 @@ jobs:
|
|
|
272
275
|
|
|
273
276
|
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
|
|
274
277
|
RETRY_COUNT=$((RETRY_COUNT + 1))
|
|
275
|
-
echo "
|
|
278
|
+
echo "$(m wf_common.push_attempt retry_count="$RETRY_COUNT" max_retries="$MAX_RETRIES")"
|
|
276
279
|
|
|
277
280
|
if git push origin HEAD:{{MAIN_BRANCH}}; then
|
|
278
281
|
PUSH_SUCCESS=true
|
|
279
|
-
echo "
|
|
282
|
+
echo "$(m wf_readme.pushed)"
|
|
280
283
|
break
|
|
281
284
|
else
|
|
282
|
-
echo "
|
|
285
|
+
echo "$(m wf_common.push_failed_syncing)"
|
|
283
286
|
|
|
284
287
|
if git pull --rebase origin {{MAIN_BRANCH}}; then
|
|
285
|
-
echo "
|
|
288
|
+
echo "$(m wf_common.rebase_ok)"
|
|
286
289
|
else
|
|
287
|
-
echo "
|
|
290
|
+
echo "$(m wf_common.rebase_failed)"
|
|
288
291
|
git rebase --abort 2>/dev/null || true
|
|
289
292
|
exit 1
|
|
290
293
|
fi
|
|
@@ -292,7 +295,7 @@ jobs:
|
|
|
292
295
|
done
|
|
293
296
|
|
|
294
297
|
if [ "$PUSH_SUCCESS" = false ]; then
|
|
295
|
-
echo "
|
|
298
|
+
echo "$(m wf_common.push_gave_up max_retries="$MAX_RETRIES")"
|
|
296
299
|
exit 1
|
|
297
300
|
fi
|
|
298
301
|
fi
|
|
@@ -94,11 +94,12 @@ jobs:
|
|
|
94
94
|
- name: Detect branch mode
|
|
95
95
|
id: mode
|
|
96
96
|
run: |
|
|
97
|
+
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
97
98
|
# scoped to the metadata: -> template: -> branches: chain so an
|
|
98
99
|
# unrelated top-level "mode:" key can never hijack the value
|
|
99
100
|
MODE=$(python3 -c 'import re; t=open("version.yml",encoding="utf-8").read(); m=re.search(r"metadata:.*?template:.*?branches:.*?mode:\s*\"?([A-Za-z-]+)", t, re.S); print(m.group(1) if m else "pr-flow")' 2>/dev/null || echo "pr-flow")
|
|
100
101
|
echo "mode=$MODE" >> $GITHUB_OUTPUT
|
|
101
|
-
echo "
|
|
102
|
+
echo "$(m wf_release.branch_mode mode="$MODE")"
|
|
102
103
|
|
|
103
104
|
- name: Release gate
|
|
104
105
|
id: gate
|
|
@@ -123,11 +124,11 @@ jobs:
|
|
|
123
124
|
|
|
124
125
|
echo "proceed=$PROCEED" >> $GITHUB_OUTPUT
|
|
125
126
|
if [ "$PROCEED" = "true" ]; then
|
|
126
|
-
echo "
|
|
127
|
+
echo "$(m wf_release.gate_open mode="$MODE" event="$EVENT")"
|
|
127
128
|
exit 0
|
|
128
129
|
fi
|
|
129
130
|
|
|
130
|
-
echo "
|
|
131
|
+
echo "$(m wf_release.gate_closed)"
|
|
131
132
|
|
|
132
133
|
# Drift guard: skipping is normal, but a version.yml that
|
|
133
134
|
# has run ahead of the newest tag is not — it means the version was
|
|
@@ -138,13 +139,13 @@ jobs:
|
|
|
138
139
|
LATEST_VERSION="${LATEST_TAG#v}"
|
|
139
140
|
|
|
140
141
|
if [ -z "$FILE_VERSION" ] || [ -z "$LATEST_VERSION" ]; then
|
|
141
|
-
echo "
|
|
142
|
+
echo "$(m wf_release.drift_skipped)"
|
|
142
143
|
exit 0
|
|
143
144
|
fi
|
|
144
145
|
|
|
145
146
|
HIGHER=$(printf '%s\n%s\n' "$FILE_VERSION" "$LATEST_VERSION" | sort -V | tail -n 1)
|
|
146
147
|
if [ "$FILE_VERSION" != "$LATEST_VERSION" ] && [ "$HIGHER" = "$FILE_VERSION" ]; then
|
|
147
|
-
echo "::error
|
|
148
|
+
echo "::error::$(m wf_release.drift_error file_version="$FILE_VERSION" latest_tag="$LATEST_TAG")"
|
|
148
149
|
{
|
|
149
150
|
echo "$(m wf_release.drift_heading)"
|
|
150
151
|
echo ""
|
|
@@ -157,7 +158,7 @@ jobs:
|
|
|
157
158
|
exit 1
|
|
158
159
|
fi
|
|
159
160
|
|
|
160
|
-
echo "
|
|
161
|
+
echo "$(m wf_release.drift_ok file_version="$FILE_VERSION" latest_tag="$LATEST_TAG")"
|
|
161
162
|
|
|
162
163
|
- name: Read semver_auto option from version.yml
|
|
163
164
|
id: semver_options
|
|
@@ -166,11 +167,12 @@ jobs:
|
|
|
166
167
|
steps.mode.outputs.mode == 'trunk-based' &&
|
|
167
168
|
github.event_name == 'push'
|
|
168
169
|
run: |
|
|
170
|
+
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
169
171
|
# scoped to the metadata: -> template: -> options: chain so an
|
|
170
172
|
# unrelated "semver_auto:" key can never hijack the value
|
|
171
173
|
SEMVER_AUTO=$(python3 -c 'import re; t=open("version.yml",encoding="utf-8").read(); m=re.search(r"metadata:.*?template:.*?options:.*?semver_auto:\s*\"?(true|false)", t, re.S); print(m.group(1) if m else "false")' 2>/dev/null || echo "false")
|
|
172
174
|
echo "semver_auto=$SEMVER_AUTO" >> $GITHUB_OUTPUT
|
|
173
|
-
echo "
|
|
175
|
+
echo "$(m wf_common.semver_auto_option semver_auto="$SEMVER_AUTO")"
|
|
174
176
|
|
|
175
177
|
- name: Read copilot_ai option from version.yml
|
|
176
178
|
id: copilot_options
|
|
@@ -179,11 +181,12 @@ jobs:
|
|
|
179
181
|
steps.mode.outputs.mode == 'trunk-based' &&
|
|
180
182
|
github.event_name == 'push'
|
|
181
183
|
run: |
|
|
184
|
+
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
182
185
|
# scoped to the metadata: -> template: -> options: chain so an
|
|
183
186
|
# unrelated "copilot_ai:" key can never hijack the value
|
|
184
187
|
COPILOT_AI=$(python3 -c 'import re; t=open("version.yml",encoding="utf-8").read(); m=re.search(r"metadata:.*?template:.*?options:.*?copilot_ai:\s*\"?(true|false)", t, re.S); print(m.group(1) if m else "false")' 2>/dev/null || echo "false")
|
|
185
188
|
echo "copilot_ai=$COPILOT_AI" >> $GITHUB_OUTPUT
|
|
186
|
-
echo "
|
|
189
|
+
echo "$(m wf_common.copilot_ai_option copilot_ai="$COPILOT_AI")"
|
|
187
190
|
|
|
188
191
|
- name: Install Copilot CLI
|
|
189
192
|
if: >-
|
|
@@ -206,13 +209,14 @@ jobs:
|
|
|
206
209
|
GITHUB_TOKEN: ${{ github.token }}
|
|
207
210
|
COPILOT_AI: ${{ steps.copilot_options.outputs.copilot_ai }}
|
|
208
211
|
run: |
|
|
212
|
+
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
209
213
|
# Idempotency: on a re-run of a failed job the checked-out HEAD may
|
|
210
214
|
# already be this workflow's own docs commit — never bump twice.
|
|
211
215
|
# Jump straight to the common tail (tag + release for the current
|
|
212
216
|
# version).
|
|
213
217
|
HEAD_MSG=$(git log -1 --pretty=%s)
|
|
214
218
|
if printf '%s\n' "$HEAD_MSG" | grep -q "^chore(version): release v.* docs \[skip ci\]"; then
|
|
215
|
-
echo "
|
|
219
|
+
echo "$(m wf_release.head_is_docs_commit)"
|
|
216
220
|
exit 0
|
|
217
221
|
fi
|
|
218
222
|
|
|
@@ -222,11 +226,11 @@ jobs:
|
|
|
222
226
|
# release (no previous tag to diff against).
|
|
223
227
|
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
|
|
224
228
|
if [ -n "$LAST_TAG" ]; then
|
|
225
|
-
echo "
|
|
229
|
+
echo "$(m wf_release.collect_since last_tag="$LAST_TAG")"
|
|
226
230
|
LOG_RANGE="${LAST_TAG}..HEAD"
|
|
227
231
|
DIFF_BASE="$LAST_TAG"
|
|
228
232
|
else
|
|
229
|
-
echo "
|
|
233
|
+
echo "$(m wf_release.collect_all)"
|
|
230
234
|
LOG_RANGE="HEAD"
|
|
231
235
|
DIFF_BASE="4b825dc642cb6eb9a060e54bf8d69288fbee4904" # git empty tree hash
|
|
232
236
|
fi
|
|
@@ -248,15 +252,15 @@ jobs:
|
|
|
248
252
|
else
|
|
249
253
|
BUMP="patch"
|
|
250
254
|
fi
|
|
251
|
-
echo "
|
|
255
|
+
echo "$(m wf_common.bump_level bump="$BUMP")"
|
|
252
256
|
|
|
253
257
|
NEW_VERSION=$(python3 .github/scripts/version_manager.py increment --bump "$BUMP" | tail -n 1)
|
|
254
258
|
if [ -z "$NEW_VERSION" ]; then
|
|
255
|
-
echo "
|
|
259
|
+
echo "$(m wf_common.version_bump_failed)"
|
|
256
260
|
exit 1
|
|
257
261
|
fi
|
|
258
262
|
python3 .github/scripts/version_manager.py sync
|
|
259
|
-
echo "
|
|
263
|
+
echo "$(m wf_release.release_version new_version="$NEW_VERSION" bump="$BUMP")"
|
|
260
264
|
|
|
261
265
|
python3 .github/scripts/changelog_manager.py ai-summary \
|
|
262
266
|
--commits-file commits.txt \
|
|
@@ -289,7 +293,7 @@ jobs:
|
|
|
289
293
|
git add -u
|
|
290
294
|
git ls-files -z --others --exclude-standard -- CHANGELOG.json CHANGELOG.md | xargs -0 -r git add --
|
|
291
295
|
if git diff --staged --quiet; then
|
|
292
|
-
echo "
|
|
296
|
+
echo "$(m wf_common.no_changes)"
|
|
293
297
|
else
|
|
294
298
|
git commit -m "chore(version): release v${NEW_VERSION} docs [skip ci]"
|
|
295
299
|
|
|
@@ -300,18 +304,18 @@ jobs:
|
|
|
300
304
|
|
|
301
305
|
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
|
|
302
306
|
RETRY_COUNT=$((RETRY_COUNT + 1))
|
|
303
|
-
echo "
|
|
307
|
+
echo "$(m wf_common.push_attempt retry_count="$RETRY_COUNT" max_retries="$MAX_RETRIES")"
|
|
304
308
|
|
|
305
309
|
if git push origin HEAD:{{MAIN_BRANCH}}; then
|
|
306
310
|
PUSH_SUCCESS=true
|
|
307
|
-
echo "
|
|
311
|
+
echo "$(m wf_release.docs_pushed)"
|
|
308
312
|
break
|
|
309
313
|
else
|
|
310
|
-
echo "
|
|
314
|
+
echo "$(m wf_common.push_failed_syncing)"
|
|
311
315
|
if git pull --rebase origin {{MAIN_BRANCH}}; then
|
|
312
|
-
echo "
|
|
316
|
+
echo "$(m wf_common.rebase_ok)"
|
|
313
317
|
else
|
|
314
|
-
echo "
|
|
318
|
+
echo "$(m wf_common.rebase_failed)"
|
|
315
319
|
git rebase --abort 2>/dev/null || true
|
|
316
320
|
exit 1
|
|
317
321
|
fi
|
|
@@ -319,7 +323,7 @@ jobs:
|
|
|
319
323
|
done
|
|
320
324
|
|
|
321
325
|
if [ "$PUSH_SUCCESS" = false ]; then
|
|
322
|
-
echo "
|
|
326
|
+
echo "$(m wf_common.push_gave_up max_retries="$MAX_RETRIES")"
|
|
323
327
|
exit 1
|
|
324
328
|
fi
|
|
325
329
|
fi
|
|
@@ -330,9 +334,10 @@ jobs:
|
|
|
330
334
|
env:
|
|
331
335
|
GH_TOKEN: ${{ github.token }}
|
|
332
336
|
run: |
|
|
337
|
+
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
333
338
|
VERSION=$(python3 .github/scripts/version_manager.py get | tail -n 1)
|
|
334
339
|
if [ -z "$VERSION" ]; then
|
|
335
|
-
echo "
|
|
340
|
+
echo "$(m wf_release.read_version_failed)"
|
|
336
341
|
exit 1
|
|
337
342
|
fi
|
|
338
343
|
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
|
@@ -344,32 +349,34 @@ jobs:
|
|
|
344
349
|
# "release created" can be re-run and still publish the release.
|
|
345
350
|
if git rev-parse "v$VERSION" >/dev/null 2>&1; then
|
|
346
351
|
echo "tag_exists=true" >> $GITHUB_OUTPUT
|
|
347
|
-
echo "
|
|
352
|
+
echo "$(m wf_release.tag_exists version="$VERSION")"
|
|
348
353
|
else
|
|
349
354
|
echo "tag_exists=false" >> $GITHUB_OUTPUT
|
|
350
355
|
fi
|
|
351
356
|
|
|
352
357
|
if gh release view "v$VERSION" >/dev/null 2>&1; then
|
|
353
358
|
echo "release_exists=true" >> $GITHUB_OUTPUT
|
|
354
|
-
echo "
|
|
359
|
+
echo "$(m wf_release.release_exists version="$VERSION")"
|
|
355
360
|
else
|
|
356
361
|
echo "release_exists=false" >> $GITHUB_OUTPUT
|
|
357
|
-
echo "publishing
|
|
362
|
+
echo "$(m wf_release.publishing version="$VERSION")"
|
|
358
363
|
fi
|
|
359
364
|
|
|
360
365
|
- name: Create and push tag
|
|
361
366
|
if: steps.gate.outputs.proceed == 'true' && steps.version.outputs.tag_exists != 'true'
|
|
362
367
|
run: |
|
|
368
|
+
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
363
369
|
VERSION="${{ steps.version.outputs.version }}"
|
|
364
370
|
git tag "v$VERSION"
|
|
365
371
|
git push origin "v$VERSION"
|
|
366
|
-
echo "
|
|
372
|
+
echo "$(m wf_release.tag_pushed version="$VERSION")"
|
|
367
373
|
|
|
368
374
|
- name: Build release notes (changelog export + GitHub generate-notes)
|
|
369
375
|
if: steps.gate.outputs.proceed == 'true' && steps.version.outputs.release_exists != 'true'
|
|
370
376
|
env:
|
|
371
377
|
GH_TOKEN: ${{ github.token }}
|
|
372
378
|
run: |
|
|
379
|
+
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
373
380
|
VERSION="${{ steps.version.outputs.version }}"
|
|
374
381
|
|
|
375
382
|
# AI/changelog notes for this version
|
|
@@ -397,7 +404,7 @@ jobs:
|
|
|
397
404
|
echo "Release v$VERSION" > notes.md
|
|
398
405
|
fi
|
|
399
406
|
|
|
400
|
-
echo "
|
|
407
|
+
echo "$(m wf_release.notes_assembled n="$(wc -c < notes.md)")"
|
|
401
408
|
|
|
402
409
|
- name: Create GitHub Release
|
|
403
410
|
if: steps.gate.outputs.proceed == 'true' && steps.version.outputs.release_exists != 'true'
|
|
@@ -408,9 +415,10 @@ jobs:
|
|
|
408
415
|
# default token.
|
|
409
416
|
GH_TOKEN: ${{ secrets.WORKFLOW_PAT || github.token }}
|
|
410
417
|
run: |
|
|
418
|
+
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
411
419
|
VERSION="${{ steps.version.outputs.version }}"
|
|
412
420
|
gh release create "v$VERSION" --title "v$VERSION" --notes-file notes.md
|
|
413
|
-
echo "
|
|
421
|
+
echo "$(m wf_release.published version="$VERSION")"
|
|
414
422
|
|
|
415
423
|
- name: Trigger README-VERSION-UPDATE
|
|
416
424
|
# Pushes made with the bot token (GITHUB_TOKEN) never wake the README update
|
|
@@ -66,20 +66,21 @@ jobs:
|
|
|
66
66
|
- name: Release merge / mode guard
|
|
67
67
|
id: release_guard
|
|
68
68
|
run: |
|
|
69
|
+
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
69
70
|
SKIP="false"
|
|
70
71
|
|
|
71
72
|
# trunk-based mode: RELEASE-PUBLISH owns versioning — skip safety net
|
|
72
73
|
MODE=$(python3 -c 'import re; t=open("version.yml",encoding="utf-8").read(); m=re.search(r"^\s*mode:\s*\"?([A-Za-z-]+)", t, re.M); print(m.group(1) if m else "pr-flow")' 2>/dev/null || echo "pr-flow")
|
|
73
74
|
if [ "$MODE" = "trunk-based" ]; then
|
|
74
75
|
SKIP="true"
|
|
75
|
-
echo "
|
|
76
|
+
echo "$(m wf_version.trunk_skip)"
|
|
76
77
|
fi
|
|
77
78
|
|
|
78
79
|
# release-confirm pattern: the merge commit of a release PR
|
|
79
80
|
HEAD_MSG=$(git log -1 --pretty=%B)
|
|
80
81
|
if echo "$HEAD_MSG" | grep -q "chore(release):"; then
|
|
81
82
|
SKIP="true"
|
|
82
|
-
echo "
|
|
83
|
+
echo "$(m wf_version.confirm_skip)"
|
|
83
84
|
fi
|
|
84
85
|
|
|
85
86
|
# release merge detection: the release push includes a version.yml change
|
|
@@ -91,51 +92,54 @@ jobs:
|
|
|
91
92
|
fi
|
|
92
93
|
if git diff --name-only $RANGE 2>/dev/null | grep -qx "version.yml"; then
|
|
93
94
|
SKIP="true"
|
|
94
|
-
echo "
|
|
95
|
+
echo "$(m wf_version.release_merge_skip)"
|
|
95
96
|
fi
|
|
96
97
|
|
|
97
98
|
echo "skip=$SKIP" >> $GITHUB_OUTPUT
|
|
98
99
|
if [ "$SKIP" = "false" ]; then
|
|
99
|
-
echo "
|
|
100
|
+
echo "$(m wf_version.direct_push main_branch="{{MAIN_BRANCH}}")"
|
|
100
101
|
fi
|
|
101
102
|
|
|
102
103
|
- name: Read current version
|
|
103
104
|
id: current_version
|
|
104
105
|
if: steps.release_guard.outputs.skip != 'true'
|
|
105
106
|
run: |
|
|
107
|
+
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
106
108
|
CURRENT_VERSION=$(python3 .github/scripts/version_manager.py get | tail -n 1)
|
|
107
109
|
if [ -z "$CURRENT_VERSION" ]; then
|
|
108
|
-
echo "
|
|
110
|
+
echo "$(m wf_version.read_current_failed)"
|
|
109
111
|
exit 1
|
|
110
112
|
fi
|
|
111
113
|
echo "current_version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
|
|
112
|
-
echo "
|
|
114
|
+
echo "$(m wf_version.current_version current_version="$CURRENT_VERSION")"
|
|
113
115
|
|
|
114
116
|
- name: Bump patch version and sync
|
|
115
117
|
id: version
|
|
116
118
|
if: steps.release_guard.outputs.skip != 'true'
|
|
117
119
|
run: |
|
|
120
|
+
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
118
121
|
NEW_VERSION=$(python3 .github/scripts/version_manager.py increment | tail -n 1)
|
|
119
122
|
if [ -z "$NEW_VERSION" ]; then
|
|
120
|
-
echo "
|
|
123
|
+
echo "$(m wf_common.version_bump_failed)"
|
|
121
124
|
exit 1
|
|
122
125
|
fi
|
|
123
126
|
python3 .github/scripts/version_manager.py sync
|
|
124
127
|
echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT
|
|
125
|
-
echo "
|
|
128
|
+
echo "$(m wf_version.new_version new_version="$NEW_VERSION")"
|
|
126
129
|
|
|
127
130
|
- name: Read project types
|
|
128
131
|
id: project_info
|
|
129
132
|
if: steps.release_guard.outputs.skip != 'true'
|
|
130
133
|
run: |
|
|
134
|
+
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
131
135
|
if [ -f "version.yml" ]; then
|
|
132
136
|
PROJECT_TYPES=$(grep "^project_types:" version.yml 2>/dev/null | sed -E 's/.*\[([^]]*)\].*/\1/' | tr -d '" ')
|
|
133
137
|
PROJECT_TYPES=${PROJECT_TYPES:-unknown}
|
|
134
138
|
echo "project_types=$PROJECT_TYPES" >> $GITHUB_OUTPUT
|
|
135
|
-
echo "
|
|
139
|
+
echo "$(m wf_version.project_types project_types="$PROJECT_TYPES")"
|
|
136
140
|
else
|
|
137
141
|
echo "project_types=unknown" >> $GITHUB_OUTPUT
|
|
138
|
-
echo "
|
|
142
|
+
echo "$(m wf_version.yml_not_found)"
|
|
139
143
|
fi
|
|
140
144
|
|
|
141
145
|
- name: Update CHANGELOG for the safety-net release
|
|
@@ -150,6 +154,7 @@ jobs:
|
|
|
150
154
|
AI_API_BASE_URL: ${{ vars.AI_API_BASE_URL }}
|
|
151
155
|
AI_MODEL: ${{ vars.AI_MODEL }}
|
|
152
156
|
run: |
|
|
157
|
+
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
153
158
|
NEW_VERSION="${{ steps.version.outputs.new_version }}"
|
|
154
159
|
|
|
155
160
|
# Commits pushed straight to {{MAIN_BRANCH}} since the last release tag (full history if there is no tag)
|
|
@@ -160,7 +165,7 @@ jobs:
|
|
|
160
165
|
# line. The script reads each line as one entry, so passing the whole body (%B)
|
|
161
166
|
# would turn description lines into change entries.
|
|
162
167
|
git log --pretty=%b "$LOG_RANGE" | grep -E '^BREAKING[ -]CHANGE[[:space:]]*:' >> commits.txt || true
|
|
163
|
-
echo "
|
|
168
|
+
echo "$(m wf_version.commits_since last_tag="${LAST_TAG:-the beginning}" n="$(wc -l < commits.txt)")"
|
|
164
169
|
|
|
165
170
|
python3 .github/scripts/changelog_manager.py ai-summary \
|
|
166
171
|
--commits-file commits.txt \
|
|
@@ -183,6 +188,7 @@ jobs:
|
|
|
183
188
|
id: commit_push
|
|
184
189
|
if: steps.release_guard.outputs.skip != 'true'
|
|
185
190
|
run: |
|
|
191
|
+
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
186
192
|
git config --local user.email "action@github.com"
|
|
187
193
|
git config --local user.name "GitHub Action"
|
|
188
194
|
|
|
@@ -193,7 +199,7 @@ jobs:
|
|
|
193
199
|
git ls-files -z --others --exclude-standard -- CHANGELOG.json CHANGELOG.md | xargs -0 -r git add --
|
|
194
200
|
|
|
195
201
|
if git diff --staged --quiet; then
|
|
196
|
-
echo "
|
|
202
|
+
echo "$(m wf_version.no_changes_synced)"
|
|
197
203
|
echo "pushed=false" >> "$GITHUB_OUTPUT"
|
|
198
204
|
else
|
|
199
205
|
NEW_VERSION="${{ steps.version.outputs.new_version }}"
|
|
@@ -207,18 +213,18 @@ jobs:
|
|
|
207
213
|
|
|
208
214
|
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
|
|
209
215
|
RETRY_COUNT=$((RETRY_COUNT + 1))
|
|
210
|
-
echo "
|
|
216
|
+
echo "$(m wf_common.push_attempt retry_count="$RETRY_COUNT" max_retries="$MAX_RETRIES")"
|
|
211
217
|
|
|
212
218
|
if git push origin HEAD:{{MAIN_BRANCH}}; then
|
|
213
219
|
PUSH_SUCCESS=true
|
|
214
|
-
echo "
|
|
220
|
+
echo "$(m wf_version.bump_pushed)"
|
|
215
221
|
break
|
|
216
222
|
else
|
|
217
|
-
echo "
|
|
223
|
+
echo "$(m wf_common.push_failed_syncing)"
|
|
218
224
|
if git pull --rebase origin {{MAIN_BRANCH}}; then
|
|
219
|
-
echo "
|
|
225
|
+
echo "$(m wf_common.rebase_ok)"
|
|
220
226
|
else
|
|
221
|
-
echo "
|
|
227
|
+
echo "$(m wf_common.rebase_failed)"
|
|
222
228
|
git rebase --abort 2>/dev/null || true
|
|
223
229
|
exit 1
|
|
224
230
|
fi
|
|
@@ -226,12 +232,12 @@ jobs:
|
|
|
226
232
|
done
|
|
227
233
|
|
|
228
234
|
if [ "$PUSH_SUCCESS" = false ]; then
|
|
229
|
-
echo "
|
|
235
|
+
echo "$(m wf_common.push_gave_up max_retries="$MAX_RETRIES")"
|
|
230
236
|
exit 1
|
|
231
237
|
fi
|
|
232
238
|
echo "pushed=true" >> "$GITHUB_OUTPUT"
|
|
233
239
|
else
|
|
234
|
-
echo "
|
|
240
|
+
echo "$(m wf_version.commit_failed)"
|
|
235
241
|
exit 1
|
|
236
242
|
fi
|
|
237
243
|
fi
|
|
@@ -260,7 +266,7 @@ jobs:
|
|
|
260
266
|
MANUAL="git checkout $DEVELOP_BRANCH && git pull && git merge origin/{{MAIN_BRANCH}} && git push"
|
|
261
267
|
|
|
262
268
|
if ! git ls-remote --exit-code --heads origin "$DEVELOP_BRANCH" >/dev/null 2>&1; then
|
|
263
|
-
echo "
|
|
269
|
+
echo "$(m wf_version.no_develop develop_branch="$DEVELOP_BRANCH")"
|
|
264
270
|
exit 0
|
|
265
271
|
fi
|
|
266
272
|
|
|
@@ -268,7 +274,7 @@ jobs:
|
|
|
268
274
|
git fetch -q origin "$DEVELOP_BRANCH" {{MAIN_BRANCH}}
|
|
269
275
|
git checkout -q -B safety-net-back-merge "origin/$DEVELOP_BRANCH"
|
|
270
276
|
if git merge-base --is-ancestor "origin/{{MAIN_BRANCH}}" HEAD; then
|
|
271
|
-
echo "$
|
|
277
|
+
echo "$(m wf_version.already_contains develop_branch="$DEVELOP_BRANCH" main_branch="{{MAIN_BRANCH}}")"
|
|
272
278
|
exit 0
|
|
273
279
|
fi
|
|
274
280
|
if ! git merge --no-edit -m "chore(version): merge v${NEW_VERSION} safety-net bump into ${DEVELOP_BRANCH} [skip ci]" "origin/{{MAIN_BRANCH}}"; then
|
|
@@ -277,10 +283,10 @@ jobs:
|
|
|
277
283
|
exit 0
|
|
278
284
|
fi
|
|
279
285
|
if git push origin "HEAD:$DEVELOP_BRANCH"; then
|
|
280
|
-
echo "
|
|
286
|
+
echo "$(m wf_version.backmerged new_version="$NEW_VERSION" develop_branch="$DEVELOP_BRANCH")"
|
|
281
287
|
exit 0
|
|
282
288
|
fi
|
|
283
|
-
echo "
|
|
289
|
+
echo "$(m wf_version.push_retry attempt="$ATTEMPT")"
|
|
284
290
|
sleep 5
|
|
285
291
|
done
|
|
286
292
|
echo "::warning::$(m wf_version.backmerge_push_failed dev="$DEVELOP_BRANCH" manual="$MANUAL")"
|
|
@@ -288,8 +294,9 @@ jobs:
|
|
|
288
294
|
- name: Summary
|
|
289
295
|
if: always()
|
|
290
296
|
run: |
|
|
291
|
-
|
|
292
|
-
echo "
|
|
293
|
-
echo "
|
|
294
|
-
echo "
|
|
295
|
-
echo "
|
|
297
|
+
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
298
|
+
echo "$(m wf_version.finished)"
|
|
299
|
+
echo "$(m wf_version.sum_skipped skip="${{ steps.release_guard.outputs.skip }}")"
|
|
300
|
+
echo "$(m wf_version.sum_previous current_version="${{ steps.current_version.outputs.current_version }}")"
|
|
301
|
+
echo "$(m wf_version.sum_new new_version="${{ steps.version.outputs.new_version }}")"
|
|
302
|
+
echo "$(m wf_version.sum_branch ref_name="${{ github.ref_name }}")"
|