project-auto-wizard 0.15.0 → 0.15.1
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 +1 -1
- package/README.ko.md +1 -1
- package/README.md +2 -2
- package/README.zh-CN.md +1 -1
- package/package.json +1 -1
- package/payload/config/breaking-changes.json +31 -5
- package/payload/config/wizard-prompts.yml +0 -4
- package/payload/scripts/messages.py +156 -26
- package/payload/scripts/version_manager.py +69 -40
- package/payload/version.yml.template +2 -2
- package/payload/workflows/common/PROJECT-COMMON-AI-PR-SUMMARY.yaml +3 -0
- package/payload/workflows/common/PROJECT-COMMON-AUTO-CHANGELOG-CONTROL.yaml +15 -1
- package/payload/workflows/common/PROJECT-COMMON-README-VERSION-UPDATE.yaml +61 -12
- package/payload/workflows/common/PROJECT-COMMON-RELEASE-PUBLISH.yaml +46 -10
- package/payload/workflows/common/PROJECT-COMMON-VERSION-CONTROL.yaml +40 -11
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-FIREBASE-CICD.yaml +24 -8
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-PLAYSTORE-CICD.yaml +29 -10
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-SELFHOSTED-CICD.yaml +57 -23
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-TEST-APK.yaml +155 -72
- package/payload/workflows/flutter/PROJECT-FLUTTER-APP-BUILD-TRIGGER.yaml +49 -20
- package/payload/workflows/flutter/PROJECT-FLUTTER-CI.yaml +162 -62
- package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TEST-TESTFLIGHT.yaml +184 -87
- package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TESTFLIGHT.yaml +38 -15
- package/payload/workflows/go/PROJECT-GO-CI.yaml +14 -5
- package/payload/workflows/go/PROJECT-GO-PR-PREVIEW.yaml +375 -120
- package/payload/workflows/go/PROJECT-GO-SIMPLE-CICD.yaml +9 -4
- package/payload/workflows/python/PROJECT-PYTHON-CI.yaml +12 -4
- package/payload/workflows/python/PROJECT-PYTHON-PR-PREVIEW.yaml +375 -120
- package/payload/workflows/python/PROJECT-PYTHON-SIMPLE-CICD.yaml +9 -4
- package/payload/workflows/react/PROJECT-REACT-CI.yaml +38 -9
- package/payload/workflows/react/PROJECT-REACT-CICD.yaml +19 -5
- package/payload/workflows/spring/PROJECT-SPRING-CI.yml +71 -35
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-NONSTOP-NGINX-CICD.yaml +9 -6
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-NONSTOP-TRAEFIK-CICD.yaml +7 -4
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-PR-PREVIEW.yaml +425 -144
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-SIMPLE-CICD.yaml +7 -4
- package/src/cli/args.js +17 -7
- package/src/commands/doctor.js +11 -0
- package/src/commands/dry-run.js +9 -1
- package/src/commands/full.js +5 -2
- package/src/commands/interactive.js +4 -1
- package/src/commands/status.js +14 -1
- package/src/core/copy/simple.js +31 -0
- package/src/core/copy/workflows.js +2 -2
- package/src/core/deploy-style.js +1 -1
- package/src/core/detect.js +3 -2
- package/src/core/types.js +15 -8
- package/src/core/version-yml.js +52 -6
- package/src/i18n/catalog/en/cli.js +1 -0
- package/src/i18n/catalog/en/commands.js +8 -0
- package/src/i18n/catalog/en/core2.js +3 -0
- package/src/i18n/catalog/ko/cli.js +1 -0
- package/src/i18n/catalog/ko/commands.js +8 -0
- package/src/i18n/catalog/ko/core2.js +3 -0
- package/src/index.js +4 -1
- package/src/ui/env-plan.js +1 -1
- package/src/ui/prompts.js +7 -3
- package/payload/workflows/next/PROJECT-NEXT-CI.yaml +0 -241
- package/payload/workflows/next/PROJECT-NEXT-CICD.yaml +0 -330
|
@@ -95,16 +95,33 @@ def read_file(path):
|
|
|
95
95
|
|
|
96
96
|
def write_file(path, text):
|
|
97
97
|
"""Write text preserving the dominant line ending of the existing file
|
|
98
|
-
on disk (LF stays LF, CRLF stays CRLF — never platform-dependent).
|
|
98
|
+
on disk (LF stays LF, CRLF stays CRLF — never platform-dependent).
|
|
99
|
+
Returns False (and leaves the file untouched) when the content is already identical."""
|
|
99
100
|
p = Path(path)
|
|
100
101
|
eol = "\n"
|
|
102
|
+
previous = None
|
|
101
103
|
if p.is_file():
|
|
102
104
|
with open(p, "r", encoding="utf-8", newline="") as f:
|
|
103
|
-
|
|
105
|
+
previous = f.read()
|
|
106
|
+
eol = _detect_eol(previous)
|
|
104
107
|
if eol != "\n":
|
|
105
108
|
text = text.replace("\n", eol)
|
|
109
|
+
if previous == text:
|
|
110
|
+
return False
|
|
106
111
|
with open(p, "w", encoding="utf-8", newline="") as f:
|
|
107
112
|
f.write(text)
|
|
113
|
+
return True
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
# Files whose content actually changed in this process. Lets the sync check tell "reconciled" from "already in sync".
|
|
117
|
+
_CHANGED_FILES = []
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def write_synced(path, text):
|
|
121
|
+
"""write_file() for version files: logs `updated:` only when the content really changed."""
|
|
122
|
+
if write_file(path, text):
|
|
123
|
+
_CHANGED_FILES.append(str(path))
|
|
124
|
+
log(t("version_manager.updated", path=path))
|
|
108
125
|
|
|
109
126
|
|
|
110
127
|
# ===================================================================
|
|
@@ -176,6 +193,21 @@ def get_current_version():
|
|
|
176
193
|
return read_scalar_key("version", "0.0.0")
|
|
177
194
|
|
|
178
195
|
|
|
196
|
+
# Names that used to be separate types. A version.yml written before the merge may still carry them,
|
|
197
|
+
# and the release workflow can run before the wizard rewrites that file, so they are read as the new name.
|
|
198
|
+
TYPE_ALIASES = {"next": "react"}
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def _canonical_types(types):
|
|
202
|
+
"""Map aliased type names to their current name, dropping duplicates while keeping order."""
|
|
203
|
+
out = []
|
|
204
|
+
for t in types:
|
|
205
|
+
t = TYPE_ALIASES.get(t, t)
|
|
206
|
+
if t not in out:
|
|
207
|
+
out.append(t)
|
|
208
|
+
return out
|
|
209
|
+
|
|
210
|
+
|
|
179
211
|
def get_project_types_csv():
|
|
180
212
|
"""Return project_types as a list. Supports both:
|
|
181
213
|
project_types: ["a", "b"]
|
|
@@ -196,7 +228,7 @@ def get_project_types_csv():
|
|
|
196
228
|
inner = m.group(1)
|
|
197
229
|
items = re.findall(r'"([^"]*)"|\'([^\']*)\'', inner)
|
|
198
230
|
types = [a or b for a, b in items]
|
|
199
|
-
return [t for t in types if t]
|
|
231
|
+
return _canonical_types([t for t in types if t])
|
|
200
232
|
|
|
201
233
|
# Block list form:
|
|
202
234
|
# project_types:
|
|
@@ -207,7 +239,7 @@ def get_project_types_csv():
|
|
|
207
239
|
block = m.group(1)
|
|
208
240
|
# trailing comments are allowed on list items too
|
|
209
241
|
types = re.findall(r'-[ \t]*["\']?([^"\'#\n]+?)["\']?[ \t]*(?:#.*)?$', block, re.MULTILINE)
|
|
210
|
-
return [t.strip() for t in types if t.strip()]
|
|
242
|
+
return _canonical_types([t.strip() for t in types if t.strip()])
|
|
211
243
|
|
|
212
244
|
return []
|
|
213
245
|
|
|
@@ -221,16 +253,19 @@ def get_type_path(project_type, project_types_list=None):
|
|
|
221
253
|
if not m:
|
|
222
254
|
return "."
|
|
223
255
|
block = m.group(1)
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
256
|
+
# The current name first, then any older name that maps to it (e.g. next -> react).
|
|
257
|
+
names = [project_type] + [old for old, new in TYPE_ALIASES.items() if new == project_type]
|
|
258
|
+
for name in names:
|
|
259
|
+
km = re.search(
|
|
260
|
+
r'^[ \t]+["\']?' + re.escape(name)
|
|
261
|
+
+ r'["\']?:[ \t]*["\']?([^"\'#\n]+?)["\']?[ \t]*(?:#.*)?$',
|
|
262
|
+
block,
|
|
263
|
+
re.MULTILINE,
|
|
264
|
+
)
|
|
265
|
+
if km:
|
|
266
|
+
val = km.group(1).strip()
|
|
267
|
+
if val and val != "null":
|
|
268
|
+
return val
|
|
234
269
|
return "."
|
|
235
270
|
|
|
236
271
|
|
|
@@ -419,8 +454,7 @@ def sync_maven(path_dir, new_version):
|
|
|
419
454
|
return True
|
|
420
455
|
new_full = _keep_snapshot(old_version, new_version)
|
|
421
456
|
new_text, _ = _pom_replace(text, ["version"], new_full)
|
|
422
|
-
|
|
423
|
-
log(t("version_manager.updated", path=root_pom))
|
|
457
|
+
write_synced(root_pom, new_text)
|
|
424
458
|
|
|
425
459
|
root_artifact = _pom_text(text, ["artifactId"])
|
|
426
460
|
for child in sorted(Path(path_dir).glob("*/pom.xml")):
|
|
@@ -432,8 +466,7 @@ def sync_maven(path_dir, new_version):
|
|
|
432
466
|
ctext, _ = _pom_replace(ctext, ["parent", "version"], new_full)
|
|
433
467
|
if _pom_text(ctext, ["version"]) == old_version:
|
|
434
468
|
ctext, _ = _pom_replace(ctext, ["version"], new_full)
|
|
435
|
-
|
|
436
|
-
log(t("version_manager.updated", path=child))
|
|
469
|
+
write_synced(child, ctext)
|
|
437
470
|
return True
|
|
438
471
|
|
|
439
472
|
|
|
@@ -524,8 +557,7 @@ def sync_spring(path_dir, new_version):
|
|
|
524
557
|
if not matches:
|
|
525
558
|
log(t("version_manager.warn_spring_no_gradle_line", file=gradle_file))
|
|
526
559
|
continue
|
|
527
|
-
|
|
528
|
-
log(t("version_manager.updated", path=gradle_file))
|
|
560
|
+
write_synced(gradle_file, new_text)
|
|
529
561
|
|
|
530
562
|
|
|
531
563
|
def _pubspec_build_number(path_dir):
|
|
@@ -566,8 +598,7 @@ def sync_flutter(path_dir, new_version, version_code):
|
|
|
566
598
|
new_text = pattern.sub(r'\1 ' + full_version, text, count=1)
|
|
567
599
|
else:
|
|
568
600
|
new_text = text.rstrip("\n") + f"\nversion: {full_version}\n"
|
|
569
|
-
|
|
570
|
-
log(t("version_manager.updated", path=target))
|
|
601
|
+
write_synced(target, new_text)
|
|
571
602
|
|
|
572
603
|
|
|
573
604
|
def _json_indent(text):
|
|
@@ -594,8 +625,7 @@ def sync_json_version(target, new_version, key_path):
|
|
|
594
625
|
for k in key_path[:-1]:
|
|
595
626
|
node = node.setdefault(k, {})
|
|
596
627
|
node[key_path[-1]] = new_version
|
|
597
|
-
|
|
598
|
-
log(t("version_manager.updated", path=target))
|
|
628
|
+
write_synced(target, json.dumps(data, indent=_json_indent(raw), ensure_ascii=False) + "\n")
|
|
599
629
|
|
|
600
630
|
|
|
601
631
|
_TOML_HEADER_RE = re.compile(r'^[ \t]*\[+[ \t]*([^\]\n]+?)[ \t]*\]+[ \t]*(?:#.*)?$', re.MULTILINE)
|
|
@@ -645,8 +675,7 @@ def sync_python(path_dir, new_version):
|
|
|
645
675
|
return
|
|
646
676
|
for target, (start, end) in spans:
|
|
647
677
|
text = read_file(target)
|
|
648
|
-
|
|
649
|
-
log(t("version_manager.updated", path=target))
|
|
678
|
+
write_synced(target, text[:start] + new_version + text[end:])
|
|
650
679
|
|
|
651
680
|
|
|
652
681
|
_PLIST_VERSION_RE = re.compile(r'(<key>CFBundleShortVersionString</key>\s*<string>)([^<]*)(</string>)')
|
|
@@ -676,8 +705,7 @@ def sync_react_native(path_dir, new_version):
|
|
|
676
705
|
log(t("version_manager.skipped_plist", file=plist_file))
|
|
677
706
|
continue
|
|
678
707
|
new_text = _PLIST_VERSION_RE.sub(lambda mm: mm.group(1) + new_version + mm.group(3), text)
|
|
679
|
-
|
|
680
|
-
log(t("version_manager.updated", path=plist_file))
|
|
708
|
+
write_synced(plist_file, new_text)
|
|
681
709
|
found_plist = True
|
|
682
710
|
else:
|
|
683
711
|
log(t("version_manager.warn_rn_ios_missing", dir=ios_dir))
|
|
@@ -686,8 +714,7 @@ def sync_react_native(path_dir, new_version):
|
|
|
686
714
|
if gradle_file.is_file():
|
|
687
715
|
text = read_file(gradle_file)
|
|
688
716
|
new_text = re.sub(r'versionName\s+"[^"]*"', f'versionName "{new_version}"', text)
|
|
689
|
-
|
|
690
|
-
log(t("version_manager.updated", path=gradle_file))
|
|
717
|
+
write_synced(gradle_file, new_text)
|
|
691
718
|
else:
|
|
692
719
|
log(t("version_manager.warn_rn_gradle_missing", file=gradle_file))
|
|
693
720
|
|
|
@@ -859,7 +886,6 @@ TYPE_HANDLERS = {
|
|
|
859
886
|
# Only types that need a build number compute version_code (this has a pubspec-adjusting side effect).
|
|
860
887
|
"flutter": TypeHandler(read=_read_flutter, sync=lambda d, v, code: sync_flutter(d, v, code())),
|
|
861
888
|
"react": _PACKAGE_JSON,
|
|
862
|
-
"next": _PACKAGE_JSON,
|
|
863
889
|
"node": _PACKAGE_JSON,
|
|
864
890
|
"python": TypeHandler(read=_read_python, sync=lambda d, v, _code: sync_python(d, v)),
|
|
865
891
|
"react-native": TypeHandler(read=_read_react_native, sync=lambda d, v, _code: sync_react_native(d, v)),
|
|
@@ -896,11 +922,12 @@ def sync_versions():
|
|
|
896
922
|
primary_type = types[0]
|
|
897
923
|
project_version = get_project_file_version(primary_type)
|
|
898
924
|
|
|
899
|
-
log(t("version_manager.sync_check"))
|
|
900
|
-
log(t("version_manager.sync_yml_version", version=yml_version))
|
|
901
|
-
log(t("version_manager.sync_project_version", version=project_version))
|
|
902
|
-
|
|
903
925
|
if yml_version != project_version:
|
|
926
|
+
# The detail lines are only useful when the two disagree; an in-sync check prints a single line
|
|
927
|
+
# (this check runs several times per job, so a multi-line block each time is just noise).
|
|
928
|
+
log(t("version_manager.sync_check"))
|
|
929
|
+
log(t("version_manager.sync_yml_version", version=yml_version))
|
|
930
|
+
log(t("version_manager.sync_project_version", version=project_version))
|
|
904
931
|
if validate_version(yml_version) and validate_version(project_version):
|
|
905
932
|
higher = get_higher_version(yml_version, project_version)
|
|
906
933
|
log(t("version_manager.sync_mismatch", version=higher))
|
|
@@ -913,11 +940,13 @@ def sync_versions():
|
|
|
913
940
|
log(t("version_manager.warn_format_invalid"))
|
|
914
941
|
return yml_version
|
|
915
942
|
else:
|
|
916
|
-
types
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
943
|
+
# The primary type matches, but the other types' files may still lag behind; reconcile them quietly.
|
|
944
|
+
changed_before = len(_CHANGED_FILES)
|
|
945
|
+
sync_all_project_files(yml_version)
|
|
946
|
+
if len(_CHANGED_FILES) > changed_before:
|
|
947
|
+
log(t("version_manager.sync_reconciled", version=yml_version))
|
|
948
|
+
else:
|
|
949
|
+
log(t("version_manager.sync_ok", version=yml_version))
|
|
921
950
|
return yml_version
|
|
922
951
|
|
|
923
952
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
# workflows call GitHub Copilot CLI, which consumes GitHub Copilot AI Credits.
|
|
11
11
|
# Falls back to rule-based summaries whenever Copilot is off or unavailable.
|
|
12
12
|
# ===
|
|
13
|
-
# Supported project types: spring, flutter,
|
|
13
|
+
# Supported project types: spring, flutter, react, react-native,
|
|
14
14
|
# react-native-expo, node, python, basic, go
|
|
15
15
|
# Multi-type projects: list every type in the project_types array
|
|
16
16
|
# -> the first entry is the primary type (project_types is the single source of truth)
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
# Synced files per type:
|
|
21
21
|
# - spring: build.gradle / build.gradle.kts / pom.xml
|
|
22
22
|
# - flutter: pubspec.yaml
|
|
23
|
-
# -
|
|
23
|
+
# - react/node: package.json
|
|
24
24
|
# - react-native: Info.plist + build.gradle
|
|
25
25
|
# - react-native-expo: app.json
|
|
26
26
|
# - python: pyproject.toml / setup.py
|
|
@@ -53,6 +53,7 @@ jobs:
|
|
|
53
53
|
- name: Read copilot_ai option from version.yml
|
|
54
54
|
id: copilot_options
|
|
55
55
|
run: |
|
|
56
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
56
57
|
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
57
58
|
# scoped to the metadata: -> template: -> options: chain so an
|
|
58
59
|
# unrelated "copilot_ai:" key can never hijack the value
|
|
@@ -75,6 +76,7 @@ jobs:
|
|
|
75
76
|
COPILOT_AI: ${{ steps.copilot_options.outputs.copilot_ai }}
|
|
76
77
|
GH_TOKEN: ${{ github.token }}
|
|
77
78
|
run: |
|
|
79
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
78
80
|
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
79
81
|
PR_NUMBER=${{ github.event.pull_request.number }}
|
|
80
82
|
|
|
@@ -154,6 +156,7 @@ jobs:
|
|
|
154
156
|
# AUTO-CHANGELOG-CONTROL).
|
|
155
157
|
HEAD_REF: ${{ github.event.pull_request.head.ref }}
|
|
156
158
|
run: |
|
|
159
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
157
160
|
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
158
161
|
ISSUE_NUM=$(python3 .github/scripts/issue_helper.py extract-branch-issue "$HEAD_REF")
|
|
159
162
|
|
|
@@ -105,6 +105,7 @@ jobs:
|
|
|
105
105
|
GH_TOKEN: ${{ github.token }}
|
|
106
106
|
GH_REPO: ${{ github.repository }}
|
|
107
107
|
run: |
|
|
108
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
108
109
|
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
109
110
|
PR_NUMBER=${{ github.event.pull_request.number }}
|
|
110
111
|
# A push to {{DEVELOP_BRANCH}} mid-pipeline queues a run that later reprocesses the
|
|
@@ -142,6 +143,7 @@ jobs:
|
|
|
142
143
|
- name: Read semver_auto option from version.yml
|
|
143
144
|
id: semver_options
|
|
144
145
|
run: |
|
|
146
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
145
147
|
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
146
148
|
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")
|
|
147
149
|
echo "semver_auto=$SEMVER_AUTO" >> $GITHUB_OUTPUT
|
|
@@ -150,6 +152,7 @@ jobs:
|
|
|
150
152
|
- name: Read copilot_ai option from version.yml
|
|
151
153
|
id: copilot_options
|
|
152
154
|
run: |
|
|
155
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
153
156
|
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
154
157
|
# scoped to the metadata: -> template: -> options: chain so an
|
|
155
158
|
# unrelated "copilot_ai:" key can never hijack the value
|
|
@@ -165,6 +168,7 @@ jobs:
|
|
|
165
168
|
- name: Collect commits since last release
|
|
166
169
|
id: collect
|
|
167
170
|
run: |
|
|
171
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
168
172
|
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
169
173
|
git fetch origin {{MAIN_BRANCH}}
|
|
170
174
|
git log --pretty=%s "origin/{{MAIN_BRANCH}}..HEAD" > commits.txt
|
|
@@ -187,6 +191,7 @@ jobs:
|
|
|
187
191
|
GH_TOKEN: ${{ github.token }}
|
|
188
192
|
GITHUB_TOKEN: ${{ github.token }}
|
|
189
193
|
run: |
|
|
194
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
190
195
|
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
191
196
|
git log --pretty=%H "origin/{{MAIN_BRANCH}}..HEAD" > commit_shas.txt
|
|
192
197
|
|
|
@@ -225,6 +230,7 @@ jobs:
|
|
|
225
230
|
GITHUB_TOKEN: ${{ github.token }}
|
|
226
231
|
COPILOT_AI: ${{ steps.copilot_options.outputs.copilot_ai }}
|
|
227
232
|
run: |
|
|
233
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
228
234
|
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
229
235
|
# Idempotency: never raise a version this PR already confirmed (not yet published).
|
|
230
236
|
# Looking only at the HEAD commit message lets the guard slip when more commits
|
|
@@ -284,6 +290,7 @@ jobs:
|
|
|
284
290
|
GITHUB_TOKEN: ${{ github.token }}
|
|
285
291
|
COPILOT_AI: ${{ steps.copilot_options.outputs.copilot_ai }}
|
|
286
292
|
run: |
|
|
293
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
287
294
|
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
288
295
|
VERSION=$(python3 .github/scripts/version_manager.py get | tail -n 1)
|
|
289
296
|
|
|
@@ -312,6 +319,7 @@ jobs:
|
|
|
312
319
|
FALLBACK_REASON: ${{ steps.summary.outputs.fallback_reason }}
|
|
313
320
|
GH_TOKEN: ${{ github.token }}
|
|
314
321
|
run: |
|
|
322
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
315
323
|
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
316
324
|
PR_NUMBER=${{ github.event.pull_request.number }}
|
|
317
325
|
# Find this bot's earlier summary comment by its marker and replace it so re-runs and re-syncs do not pile up comments
|
|
@@ -361,9 +369,12 @@ jobs:
|
|
|
361
369
|
- name: Commit release docs to the PR head branch
|
|
362
370
|
env:
|
|
363
371
|
GH_TOKEN: ${{ github.token }}
|
|
372
|
+
# Passed through env so shell metacharacters in the branch name are never parsed as commands
|
|
373
|
+
PAW_HEAD_REF: ${{ github.event.pull_request.head.ref }}
|
|
364
374
|
run: |
|
|
375
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
365
376
|
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
366
|
-
HEAD_BRANCH="$
|
|
377
|
+
HEAD_BRANCH="$PAW_HEAD_REF"
|
|
367
378
|
VERSION="${{ steps.bump.outputs.new_version }}"
|
|
368
379
|
|
|
369
380
|
# Working files must not land in the repo
|
|
@@ -426,6 +437,7 @@ jobs:
|
|
|
426
437
|
# (RELEASE-PUBLISH etc.); GITHUB_TOKEN merges do not.
|
|
427
438
|
GH_TOKEN: ${{ secrets.WORKFLOW_PAT || github.token }}
|
|
428
439
|
run: |
|
|
440
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
429
441
|
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
430
442
|
PR_NUMBER=${{ github.event.pull_request.number }}
|
|
431
443
|
VERSION="${{ steps.bump.outputs.new_version }}"
|
|
@@ -514,6 +526,7 @@ jobs:
|
|
|
514
526
|
GH_TOKEN: ${{ github.token }}
|
|
515
527
|
GH_REPO: ${{ github.repository }}
|
|
516
528
|
run: |
|
|
529
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
517
530
|
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
518
531
|
PR_NUMBER=${{ github.event.pull_request.number }}
|
|
519
532
|
MAX_WAIT=1800
|
|
@@ -545,6 +558,7 @@ jobs:
|
|
|
545
558
|
GH_TOKEN: ${{ github.token }}
|
|
546
559
|
GH_REPO: ${{ github.repository }}
|
|
547
560
|
run: |
|
|
561
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
548
562
|
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
549
563
|
gh workflow run PROJECT-COMMON-RELEASE-PUBLISH.yaml --ref {{MAIN_BRANCH}}
|
|
550
564
|
echo "$(m wf_changelog.release_publish_triggered)"
|
|
@@ -39,6 +39,15 @@
|
|
|
39
39
|
# README always ends on the released version. Run it manually
|
|
40
40
|
# (workflow_dispatch) to catch up at any other time.
|
|
41
41
|
#
|
|
42
|
+
# trunk-based mode: RELEASE-PUBLISH bumps the version, rewrites the README
|
|
43
|
+
# line in its own commit and then dispatches this workflow, so the push
|
|
44
|
+
# run is skipped there. Two workflows committing to the same README line
|
|
45
|
+
# at the same time is what made releases fail on a rebase conflict.
|
|
46
|
+
#
|
|
47
|
+
# Push conflicts: if the README on {{MAIN_BRANCH}} moved in the meantime
|
|
48
|
+
# (a release commit rewrote the same line), a run that shows the same
|
|
49
|
+
# version, or whose version is already stale, is skipped instead of failing.
|
|
50
|
+
#
|
|
42
51
|
# The version line under the AUTO-VERSION-SECTION marker is already
|
|
43
52
|
# rewritten inside the release commit itself (version_manager.py
|
|
44
53
|
# increment/set), so the release tag snapshot shows the released
|
|
@@ -83,9 +92,29 @@ jobs:
|
|
|
83
92
|
git config --local user.email "action@github.com"
|
|
84
93
|
git config --local user.name "GitHub Action"
|
|
85
94
|
|
|
95
|
+
- name: Detect branch mode
|
|
96
|
+
id: mode
|
|
97
|
+
run: |
|
|
98
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
99
|
+
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
100
|
+
# scoped to the metadata: -> template: -> branches: chain so an
|
|
101
|
+
# unrelated top-level "mode:" key can never hijack the value
|
|
102
|
+
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")
|
|
103
|
+
# A push in trunk-based mode is a release: RELEASE-PUBLISH rewrites the
|
|
104
|
+
# README itself and dispatches this workflow afterwards. Running on the
|
|
105
|
+
# push too would race it on the same README line.
|
|
106
|
+
if [ "$MODE" = "trunk-based" ] && [ "${{ github.event_name }}" = "push" ]; then
|
|
107
|
+
echo "skip=true" >> "$GITHUB_OUTPUT"
|
|
108
|
+
echo "$(m wf_readme.trunk_skip)"
|
|
109
|
+
else
|
|
110
|
+
echo "skip=false" >> "$GITHUB_OUTPUT"
|
|
111
|
+
fi
|
|
112
|
+
|
|
86
113
|
- name: Check README.md exists
|
|
87
114
|
id: precheck
|
|
115
|
+
if: steps.mode.outputs.skip != 'true'
|
|
88
116
|
run: |
|
|
117
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
89
118
|
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
90
119
|
if [ -f README.md ]; then
|
|
91
120
|
echo "readme_exists=true" >> $GITHUB_OUTPUT
|
|
@@ -98,6 +127,7 @@ jobs:
|
|
|
98
127
|
id: version_info
|
|
99
128
|
if: steps.precheck.outputs.readme_exists == 'true'
|
|
100
129
|
run: |
|
|
130
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
101
131
|
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
102
132
|
LATEST_VERSION=$(python3 .github/scripts/version_manager.py get | tail -n 1)
|
|
103
133
|
# Guard: an empty version must never reach the README rewrite —
|
|
@@ -114,6 +144,7 @@ jobs:
|
|
|
114
144
|
- name: Update version line in README.md
|
|
115
145
|
if: steps.precheck.outputs.readme_exists == 'true'
|
|
116
146
|
run: |
|
|
147
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
117
148
|
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
118
149
|
LATEST_VERSION="${{ steps.version_info.outputs.latest_version }}"
|
|
119
150
|
RELEASE_DATE="${{ steps.version_info.outputs.release_date }}"
|
|
@@ -258,6 +289,7 @@ jobs:
|
|
|
258
289
|
- name: Commit and push changes
|
|
259
290
|
if: steps.precheck.outputs.readme_exists == 'true'
|
|
260
291
|
run: |
|
|
292
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
261
293
|
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
262
294
|
git add README.md
|
|
263
295
|
|
|
@@ -268,8 +300,9 @@ jobs:
|
|
|
268
300
|
|
|
269
301
|
git commit -m "docs(readme): update version to v$VERSION [skip ci]"
|
|
270
302
|
|
|
271
|
-
#
|
|
272
|
-
|
|
303
|
+
# >>> push-with-retry
|
|
304
|
+
# Race-condition guard: fetch -> rebase -> push, retried
|
|
305
|
+
MAX_RETRIES=5
|
|
273
306
|
RETRY_COUNT=0
|
|
274
307
|
PUSH_SUCCESS=false
|
|
275
308
|
|
|
@@ -281,21 +314,37 @@ jobs:
|
|
|
281
314
|
PUSH_SUCCESS=true
|
|
282
315
|
echo "$(m wf_readme.pushed)"
|
|
283
316
|
break
|
|
284
|
-
else
|
|
285
|
-
echo "$(m wf_common.push_failed_syncing)"
|
|
286
|
-
|
|
287
|
-
if git pull --rebase origin {{MAIN_BRANCH}}; then
|
|
288
|
-
echo "$(m wf_common.rebase_ok)"
|
|
289
|
-
else
|
|
290
|
-
echo "$(m wf_common.rebase_failed)"
|
|
291
|
-
git rebase --abort 2>/dev/null || true
|
|
292
|
-
exit 1
|
|
293
|
-
fi
|
|
294
317
|
fi
|
|
318
|
+
|
|
319
|
+
echo "$(m wf_common.push_failed_syncing)"
|
|
320
|
+
git fetch origin {{MAIN_BRANCH}}
|
|
321
|
+
if git rebase origin/{{MAIN_BRANCH}}; then
|
|
322
|
+
echo "$(m wf_common.rebase_ok)"
|
|
323
|
+
continue
|
|
324
|
+
fi
|
|
325
|
+
git rebase --abort 2>/dev/null || true
|
|
326
|
+
|
|
327
|
+
# The same README line was rewritten on the remote (a release commit).
|
|
328
|
+
# Nothing is lost when it already shows this version or is ahead of it.
|
|
329
|
+
REMOTE_VERSION=$(git show origin/{{MAIN_BRANCH}}:version.yml | grep -m1 '^version:' | sed 's/version:[ \t]*"\{0,1\}\([0-9][0-9.]*\)"\{0,1\}.*/\1/')
|
|
330
|
+
if [ -n "$REMOTE_VERSION" ] && [ "$REMOTE_VERSION" != "$VERSION" ]; then
|
|
331
|
+
echo "$(m wf_readme.conflict_skip_stale version="$VERSION" remote_version="$REMOTE_VERSION")"
|
|
332
|
+
PUSH_SUCCESS=true
|
|
333
|
+
break
|
|
334
|
+
fi
|
|
335
|
+
if git show origin/{{MAIN_BRANCH}}:README.md | grep -qF "v${VERSION}"; then
|
|
336
|
+
echo "$(m wf_readme.conflict_skip_same version="$VERSION")"
|
|
337
|
+
PUSH_SUCCESS=true
|
|
338
|
+
break
|
|
339
|
+
fi
|
|
340
|
+
|
|
341
|
+
echo "$(m wf_common.rebase_failed)"
|
|
342
|
+
exit 1
|
|
295
343
|
done
|
|
296
344
|
|
|
297
345
|
if [ "$PUSH_SUCCESS" = false ]; then
|
|
298
346
|
echo "$(m wf_common.push_gave_up max_retries="$MAX_RETRIES")"
|
|
299
347
|
exit 1
|
|
300
348
|
fi
|
|
349
|
+
# <<< push-with-retry
|
|
301
350
|
fi
|
|
@@ -35,6 +35,13 @@
|
|
|
35
35
|
# trigger and workflow_dispatch is dispatched too. A PAT or human merge
|
|
36
36
|
# already fired the push event, so those are left alone (no double deploy).
|
|
37
37
|
#
|
|
38
|
+
# The trunk-based docs commit is pushed with fetch -> rebase -> push retries.
|
|
39
|
+
# If README.md conflicts with a concurrent README commit (a date refresh),
|
|
40
|
+
# the remote README is kept and the released version line is reapplied, so
|
|
41
|
+
# a README conflict never stops the tag and the Release from being created.
|
|
42
|
+
# README-VERSION-UPDATE skips its own push run in trunk-based mode; this
|
|
43
|
+
# workflow dispatches it after publishing instead.
|
|
44
|
+
#
|
|
38
45
|
# Release-confirm pattern: "chore(release):" — keep in sync with
|
|
39
46
|
# PROJECT-COMMON-AUTO-CHANGELOG-CONTROL and PROJECT-COMMON-VERSION-CONTROL.
|
|
40
47
|
#
|
|
@@ -94,6 +101,7 @@ jobs:
|
|
|
94
101
|
- name: Detect branch mode
|
|
95
102
|
id: mode
|
|
96
103
|
run: |
|
|
104
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
97
105
|
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
98
106
|
# scoped to the metadata: -> template: -> branches: chain so an
|
|
99
107
|
# unrelated top-level "mode:" key can never hijack the value
|
|
@@ -104,6 +112,7 @@ jobs:
|
|
|
104
112
|
- name: Release gate
|
|
105
113
|
id: gate
|
|
106
114
|
run: |
|
|
115
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
107
116
|
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
108
117
|
MODE="${{ steps.mode.outputs.mode }}"
|
|
109
118
|
EVENT="${{ github.event_name }}"
|
|
@@ -167,6 +176,7 @@ jobs:
|
|
|
167
176
|
steps.mode.outputs.mode == 'trunk-based' &&
|
|
168
177
|
github.event_name == 'push'
|
|
169
178
|
run: |
|
|
179
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
170
180
|
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
171
181
|
# scoped to the metadata: -> template: -> options: chain so an
|
|
172
182
|
# unrelated "semver_auto:" key can never hijack the value
|
|
@@ -181,6 +191,7 @@ jobs:
|
|
|
181
191
|
steps.mode.outputs.mode == 'trunk-based' &&
|
|
182
192
|
github.event_name == 'push'
|
|
183
193
|
run: |
|
|
194
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
184
195
|
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
185
196
|
# scoped to the metadata: -> template: -> options: chain so an
|
|
186
197
|
# unrelated "copilot_ai:" key can never hijack the value
|
|
@@ -209,6 +220,7 @@ jobs:
|
|
|
209
220
|
GITHUB_TOKEN: ${{ github.token }}
|
|
210
221
|
COPILOT_AI: ${{ steps.copilot_options.outputs.copilot_ai }}
|
|
211
222
|
run: |
|
|
223
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
212
224
|
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
213
225
|
# Idempotency: on a re-run of a failed job the checked-out HEAD may
|
|
214
226
|
# already be this workflow's own docs commit — never bump twice.
|
|
@@ -297,8 +309,12 @@ jobs:
|
|
|
297
309
|
else
|
|
298
310
|
git commit -m "chore(version): release v${NEW_VERSION} docs [skip ci]"
|
|
299
311
|
|
|
300
|
-
#
|
|
301
|
-
|
|
312
|
+
# >>> push-with-retry
|
|
313
|
+
# Race-condition guard: fetch -> rebase -> push, retried. A concurrent
|
|
314
|
+
# README-only commit (date refresh) touches the same version line and
|
|
315
|
+
# conflicts on rebase; the remote README is kept and this run's version
|
|
316
|
+
# line is reapplied, so a README conflict never blocks the release.
|
|
317
|
+
MAX_RETRIES=5
|
|
302
318
|
RETRY_COUNT=0
|
|
303
319
|
PUSH_SUCCESS=false
|
|
304
320
|
|
|
@@ -310,22 +326,36 @@ jobs:
|
|
|
310
326
|
PUSH_SUCCESS=true
|
|
311
327
|
echo "$(m wf_release.docs_pushed)"
|
|
312
328
|
break
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
329
|
+
fi
|
|
330
|
+
|
|
331
|
+
echo "$(m wf_common.push_failed_syncing)"
|
|
332
|
+
git fetch origin {{MAIN_BRANCH}}
|
|
333
|
+
if git rebase origin/{{MAIN_BRANCH}}; then
|
|
334
|
+
echo "$(m wf_common.rebase_ok)"
|
|
335
|
+
continue
|
|
336
|
+
fi
|
|
337
|
+
|
|
338
|
+
# Only README.md conflicting: "ours" is the remote side during a rebase
|
|
339
|
+
if [ "$(git diff --name-only --diff-filter=U)" = "README.md" ]; then
|
|
340
|
+
git checkout --ours -- README.md
|
|
341
|
+
python3 -c 'import sys; sys.path.insert(0, ".github/scripts"); import version_manager as vm; vm.update_readme_version(vm.get_current_version())' || true
|
|
342
|
+
git add README.md
|
|
343
|
+
if GIT_EDITOR=true git rebase --continue; then
|
|
344
|
+
echo "$(m wf_common.readme_conflict_resolved)"
|
|
345
|
+
continue
|
|
321
346
|
fi
|
|
322
347
|
fi
|
|
348
|
+
|
|
349
|
+
echo "$(m wf_common.rebase_failed)"
|
|
350
|
+
git rebase --abort 2>/dev/null || true
|
|
351
|
+
exit 1
|
|
323
352
|
done
|
|
324
353
|
|
|
325
354
|
if [ "$PUSH_SUCCESS" = false ]; then
|
|
326
355
|
echo "$(m wf_common.push_gave_up max_retries="$MAX_RETRIES")"
|
|
327
356
|
exit 1
|
|
328
357
|
fi
|
|
358
|
+
# <<< push-with-retry
|
|
329
359
|
fi
|
|
330
360
|
|
|
331
361
|
- name: Resolve version + idempotency guard
|
|
@@ -334,6 +364,7 @@ jobs:
|
|
|
334
364
|
env:
|
|
335
365
|
GH_TOKEN: ${{ github.token }}
|
|
336
366
|
run: |
|
|
367
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
337
368
|
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
338
369
|
VERSION=$(python3 .github/scripts/version_manager.py get | tail -n 1)
|
|
339
370
|
if [ -z "$VERSION" ]; then
|
|
@@ -365,6 +396,7 @@ jobs:
|
|
|
365
396
|
- name: Create and push tag
|
|
366
397
|
if: steps.gate.outputs.proceed == 'true' && steps.version.outputs.tag_exists != 'true'
|
|
367
398
|
run: |
|
|
399
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
368
400
|
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
369
401
|
VERSION="${{ steps.version.outputs.version }}"
|
|
370
402
|
git tag "v$VERSION"
|
|
@@ -376,6 +408,7 @@ jobs:
|
|
|
376
408
|
env:
|
|
377
409
|
GH_TOKEN: ${{ github.token }}
|
|
378
410
|
run: |
|
|
411
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
379
412
|
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
380
413
|
VERSION="${{ steps.version.outputs.version }}"
|
|
381
414
|
|
|
@@ -415,6 +448,7 @@ jobs:
|
|
|
415
448
|
# default token.
|
|
416
449
|
GH_TOKEN: ${{ secrets.WORKFLOW_PAT || github.token }}
|
|
417
450
|
run: |
|
|
451
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
418
452
|
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
419
453
|
VERSION="${{ steps.version.outputs.version }}"
|
|
420
454
|
gh release create "v$VERSION" --title "v$VERSION" --notes-file notes.md
|
|
@@ -430,6 +464,7 @@ jobs:
|
|
|
430
464
|
env:
|
|
431
465
|
GH_TOKEN: ${{ github.token }}
|
|
432
466
|
run: |
|
|
467
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
433
468
|
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
434
469
|
if gh workflow run PROJECT-COMMON-README-VERSION-UPDATE.yaml --ref {{MAIN_BRANCH}}; then
|
|
435
470
|
echo "$(m wf_release.readme_dispatch_ok)"
|
|
@@ -457,6 +492,7 @@ jobs:
|
|
|
457
492
|
RELEASE_VERSION: ${{ steps.version.outputs.version }}
|
|
458
493
|
MAIN_BRANCH: "{{MAIN_BRANCH}}"
|
|
459
494
|
run: |
|
|
495
|
+
[ -f "$GITHUB_WORKSPACE/.github/scripts/messages.py" ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
460
496
|
m() { python3 "$GITHUB_WORKSPACE/.github/scripts/messages.py" get "$@"; }
|
|
461
497
|
# Merge commit of this version's release PR - releases that are not merges
|
|
462
498
|
# (safety-net bump, manual republish) were already deployed by a human push,
|