@mokoconsulting/mokoabs-mcp 0.0.0-stage → 4.0.2
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/.editorconfig +41 -0
- package/.gitattributes +94 -0
- package/.gitmessage +9 -0
- package/.mokogit/ISSUE_TEMPLATE/adr.md +110 -0
- package/.mokogit/ISSUE_TEMPLATE/bug_report.md +48 -0
- package/.mokogit/ISSUE_TEMPLATE/config.yml +18 -0
- package/.mokogit/ISSUE_TEMPLATE/documentation.md +52 -0
- package/.mokogit/ISSUE_TEMPLATE/feature_request.md +51 -0
- package/.mokogit/ISSUE_TEMPLATE/mcp_api_integration.md +48 -0
- package/.mokogit/ISSUE_TEMPLATE/mcp_connection_issue.md +69 -0
- package/.mokogit/ISSUE_TEMPLATE/mcp_tool_request.md +50 -0
- package/.mokogit/ISSUE_TEMPLATE/question.md +82 -0
- package/.mokogit/ISSUE_TEMPLATE/rfc.md +126 -0
- package/.mokogit/ISSUE_TEMPLATE/security.md +51 -0
- package/.mokogit/ISSUE_TEMPLATE/version.md +24 -0
- package/.mokogit/actions/resolve-source-dir/action.yml +72 -0
- package/.mokogit/workflows/apidocs.yml +132 -0
- package/.mokogit/workflows/auto-assign.yml +76 -0
- package/.mokogit/workflows/auto-dev-issue.yml +207 -0
- package/.mokogit/workflows/auto-release.yml +1787 -0
- package/.mokogit/workflows/branch-cleanup.yml +63 -0
- package/.mokogit/workflows/cascade.yml +645 -0
- package/.mokogit/workflows/ci-issue-reporter.yml +100 -0
- package/.mokogit/workflows/cleanup.yml +112 -0
- package/.mokogit/workflows/makefile-lint.yml +240 -0
- package/.mokogit/workflows/npm-build-test.yml +507 -0
- package/.mokogit/workflows/npm-sdk-check.yml +110 -0
- package/.mokogit/workflows/npm-tool-inventory.yml +81 -0
- package/.mokogit/workflows/pr-branch-check.yml +92 -0
- package/.mokogit/workflows/pre-release.yml +1134 -0
- package/.mokogit/workflows/rc-revert.yml +75 -0
- package/AGENTS.md +48 -0
- package/CHANGELOG.md +37 -0
- package/CODE_OF_CONDUCT.md +70 -0
- package/CONTRIBUTING.md +164 -0
- package/LICENSE +696 -0
- package/Makefile +94 -0
- package/README.md +109 -2
- package/SECURITY.md +245 -0
- package/build/README.md +7 -0
- package/dist/README.md +7 -0
- package/dist/index.js +153 -0
- package/package.json +34 -5
- package/sample/config.example.json +15 -0
- package/source/client.ts +132 -0
- package/source/config.ts +139 -0
- package/source/credentialStore.ts +216 -0
- package/source/index.ts +235 -0
- package/source/tokenReader.ts +120 -0
- package/source/types.ts +63 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,100 @@
|
|
|
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/Template-Generic
|
|
9
|
+
# PATH: /.mokogit/workflows/ci-issue-reporter.yml
|
|
10
|
+
# VERSION: 01.00.00
|
|
11
|
+
# BRIEF: Reusable workflow � creates/updates a MokoGIT issue when a CI gate fails.
|
|
12
|
+
# Clones MokoCLI and runs cli/ci_issue_reporter.sh.
|
|
13
|
+
|
|
14
|
+
name: "Universal: CI Issue Reporter"
|
|
15
|
+
|
|
16
|
+
on:
|
|
17
|
+
workflow_call:
|
|
18
|
+
inputs:
|
|
19
|
+
gate:
|
|
20
|
+
description: "CI gate name (e.g. PR Validation, Repository Health)"
|
|
21
|
+
required: true
|
|
22
|
+
type: string
|
|
23
|
+
details:
|
|
24
|
+
description: "Human-readable failure description"
|
|
25
|
+
required: true
|
|
26
|
+
type: string
|
|
27
|
+
severity:
|
|
28
|
+
description: "error or warning"
|
|
29
|
+
required: false
|
|
30
|
+
type: string
|
|
31
|
+
default: "error"
|
|
32
|
+
workflow:
|
|
33
|
+
description: "Workflow name for the issue title"
|
|
34
|
+
required: false
|
|
35
|
+
type: string
|
|
36
|
+
default: ""
|
|
37
|
+
secrets:
|
|
38
|
+
MOKOGIT_TOKEN:
|
|
39
|
+
required: false
|
|
40
|
+
|
|
41
|
+
env:
|
|
42
|
+
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
|
43
|
+
|
|
44
|
+
permissions:
|
|
45
|
+
contents: read
|
|
46
|
+
issues: write
|
|
47
|
+
|
|
48
|
+
jobs:
|
|
49
|
+
report:
|
|
50
|
+
name: "Report: ${{ inputs.gate }}"
|
|
51
|
+
runs-on: ubuntu-latest
|
|
52
|
+
|
|
53
|
+
steps:
|
|
54
|
+
- name: Setup MokoCLI tools
|
|
55
|
+
run: |
|
|
56
|
+
# Standard mokocli install: FRESH from the MokoGIT Composer registry every
|
|
57
|
+
# run (PRIMARY); /opt/mokocli is a FAILSAFE only (its sync unit is disabled,
|
|
58
|
+
# so it rots). Registry path /api/packages/** is anon-allowlisted (no token)
|
|
59
|
+
# and reliable — unlike the former anonymous git clone, which REQUIRE_SIGNIN
|
|
60
|
+
# can block. Installs to /tmp/mokocli (the path this workflow's steps use).
|
|
61
|
+
if ! command -v composer > /dev/null 2>&1; then
|
|
62
|
+
sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer > /dev/null 2>&1 || true
|
|
63
|
+
fi
|
|
64
|
+
rm -rf /tmp/mokocli
|
|
65
|
+
REG='{"type":"composer","url":"https://git.mokoconsulting.tech/api/packages/MokoConsulting/composer"}'
|
|
66
|
+
if composer create-project --no-install --no-interaction --no-progress --quiet \
|
|
67
|
+
--repository="${REG}" mokoconsulting/mokocli /tmp/mokocli >/dev/null 2>&1 \
|
|
68
|
+
&& [ -f /tmp/mokocli/cli/version_bump.php ]; then
|
|
69
|
+
echo "Installed mokocli fresh from the Composer registry (primary)"
|
|
70
|
+
echo "MOKO_CLI=/tmp/mokocli/cli" >> $GITHUB_ENV
|
|
71
|
+
if command -v sudo >/dev/null 2>&1 && [ -d /opt/mokocli ] \
|
|
72
|
+
&& ! cmp -s /tmp/mokocli/cli/version_reset_dev.php /opt/mokocli/cli/version_reset_dev.php 2>/dev/null; then
|
|
73
|
+
sudo cp -a /tmp/mokocli/. /opt/mokocli/ 2>/dev/null && echo "Refreshed /opt/mokocli failsafe from the fresh registry copy" || true
|
|
74
|
+
fi
|
|
75
|
+
elif [ -f /opt/mokocli/cli/version_bump.php ]; then
|
|
76
|
+
echo "::warning::Registry install failed — using /opt/mokocli FAILSAFE (may be stale)"
|
|
77
|
+
echo "MOKO_CLI=/opt/mokocli/cli" >> $GITHUB_ENV
|
|
78
|
+
[ -d /tmp/mokocli ] || cp -a /opt/mokocli /tmp/mokocli 2>/dev/null || true
|
|
79
|
+
else
|
|
80
|
+
echo "::warning::mokocli unavailable — issue-reporter steps may be degraded"
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
- name: Report CI failure
|
|
84
|
+
env:
|
|
85
|
+
MOKOGIT_TOKEN: ${{ github.token }}
|
|
86
|
+
MOKOGIT_URL: ${{ vars.MOKOGIT_URL || 'https://git.mokoconsulting.tech' }}
|
|
87
|
+
# Route all workflow_call inputs through env vars — referencing ${{ inputs.* }}
|
|
88
|
+
# directly in a run: block interpolates at YAML-parse time and is a shell-injection
|
|
89
|
+
# vector. Shell variables are not re-parsed, so a crafted input can't break out.
|
|
90
|
+
INPUT_GATE: ${{ inputs.gate }}
|
|
91
|
+
INPUT_DETAILS: ${{ inputs.details }}
|
|
92
|
+
INPUT_SEVERITY: ${{ inputs.severity }}
|
|
93
|
+
INPUT_WORKFLOW: ${{ inputs.workflow }}
|
|
94
|
+
run: |
|
|
95
|
+
chmod +x /tmp/mokocli/cli/ci_issue_reporter.sh
|
|
96
|
+
/tmp/mokocli/cli/ci_issue_reporter.sh \
|
|
97
|
+
--gate "$INPUT_GATE" \
|
|
98
|
+
--details "$INPUT_DETAILS" \
|
|
99
|
+
--severity "$INPUT_SEVERITY" \
|
|
100
|
+
--workflow "$INPUT_WORKFLOW"
|
|
@@ -0,0 +1,112 @@
|
|
|
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.Maintenance
|
|
8
|
+
# REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Generic
|
|
9
|
+
# PATH: /.mokogit/workflows/cleanup.yml
|
|
10
|
+
# VERSION: 01.01.00
|
|
11
|
+
# CHANGE (01.01.00): fail-open branch/run cleanup (#430) — the run token may lack REST read on some repos, returning an error OBJECT; `jq '.[]'` on it exit-5'd the job under pipefail (fleet-wide red). Guard type=="array" / `(.workflow_runs // [])` and skip gracefully; cleanup is best-effort housekeeping and must never red the run.
|
|
12
|
+
# BRIEF: Scheduled cleanup — delete merged branches and old workflow runs
|
|
13
|
+
|
|
14
|
+
name: "Universal: Repository Cleanup"
|
|
15
|
+
|
|
16
|
+
on:
|
|
17
|
+
schedule:
|
|
18
|
+
- cron: '0 3 * * 0' # Weekly on Sunday at 03:00 UTC
|
|
19
|
+
workflow_dispatch:
|
|
20
|
+
|
|
21
|
+
permissions:
|
|
22
|
+
contents: write
|
|
23
|
+
actions: write
|
|
24
|
+
|
|
25
|
+
env:
|
|
26
|
+
MOKOGIT_URL: ${{ vars.MOKOGIT_URL || 'https://git.mokoconsulting.tech' }}
|
|
27
|
+
|
|
28
|
+
jobs:
|
|
29
|
+
cleanup:
|
|
30
|
+
name: Clean Merged Branches
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
|
|
33
|
+
steps:
|
|
34
|
+
- name: Checkout
|
|
35
|
+
uses: actions/checkout@v4
|
|
36
|
+
with:
|
|
37
|
+
fetch-depth: 0
|
|
38
|
+
token: ${{ github.token }}
|
|
39
|
+
|
|
40
|
+
- name: Delete merged branches
|
|
41
|
+
env:
|
|
42
|
+
MOKOGIT_TOKEN: ${{ github.token }}
|
|
43
|
+
run: |
|
|
44
|
+
echo "=== Merged Branch Cleanup ==="
|
|
45
|
+
API="${MOKOGIT_URL}/api/v1/repos/${{ github.repository }}"
|
|
46
|
+
|
|
47
|
+
# List branches via API. FAIL-OPEN (#430): the run token may lack REST read
|
|
48
|
+
# on some repos, so the API returns an error OBJECT (not an array); piping
|
|
49
|
+
# that into `jq '.[]'` errors (exit 5) and, under `set -o pipefail`, fails the
|
|
50
|
+
# whole job. Guard type=="array" and skip gracefully — branch cleanup is
|
|
51
|
+
# best-effort housekeeping and must never red the run.
|
|
52
|
+
BR_RESP=$(curl -sS -H "Authorization: token ${MOKOGIT_TOKEN}" \
|
|
53
|
+
"${API}/branches?limit=50" 2>/dev/null || true)
|
|
54
|
+
BRANCHES=$(printf '%s' "$BR_RESP" | jq -r 'if type=="array" then .[].name else empty end' 2>/dev/null || true)
|
|
55
|
+
if [ -z "$BRANCHES" ]; then
|
|
56
|
+
echo "::warning::branch cleanup: could not list branches (token/API); skipping (not a failure)."
|
|
57
|
+
exit 0
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
# Head refs of every OPEN pull request — never delete one of these. A
|
|
61
|
+
# branch can be an ancestor of main yet still back an open PR (e.g. the
|
|
62
|
+
# native sync engine's moko-sync/* review PRs); deleting it orphans the PR.
|
|
63
|
+
OPEN_PR_HEADS=$(curl -sS -H "Authorization: token ${MOKOGIT_TOKEN}" \
|
|
64
|
+
"${API}/pulls?state=open&limit=100" 2>/dev/null \
|
|
65
|
+
| jq -r 'if type=="array" then .[].head.ref else empty end' 2>/dev/null || true)
|
|
66
|
+
|
|
67
|
+
DELETED=0
|
|
68
|
+
for BRANCH in $BRANCHES; do
|
|
69
|
+
# Skip protected branches
|
|
70
|
+
case "$BRANCH" in
|
|
71
|
+
main|master|dev|develop|rc|beta|alpha|release|release/*|production|stable|staging|hotfix/*|version/*) continue ;;
|
|
72
|
+
esac
|
|
73
|
+
|
|
74
|
+
# Skip any branch that backs an open PR
|
|
75
|
+
if echo "${OPEN_PR_HEADS}" | grep -qxF "${BRANCH}"; then
|
|
76
|
+
echo " Skipping (open PR): ${BRANCH}"
|
|
77
|
+
continue
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
# Check if branch is merged into main
|
|
81
|
+
if git merge-base --is-ancestor "origin/${BRANCH}" "origin/${{ github.event.repository.default_branch }}" 2>/dev/null; then
|
|
82
|
+
echo " Deleting merged branch: ${BRANCH}"
|
|
83
|
+
curl -sS -X DELETE -H "Authorization: token ${MOKOGIT_TOKEN}" \
|
|
84
|
+
"${API}/branches/${BRANCH}" 2>/dev/null || true
|
|
85
|
+
DELETED=$((DELETED + 1))
|
|
86
|
+
fi
|
|
87
|
+
done
|
|
88
|
+
|
|
89
|
+
echo "Deleted ${DELETED} merged branch(es)"
|
|
90
|
+
|
|
91
|
+
- name: Clean old workflow runs
|
|
92
|
+
env:
|
|
93
|
+
MOKOGIT_TOKEN: ${{ github.token }}
|
|
94
|
+
run: |
|
|
95
|
+
echo "=== Workflow Run Cleanup ==="
|
|
96
|
+
API="${MOKOGIT_URL}/api/v1/repos/${{ github.repository }}"
|
|
97
|
+
CUTOFF=$(date -d "30 days ago" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -v-30d +%Y-%m-%dT%H:%M:%SZ)
|
|
98
|
+
|
|
99
|
+
# Get old completed runs. FAIL-OPEN (#430): `(.workflow_runs // [])` guards a
|
|
100
|
+
# non-array/error response so `jq` can't exit-5 the job under pipefail.
|
|
101
|
+
RUNS=$(curl -sS -H "Authorization: token ${MOKOGIT_TOKEN}" \
|
|
102
|
+
"${API}/actions/runs?status=completed&limit=50" 2>/dev/null \
|
|
103
|
+
| jq -r "(.workflow_runs // []) | .[] | select(.created_at < \"${CUTOFF}\") | .id" 2>/dev/null || true)
|
|
104
|
+
|
|
105
|
+
DELETED=0
|
|
106
|
+
for RUN_ID in $RUNS; do
|
|
107
|
+
curl -sS -X DELETE -H "Authorization: token ${MOKOGIT_TOKEN}" \
|
|
108
|
+
"${API}/actions/runs/${RUN_ID}" 2>/dev/null || true
|
|
109
|
+
DELETED=$((DELETED + 1))
|
|
110
|
+
done
|
|
111
|
+
|
|
112
|
+
echo "Deleted ${DELETED} old workflow run(s)"
|
|
@@ -0,0 +1,240 @@
|
|
|
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.Validation
|
|
8
|
+
# REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Generic
|
|
9
|
+
# PATH: /.mokogit/workflows/makefile-lint.yml
|
|
10
|
+
# VERSION: 01.02.00
|
|
11
|
+
# BRIEF: Makefile sanity lint -- identity fields + release contract (SRC_DIR, PROJECT_VERSION format, BUILD_DIR, required targets, parse). Release-contract checks are WARN by default; set vars.MAKEFILE_LINT_ENFORCE=enforce to hard-fail (JOOMLA_I18N_ENFORCE-style, per-repo opt-in).
|
|
12
|
+
#
|
|
13
|
+
# +========================================================================+
|
|
14
|
+
# | MAKEFILE IDENTITY LINT |
|
|
15
|
+
# +========================================================================+
|
|
16
|
+
# | |
|
|
17
|
+
# | The release pipeline reads project identity from the Makefile |
|
|
18
|
+
# | (PROJECT_VERSION drives the version; PROJECT_AUTHOR is stamped into |
|
|
19
|
+
# | Joomla <author> at build -- see MokoCLI #803 / #289). A missing field |
|
|
20
|
+
# | degrades silently (the build just omits it), so this lints the |
|
|
21
|
+
# | Makefile on every PR and surfaces gaps early. |
|
|
22
|
+
# | |
|
|
23
|
+
# | Tiering (so a fleet-wide sync does NOT redden CI everywhere): |
|
|
24
|
+
# | - EXEMPT: a Makefile with NO PROJECT_* fields (foreign/native, e.g. |
|
|
25
|
+
# | MokoGIT=gitea, MokoNtfy=ntfy) is skipped, not failed. |
|
|
26
|
+
# | - HARD FAIL: no Makefile, or PROJECT_NAME / PROJECT_VERSION missing |
|
|
27
|
+
# | or empty (long-established, every repo already has them). |
|
|
28
|
+
# | - WARN only: PROJECT_AUTHOR missing (newly required -- grace period), |
|
|
29
|
+
# | or an identity value left at a scaffold placeholder. |
|
|
30
|
+
# | - PLATFORM is validated only IF present (it is platform-specific; |
|
|
31
|
+
# | generic repos derive platform from .mokogit/manifest.xml). |
|
|
32
|
+
# | |
|
|
33
|
+
# +========================================================================+
|
|
34
|
+
|
|
35
|
+
name: "Universal: Makefile Identity Lint"
|
|
36
|
+
|
|
37
|
+
on:
|
|
38
|
+
pull_request:
|
|
39
|
+
workflow_dispatch:
|
|
40
|
+
|
|
41
|
+
permissions:
|
|
42
|
+
contents: read
|
|
43
|
+
|
|
44
|
+
jobs:
|
|
45
|
+
makefile-identity:
|
|
46
|
+
name: Makefile Identity Lint
|
|
47
|
+
runs-on: ubuntu-latest
|
|
48
|
+
|
|
49
|
+
steps:
|
|
50
|
+
- name: Checkout
|
|
51
|
+
uses: actions/checkout@v4
|
|
52
|
+
|
|
53
|
+
- name: Lint Makefile identity block
|
|
54
|
+
env:
|
|
55
|
+
# Opt-in hard-fail for the release-contract checks (SRC_DIR, parse),
|
|
56
|
+
# mirroring the JOOMLA_I18N_ENFORCE rollout: unset => WARN only (a
|
|
57
|
+
# fleet-wide sync never reddens anyone), enforce|true|1 => hard fail.
|
|
58
|
+
MAKEFILE_LINT_ENFORCE: ${{ vars.MAKEFILE_LINT_ENFORCE }}
|
|
59
|
+
# Mirror the pre-release #469 SRC_DIR gate opt-out: electron-style repos
|
|
60
|
+
# set this "off" (always-bump) and are not required to declare SRC_DIR.
|
|
61
|
+
RELEASE_SRCDIR_GATE: ${{ vars.RELEASE_SRCDIR_GATE }}
|
|
62
|
+
run: |
|
|
63
|
+
# The runner shell is `bash -e -o pipefail`. `read_field` greps the
|
|
64
|
+
# Makefile, and a MISSING field makes grep exit 1 -> pipefail would abort
|
|
65
|
+
# the whole script (set -e) before the warn/heal logic runs. Disable
|
|
66
|
+
# pipefail here so a grep non-match is treated as "field absent", not a
|
|
67
|
+
# fatal error (the field-presence logic below handles absence explicitly).
|
|
68
|
+
set +o pipefail
|
|
69
|
+
echo "### Makefile Identity Lint" >> "$GITHUB_STEP_SUMMARY"
|
|
70
|
+
|
|
71
|
+
if [ ! -f Makefile ]; then
|
|
72
|
+
echo "::notice::No Makefile in repo root -- skipping identity lint (nothing to release from a Makefile)."
|
|
73
|
+
echo "No Makefile -- skipped." >> "$GITHUB_STEP_SUMMARY"
|
|
74
|
+
exit 0
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
# Exempt foreign/native Makefiles that don't participate in the Moko
|
|
78
|
+
# identity convention at all (no PROJECT_* fields) -- e.g. MokoGIT ships
|
|
79
|
+
# the upstream gitea Makefile and MokoNtfy the ntfy Makefile. A
|
|
80
|
+
# Moko-standard Makefile always declares at least one PROJECT_* field,
|
|
81
|
+
# so a half-configured standard Makefile (has some PROJECT_* but is
|
|
82
|
+
# missing NAME/VERSION) is still caught below; only genuinely-foreign
|
|
83
|
+
# Makefiles are skipped, so a fleet-wide sync does not redden them.
|
|
84
|
+
if ! grep -qE '^[[:space:]]*PROJECT_[A-Z_]+[[:space:]]*:?=' Makefile; then
|
|
85
|
+
echo "::notice::Makefile has no PROJECT_* identity fields -- treating as a non-Moko/native Makefile and skipping identity lint."
|
|
86
|
+
echo "Non-Moko Makefile (no PROJECT_* fields) -- skipped." >> "$GITHUB_STEP_SUMMARY"
|
|
87
|
+
exit 0
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
# Read a `FIELD := value` (or `FIELD = value`) identity line, trimmed.
|
|
91
|
+
read_field() {
|
|
92
|
+
{ grep -m1 -E "^[[:space:]]*$1[[:space:]]*:?=" Makefile 2>/dev/null || true; } \
|
|
93
|
+
| sed -E 's/^[^=]*:?=[[:space:]]*//' \
|
|
94
|
+
| sed -E 's/[[:space:]]+#.*$//' \
|
|
95
|
+
| sed -E 's/[[:space:]]*$//'
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
is_placeholder() {
|
|
99
|
+
# scaffold leftovers: myproject, {{PROJECT_NAME}}, CHANGEME, etc.
|
|
100
|
+
case "$1" in
|
|
101
|
+
myproject|CHANGEME|TODO|"{{"*"}}"|"") return 0 ;;
|
|
102
|
+
*) return 1 ;;
|
|
103
|
+
esac
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
# Release-contract severity: hard-fail only when enforce is opted in
|
|
107
|
+
# (per-repo vars.MAKEFILE_LINT_ENFORCE), else warn -- so a fleet-wide
|
|
108
|
+
# sync never reddens a repo that has not adopted the contract yet.
|
|
109
|
+
ENFORCE=0
|
|
110
|
+
case "${MAKEFILE_LINT_ENFORCE:-}" in enforce|true|1) ENFORCE=1 ;; esac
|
|
111
|
+
|
|
112
|
+
gate() { # gate "<message>" "<summary-label>"
|
|
113
|
+
if [ "$ENFORCE" -eq 1 ]; then
|
|
114
|
+
echo "::error::$1"
|
|
115
|
+
echo "- [FAIL] $2" >> "$GITHUB_STEP_SUMMARY"
|
|
116
|
+
FAIL=1
|
|
117
|
+
else
|
|
118
|
+
echo "::warning::$1"
|
|
119
|
+
echo "- [WARN] $2 (MAKEFILE_LINT_ENFORCE off)" >> "$GITHUB_STEP_SUMMARY"
|
|
120
|
+
fi
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
FAIL=0
|
|
124
|
+
|
|
125
|
+
# -- Hard-required fields --
|
|
126
|
+
for f in PROJECT_NAME PROJECT_VERSION; do
|
|
127
|
+
v="$(read_field "$f")"
|
|
128
|
+
if [ -z "$v" ]; then
|
|
129
|
+
echo "::error::Makefile is missing required identity field ${f} (expected e.g. '${f} := ...')."
|
|
130
|
+
echo "- [FAIL] ${f}: missing" >> "$GITHUB_STEP_SUMMARY"
|
|
131
|
+
FAIL=1
|
|
132
|
+
elif is_placeholder "$v"; then
|
|
133
|
+
echo "::warning::Makefile ${f} is still a scaffold placeholder ('${v}') -- set it for this project."
|
|
134
|
+
echo "- [WARN] ${f}: placeholder (${v})" >> "$GITHUB_STEP_SUMMARY"
|
|
135
|
+
else
|
|
136
|
+
echo "- [OK] ${f}: ${v}" >> "$GITHUB_STEP_SUMMARY"
|
|
137
|
+
fi
|
|
138
|
+
done
|
|
139
|
+
|
|
140
|
+
# -- Newly-required (warn only for now: #289/#408 rollout grace period) --
|
|
141
|
+
author="$(read_field PROJECT_AUTHOR)"
|
|
142
|
+
if [ -z "$author" ]; then
|
|
143
|
+
echo "::warning::Makefile is missing PROJECT_AUTHOR -- release builds cannot stamp Joomla <author> (MokoCLI #803/#289). Add 'PROJECT_AUTHOR := <name>'."
|
|
144
|
+
echo "- [WARN] PROJECT_AUTHOR: missing (recommended)" >> "$GITHUB_STEP_SUMMARY"
|
|
145
|
+
elif is_placeholder "$author"; then
|
|
146
|
+
echo "::warning::Makefile PROJECT_AUTHOR is still a placeholder ('${author}')."
|
|
147
|
+
echo "- [WARN] PROJECT_AUTHOR: placeholder (${author})" >> "$GITHUB_STEP_SUMMARY"
|
|
148
|
+
else
|
|
149
|
+
echo "- [OK] PROJECT_AUTHOR: ${author}" >> "$GITHUB_STEP_SUMMARY"
|
|
150
|
+
fi
|
|
151
|
+
|
|
152
|
+
# -- PLATFORM: validate only if the repo declares one (platform-specific) --
|
|
153
|
+
if grep -qE '^[[:space:]]*PLATFORM[[:space:]]*:?=' Makefile; then
|
|
154
|
+
platform="$(read_field PLATFORM)"
|
|
155
|
+
if [ -z "$platform" ] || is_placeholder "$platform"; then
|
|
156
|
+
echo "::warning::Makefile declares PLATFORM but it is empty/placeholder ('${platform}')."
|
|
157
|
+
echo "- [WARN] PLATFORM: empty/placeholder" >> "$GITHUB_STEP_SUMMARY"
|
|
158
|
+
else
|
|
159
|
+
echo "- [OK] PLATFORM: ${platform}" >> "$GITHUB_STEP_SUMMARY"
|
|
160
|
+
fi
|
|
161
|
+
fi
|
|
162
|
+
|
|
163
|
+
# === Release-contract checks (beyond identity) -- #280 / #483 ===
|
|
164
|
+
# The pre-release pipeline reads SRC_DIR (the #469 bump gate) and
|
|
165
|
+
# PROJECT_VERSION, and runs `make build/package/version`. A stale,
|
|
166
|
+
# renamed, or missing var -- or a Makefile that doesn't parse --
|
|
167
|
+
# becomes a LATE, silent pre-release failure (no artifact). Surface it
|
|
168
|
+
# here at PR time. WARN unless vars.MAKEFILE_LINT_ENFORCE is set.
|
|
169
|
+
platform="$(read_field PLATFORM)"
|
|
170
|
+
platform_lc="$(printf '%s' "$platform" | tr '[:upper:]' '[:lower:]')"
|
|
171
|
+
|
|
172
|
+
# -- SRC_DIR: source root the #469 pre-release gate greps for.
|
|
173
|
+
# electron / RELEASE_SRCDIR_GATE=off opt out (always-bump). --
|
|
174
|
+
if [ "$platform_lc" = "electron" ] || [ "${RELEASE_SRCDIR_GATE:-}" = "off" ]; then
|
|
175
|
+
echo "- [OK] SRC_DIR: n/a (electron / RELEASE_SRCDIR_GATE=off)" >> "$GITHUB_STEP_SUMMARY"
|
|
176
|
+
elif grep -qE '^[[:space:]]*SRC_DIR[[:space:]]*:?=' Makefile; then
|
|
177
|
+
srcdir="$(read_field SRC_DIR)"
|
|
178
|
+
if [ -z "$srcdir" ] || is_placeholder "$srcdir"; then
|
|
179
|
+
gate "Makefile SRC_DIR is empty/placeholder ('${srcdir}') -- the pre-release #469 bump gate needs a real source root." "SRC_DIR: empty/placeholder"
|
|
180
|
+
else
|
|
181
|
+
echo "- [OK] SRC_DIR: ${srcdir}" >> "$GITHUB_STEP_SUMMARY"
|
|
182
|
+
if [ ! -d "$srcdir" ]; then
|
|
183
|
+
echo "::warning::SRC_DIR='${srcdir}' but no such directory exists in the repo."
|
|
184
|
+
echo "- [WARN] SRC_DIR: '${srcdir}' not on disk" >> "$GITHUB_STEP_SUMMARY"
|
|
185
|
+
fi
|
|
186
|
+
fi
|
|
187
|
+
elif grep -qE '^[[:space:]]*SRC[[:space:]]*:?=' Makefile; then
|
|
188
|
+
gate "Makefile uses legacy 'SRC :=' but not 'SRC_DIR :='. The pre-release #469 gate greps ^SRC_DIR= and will HARD-FAIL the publish (no artifact). Rename SRC -> SRC_DIR, or re-run 'mokocli workflow sync --makefiles'. See MokonyxSocial #280." "SRC_DIR: legacy 'SRC' var (#280)"
|
|
189
|
+
else
|
|
190
|
+
gate "Makefile is missing SRC_DIR (source root). The pre-release #469 bump gate requires it on non-electron repos; add 'SRC_DIR := <dir>' (or set vars.RELEASE_SRCDIR_GATE=off to opt out)." "SRC_DIR: missing"
|
|
191
|
+
fi
|
|
192
|
+
|
|
193
|
+
# -- PROJECT_VERSION format (warn; scheme varies by platform) --
|
|
194
|
+
ver="$(read_field PROJECT_VERSION)"
|
|
195
|
+
if printf '%s' "$ver" | grep -qE '^[0-9]{2}\.[0-9]{2}\.[0-9]{2}$'; then
|
|
196
|
+
echo "- [OK] PROJECT_VERSION format: NN.NN.NN" >> "$GITHUB_STEP_SUMMARY"
|
|
197
|
+
elif printf '%s' "$ver" | grep -qE '^v?[0-9]+\.[0-9]+\.[0-9]+([.+-].*)?$'; then
|
|
198
|
+
echo "- [OK] PROJECT_VERSION format: semver-ish (${ver})" >> "$GITHUB_STEP_SUMMARY"
|
|
199
|
+
else
|
|
200
|
+
echo "::warning::PROJECT_VERSION '${ver}' matches neither zero-padded NN.NN.NN (Joomla/PHP) nor semver x.y.z -- release tagging/version integrity may misbehave."
|
|
201
|
+
echo "- [WARN] PROJECT_VERSION format: unrecognized (${ver})" >> "$GITHUB_STEP_SUMMARY"
|
|
202
|
+
fi
|
|
203
|
+
|
|
204
|
+
# -- BUILD_DIR present (warn) --
|
|
205
|
+
if grep -qE '^[[:space:]]*BUILD_DIR[[:space:]]*:?=' Makefile; then
|
|
206
|
+
echo "- [OK] BUILD_DIR: present" >> "$GITHUB_STEP_SUMMARY"
|
|
207
|
+
else
|
|
208
|
+
echo "::warning::Makefile has no BUILD_DIR -- build/package targets usually stage into it."
|
|
209
|
+
echo "- [WARN] BUILD_DIR: missing" >> "$GITHUB_STEP_SUMMARY"
|
|
210
|
+
fi
|
|
211
|
+
|
|
212
|
+
# -- Required release targets the pipeline invokes (warn) --
|
|
213
|
+
missing_targets=""
|
|
214
|
+
for t in build package version; do
|
|
215
|
+
grep -qE "^${t}:" Makefile || missing_targets="${missing_targets} ${t}"
|
|
216
|
+
done
|
|
217
|
+
if [ -n "$missing_targets" ]; then
|
|
218
|
+
echo "::warning::Makefile is missing release target(s):${missing_targets} -- the pipeline runs 'make <target>'."
|
|
219
|
+
echo "- [WARN] targets: missing${missing_targets}" >> "$GITHUB_STEP_SUMMARY"
|
|
220
|
+
else
|
|
221
|
+
echo "- [OK] targets: build, package, version present" >> "$GITHUB_STEP_SUMMARY"
|
|
222
|
+
fi
|
|
223
|
+
|
|
224
|
+
# -- Makefile parses cleanly -- dry-run the always-present `version`
|
|
225
|
+
# target so a syntax/eval error is caught without running a build. --
|
|
226
|
+
if command -v make >/dev/null 2>&1 && grep -qE '^version:' Makefile; then
|
|
227
|
+
if make -n version >/dev/null 2>parse.err; then
|
|
228
|
+
echo "- [OK] make -n version: parses" >> "$GITHUB_STEP_SUMMARY"
|
|
229
|
+
else
|
|
230
|
+
gate "'make -n version' failed -- the Makefile has a parse/evaluation error: $(sed -n '1,3p' parse.err | tr '\n' ' ')" "make -n version: parse/eval error"
|
|
231
|
+
fi
|
|
232
|
+
rm -f parse.err
|
|
233
|
+
fi
|
|
234
|
+
|
|
235
|
+
if [ "$FAIL" -ne 0 ]; then
|
|
236
|
+
echo "" >> "$GITHUB_STEP_SUMMARY"
|
|
237
|
+
echo "**Fix the FAIL item(s) above (identity + release contract).**" >> "$GITHUB_STEP_SUMMARY"
|
|
238
|
+
exit 1
|
|
239
|
+
fi
|
|
240
|
+
echo "Makefile sanity OK ($([ "$ENFORCE" -eq 1 ] && echo 'enforce' || echo 'contract checks warn-only'))." >> "$GITHUB_STEP_SUMMARY"
|