@mokoconsulting/mcp-mokosuite 1.0.0 → 1.1.0-dev.372
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/.mokogit/workflows/auto-bump.yml +8 -0
- package/.mokogit/workflows/auto-release.yml +184 -71
- package/.mokogit/workflows/cascade-dev.yml +128 -60
- package/.mokogit/workflows/changelog-validation.yml +41 -25
- package/.mokogit/workflows/ci-issue-reporter.yml +1 -1
- package/.mokogit/workflows/cleanup.yml +3 -3
- package/.mokogit/workflows/custom-workflow-sync-trigger.yml +83 -0
- package/.mokogit/workflows/issue-branch.yml +1 -1
- package/.mokogit/workflows/npm-build-test.yml +103 -19
- package/.mokogit/workflows/npm-prerelease.yml +174 -0
- package/.mokogit/workflows/npm-publish.yml +44 -17
- package/.mokogit/workflows/pr-check.yml +181 -53
- package/.mokogit/workflows/pre-release.yml +174 -35
- package/.mokogit/workflows/rc-revert.yml +1 -1
- package/.mokogit/workflows/version-set.yml +4 -4
- package/AGENTS.md +39 -0
- package/CHANGELOG.md +46 -10
- package/dist/index.js +28 -1
- package/docs/API.md +54 -45
- package/package.json +1 -1
- package/src/index.ts +59 -1
- package/.mokogit/workflows/ci-generic.yml +0 -203
- package/.mokogit/workflows/repo-health.yml +0 -700
- package/.mokogit/workflows/standards-compliance.yml +0 -2507
|
@@ -7,27 +7,20 @@
|
|
|
7
7
|
# INGROUP: MokoCLI.Cascade
|
|
8
8
|
# REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Generic
|
|
9
9
|
# PATH: /.mokogit/workflows/cascade-dev.yml
|
|
10
|
-
# VERSION: 02.
|
|
11
|
-
# BRIEF: Cascade main -> dev; auto-merge clean, auto-resolve
|
|
10
|
+
# VERSION: 02.04.00
|
|
11
|
+
# BRIEF: Cascade main -> dev; branch-motivated (no schedule); skips dev-only repos (no main); auto-merge clean, auto-resolve routine conflicts INLINE (manifest version / .mokogit-.gitea-.github / docs-stamps) with no mokocli dependency, fall back to cascade_resolve.php then notify
|
|
12
12
|
|
|
13
13
|
name: "Cascade Main -> Dev"
|
|
14
14
|
|
|
15
15
|
on:
|
|
16
|
+
# Branch-motivated (no time-based schedule): any real push to main cascades to
|
|
17
|
+
# dev immediately. Sync commits from workflow_sync.php carry [skip ci] and are
|
|
18
|
+
# skipped by the platform (they fire no trigger at all), so workflow_sync.php
|
|
19
|
+
# dispatches this workflow directly (workflow_dispatch) after it changes a repo
|
|
20
|
+
# — that is what carries .mokogit drift down to dev, replacing the old daily cron.
|
|
16
21
|
push:
|
|
17
22
|
branches:
|
|
18
23
|
- main
|
|
19
|
-
# A sync-only push to main (workflow/CI-config files) should not immediately
|
|
20
|
-
# cascade to dev and light up the release pipeline. The daily schedule below
|
|
21
|
-
# still carries the .mokogit drift down to dev.
|
|
22
|
-
paths-ignore:
|
|
23
|
-
- '.mokogit/**'
|
|
24
|
-
- '.gitea/**'
|
|
25
|
-
- '.github/**'
|
|
26
|
-
# Daily safety net: catches drift even when main only received [skip ci] pushes
|
|
27
|
-
# (which never fire the push trigger above), and .mokogit-only syncs ignored above.
|
|
28
|
-
# Off-round minute to avoid a fleet-wide spike.
|
|
29
|
-
schedule:
|
|
30
|
-
- cron: '23 7 * * *'
|
|
31
24
|
workflow_dispatch:
|
|
32
25
|
|
|
33
26
|
permissions:
|
|
@@ -51,10 +44,11 @@ jobs:
|
|
|
51
44
|
fetch-depth: 0
|
|
52
45
|
token: ${{ github.token }}
|
|
53
46
|
|
|
54
|
-
- name: Cascade main -> dev (auto-resolve
|
|
47
|
+
- name: Cascade main -> dev (auto-resolve routine conflicts, else notify)
|
|
55
48
|
env:
|
|
56
49
|
TOKEN: ${{ github.token }}
|
|
57
50
|
REPO: ${{ github.repository }}
|
|
51
|
+
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
|
|
58
52
|
run: |
|
|
59
53
|
set -uo pipefail
|
|
60
54
|
API="${MOKOGIT_URL}/api/v1/repos/${REPO}"
|
|
@@ -66,6 +60,13 @@ jobs:
|
|
|
66
60
|
echo "No dev branch - nothing to cascade."; exit 0
|
|
67
61
|
fi
|
|
68
62
|
|
|
63
|
+
# 0b. main must exist too. A dev-only repo (no main branch) has nothing to
|
|
64
|
+
# cascade FROM, so skip immediately instead of spinning up on the daily
|
|
65
|
+
# schedule / manual dispatch and no-op'ing later via a failed compare.
|
|
66
|
+
if ! curl -sf -H "$AUTH" "${API}/branches/main" >/dev/null 2>&1; then
|
|
67
|
+
echo "No main branch (dev-only repo) - nothing to cascade."; exit 0
|
|
68
|
+
fi
|
|
69
|
+
|
|
69
70
|
# 1. is main ahead of dev?
|
|
70
71
|
AHEAD=$(curl -sf -H "$AUTH" "${API}/compare/dev...main" \
|
|
71
72
|
| python3 -c "import sys,json; print(json.load(sys.stdin).get('total_commits',0))" 2>/dev/null || echo 0)
|
|
@@ -139,60 +140,127 @@ jobs:
|
|
|
139
140
|
CONFLICTS=$(git diff --name-only --diff-filter=U)
|
|
140
141
|
echo "Conflicted files:"; echo "${CONFLICTS}"
|
|
141
142
|
|
|
142
|
-
#
|
|
143
|
-
#
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
#
|
|
154
|
-
#
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
143
|
+
# --- Inline resolver (pure bash/git, NO mokocli dependency) -------------
|
|
144
|
+
# The common cascade churn is routine and deterministic, so resolve it here
|
|
145
|
+
# BEFORE reaching for cascade_resolve.php. This is what keeps the version
|
|
146
|
+
# ladder moving even when mokocli is unreachable on an ephemeral runner
|
|
147
|
+
# (the failure mode this workflow was hardened against): a pure
|
|
148
|
+
# version-stamp conflict must never stall dev behind main.
|
|
149
|
+
#
|
|
150
|
+
# * manifest <version> conflicts (*.xml containing <extension) ->
|
|
151
|
+
# version = max(dev, main) via `sort -V`, rewriting the tag while
|
|
152
|
+
# preserving the file's own indentation (repos MIX tab and 2-space).
|
|
153
|
+
# * .mokogit/** .gitea/** .github/** -> take main/canonical (--theirs).
|
|
154
|
+
# * docs / CHANGELOG / stamp files -> keep dev (--ours).
|
|
155
|
+
# Anything still conflicted afterwards falls through to cascade_resolve.php
|
|
156
|
+
# (if available) and finally to a human, exactly as before.
|
|
157
|
+
resolve_manifest_version() {
|
|
158
|
+
# $1 = path to a conflicted *.xml manifest. Resolves ONLY the <version>
|
|
159
|
+
# conflict to max(dev,main); returns 0 if fully resolved, 1 otherwise.
|
|
160
|
+
local f="$1"
|
|
161
|
+
# Bail if the conflict touches anything other than a single <version> line
|
|
162
|
+
# on each side (i.e. a real content conflict, not just the stamp).
|
|
163
|
+
local nonver
|
|
164
|
+
nonver=$(awk '
|
|
165
|
+
/^<<<<<<< /{c=1;next} /^=======$/{c=2;next} /^>>>>>>> /{c=0;next}
|
|
166
|
+
(c==1||c==2) && $0 !~ /<version>[^<]*<\/version>/ {print "X"}
|
|
167
|
+
' "$f")
|
|
168
|
+
[ -n "$nonver" ] && return 1
|
|
169
|
+
# Collect the version value from each side of every conflict hunk.
|
|
170
|
+
local ours theirs maxv
|
|
171
|
+
ours=$(awk '
|
|
172
|
+
/^<<<<<<< /{c=1;next} /^=======$/{c=2;next} /^>>>>>>> /{c=0;next}
|
|
173
|
+
c==1' "$f" | sed -n 's/.*<version>\([^<]*\)<\/version>.*/\1/p' | head -n1)
|
|
174
|
+
theirs=$(awk '
|
|
175
|
+
/^<<<<<<< /{c=1;next} /^=======$/{c=2;next} /^>>>>>>> /{c=0;next}
|
|
176
|
+
c==2' "$f" | sed -n 's/.*<version>\([^<]*\)<\/version>.*/\1/p' | head -n1)
|
|
177
|
+
[ -z "$ours" ] && [ -z "$theirs" ] && return 1
|
|
178
|
+
maxv=$(printf '%s\n%s\n' "$ours" "$theirs" | grep -v '^$' | sort -V | tail -n1)
|
|
179
|
+
[ -z "$maxv" ] && return 1
|
|
180
|
+
# Rewrite: drop conflict markers, keep OUR side's <version> line but with
|
|
181
|
+
# the max value substituted (preserves this file's leading indentation,
|
|
182
|
+
# tab or spaces). Drop the theirs-side version line.
|
|
183
|
+
awk -v maxv="$maxv" '
|
|
184
|
+
/^<<<<<<< /{c=1;next}
|
|
185
|
+
/^=======$/{c=2;next}
|
|
186
|
+
/^>>>>>>> /{c=0;next}
|
|
187
|
+
{
|
|
188
|
+
if (c==2) next
|
|
189
|
+
if (($0 ~ /<version>[^<]*<\/version>/) && (c==1)) {
|
|
190
|
+
sub(/<version>[^<]*<\/version>/, "<version>" maxv "</version>")
|
|
191
|
+
}
|
|
192
|
+
print
|
|
193
|
+
}' "$f" > "${f}.resolved" && mv "${f}.resolved" "$f"
|
|
194
|
+
# Fully resolved only if no markers remain.
|
|
195
|
+
! grep -qE '^(<<<<<<< |=======$|>>>>>>> )' "$f"
|
|
162
196
|
}
|
|
163
197
|
|
|
164
|
-
ALL_STAMP=1
|
|
165
198
|
for f in ${CONFLICTS}; do
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
199
|
+
case "$f" in
|
|
200
|
+
.mokogit/*|.gitea/*|.github/*)
|
|
201
|
+
git checkout --theirs -- "$f" && git add -- "$f" \
|
|
202
|
+
&& echo "resolved (theirs/main): $f" ;;
|
|
203
|
+
*CHANGELOG*|*/docs/*|docs/*|*.md|*VERSION*|*.stamp)
|
|
204
|
+
git checkout --ours -- "$f" && git add -- "$f" \
|
|
205
|
+
&& echo "resolved (ours/dev): $f" ;;
|
|
206
|
+
*.xml)
|
|
207
|
+
if grep -q '<extension' "$f" 2>/dev/null && resolve_manifest_version "$f"; then
|
|
208
|
+
git add -- "$f"; echo "resolved (manifest version=max): $f"
|
|
209
|
+
else
|
|
210
|
+
echo "unresolved (xml, not a simple version stamp): $f"
|
|
211
|
+
fi ;;
|
|
212
|
+
*)
|
|
213
|
+
echo "unresolved (needs deeper resolver): $f" ;;
|
|
214
|
+
esac
|
|
170
215
|
done
|
|
171
216
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
217
|
+
# If the inline pass cleared every conflict, commit + push and we are done —
|
|
218
|
+
# no mokocli needed.
|
|
219
|
+
if [ -z "$(git diff --name-only --diff-filter=U)" ]; then
|
|
220
|
+
git commit -m "chore(sync): cascade main -> dev (auto-resolved inline) [skip ci]" >/dev/null
|
|
221
|
+
git push origin dev
|
|
222
|
+
echo "Cascade auto-resolved inline (no mokocli) and pushed to dev."
|
|
223
|
+
curl -s -H "$AUTH" -H "Content-Type: application/json" -X POST "${API}/issues/${PR}/comments" \
|
|
224
|
+
-d '{"body":"Cascade auto-resolved inline (manifest version=max(dev,main), .mokogit/.gitea/.github -> main, docs/stamps -> dev) with no mokocli dependency, and pushed to dev. Closing."}' >/dev/null || true
|
|
225
|
+
curl -s -H "$AUTH" -H "Content-Type: application/json" -X PATCH "${API}/pulls/${PR}" \
|
|
226
|
+
-d '{"state":"closed"}' >/dev/null || true
|
|
175
227
|
exit 0
|
|
176
228
|
fi
|
|
177
229
|
|
|
178
|
-
echo "
|
|
179
|
-
|
|
180
|
-
keep_ours "$f"
|
|
181
|
-
git add "$f"
|
|
182
|
-
done
|
|
230
|
+
echo "Inline pass left conflicts; falling back to cascade_resolve.php..."
|
|
231
|
+
echo "Still conflicted:"; git diff --name-only --diff-filter=U
|
|
183
232
|
|
|
184
|
-
#
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
233
|
+
# --- Fallback: cascade_resolve.php (existing behaviour) -----------------
|
|
234
|
+
# Handles the messier cases (modify/delete, plugin renames, etc.). It BAILS
|
|
235
|
+
# (exit 2) on real code conflicts, so those still get a human. ubuntu-latest
|
|
236
|
+
# has no /opt/mokocli, so clone mokocli on demand.
|
|
237
|
+
RESOLVER=/opt/mokocli/cli/cascade_resolve.php
|
|
238
|
+
if [ ! -f "$RESOLVER" ]; then
|
|
239
|
+
if git clone --depth 1 --quiet \
|
|
240
|
+
"https://x-access-token:${MOKOGIT_TOKEN}@${MOKOGIT_URL#https://}/MokoConsulting/mokocli.git" \
|
|
241
|
+
/tmp/mokocli 2>/dev/null \
|
|
242
|
+
|| git clone --depth 1 --quiet "${MOKOGIT_URL}/MokoConsulting/mokocli.git" /tmp/mokocli 2>/dev/null; then
|
|
243
|
+
RESOLVER=/tmp/mokocli/cli/cascade_resolve.php
|
|
244
|
+
else
|
|
245
|
+
# Do NOT swallow this silently: a degraded run must be visible so the
|
|
246
|
+
# operator knows the fallback resolver was unavailable.
|
|
247
|
+
echo "::warning::On-demand mokocli clone failed; cascade_resolve.php is UNAVAILABLE. Inline resolver handled the routine classes; any remaining conflicts need a human."
|
|
248
|
+
RESOLVER=/tmp/mokocli/cli/cascade_resolve.php
|
|
249
|
+
fi
|
|
188
250
|
fi
|
|
189
251
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
252
|
+
if [ -f "$RESOLVER" ] && php "$RESOLVER" --path . --theirs-ref origin/main; then
|
|
253
|
+
git commit -m "chore(sync): cascade main -> dev (auto-resolved) [skip ci]" >/dev/null
|
|
254
|
+
git push origin dev
|
|
255
|
+
echo "Cascade auto-resolved and pushed to dev."
|
|
256
|
+
curl -s -H "$AUTH" -H "Content-Type: application/json" -X POST "${API}/issues/${PR}/comments" \
|
|
257
|
+
-d '{"body":"cascade_resolve auto-resolved the merge (manifests/workflows/docs/stamps, modify-delete) and pushed to dev. Closing."}' >/dev/null || true
|
|
258
|
+
curl -s -H "$AUTH" -H "Content-Type: application/json" -X PATCH "${API}/pulls/${PR}" \
|
|
259
|
+
-d '{"state":"closed"}' >/dev/null || true
|
|
260
|
+
exit 0
|
|
261
|
+
fi
|
|
193
262
|
|
|
194
|
-
#
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
-d '{"state":"closed"}' >/dev/null || true
|
|
263
|
+
# Resolver unavailable, or it bailed on a real (code) conflict -> human.
|
|
264
|
+
git merge --abort || true
|
|
265
|
+
notify "has code conflicts cascade_resolve could not safely auto-resolve."
|
|
266
|
+
exit 0
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
# INGROUP: MokoStandards.CI
|
|
10
10
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
|
11
11
|
# PATH: /templates/workflows/shared/changelog-validation.yml.template
|
|
12
|
-
# VERSION: 04.06.
|
|
12
|
+
# VERSION: 04.06.01
|
|
13
13
|
# BRIEF: Validates CHANGELOG.md format and version consistency
|
|
14
14
|
# NOTE: Deployed to .mokogit/workflows/changelog-validation.yml in governed repos.
|
|
15
15
|
|
|
@@ -30,6 +30,11 @@ permissions:
|
|
|
30
30
|
env:
|
|
31
31
|
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
|
32
32
|
|
|
33
|
+
concurrency:
|
|
34
|
+
# storm-reduction: collapse superseded validation runs on the same ref
|
|
35
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
36
|
+
cancel-in-progress: true
|
|
37
|
+
|
|
33
38
|
jobs:
|
|
34
39
|
validate-changelog:
|
|
35
40
|
name: Validate CHANGELOG.md
|
|
@@ -41,61 +46,72 @@ jobs:
|
|
|
41
46
|
|
|
42
47
|
- name: Check CHANGELOG.md exists
|
|
43
48
|
run: |
|
|
44
|
-
echo "### Changelog Validation"
|
|
49
|
+
echo "### Changelog Validation" | tee -a $GITHUB_STEP_SUMMARY
|
|
45
50
|
if [ ! -f "CHANGELOG.md" ]; then
|
|
46
|
-
echo "CHANGELOG.md not found in repository root."
|
|
51
|
+
echo "CHANGELOG.md not found in repository root." | tee -a $GITHUB_STEP_SUMMARY
|
|
47
52
|
exit 1
|
|
48
53
|
fi
|
|
49
|
-
echo "CHANGELOG.md exists."
|
|
54
|
+
echo "CHANGELOG.md exists." | tee -a $GITHUB_STEP_SUMMARY
|
|
50
55
|
|
|
51
|
-
- name: Check VERSION header matches README.md
|
|
56
|
+
- name: Check VERSION header matches README.md (only if README declares one)
|
|
52
57
|
run: |
|
|
53
|
-
#
|
|
54
|
-
|
|
58
|
+
# A FILE INFORMATION VERSION block is optional in README.md — public-facing
|
|
59
|
+
# READMEs typically have none. Only enforce a CHANGELOG match when README
|
|
60
|
+
# actually declares a version; otherwise skip (not a failure).
|
|
61
|
+
# `|| true`: under the default `bash -e -o pipefail`, a grep with no match
|
|
62
|
+
# exits 1 and pipefail propagates it, which would abort the step BEFORE the
|
|
63
|
+
# `-z` skip below — the exact common case (README with no VERSION block). Keep
|
|
64
|
+
# the empty result non-fatal so the intended skip path stays reachable.
|
|
65
|
+
README_VERSION=$(grep -oP '^\s*VERSION:\s*\K[0-9]+\.[0-9]+\.[0-9]+' README.md 2>/dev/null | head -1 || true)
|
|
55
66
|
if [ -z "$README_VERSION" ]; then
|
|
56
|
-
echo "
|
|
57
|
-
exit
|
|
67
|
+
echo "README.md has no FILE INFORMATION VERSION block — skipping version-match check." | tee -a $GITHUB_STEP_SUMMARY
|
|
68
|
+
exit 0
|
|
58
69
|
fi
|
|
59
70
|
|
|
60
|
-
|
|
61
|
-
CHANGELOG_VERSION=$(grep -oP '^\#\#\s*\[\K[0-9]{2}\.[0-9]{2}\.[0-9]{2}' CHANGELOG.md | head -1)
|
|
71
|
+
CHANGELOG_VERSION=$(grep -oP '^\#\#\s*\[\K[0-9]+\.[0-9]+\.[0-9]+' CHANGELOG.md | head -1 || true)
|
|
62
72
|
if [ -z "$CHANGELOG_VERSION" ]; then
|
|
63
|
-
echo "
|
|
73
|
+
echo "README declares VERSION \`${README_VERSION}\` but CHANGELOG.md has no matching \`## [X.Y.Z]\` header." | tee -a $GITHUB_STEP_SUMMARY
|
|
64
74
|
exit 1
|
|
65
75
|
fi
|
|
66
76
|
|
|
67
77
|
if [ "$CHANGELOG_VERSION" != "$README_VERSION" ]; then
|
|
68
|
-
echo "CHANGELOG latest version \`${CHANGELOG_VERSION}\` does not match README VERSION \`${README_VERSION}\`."
|
|
78
|
+
echo "CHANGELOG latest version \`${CHANGELOG_VERSION}\` does not match README VERSION \`${README_VERSION}\`." | tee -a $GITHUB_STEP_SUMMARY
|
|
69
79
|
exit 1
|
|
70
80
|
fi
|
|
71
81
|
|
|
72
|
-
echo "CHANGELOG version \`${CHANGELOG_VERSION}\` matches README VERSION."
|
|
82
|
+
echo "CHANGELOG version \`${CHANGELOG_VERSION}\` matches README VERSION." | tee -a $GITHUB_STEP_SUMMARY
|
|
73
83
|
|
|
74
84
|
- name: Validate conventional changelog format
|
|
75
85
|
run: |
|
|
76
86
|
ERRORS=0
|
|
77
87
|
|
|
78
|
-
#
|
|
88
|
+
# Validate the format of each version entry. `## [Unreleased]` is a valid
|
|
89
|
+
# Keep-a-Changelog section (not a dated version) and is skipped.
|
|
79
90
|
while IFS= read -r LINE; do
|
|
80
|
-
if
|
|
81
|
-
|
|
82
|
-
|
|
91
|
+
if echo "$LINE" | grep -qiE '^\#\#[[:space:]]*\[unreleased\]'; then
|
|
92
|
+
continue
|
|
93
|
+
fi
|
|
94
|
+
if ! echo "$LINE" | grep -qP '^\#\#\s*\[[0-9]+\.[0-9]+\.[0-9]+\]\s*[-–—]+\s*[0-9]{4}-[0-9]{2}-[0-9]{2}'; then
|
|
95
|
+
echo "Malformed version header: \`${LINE}\`" | tee -a $GITHUB_STEP_SUMMARY
|
|
96
|
+
echo " Expected format: \`## [X.Y.Z] --- YYYY-MM-DD\` (any hyphen/dash separator)" | tee -a $GITHUB_STEP_SUMMARY
|
|
83
97
|
ERRORS=$((ERRORS + 1))
|
|
84
98
|
fi
|
|
85
99
|
done < <(grep -P '^\#\#\s*\[' CHANGELOG.md)
|
|
86
100
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
101
|
+
# Count real (dated) version entries, excluding the Unreleased section.
|
|
102
|
+
VERSION_COUNT=$(grep -P '^\#\#\s*\[' CHANGELOG.md | { grep -viE '\[unreleased\]' || true; } | wc -l | tr -d ' ')
|
|
103
|
+
HAS_UNRELEASED=$(grep -ciE '^\#\#[[:space:]]*\[unreleased\]' CHANGELOG.md | tr -d ' ')
|
|
104
|
+
if [ "$VERSION_COUNT" -eq 0 ] && [ "$HAS_UNRELEASED" -eq 0 ]; then
|
|
105
|
+
echo "No version entries or Unreleased section found in CHANGELOG.md." | tee -a $GITHUB_STEP_SUMMARY
|
|
90
106
|
ERRORS=$((ERRORS + 1))
|
|
91
107
|
else
|
|
92
|
-
echo "Found ${
|
|
108
|
+
echo "Found ${VERSION_COUNT} released version entr(ies)$([ "$HAS_UNRELEASED" -gt 0 ] && echo ' + an Unreleased section') in CHANGELOG.md." | tee -a $GITHUB_STEP_SUMMARY
|
|
93
109
|
fi
|
|
94
110
|
|
|
95
|
-
echo ""
|
|
111
|
+
echo "" | tee -a $GITHUB_STEP_SUMMARY
|
|
96
112
|
if [ "${ERRORS}" -gt 0 ]; then
|
|
97
|
-
echo "**${ERRORS} format issue(s) found.**"
|
|
113
|
+
echo "**${ERRORS} format issue(s) found.**" | tee -a $GITHUB_STEP_SUMMARY
|
|
98
114
|
exit 1
|
|
99
115
|
else
|
|
100
|
-
echo "**Changelog format validation passed.**"
|
|
116
|
+
echo "**Changelog format validation passed.**" | tee -a $GITHUB_STEP_SUMMARY
|
|
101
117
|
fi
|
|
@@ -53,7 +53,7 @@ jobs:
|
|
|
53
53
|
MOKOGIT_URL: ${{ vars.MOKOGIT_URL || 'https://git.mokoconsulting.tech' }}
|
|
54
54
|
run: |
|
|
55
55
|
git clone --depth 1 --filter=blob:none --sparse "${MOKOGIT_URL}/MokoConsulting/mokocli.git" /tmp/mokocli
|
|
56
|
-
cd /tmp/mokocli && git sparse-checkout set cli
|
|
56
|
+
cd /tmp/mokocli && git sparse-checkout set cli
|
|
57
57
|
|
|
58
58
|
- name: Report CI failure
|
|
59
59
|
env:
|
|
@@ -33,11 +33,11 @@ jobs:
|
|
|
33
33
|
uses: actions/checkout@v4
|
|
34
34
|
with:
|
|
35
35
|
fetch-depth: 0
|
|
36
|
-
token: ${{ secrets.MOKOGIT_TOKEN }}
|
|
36
|
+
token: ${{ secrets.MOKOGIT_TOKEN || github.token }}
|
|
37
37
|
|
|
38
38
|
- name: Delete merged branches
|
|
39
39
|
env:
|
|
40
|
-
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
|
|
40
|
+
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN || github.token }}
|
|
41
41
|
run: |
|
|
42
42
|
echo "=== Merged Branch Cleanup ==="
|
|
43
43
|
API="${MOKOGIT_URL}/api/v1/repos/${{ github.repository }}"
|
|
@@ -66,7 +66,7 @@ jobs:
|
|
|
66
66
|
|
|
67
67
|
- name: Clean old workflow runs
|
|
68
68
|
env:
|
|
69
|
-
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
|
|
69
|
+
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN || github.token }}
|
|
70
70
|
run: |
|
|
71
71
|
echo "=== Workflow Run Cleanup ==="
|
|
72
72
|
API="${MOKOGIT_URL}/api/v1/repos/${{ github.repository }}"
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
#
|
|
5
|
+
# FILE INFORMATION
|
|
6
|
+
# DEFGROUP: MokoGIT.Workflow
|
|
7
|
+
# INGROUP: MokoCLI.Universal
|
|
8
|
+
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli
|
|
9
|
+
# PATH: /.mokogit/workflows/workflow-sync-trigger.yml
|
|
10
|
+
# VERSION: 01.01.01
|
|
11
|
+
# BRIEF: Trigger workflow sync to live repos when a PR is merged to main
|
|
12
|
+
|
|
13
|
+
name: "Universal: Workflow Sync Trigger"
|
|
14
|
+
|
|
15
|
+
on:
|
|
16
|
+
workflow_dispatch:
|
|
17
|
+
pull_request:
|
|
18
|
+
types: [closed]
|
|
19
|
+
branches:
|
|
20
|
+
- main
|
|
21
|
+
|
|
22
|
+
env:
|
|
23
|
+
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
|
24
|
+
|
|
25
|
+
jobs:
|
|
26
|
+
sync:
|
|
27
|
+
name: Sync workflows to live repos
|
|
28
|
+
runs-on: release
|
|
29
|
+
if: >-
|
|
30
|
+
startsWith(github.event.repository.name, 'Template-') &&
|
|
31
|
+
(github.event_name == 'workflow_dispatch' ||
|
|
32
|
+
(github.event.pull_request.merged == true &&
|
|
33
|
+
!contains(github.event.pull_request.title, '[skip sync]')))
|
|
34
|
+
|
|
35
|
+
steps:
|
|
36
|
+
- name: Determine platform from repo name
|
|
37
|
+
id: platform
|
|
38
|
+
run: |
|
|
39
|
+
REPO="${{ github.event.repository.name }}"
|
|
40
|
+
case "$REPO" in
|
|
41
|
+
Template-Joomla) PLATFORM="joomla" ;;
|
|
42
|
+
Template-Dolibarr) PLATFORM="dolibarr" ;;
|
|
43
|
+
Template-Go) PLATFORM="go" ;;
|
|
44
|
+
Template-NPM) PLATFORM="npm" ;;
|
|
45
|
+
Template-Generic) PLATFORM="" ;;
|
|
46
|
+
*) PLATFORM="" ;;
|
|
47
|
+
esac
|
|
48
|
+
echo "platform=$PLATFORM" >> "$GITHUB_OUTPUT"
|
|
49
|
+
echo "Platform: ${PLATFORM:-all}"
|
|
50
|
+
|
|
51
|
+
- name: Clone MokoCLI
|
|
52
|
+
env:
|
|
53
|
+
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
|
|
54
|
+
run: |
|
|
55
|
+
MOKOGIT_URL="${{ vars.MOKOGIT_URL || 'https://git.mokoconsulting.tech' }}"
|
|
56
|
+
git clone --depth 1 "${MOKOGIT_URL}/MokoConsulting/mokocli.git" /tmp/mokocli
|
|
57
|
+
|
|
58
|
+
- name: Install PHP
|
|
59
|
+
run: |
|
|
60
|
+
if ! command -v php &> /dev/null; then
|
|
61
|
+
apt-get update -qq && apt-get install -y -qq php-cli php-json php-curl > /dev/null 2>&1
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
- name: Install dependencies
|
|
65
|
+
run: |
|
|
66
|
+
cd /tmp/mokocli
|
|
67
|
+
composer install --no-dev --no-interaction --quiet 2>/dev/null || true
|
|
68
|
+
|
|
69
|
+
- name: Run workflow sync
|
|
70
|
+
env:
|
|
71
|
+
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
|
|
72
|
+
run: |
|
|
73
|
+
ARGS="--token ${MOKOGIT_TOKEN}"
|
|
74
|
+
ARGS="${ARGS} --org ${{ vars.MOKOGIT_ORG || github.repository_owner }}"
|
|
75
|
+
ARGS="${ARGS} --phase repos"
|
|
76
|
+
ARGS="${ARGS} --delete-orphans"
|
|
77
|
+
|
|
78
|
+
PLATFORM="${{ steps.platform.outputs.platform }}"
|
|
79
|
+
if [ -n "$PLATFORM" ]; then
|
|
80
|
+
ARGS="${ARGS} --platform-filter ${PLATFORM}"
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
php /tmp/mokocli/cli/workflow_sync.php ${ARGS}
|
|
@@ -32,7 +32,7 @@ jobs:
|
|
|
32
32
|
# injection via a crafted issue title). Pass everything through env so
|
|
33
33
|
# the values arrive as ordinary shell variables that are not re-parsed.
|
|
34
34
|
env:
|
|
35
|
-
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
|
|
35
|
+
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN || github.token }}
|
|
36
36
|
REPO: ${{ github.repository }}
|
|
37
37
|
ISSUE_NUM: ${{ github.event.issue.number }}
|
|
38
38
|
ISSUE_TITLE: ${{ github.event.issue.title }}
|