Compare commits

..

36 Commits

Author SHA1 Message Date
jmiller 1fe4f83e73 Merge pull request 'chore(release): v09.00.00' (#140) from dev into main
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (push) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (push) Blocked by required conditions
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Universal: Cascade Main → Dev / Cascade main → branches (push) Successful in 3s
Generic: Repo Health / Release configuration (push) Blocked by required conditions
Generic: Repo Health / Scripts governance (push) Blocked by required conditions
Generic: Repo Health / Repository health (push) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 4s
Platform: moko-platform CI / Gate 1: Code Quality (push) Successful in 50s
2026-05-26 04:33:40 +00:00
Jonathan Miller 7e5c322792 chore(release): bump to 09.00.00
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (push) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (push) Blocked by required conditions
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Generic: Repo Health / Release configuration (push) Blocked by required conditions
Generic: Repo Health / Scripts governance (push) Blocked by required conditions
Generic: Repo Health / Repository health (push) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 4s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Blocked by required conditions
Platform: moko-platform CI / CI Summary (pull_request) Blocked by required conditions
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Generic: Repo Health / Release configuration (pull_request) Blocked by required conditions
Generic: Repo Health / Scripts governance (pull_request) Blocked by required conditions
Generic: Repo Health / Repository health (pull_request) Blocked by required conditions
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: PR Check / Branch Policy (pull_request) Successful in 5s
Generic: Repo Health / Access control (pull_request) Successful in 6s
Universal: PR Check / Validate PR (pull_request) Successful in 11s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 12s
Universal: Security Audit / Dependency Audit (pull_request) Successful in 9s
Platform: moko-platform CI / Gate 1: Code Quality (push) Successful in 1m21s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Successful in 59s
PHPDoc standard, CI enforcement, updates_xml_build fixes.

Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-25 23:32:42 -05:00
jmiller b010677d75 Merge pull request 'chore: cascade main → dev (9275e58) [skip ci]' (#139) from main into dev
chore: cascade main → dev [skip ci]
2026-05-26 04:29:33 +00:00
jmiller 9275e581c2 Merge pull request 'chore: PHPDoc Priority 1 + Coding Standards wiki' (#138) from dev into main
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (push) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (push) Blocked by required conditions
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Generic: Repo Health / Release configuration (push) Blocked by required conditions
Generic: Repo Health / Scripts governance (push) Blocked by required conditions
Generic: Repo Health / Repository health (push) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Universal: Cascade Main → Dev / Cascade main → branches (push) Successful in 3s
Platform: moko-platform CI / Gate 1: Code Quality (push) Successful in 46s
2026-05-26 04:29:29 +00:00
Jonathan Miller 3f3b1f79a0 chore: add PHPDoc to Priority 1 Enterprise classes
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (push) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (push) Blocked by required conditions
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Generic: Repo Health / Release configuration (push) Blocked by required conditions
Generic: Repo Health / Scripts governance (push) Blocked by required conditions
Generic: Repo Health / Repository health (push) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Platform: moko-platform CI / Gate 1: Code Quality (push) Successful in 42s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Blocked by required conditions
Platform: moko-platform CI / CI Summary (pull_request) Blocked by required conditions
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Generic: Repo Health / Release configuration (pull_request) Blocked by required conditions
Generic: Repo Health / Scripts governance (pull_request) Blocked by required conditions
Generic: Repo Health / Repository health (pull_request) Blocked by required conditions
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 4s
Universal: PR Check / Validate PR (pull_request) Successful in 4s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Successful in 45s
Added @since, @param, @see tags to:
- CliFramework: class-level @since, 2 undocumented methods
- GitHubAdapter: class @since/@see, constructor @param, property docs
- MokoGiteaAdapter: class @since/@see, constructor @param, property docs
- ApiClient: class @since

Wiki: created Coding-Standards page with full PHPDoc standard,
PHPCS exclusion rationale, and file structure patterns.

Partial progress on #137

Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-25 23:26:07 -05:00
Jonathan Miller 83842c50ad docs(changelog): add updates_xml_build fixes to Unreleased
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Generic: Repo Health / Scripts governance (push) Successful in 4s
Generic: Repo Health / Release configuration (push) Successful in 5s
Generic: Repo Health / Repository health (push) Successful in 10s
Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-25 23:12:12 -05:00
Jonathan Miller fbedd5966c fix(updates_xml): cascade entries down, fix Gitea release tag URLs, fix client tag
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (push) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (push) Blocked by required conditions
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Generic: Repo Health / Release configuration (push) Successful in 4s
Generic: Repo Health / Scripts governance (push) Successful in 4s
Generic: Repo Health / Repository health (push) Successful in 13s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 46s
- Cascade: when stable releases, write all 5 channel entries pointing to stable
- Separate Joomla tags from Gitea release tags via releaseTagMap
- Only add client tag for templates and modules, not packages
- Preservation logic matches against Joomla tag names correctly

Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-25 23:10:29 -05:00
jmiller eca2c13018 Merge pull request 'chore: cascade main → dev (48d0001) [skip ci]' (#136) from main into dev
chore: cascade main → dev [skip ci]
2026-05-26 04:09:19 +00:00
jmiller 48d000107d Merge pull request 'fix(ci): enforce PHPStan + PHPUnit in CI' (#135) from dev into main
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (push) Blocked by required conditions
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Universal: Cascade Main → Dev / Cascade main → branches (push) Successful in 3s
Generic: Repo Health / Access control (push) Successful in 1s
Generic: Repo Health / Release configuration (push) Successful in 5s
Generic: Repo Health / Scripts governance (push) Successful in 6s
Generic: Repo Health / Repository health (push) Successful in 11s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 49s
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been skipped
2026-05-26 04:09:14 +00:00
Jonathan Miller 7ceb9528cc fix(ci): enforce PHPStan + PHPUnit in CI gates
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (push) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (push) Blocked by required conditions
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Generic: Repo Health / Release configuration (push) Successful in 4s
Generic: Repo Health / Scripts governance (push) Successful in 4s
Generic: Repo Health / Repository health (push) Successful in 10s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Blocked by required conditions
Platform: moko-platform CI / CI Summary (pull_request) Blocked by required conditions
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (pull_request) Successful in 2s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 4s
Universal: PR Check / Validate PR (pull_request) Successful in 4s
Universal: PR Check / Build RC Package (pull_request) Successful in 2s
Generic: Repo Health / Release configuration (pull_request) Successful in 3s
Generic: Repo Health / Scripts governance (pull_request) Successful in 4s
Generic: Repo Health / Repository health (pull_request) Successful in 11s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 51s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 51s
- PHPStan: remove continue-on-error, update label to Level 6,
  add --memory-limit=512M, fail on errors (was advisory)
- PHPUnit: add error handling — tests now block merges on failure
  (was silently passing even on test failures)

Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-25 23:08:33 -05:00
jmiller 5fabaec477 Merge pull request 'chore: cascade main → dev (e40b799) [skip ci]' (#134) from main into dev
chore: cascade main → dev [skip ci]
2026-05-26 03:55:23 +00:00
jmiller e40b799101 Merge pull request 'chore(release): v08.00.00' (#133) from dev into main
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (push) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (push) Blocked by required conditions
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Universal: Cascade Main → Dev / Cascade main → branches (push) Successful in 5s
Platform: moko-platform CI / Gate 1: Code Quality (push) Successful in 1m17s
Generic: Repo Health / Repository health (push) Successful in 16s
Generic: Repo Health / Access control (push) Successful in 3s
Generic: Repo Health / Release configuration (push) Successful in 13s
Generic: Repo Health / Scripts governance (push) Successful in 10s
Generic: Repo Health / Site Health (push) Has been skipped
2026-05-26 03:53:20 +00:00
Jonathan Miller 7e9784e723 chore(release): bump to 08.00.00
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Blocked by required conditions
Platform: moko-platform CI / CI Summary (pull_request) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 5s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: PR Check / Branch Policy (pull_request) Successful in 3s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Successful in 6s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 7s
Universal: Security Audit / Dependency Audit (pull_request) Successful in 7s
Generic: Repo Health / Release configuration (push) Successful in 7s
Generic: Repo Health / Scripts governance (push) Successful in 11s
Platform: moko-platform CI / Gate 1: Code Quality (push) Successful in 1m43s
Generic: Repo Health / Repository health (push) Successful in 21s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Successful in 1m24s
Universal: PR Check / Build RC Package (pull_request) Successful in 4s
Generic: Repo Health / Scripts governance (pull_request) Successful in 7s
Generic: Repo Health / Release configuration (pull_request) Successful in 9s
Generic: Repo Health / Repository health (pull_request) Successful in 16s
Platform: moko-platform CI / Gate 5: Template Integrity (push) Failing after 4s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Successful in 47s
Platform: moko-platform CI / Gate 4: Governance (push) Successful in 47s
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Successful in 51s
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Failing after 50s
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Successful in 54s
PHPStan level 0 → 6, branch protection restored, workflows synced,
44 stale runners flushed. Found and fixed real metrics bug at level 5.

Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-25 22:52:00 -05:00
jmiller 209dee14fd Merge pull request 'chore: cascade main → dev (81351f4) [skip ci]' (#132) from main into dev
chore: cascade main → dev [skip ci]
2026-05-26 03:50:21 +00:00
Jonathan Miller 81351f45fd fix: updates_xml_build — tag 'dev' not 'development', client for all types
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 3s
Universal: Cascade Main → Dev / Cascade main → branches (push) Successful in 8s
Generic: Repo Health / Release configuration (push) Successful in 11s
Generic: Repo Health / Scripts governance (push) Successful in 5s
Generic: Repo Health / Repository health (push) Successful in 15s
Platform: moko-platform CI / Gate 1: Code Quality (push) Successful in 1m25s
Platform: moko-platform CI / Gate 5: Template Integrity (push) Failing after 14s
Platform: moko-platform CI / Gate 4: Governance (push) Successful in 1m14s
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Successful in 1m19s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Successful in 1m27s
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Failing after 1m27s
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Successful in 1m29s
Two root causes of Joomla updater not finding MokoWaaS updates:

1. stabilityTagToInteger('development') looks for STABILITY_DEVELOPMENT
   which doesn't exist → defaults to STABLE. Changed to 'dev' which
   maps to STABILITY_DEV (0).

2. Missing <client> tag defaults to client_id=1 (administrator) in
   Joomla's ExtensionAdapter. Packages install with client_id=0 (site).
   Now adds <client>site</client> for all extension types.

Fixes: #129

Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-25 22:50:07 -05:00
jmiller fd451b4b73 Merge pull request 'chore: cascade main → dev (d0dbd1d) [skip ci]' (#131) from main into dev
chore: cascade main → dev [skip ci]
2026-05-26 03:48:35 +00:00
jmiller d0dbd1dceb Merge pull request 'fix: PHPStan level 6 with baseline' (#130) from dev into main
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 5s
Universal: Cascade Main → Dev / Cascade main → branches (push) Successful in 9s
Generic: Repo Health / Release configuration (push) Successful in 7s
Generic: Repo Health / Scripts governance (push) Successful in 7s
Generic: Repo Health / Repository health (push) Successful in 17s
Platform: moko-platform CI / Gate 1: Code Quality (push) Successful in 2m19s
Platform: moko-platform CI / Gate 5: Template Integrity (push) Failing after 8s
Platform: moko-platform CI / Gate 4: Governance (push) Successful in 50s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Successful in 55s
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Successful in 57s
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Failing after 1m0s
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Successful in 1m4s
2026-05-26 03:48:21 +00:00
Jonathan Miller 3e2e291819 fix: PHPStan level 5 → 6 — baseline 360 missing array generics
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Generic: Repo Health / Release configuration (push) Successful in 5s
Generic: Repo Health / Scripts governance (push) Successful in 4s
Generic: Repo Health / Repository health (push) Successful in 12s
Platform: moko-platform CI / CI Summary (pull_request) Blocked by required conditions
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 4s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Successful in 4s
Universal: PR Check / Build RC Package (pull_request) Successful in 2s
Generic: Repo Health / Release configuration (pull_request) Successful in 5s
Generic: Repo Health / Scripts governance (pull_request) Successful in 5s
Generic: Repo Health / Repository health (pull_request) Successful in 14s
Platform: moko-platform CI / Gate 1: Code Quality (push) Successful in 1m10s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Successful in 1m24s
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Failing after 10s
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Successful in 1m9s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Successful in 1m10s
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Failing after 58s
Platform: moko-platform CI / Gate 4: Governance (pull_request) Successful in 59s
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Successful in 1m6s
Platform: moko-platform CI / Gate 5: Template Integrity (push) Failing after 7s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Successful in 52s
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Successful in 52s
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Failing after 51s
Platform: moko-platform CI / Gate 4: Governance (push) Successful in 50s
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Successful in 54s
Level 6 requires generic type annotations on all arrays. 357 of 360
errors are missingType.iterableValue (bare array without generics).
Baselined — these are PHPDoc-only changes with no functional impact.

PHPStan level 6: 0 errors with baseline.

Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-25 22:47:39 -05:00
jmiller 5975ea38d8 Merge pull request 'chore: cascade main → dev (8ad548f) [skip ci]' (#128) from main into dev
chore: cascade main → dev [skip ci]
2026-05-26 03:43:49 +00:00
jmiller 8ad548f4a3 Merge pull request 'fix: PHPStan level 5 - fix metrics increment bug' (#127) from dev into main
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Generic: Repo Health / Access control (push) Successful in 5s
Generic: Repo Health / Site Health (push) Has been skipped
Universal: Cascade Main → Dev / Cascade main → branches (push) Successful in 8s
Generic: Repo Health / Release configuration (push) Successful in 5s
Generic: Repo Health / Scripts governance (push) Successful in 4s
Generic: Repo Health / Repository health (push) Successful in 11s
Platform: moko-platform CI / Gate 1: Code Quality (push) Successful in 56s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Successful in 1m20s
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Successful in 1m15s
Platform: moko-platform CI / Gate 5: Template Integrity (push) Failing after 10s
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Successful in 54s
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Failing after 1m17s
Platform: moko-platform CI / Gate 4: Governance (push) Successful in 1m14s
2026-05-26 03:43:42 +00:00
Jonathan Miller cbb4d73df5 fix: PHPStan level 4 → 5 — fix 4 errors
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Generic: Repo Health / Release configuration (push) Successful in 7s
Generic: Repo Health / Scripts governance (push) Successful in 7s
Generic: Repo Health / Repository health (push) Successful in 19s
Platform: moko-platform CI / CI Summary (pull_request) Blocked by required conditions
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 6s
Universal: PR Check / Validate PR (pull_request) Successful in 6s
Generic: Repo Health / Release configuration (pull_request) Successful in 6s
Generic: Repo Health / Scripts governance (pull_request) Successful in 6s
Universal: PR Check / Build RC Package (pull_request) Successful in 5s
Generic: Repo Health / Repository health (pull_request) Successful in 15s
Platform: moko-platform CI / Gate 1: Code Quality (push) Successful in 1m19s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Successful in 59s
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Failing after 5s
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Successful in 58s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Successful in 1m1s
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Successful in 1m0s
Platform: moko-platform CI / Gate 4: Governance (pull_request) Successful in 49s
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Failing after 51s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Successful in 1m2s
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Successful in 1m7s
Platform: moko-platform CI / Gate 5: Template Integrity (push) Failing after 7s
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Successful in 1m9s
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Failing after 55s
Platform: moko-platform CI / Gate 4: Governance (push) Successful in 1m0s
- bulk_sync: remove redundant array_values on already-list array
- RepositorySynchronizer: fix metrics increment() — labels passed as
  2nd param (value) instead of 3rd (labels), was a real bug

PHPStan level 5: 0 errors.

Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-25 22:42:50 -05:00
jmiller 47cb47ebdb Merge pull request 'chore: cascade main → dev (22b0f8a) [skip ci]' (#126) from main into dev
chore: cascade main → dev [skip ci]
2026-05-26 03:34:38 +00:00
jmiller 22b0f8af7e Merge pull request 'fix: PHPStan level 4 with baseline' (#125) from dev into main
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Universal: Cascade Main → Dev / Cascade main → branches (push) Successful in 2s
Generic: Repo Health / Release configuration (push) Successful in 4s
Generic: Repo Health / Scripts governance (push) Successful in 4s
Generic: Repo Health / Repository health (push) Successful in 11s
Platform: moko-platform CI / Gate 1: Code Quality (push) Successful in 44s
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Successful in 1m6s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Successful in 1m10s
Platform: moko-platform CI / Gate 4: Governance (push) Successful in 1m8s
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Successful in 1m12s
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Failing after 1m11s
Platform: moko-platform CI / Gate 5: Template Integrity (push) Failing after 7s
2026-05-26 03:34:34 +00:00
jmiller 08ca1429ae Merge branch 'main' into dev
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Platform: moko-platform CI / CI Summary (pull_request) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 3s
Universal: PR Check / Branch Policy (pull_request) Successful in 4s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 8s
Generic: Repo Health / Access control (pull_request) Successful in 4s
Universal: PR Check / Validate PR (pull_request) Successful in 8s
Generic: Repo Health / Scripts governance (push) Successful in 10s
Generic: Repo Health / Release configuration (push) Successful in 10s
Generic: Repo Health / Repository health (push) Successful in 18s
Generic: Repo Health / Release configuration (pull_request) Successful in 13s
Platform: moko-platform CI / Gate 1: Code Quality (push) Successful in 1m30s
Universal: PR Check / Build RC Package (pull_request) Successful in 5s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Successful in 1m32s
Generic: Repo Health / Scripts governance (pull_request) Successful in 11s
Generic: Repo Health / Repository health (pull_request) Successful in 19s
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Failing after 9s
Platform: moko-platform CI / Gate 4: Governance (pull_request) Successful in 1m49s
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Successful in 1m49s
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Failing after 1m51s
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Successful in 1m52s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Successful in 1m55s
Platform: moko-platform CI / Gate 5: Template Integrity (push) Failing after 7s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Successful in 54s
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Successful in 55s
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Failing after 55s
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Successful in 57s
Platform: moko-platform CI / Gate 4: Governance (push) Successful in 52s
2026-05-26 03:32:18 +00:00
Jonathan Miller e8da1a30ff fix: PHPStan level 3 → 4 — remove dead code, baseline 41 items
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 2s
Generic: Repo Health / Release configuration (push) Successful in 10s
Generic: Repo Health / Scripts governance (push) Successful in 9s
Generic: Repo Health / Repository health (push) Successful in 17s
Platform: moko-platform CI / CI Summary (pull_request) Blocked by required conditions
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 8s
Universal: PR Check / Validate PR (pull_request) Successful in 8s
Generic: Repo Health / Release configuration (pull_request) Successful in 6s
Generic: Repo Health / Scripts governance (pull_request) Successful in 8s
Universal: PR Check / Build RC Package (pull_request) Successful in 5s
Generic: Repo Health / Repository health (pull_request) Successful in 19s
Platform: moko-platform CI / Gate 1: Code Quality (push) Successful in 1m16s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Successful in 1m29s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Successful in 41s
Platform: moko-platform CI / Gate 5: Template Integrity (push) Failing after 6s
Platform: moko-platform CI / Gate 4: Governance (push) Successful in 1m38s
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Successful in 1m40s
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Successful in 1m41s
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Failing after 1m40s
Platform: moko-platform CI / Gate 4: Governance (pull_request) Successful in 1m20s
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Successful in 1m24s
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Failing after 1m24s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Successful in 1m26s
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Successful in 1m30s
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Failing after 12s
Removed 13 write-only properties and unused code. Remaining 41
baselined items are defensive patterns (null coalesce on API responses,
boolean safety checks) that are intentional.

PHPStan level 4: 0 errors with baseline.

Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-25 22:31:25 -05:00
gitea-actions[bot] fb754b1a07 refactor(ci): clean up auto-release, move logic to CLI [skip ci] 2026-05-25 22:21:10 -05:00
jmiller 9a2c164207 Merge pull request 'chore: cascade main → dev (78c1329) [skip ci]' (#124) from main into dev
chore: cascade main → dev [skip ci]
2026-05-26 03:19:46 +00:00
jmiller 78c1329a83 Merge pull request 'fix: PHPStan level 3 - 12 return type errors fixed' (#123) from dev into main
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Universal: Cascade Main → Dev / Cascade main → branches (push) Successful in 4s
Generic: Repo Health / Scripts governance (push) Successful in 5s
Generic: Repo Health / Release configuration (push) Successful in 5s
Generic: Repo Health / Repository health (push) Successful in 11s
Platform: moko-platform CI / Gate 1: Code Quality (push) Successful in 45s
Platform: moko-platform CI / Gate 5: Template Integrity (push) Failing after 5s
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Successful in 55s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Successful in 57s
Platform: moko-platform CI / Gate 4: Governance (push) Successful in 57s
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Failing after 58s
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Successful in 1m0s
2026-05-26 03:19:41 +00:00
jmiller 05f43ed88f Merge branch 'main' into dev
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Platform: moko-platform CI / CI Summary (pull_request) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (push) Successful in 2s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Successful in 5s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 5s
Generic: Repo Health / Release configuration (push) Successful in 4s
Generic: Repo Health / Scripts governance (push) Successful in 5s
Universal: PR Check / Build RC Package (pull_request) Successful in 3s
Generic: Repo Health / Release configuration (pull_request) Successful in 5s
Generic: Repo Health / Scripts governance (pull_request) Successful in 5s
Generic: Repo Health / Repository health (push) Successful in 13s
Generic: Repo Health / Repository health (pull_request) Successful in 13s
Platform: moko-platform CI / Gate 1: Code Quality (push) Successful in 57s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Successful in 57s
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Failing after 8s
Platform: moko-platform CI / Gate 4: Governance (pull_request) Successful in 44s
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Failing after 47s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Successful in 48s
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Successful in 49s
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Successful in 50s
Platform: moko-platform CI / Gate 5: Template Integrity (push) Failing after 6s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Successful in 1m0s
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Successful in 1m7s
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Failing after 1m4s
Platform: moko-platform CI / Gate 4: Governance (push) Successful in 1m4s
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Successful in 1m13s
2026-05-26 03:18:36 +00:00
Jonathan Miller 05e4f39e7d fix: PHPStan level 2 → 3 — fix 12 return type errors
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Generic: Repo Health / Release configuration (push) Successful in 4s
Generic: Repo Health / Scripts governance (push) Successful in 4s
Generic: Repo Health / Repository health (push) Successful in 11s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 4: Governance (pull_request) Blocked by required conditions
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Blocked by required conditions
Platform: moko-platform CI / CI Summary (pull_request) Blocked by required conditions
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 7s
Universal: PR Check / Validate PR (pull_request) Successful in 7s
Generic: Repo Health / Release configuration (pull_request) Successful in 5s
Generic: Repo Health / Scripts governance (pull_request) Successful in 5s
Universal: PR Check / Build RC Package (pull_request) Successful in 2s
Generic: Repo Health / Repository health (pull_request) Successful in 15s
Platform: moko-platform CI / Gate 1: Code Quality (push) Successful in 59s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Successful in 57s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Successful in 51s
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Failing after 57s
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Successful in 1m4s
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Successful in 1m6s
Platform: moko-platform CI / Gate 5: Template Integrity (push) Failing after 11s
Platform: moko-platform CI / Gate 4: Governance (push) Successful in 54s
- Interface return types: narrowed list types to array<mixed> for API
  responses (ApiClient returns array<string, mixed>, not typed lists)
- paginateAll(): wrap return with array_values() for numeric keys
- listLabels: include id in return type
- check_file_integrity: fix sftpConfig default value type

Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-25 22:18:07 -05:00
jmiller 3dcb3b6d3a chore: sync .mokogitea/workflows/auto-release.yml from moko-platform [skip ci] 2026-05-26 03:07:21 +00:00
jmiller db4e6f5c6b Merge pull request 'chore: cascade main → dev (aa7fc45) [skip ci]' (#121) from main into dev
chore: cascade main → dev [skip ci]
2026-05-26 03:07:10 +00:00
Jonathan Miller aa7fc45a67 feat: version_check.php — validate version consistency across files
Platform: moko-platform CI / CI Summary (push) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Universal: Cascade Main → Dev / Cascade main → branches (push) Successful in 4s
Generic: Repo Health / Release configuration (push) Successful in 5s
Generic: Repo Health / Scripts governance (push) Successful in 5s
Generic: Repo Health / Repository health (push) Successful in 16s
Platform: moko-platform CI / Gate 1: Code Quality (push) Successful in 55s
Platform: moko-platform CI / Gate 5: Template Integrity (push) Failing after 7s
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Successful in 52s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Successful in 52s
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Successful in 54s
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Failing after 54s
Platform: moko-platform CI / Gate 4: Governance (push) Successful in 53s
Checks README.md VERSION header and all manifest XML <version> tags.
Flags mismatches, reports highest version, and optionally fixes them.

Usage:
  php version_check.php --path /repo           # report only
  php version_check.php --path /repo --strict  # exit 1 on mismatch
  php version_check.php --path /repo --fix     # fix to highest version

Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-25 22:07:04 -05:00
jmiller 03fe66238f chore: sync .mokogitea/workflows/pre-release.yml from moko-platform [skip ci] 2026-05-26 03:05:28 +00:00
gitea-actions[bot] a5ae616a94 fix(ci): auto-release preserves all update channels [skip ci] 2026-05-25 21:59:33 -05:00
jmiller ff7924de7d Merge pull request 'chore: cascade main → dev (1690e29) [skip ci]' (#120) from main into dev
chore: cascade main → dev [skip ci]
2026-05-26 02:56:24 +00:00
24 changed files with 3080 additions and 630 deletions
+67 -162
View File
@@ -26,7 +26,8 @@
name: "Universal: Build & Release"
on:
push:
pull_request:
types: [closed]
branches:
- main
paths:
@@ -47,7 +48,8 @@ jobs:
release:
name: Build & Release Pipeline
runs-on: release
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
if: >-
github.event.pull_request.merged == true || github.event_name == 'workflow_dispatch'
steps:
- name: Checkout repository
@@ -94,9 +96,9 @@ jobs:
fi
MAJOR=$(echo "$VERSION" | cut -d. -f1)
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
echo "release_tag=v${MAJOR}" >> "$GITHUB_OUTPUT"
echo "release_tag=stable" >> "$GITHUB_OUTPUT"
echo "skip=false" >> "$GITHUB_OUTPUT"
echo "branch=version/${MAJOR}" >> "$GITHUB_OUTPUT"
echo "branch=main" >> "$GITHUB_OUTPUT"
- name: "Step 1b: Bump version"
id: bump
@@ -261,6 +263,7 @@ jobs:
run: |
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
php /tmp/moko-platform-api/cli/badge_update.php --path . --version "${VERSION}" 2>/dev/null || true
php /tmp/moko-platform-api/cli/version_check.php --path . --fix 2>/dev/null || true
- name: "Step 5: Write update stream"
if: >-
@@ -268,6 +271,15 @@ jobs:
steps.platform.outputs.platform == 'joomla'
run: |
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
# Fetch latest updates.xml from main so preserve logic has all channels
GA_TOKEN="${{ secrets.GA_TOKEN }}"
API="${GITEA_URL}/api/v1/repos/${{ github.repository }}"
curl -sf -H "Authorization: token ${GA_TOKEN}" \
"${API}/contents/updates.xml?ref=main" 2>/dev/null | \
python3 -c "import sys,json,base64; print(base64.b64decode(json.load(sys.stdin)['content']).decode())" \
> updates.xml 2>/dev/null || true
php /tmp/moko-platform-api/cli/updates_xml_build.php \
--path . --version "${VERSION}" --stability stable \
--gitea-url "${GITEA_URL}" --org "${GITEA_ORG}" --repo "${GITEA_REPO}" \
@@ -295,9 +307,7 @@ jobs:
# -- STEP 6: Create tag ---------------------------------------------------
- name: "Step 6: Create git tag"
if: >-
steps.version.outputs.skip != 'true' &&
steps.check.outputs.tag_exists != 'true' &&
steps.version.outputs.is_minor == 'true'
steps.version.outputs.skip != 'true'
run: |
RELEASE_TAG="${{ steps.version.outputs.release_tag }}"
# Only create the major release tag if it doesn't exist yet
@@ -337,6 +347,8 @@ jobs:
[ -z "$NOTES" ] && NOTES="Release ${VERSION}"
# Build release name: "Pretty Name VERSION (type_element-VERSION)"
# Strip existing type prefix to prevent duplication
EXT_ELEMENT=$(echo "$EXT_ELEMENT" | sed -E 's/^(pkg_|com_|mod_|plg_[a-z]+_|tpl_|lib_)//')
TYPE_PREFIX=""
case "${EXT_TYPE}" in
plugin) TYPE_PREFIX="plg_${EXT_FOLDER}_" ;;
@@ -407,6 +419,13 @@ jobs:
# ZIP name: type_folder_element-VERSION (e.g. plg_system_mokojgdpc-01.01.00.zip)
EXT_TYPE=$(sed -n 's/.*<extension[^>]*type="\([^"]*\)".*/\1/p' "$MANIFEST" | head -1)
EXT_FOLDER=$(sed -n 's/.*<extension[^>]*group="\([^"]*\)".*/\1/p' "$MANIFEST" | head -1)
# For packages, prefer <packagename> over filename-derived element
if [ "$EXT_TYPE" = "package" ]; then
PKG_NAME=$(sed -n 's/.*<packagename>\([^<]*\)<\/packagename>.*/\1/p' "$MANIFEST" 2>/dev/null | head -1)
[ -n "$PKG_NAME" ] && EXT_ELEMENT="$PKG_NAME"
fi
# Strip existing type prefix to prevent duplication (e.g. pkg_mokowaas → mokowaas)
EXT_ELEMENT=$(echo "$EXT_ELEMENT" | sed -E 's/^(pkg_|com_|mod_|plg_[a-z]+_|tpl_|lib_)//')
TYPE_PREFIX=""
case "${EXT_TYPE}" in
plugin) TYPE_PREFIX="plg_${EXT_FOLDER}_" ;;
@@ -442,110 +461,35 @@ jobs:
SHA256_ZIP=$(sha256sum "/tmp/${ZIP_NAME}" | cut -d' ' -f1)
SHA256_TAR=$(sha256sum "/tmp/${TAR_NAME}" | cut -d' ' -f1)
# -- Delete existing assets with same name before uploading ------
# -- Get existing assets for cleanup --------------------------------
ASSETS=$(curl -sf -H "Authorization: token ${{ secrets.GA_TOKEN }}" \
"${API_BASE}/releases/${RELEASE_ID}/assets" 2>/dev/null || echo "[]")
for ASSET_NAME in "$ZIP_NAME" "$TAR_NAME"; do
# -- Create per-file .sha256 checksum files -------------------------
echo "${SHA256_ZIP} ${ZIP_NAME}" > "/tmp/${ZIP_NAME}.sha256"
echo "${SHA256_TAR} ${TAR_NAME}" > "/tmp/${TAR_NAME}.sha256"
# -- Upload packages + checksums to release tag --------------------
for ASSET in "${ZIP_NAME}" "${TAR_NAME}" "${ZIP_NAME}.sha256" "${TAR_NAME}.sha256"; do
[ ! -f "/tmp/${ASSET}" ] && continue
# Delete existing asset with same name
ASSET_ID=$(echo "$ASSETS" | python3 -c "
import sys,json
assets = json.load(sys.stdin)
for a in assets:
if a['name'] == '${ASSET_NAME}':
if a['name'] == '${ASSET}':
print(a['id']); break
" 2>/dev/null || true)
if [ -n "$ASSET_ID" ]; then
curl -sf -X DELETE -H "Authorization: token ${{ secrets.GA_TOKEN }}" \
"${API_BASE}/releases/${RELEASE_ID}/assets/${ASSET_ID}" 2>/dev/null || true
fi
[ -n "$ASSET_ID" ] && curl -sf -X DELETE -H "Authorization: token ${{ secrets.GA_TOKEN }}" \
"${API_BASE}/releases/${RELEASE_ID}/assets/${ASSET_ID}" 2>/dev/null || true
# Upload
curl -sf -X POST -H "Authorization: token ${{ secrets.GA_TOKEN }}" \
-H "Content-Type: application/octet-stream" \
--data-binary @"/tmp/${ASSET}" \
"${API_BASE}/releases/${RELEASE_ID}/assets?name=${ASSET}" > /dev/null 2>&1 || true
done
# -- Upload both to release tag ----------------------------------
curl -sf -X POST -H "Authorization: token ${{ secrets.GA_TOKEN }}" \
-H "Content-Type: application/octet-stream" \
--data-binary @"/tmp/${ZIP_NAME}" \
"${API_BASE}/releases/${RELEASE_ID}/assets?name=${ZIP_NAME}" > /dev/null 2>&1 || true
curl -sf -X POST -H "Authorization: token ${{ secrets.GA_TOKEN }}" \
-H "Content-Type: application/octet-stream" \
--data-binary @"/tmp/${TAR_NAME}" \
"${API_BASE}/releases/${RELEASE_ID}/assets?name=${TAR_NAME}" > /dev/null 2>&1 || true
# -- Update updates.xml with both download formats ---------------
if [ -f "updates.xml" ]; then
ZIP_URL="${GITEA_URL}/${GITEA_ORG}/${GITEA_REPO}/releases/download/${RELEASE_TAG}/${ZIP_NAME}"
TAR_URL="${GITEA_URL}/${GITEA_ORG}/${GITEA_REPO}/releases/download/${RELEASE_TAG}/${TAR_NAME}"
# Use Python to update only the stable entry's downloads + sha256
export PY_ZIP_URL="$ZIP_URL" PY_TAR_URL="$TAR_URL" PY_SHA="$SHA256_ZIP"
python3 << 'PYEOF'
import re, os
with open("updates.xml") as f:
content = f.read()
zip_url = os.environ["PY_ZIP_URL"]
tar_url = os.environ["PY_TAR_URL"]
sha = os.environ["PY_SHA"]
# Find the stable update block and replace its downloads + sha256
def replace_stable(m):
block = m.group(0)
# Replace downloads block
new_downloads = (
" <downloads>\n"
f" <downloadurl type=\"full\" format=\"zip\">{zip_url}</downloadurl>\n"
" </downloads>"
)
block = re.sub(r' <downloads>.*?</downloads>', new_downloads, block, flags=re.DOTALL)
# Add or replace sha256
if '<sha256>' in block:
block = re.sub(r' <sha256>.*?</sha256>', f' <sha256>{sha}</sha256>', block)
else:
block = block.replace('</downloads>', f'</downloads>\n <sha256>{sha}</sha256>')
return block
content = re.sub(
r' <update>.*?<tag>stable</tag>.*?</update>',
replace_stable,
content,
flags=re.DOTALL
)
with open("updates.xml", "w") as f:
f.write(content)
PYEOF
CURRENT_BRANCH="${{ github.ref_name }}"
git add updates.xml
git commit -m "chore(release): ZIP + tar.gz for ${VERSION} [skip ci]" \
--author="gitea-actions[bot] <gitea-actions[bot]@mokoconsulting.tech>" || true
git push || true
# Sync updates.xml to main via direct API (always runs — may be on version/XX branch)
GA_TOKEN="${{ secrets.GA_TOKEN }}"
API="${GITEA_URL:-https://git.mokoconsulting.tech}/api/v1/repos/${{ github.repository }}"
FILE_SHA=$(curl -sf -H "Authorization: token ${GA_TOKEN}" \
"${API}/contents/updates.xml?ref=main" | jq -r '.sha // empty')
if [ -n "$FILE_SHA" ]; then
CONTENT=$(base64 -w0 updates.xml)
curl -sf -X PUT -H "Authorization: token ${GA_TOKEN}" \
-H "Content-Type: application/json" \
"${API}/contents/updates.xml" \
-d "$(jq -n \
--arg content "$CONTENT" \
--arg sha "$FILE_SHA" \
--arg msg "chore: sync updates.xml ${VERSION} [skip ci]" \
--arg branch "main" \
'{content: $content, sha: $sha, message: $msg, branch: $branch}'
)" > /dev/null 2>&1 \
&& echo "updates.xml synced to main via API" \
|| echo "WARNING: failed to sync updates.xml to main"
else
echo "WARNING: could not get updates.xml SHA from main"
fi
fi
# updates.xml already handled by Step 5 (updates_xml_build.php with preserve logic)
echo "### Packages" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
@@ -556,72 +500,33 @@ jobs:
echo "| Release | \`${RELEASE_TAG}\` | |" >> $GITHUB_STEP_SUMMARY
echo "| Download | [${ZIP_NAME}](${GITEA_URL}/${GITEA_ORG}/${GITEA_REPO}/releases/download/${RELEASE_TAG}/${ZIP_NAME}) |" >> $GITHUB_STEP_SUMMARY
# -- STEP 8b: Update release description with changelog + SHA ----------------
- name: "Step 8b: Update release body with changelog and SHA"
# -- STEP 8b: Update release description with changelog ----------------------
- name: "Step 8b: Update release body"
if: steps.version.outputs.skip != 'true'
run: |
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
RELEASE_TAG="${{ steps.version.outputs.release_tag }}"
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
EXT_ELEMENT="${{ steps.updates.outputs.ext_element }}"
EXT_TYPE="${{ steps.updates.outputs.ext_type }}"
EXT_FOLDER="${{ steps.updates.outputs.ext_folder }}"
MOKO_CLI="/tmp/moko-platform-api/cli"
# Build TYPE_PREFIX to match Step 8's ZIP naming
TYPE_PREFIX=""
case "${EXT_TYPE}" in
plugin) TYPE_PREFIX="plg_${EXT_FOLDER}_" ;;
module) TYPE_PREFIX="mod_" ;;
component) TYPE_PREFIX="com_" ;;
template) TYPE_PREFIX="tpl_" ;;
library) TYPE_PREFIX="lib_" ;;
package) TYPE_PREFIX="pkg_" ;;
esac
ZIP_NAME="${TYPE_PREFIX}${EXT_ELEMENT}-${VERSION}.zip"
TAR_NAME="${TYPE_PREFIX}${EXT_ELEMENT}-${VERSION}.tar.gz"
# Get SHA from the built files
SHA256_ZIP=""
[ -f "/tmp/${ZIP_NAME}" ] && SHA256_ZIP=$(sha256sum "/tmp/${ZIP_NAME}" | cut -d' ' -f1)
SHA256_TAR=""
[ -f "/tmp/${TAR_NAME}" ] && SHA256_TAR=$(sha256sum "/tmp/${TAR_NAME}" | cut -d' ' -f1)
# Extract latest changelog entry (strip the ## header to avoid duplicate)
CHANGELOG=""
if [ -f "CHANGELOG.md" ]; then
CHANGELOG=$(sed -n "/^## \[*${VERSION}/,/^## \[*[0-9]/p" CHANGELOG.md | sed '$d' | sed '1d')
[ -z "$CHANGELOG" ] && CHANGELOG=$(sed -n '/^## /,/^## /p' CHANGELOG.md | sed '$d' | sed '1d' | head -30)
fi
# Build release body (single header, no duplicate from changelog)
BODY="## ${VERSION} ($(date +%Y-%m-%d))\n\n"
if [ -n "$CHANGELOG" ]; then
BODY="${BODY}${CHANGELOG}\n\n"
fi
BODY="${BODY}---\n\n### Checksums\n\n"
BODY="${BODY}| File | SHA-256 |\n|------|--------|\n"
[ -n "$SHA256_ZIP" ] && BODY="${BODY}| \`${ZIP_NAME}\` | \`${SHA256_ZIP}\` |\n"
[ -n "$SHA256_TAR" ] && BODY="${BODY}| \`${TAR_NAME}\` | \`${SHA256_TAR}\` |\n"
# Get release ID and update body
RELEASE_ID=$(curl -sf -H "Authorization: token ${{ secrets.GA_TOKEN }}" \
"${API_BASE}/releases/tags/${RELEASE_TAG}" 2>/dev/null | \
python3 -c "import sys,json; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true)
if [ -n "$RELEASE_ID" ] && [ "$RELEASE_ID" != "None" ]; then
python3 -c "
import json, urllib.request
body = '''$(printf '%b' "$BODY")'''
data = json.dumps({'body': body}).encode()
req = urllib.request.Request(
'${API_BASE}/releases/${RELEASE_ID}',
data=data,
headers={'Authorization': 'token ${{ secrets.GA_TOKEN }}', 'Content-Type': 'application/json'},
method='PATCH'
)
urllib.request.urlopen(req)
" 2>/dev/null && echo "Release body updated with changelog + SHA" >> $GITHUB_STEP_SUMMARY
fi
php ${MOKO_CLI}/release_body_update.php \
--path . --version "${VERSION}" --tag "${RELEASE_TAG}" \
--token "${{ secrets.GA_TOKEN }}" \
--gitea-url "${GITEA_URL}" --org "${GITEA_ORG}" --repo "${GITEA_REPO}" \
2>/dev/null || {
# Fallback: simple body update if CLI not available
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
RELEASE_ID=$(curl -sf -H "Authorization: token ${{ secrets.GA_TOKEN }}" \
"${API_BASE}/releases/tags/${RELEASE_TAG}" 2>/dev/null | \
python3 -c "import sys,json; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true)
if [ -n "$RELEASE_ID" ] && [ "$RELEASE_ID" != "None" ]; then
BODY="## ${VERSION} ($(date +%Y-%m-%d))\n\nChecksum files attached as \`*.sha256\` assets."
curl -sf -X PATCH -H "Authorization: token ${{ secrets.GA_TOKEN }}" \
-H "Content-Type: application/json" \
"${API_BASE}/releases/${RELEASE_ID}" \
-d "{\"body\":\"${BODY}\"}" > /dev/null 2>&1
fi
}
echo "Release body updated" >> $GITHUB_STEP_SUMMARY
# -- STEP 9: Mirror to GitHub (stable only) --------------------------------
- name: "Step 9: Mirror release to GitHub"
+13 -10
View File
@@ -124,16 +124,16 @@ jobs:
echo "### PHPCS" >> $GITHUB_STEP_SUMMARY
echo "PSR-12 compliance: passed" >> $GITHUB_STEP_SUMMARY
- name: "PHPStan (Level 2)"
continue-on-error: true
- name: "PHPStan (Level 6)"
run: |
vendor/bin/phpstan analyse -c phpstan.neon --no-progress --error-format=github 2>&1 || {
echo "::warning::PHPStan found type errors (advisory)"
vendor/bin/phpstan analyse -c phpstan.neon --no-progress --memory-limit=512M --error-format=github 2>&1 || {
echo "::error::PHPStan found type errors"
echo "### PHPStan" >> $GITHUB_STEP_SUMMARY
echo "Static analysis errors detected. Run \`composer phpstan\` locally." >> $GITHUB_STEP_SUMMARY
exit 1
}
echo "### PHPStan" >> $GITHUB_STEP_SUMMARY
echo "Static analysis: advisory (level 0)" >> $GITHUB_STEP_SUMMARY
echo "Static analysis (level 6): passed" >> $GITHUB_STEP_SUMMARY
- name: "Psalm"
continue-on-error: true
@@ -177,11 +177,14 @@ jobs:
- name: "PHPUnit (PHP ${{ matrix.php }})"
run: |
vendor/bin/phpunit --testdox 2>&1
{
echo "### PHPUnit (PHP ${{ matrix.php }})"
echo "All tests passed."
} >> $GITHUB_STEP_SUMMARY
vendor/bin/phpunit --testdox 2>&1 || {
echo "::error::PHPUnit tests failed"
echo "### PHPUnit (PHP ${{ matrix.php }})" >> $GITHUB_STEP_SUMMARY
echo "Tests failed. Run \`vendor/bin/phpunit --testdox\` locally." >> $GITHUB_STEP_SUMMARY
exit 1
}
echo "### PHPUnit (PHP ${{ matrix.php }})" >> $GITHUB_STEP_SUMMARY
echo "All tests passed." >> $GITHUB_STEP_SUMMARY
# ═══════════════════════════════════════════════════════════════════════
# Gate 3 — Self-Health (Dogfood)
+375 -375
View File
@@ -1,375 +1,375 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.Release
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
# PATH: /templates/workflows/universal/pre-release.yml.template
# VERSION: 05.01.00
# BRIEF: Manual pre-release -- builds dev/alpha/beta/rc packages from any branch
name: "Universal: Pre-Release"
on:
workflow_dispatch:
inputs:
stability:
description: 'Pre-release channel'
required: true
type: choice
options:
- development
- alpha
- beta
- release-candidate
permissions:
contents: write
env:
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
GITEA_ORG: ${{ vars.GITEA_ORG || github.repository_owner }}
GITEA_REPO: ${{ vars.GITEA_REPO || github.event.repository.name }}
jobs:
build:
name: "Build Pre-Release (${{ inputs.stability }})"
runs-on: release
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GA_TOKEN }}
- name: Setup tools
run: |
# Update moko-platform CLI tools if available; install PHP if missing
if command -v moko-platform-update &> /dev/null; then
moko-platform-update
elif [ -d "/opt/moko-platform" ]; then
cd /opt/moko-platform && git pull origin main --quiet 2>/dev/null || true
else
if ! command -v php &> /dev/null; then
sudo apt-get update -qq
sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl >/dev/null 2>&1
fi
git clone --depth 1 --branch main --quiet \
"https://x-access-token:${{ secrets.GA_TOKEN }}@git.mokoconsulting.tech/MokoConsulting/moko-platform.git" \
/tmp/moko-platform-api
fi
# Set MOKO_CLI to whichever path exists
if [ -d "/opt/moko-platform/cli" ]; then
echo "MOKO_CLI=/opt/moko-platform/cli" >> "$GITHUB_ENV"
else
echo "MOKO_CLI=/tmp/moko-platform-api/cli" >> "$GITHUB_ENV"
fi
- name: Detect platform
id: platform
run: |
PLATFORM=$(sed -n 's/.*<platform>\([^<]*\)<\/platform>.*/\1/p' .mokogitea/manifest.xml 2>/dev/null | head -1 | tr -d '[:space:]')
[ -z "$PLATFORM" ] && PLATFORM="generic"
echo "platform=$PLATFORM" >> "$GITHUB_OUTPUT"
MANIFEST=$(find ./src -maxdepth 1 -name "pkg_*.xml" -exec grep -l '<extension' {} \; 2>/dev/null | head -1)
[ -z "$MANIFEST" ] && MANIFEST=$(find . -maxdepth 3 -name "*.xml" ! -path "./.git/*" ! -path "*/packages/*" -exec grep -l '<extension' {} \; 2>/dev/null | head -1)
[ -z "$MANIFEST" ] && MANIFEST=$(find . -maxdepth 3 -name "*.xml" ! -path "./.git/*" -exec grep -l '<extension' {} \; 2>/dev/null | head -1)
MOD_FILE=$(find . -maxdepth 4 -name "mod*.class.php" ! -path "./.git/*" -exec grep -l 'extends DolibarrModules' {} \; 2>/dev/null | head -1)
echo "manifest=${MANIFEST}" >> "$GITHUB_OUTPUT"
echo "mod_file=${MOD_FILE}" >> "$GITHUB_OUTPUT"
- name: Resolve metadata and bump version
id: meta
run: |
STABILITY="${{ inputs.stability }}"
case "$STABILITY" in
development) SUFFIX="-dev"; TAG="development" ;;
alpha) SUFFIX="-alpha"; TAG="alpha" ;;
beta) SUFFIX="-beta"; TAG="beta" ;;
release-candidate) SUFFIX="-rc"; TAG="release-candidate" ;;
esac
# Patch bump via CLI tool
php ${MOKO_CLI}/version_bump.php --path .
VERSION=$(php ${MOKO_CLI}/version_read.php --path . 2>/dev/null)
[ -z "$VERSION" ] && VERSION="00.00.01"
TODAY=$(date +%Y-%m-%d)
# Update platform-specific manifest
PLATFORM="${{ steps.platform.outputs.platform }}"
MANIFEST="${{ steps.platform.outputs.manifest }}"
MOD_FILE="${{ steps.platform.outputs.mod_file }}"
php ${MOKO_CLI}/version_set_platform.php \
--path . --version "$VERSION" --branch "${{ github.ref_name }}" 2>/dev/null || true
# Commit version bump
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
git config --local user.name "gitea-actions[bot]"
git remote set-url origin "https://jmiller:${{ secrets.GA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
git add -A
git diff --cached --quiet || {
git commit -m "chore(version): pre-release bump to ${VERSION} [skip ci]"
git push origin HEAD 2>&1
}
# Auto-detect element (platform-aware)
EXT_ELEMENT=""
case "$PLATFORM" in
joomla)
if [ -n "$MANIFEST" ]; then
EXT_ELEMENT=$(sed -n 's/.*<element>\([^<]*\)<\/element>.*/\1/p' "$MANIFEST" 2>/dev/null | head -1)
if [ -z "$EXT_ELEMENT" ]; then
EXT_ELEMENT=$(basename "$MANIFEST" .xml | tr '[:upper:]' '[:lower:]')
case "$EXT_ELEMENT" in
templatedetails|manifest) EXT_ELEMENT=$(echo "${GITEA_REPO}" | tr '[:upper:]' '[:lower:]' | tr -d ' -') ;;
esac
fi
else
EXT_ELEMENT=$(echo "${GITEA_REPO}" | tr '[:upper:]' '[:lower:]' | tr -d ' -')
fi
;;
dolibarr)
if [ -n "$MOD_FILE" ]; then
MOD_BASENAME=$(basename "$MOD_FILE" .class.php)
EXT_ELEMENT=$(echo "$MOD_BASENAME" | sed 's/^mod//' | tr '[:upper:]' '[:lower:]')
else
EXT_ELEMENT=$(echo "${GITEA_REPO}" | tr '[:upper:]' '[:lower:]' | tr -d ' -')
fi
;;
*)
EXT_ELEMENT=$(echo "${GITEA_REPO}" | tr '[:upper:]' '[:lower:]' | tr -d ' -')
;;
esac
ZIP_NAME="${EXT_ELEMENT}-${VERSION}${SUFFIX}.zip"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
echo "stability=${STABILITY}" >> "$GITHUB_OUTPUT"
echo "suffix=${SUFFIX}" >> "$GITHUB_OUTPUT"
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
echo "zip_name=${ZIP_NAME}" >> "$GITHUB_OUTPUT"
echo "ext_element=${EXT_ELEMENT}" >> "$GITHUB_OUTPUT"
echo "manifest=${MANIFEST}" >> "$GITHUB_OUTPUT"
echo "=== Pre-Release: ${EXT_ELEMENT} ${VERSION}${SUFFIX} ==="
- name: Build package
run: |
SOURCE_DIR="src"
[ ! -d "$SOURCE_DIR" ] && SOURCE_DIR="htdocs"
if [ ! -d "$SOURCE_DIR" ]; then
echo "::error::No src/ or htdocs/ directory"
exit 1
fi
MANIFEST="${{ steps.meta.outputs.manifest }}"
EXT_TYPE=""
if [ -n "$MANIFEST" ]; then
EXT_TYPE=$(sed -n 's/.*<extension[^>]*type="\([^"]*\)".*/\1/p' "$MANIFEST" | head -1)
fi
EXCLUDES="sftp-config* .ftpignore *.ppk *.pem *.key .env* *.local .build-trigger"
mkdir -p build/package
if [ "$EXT_TYPE" = "package" ] && [ -d "${SOURCE_DIR}/packages" ]; then
echo "=== Building Joomla PACKAGE (multi-extension) ==="
for ext_dir in "${SOURCE_DIR}"/packages/*/; do
[ ! -d "$ext_dir" ] && continue
EXT_NAME=$(basename "$ext_dir")
echo " Packaging sub-extension: ${EXT_NAME}"
cd "$ext_dir"
zip -r "../../build/package/${EXT_NAME}.zip" . -x $EXCLUDES
cd "$OLDPWD"
done
for f in "${SOURCE_DIR}"/*.xml "${SOURCE_DIR}"/*.php; do
[ -f "$f" ] && cp "$f" build/package/
done
else
echo "=== Building standard extension ==="
rsync -a \
--exclude='sftp-config*' \
--exclude='.ftpignore' \
--exclude='*.ppk' \
--exclude='*.pem' \
--exclude='*.key' \
--exclude='.env*' \
--exclude='*.local' \
--exclude='.build-trigger' \
"${SOURCE_DIR}/" build/package/
fi
- name: Create ZIP
id: zip
run: |
ZIP_NAME="${{ steps.meta.outputs.zip_name }}"
cd build/package
zip -r "../${ZIP_NAME}" .
cd ..
SHA256=$(sha256sum "${ZIP_NAME}" | cut -d' ' -f1)
echo "sha256=${SHA256}" >> "$GITHUB_OUTPUT"
echo "ZIP: ${ZIP_NAME} (SHA: ${SHA256:0:16}...)"
- name: Create or replace Gitea release
id: release
run: |
TAG="${{ steps.meta.outputs.tag }}"
VERSION="${{ steps.meta.outputs.version }}"
STABILITY="${{ steps.meta.outputs.stability }}"
SHA256="${{ steps.zip.outputs.sha256 }}"
ZIP_NAME="${{ steps.meta.outputs.zip_name }}"
EXT_ELEMENT="${{ steps.meta.outputs.ext_element }}"
TOKEN="${{ secrets.GA_TOKEN }}"
API="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
BRANCH=$(git branch --show-current)
BODY="## ${VERSION} ($(date +%Y-%m-%d))
**Channel:** ${STABILITY}
**SHA-256:** \`${SHA256}\`"
# Delete existing release
EXISTING_ID=$(curl -sS -H "Authorization: token ${TOKEN}" \
"${API}/releases/tags/${TAG}" | jq -r '.id // empty' 2>/dev/null)
if [ -n "$EXISTING_ID" ]; then
curl -sS -X DELETE -H "Authorization: token ${TOKEN}" \
"${API}/releases/${EXISTING_ID}" 2>/dev/null || true
curl -sS -X DELETE -H "Authorization: token ${TOKEN}" \
"${API}/tags/${TAG}" 2>/dev/null || true
fi
# Create release
RELEASE_ID=$(curl -sS -X POST -H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
"${API}/releases" \
-d "$(jq -n \
--arg tag "$TAG" \
--arg target "$BRANCH" \
--arg name "${EXT_ELEMENT} ${VERSION} (${STABILITY})" \
--arg body "$BODY" \
'{tag_name: $tag, target_commitish: $target, name: $name, body: $body, prerelease: true}'
)" | jq -r '.id')
echo "release_id=${RELEASE_ID}" >> "$GITHUB_OUTPUT"
# Upload ZIP
curl -sS -X POST -H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/octet-stream" \
"${API}/releases/${RELEASE_ID}/assets?name=${ZIP_NAME}" \
--data-binary "@build/${ZIP_NAME}"
echo "Released: ${EXT_ELEMENT} ${VERSION} (${STABILITY})"
- name: Update updates.xml
if: steps.platform.outputs.platform == 'joomla'
run: |
STABILITY="${{ steps.meta.outputs.stability }}"
VERSION="${{ steps.meta.outputs.version }}"
SHA256="${{ steps.zip.outputs.sha256 }}"
ZIP_NAME="${{ steps.meta.outputs.zip_name }}"
TAG="${{ steps.meta.outputs.tag }}"
if [ ! -f "updates.xml" ]; then
echo "No updates.xml -- skipping"
exit 0
fi
# Map stability to XML tag name
case "$STABILITY" in
development) XML_TAG="development" ;;
alpha) XML_TAG="alpha" ;;
beta) XML_TAG="beta" ;;
release-candidate) XML_TAG="rc" ;;
*) XML_TAG="$STABILITY" ;;
esac
DOWNLOAD_URL="${GITEA_URL}/${GITEA_ORG}/${GITEA_REPO}/releases/download/${TAG}/${ZIP_NAME}"
# Use PHP to update the channel in updates.xml
php -r '
$xml_tag = $argv[1];
$version = $argv[2];
$sha256 = $argv[3];
$url = $argv[4];
$date = date("Y-m-d");
$content = file_get_contents("updates.xml");
$pattern = "/(<update>(?:(?!<\/update>).)*?<tag>" . preg_quote($xml_tag) . "<\/tag>.*?<\/update>)/s";
$content = preg_replace_callback($pattern, function($m) use ($version, $sha256, $url, $date) {
$block = $m[0];
$block = preg_replace("/<version>[^<]*<\/version>/", "<version>{$version}</version>", $block);
if (strpos($block, "<sha256>") !== false) {
$block = preg_replace("/<sha256>[^<]*<\/sha256>/", "<sha256>{$sha256}</sha256>", $block);
} else {
$block = str_replace("</downloads>", "</downloads>\n <sha256>{$sha256}</sha256>", $block);
}
$block = preg_replace("/(<downloadurl[^>]*>)[^<]*(<\/downloadurl>)/", "\${1}{$url}\${2}", $block);
return $block;
}, $content);
file_put_contents("updates.xml", $content);
echo "Updated {$xml_tag} channel: version={$version}\n";
' "$XML_TAG" "$VERSION" "$SHA256" "$DOWNLOAD_URL"
# Commit and push
if ! git diff --quiet updates.xml 2>/dev/null; then
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
git config --local user.name "gitea-actions[bot]"
git add updates.xml
git commit -m "chore: update ${STABILITY} channel ${VERSION} [skip ci]"
git push origin HEAD 2>&1 || echo "WARNING: push failed"
fi
- name: "Sync updates.xml to all branches"
if: steps.platform.outputs.platform == 'joomla'
run: |
CURRENT_BRANCH="${{ github.ref_name }}"
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
git config --local user.name "gitea-actions[bot]"
for BRANCH in main dev; do
[ "$BRANCH" = "$CURRENT_BRANCH" ] && continue
echo "Syncing updates.xml -> ${BRANCH}"
git fetch origin "${BRANCH}" 2>/dev/null || continue
git checkout "origin/${BRANCH}" -- . 2>/dev/null || continue
git checkout "${CURRENT_BRANCH}" -- updates.xml
if ! git diff --quiet updates.xml 2>/dev/null; then
git add updates.xml
git commit -m "chore: sync updates.xml from ${CURRENT_BRANCH} [skip ci]"
git push origin HEAD:refs/heads/${BRANCH} 2>&1 || echo "WARNING: push to ${BRANCH} failed"
fi
git checkout "${CURRENT_BRANCH}" 2>/dev/null
done
- name: "Delete lesser pre-release channels (cascade)"
continue-on-error: true
run: |
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
TOKEN="${{ secrets.GA_TOKEN }}"
php ${MOKO_CLI}/release_cascade.php \
--stability "${{ steps.meta.outputs.stability }}" \
--token "${TOKEN}" \
--api-base "${API_BASE}"
- name: Summary
if: always()
run: |
VERSION="${{ steps.meta.outputs.version }}"
STABILITY="${{ steps.meta.outputs.stability }}"
ZIP_NAME="${{ steps.meta.outputs.zip_name }}"
SHA256="${{ steps.zip.outputs.sha256 }}"
echo "## Pre-Release Complete" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
echo "|-------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| Version | \`${VERSION}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Channel | ${STABILITY} |" >> $GITHUB_STEP_SUMMARY
echo "| Package | \`${ZIP_NAME}\` |" >> $GITHUB_STEP_SUMMARY
echo "| SHA-256 | \`${SHA256:-n/a}\` |" >> $GITHUB_STEP_SUMMARY
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.Release
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
# PATH: /templates/workflows/universal/pre-release.yml.template
# VERSION: 05.01.00
# BRIEF: Manual pre-release -- builds dev/alpha/beta/rc packages from any branch
name: "Universal: Pre-Release"
on:
workflow_dispatch:
inputs:
stability:
description: 'Pre-release channel'
required: true
type: choice
options:
- development
- alpha
- beta
- release-candidate
permissions:
contents: write
env:
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
GITEA_ORG: ${{ vars.GITEA_ORG || github.repository_owner }}
GITEA_REPO: ${{ vars.GITEA_REPO || github.event.repository.name }}
jobs:
build:
name: "Build Pre-Release (${{ inputs.stability }})"
runs-on: release
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GA_TOKEN }}
- name: Setup tools
run: |
# Update moko-platform CLI tools if available; install PHP if missing
if command -v moko-platform-update &> /dev/null; then
moko-platform-update
elif [ -d "/opt/moko-platform" ]; then
cd /opt/moko-platform && git pull origin main --quiet 2>/dev/null || true
else
if ! command -v php &> /dev/null; then
sudo apt-get update -qq
sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl >/dev/null 2>&1
fi
git clone --depth 1 --branch main --quiet \
"https://x-access-token:${{ secrets.GA_TOKEN }}@git.mokoconsulting.tech/MokoConsulting/moko-platform.git" \
/tmp/moko-platform-api
fi
# Set MOKO_CLI to whichever path exists
if [ -d "/opt/moko-platform/cli" ]; then
echo "MOKO_CLI=/opt/moko-platform/cli" >> "$GITHUB_ENV"
else
echo "MOKO_CLI=/tmp/moko-platform-api/cli" >> "$GITHUB_ENV"
fi
- name: Detect platform
id: platform
run: |
PLATFORM=$(sed -n 's/.*<platform>\([^<]*\)<\/platform>.*/\1/p' .mokogitea/manifest.xml 2>/dev/null | head -1 | tr -d '[:space:]')
[ -z "$PLATFORM" ] && PLATFORM="generic"
echo "platform=$PLATFORM" >> "$GITHUB_OUTPUT"
MANIFEST=$(find ./src -maxdepth 1 -name "pkg_*.xml" -exec grep -l '<extension' {} \; 2>/dev/null | head -1)
[ -z "$MANIFEST" ] && MANIFEST=$(find . -maxdepth 3 -name "*.xml" ! -path "./.git/*" ! -path "*/packages/*" -exec grep -l '<extension' {} \; 2>/dev/null | head -1)
[ -z "$MANIFEST" ] && MANIFEST=$(find . -maxdepth 3 -name "*.xml" ! -path "./.git/*" -exec grep -l '<extension' {} \; 2>/dev/null | head -1)
MOD_FILE=$(find . -maxdepth 4 -name "mod*.class.php" ! -path "./.git/*" -exec grep -l 'extends DolibarrModules' {} \; 2>/dev/null | head -1)
echo "manifest=${MANIFEST}" >> "$GITHUB_OUTPUT"
echo "mod_file=${MOD_FILE}" >> "$GITHUB_OUTPUT"
- name: Resolve metadata and bump version
id: meta
run: |
STABILITY="${{ inputs.stability }}"
case "$STABILITY" in
development) SUFFIX="-dev"; TAG="development" ;;
alpha) SUFFIX="-alpha"; TAG="alpha" ;;
beta) SUFFIX="-beta"; TAG="beta" ;;
release-candidate) SUFFIX="-rc"; TAG="release-candidate" ;;
esac
# Patch bump via CLI tool
php ${MOKO_CLI}/version_bump.php --path .
VERSION=$(php ${MOKO_CLI}/version_read.php --path . 2>/dev/null)
[ -z "$VERSION" ] && VERSION="00.00.01"
TODAY=$(date +%Y-%m-%d)
# Update platform-specific manifest
PLATFORM="${{ steps.platform.outputs.platform }}"
MANIFEST="${{ steps.platform.outputs.manifest }}"
MOD_FILE="${{ steps.platform.outputs.mod_file }}"
php ${MOKO_CLI}/version_set_platform.php \
--path . --version "$VERSION" --branch "${{ github.ref_name }}" 2>/dev/null || true
# Commit version bump
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
git config --local user.name "gitea-actions[bot]"
git remote set-url origin "https://jmiller:${{ secrets.GA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
git add -A
git diff --cached --quiet || {
git commit -m "chore(version): pre-release bump to ${VERSION} [skip ci]"
git push origin HEAD 2>&1
}
# Auto-detect element (platform-aware)
EXT_ELEMENT=""
case "$PLATFORM" in
joomla)
if [ -n "$MANIFEST" ]; then
EXT_ELEMENT=$(sed -n 's/.*<element>\([^<]*\)<\/element>.*/\1/p' "$MANIFEST" 2>/dev/null | head -1)
if [ -z "$EXT_ELEMENT" ]; then
EXT_ELEMENT=$(basename "$MANIFEST" .xml | tr '[:upper:]' '[:lower:]')
case "$EXT_ELEMENT" in
templatedetails|manifest) EXT_ELEMENT=$(echo "${GITEA_REPO}" | tr '[:upper:]' '[:lower:]' | tr -d ' -') ;;
esac
fi
else
EXT_ELEMENT=$(echo "${GITEA_REPO}" | tr '[:upper:]' '[:lower:]' | tr -d ' -')
fi
;;
dolibarr)
if [ -n "$MOD_FILE" ]; then
MOD_BASENAME=$(basename "$MOD_FILE" .class.php)
EXT_ELEMENT=$(echo "$MOD_BASENAME" | sed 's/^mod//' | tr '[:upper:]' '[:lower:]')
else
EXT_ELEMENT=$(echo "${GITEA_REPO}" | tr '[:upper:]' '[:lower:]' | tr -d ' -')
fi
;;
*)
EXT_ELEMENT=$(echo "${GITEA_REPO}" | tr '[:upper:]' '[:lower:]' | tr -d ' -')
;;
esac
ZIP_NAME="${EXT_ELEMENT}-${VERSION}${SUFFIX}.zip"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
echo "stability=${STABILITY}" >> "$GITHUB_OUTPUT"
echo "suffix=${SUFFIX}" >> "$GITHUB_OUTPUT"
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
echo "zip_name=${ZIP_NAME}" >> "$GITHUB_OUTPUT"
echo "ext_element=${EXT_ELEMENT}" >> "$GITHUB_OUTPUT"
echo "manifest=${MANIFEST}" >> "$GITHUB_OUTPUT"
echo "=== Pre-Release: ${EXT_ELEMENT} ${VERSION}${SUFFIX} ==="
- name: Build package
run: |
SOURCE_DIR="src"
[ ! -d "$SOURCE_DIR" ] && SOURCE_DIR="htdocs"
if [ ! -d "$SOURCE_DIR" ]; then
echo "::error::No src/ or htdocs/ directory"
exit 1
fi
MANIFEST="${{ steps.meta.outputs.manifest }}"
EXT_TYPE=""
if [ -n "$MANIFEST" ]; then
EXT_TYPE=$(sed -n 's/.*<extension[^>]*type="\([^"]*\)".*/\1/p' "$MANIFEST" | head -1)
fi
EXCLUDES="sftp-config* .ftpignore *.ppk *.pem *.key .env* *.local .build-trigger"
mkdir -p build/package
if [ "$EXT_TYPE" = "package" ] && [ -d "${SOURCE_DIR}/packages" ]; then
echo "=== Building Joomla PACKAGE (multi-extension) ==="
for ext_dir in "${SOURCE_DIR}"/packages/*/; do
[ ! -d "$ext_dir" ] && continue
EXT_NAME=$(basename "$ext_dir")
echo " Packaging sub-extension: ${EXT_NAME}"
cd "$ext_dir"
zip -r "../../build/package/${EXT_NAME}.zip" . -x $EXCLUDES
cd "$OLDPWD"
done
for f in "${SOURCE_DIR}"/*.xml "${SOURCE_DIR}"/*.php; do
[ -f "$f" ] && cp "$f" build/package/
done
else
echo "=== Building standard extension ==="
rsync -a \
--exclude='sftp-config*' \
--exclude='.ftpignore' \
--exclude='*.ppk' \
--exclude='*.pem' \
--exclude='*.key' \
--exclude='.env*' \
--exclude='*.local' \
--exclude='.build-trigger' \
"${SOURCE_DIR}/" build/package/
fi
- name: Create ZIP
id: zip
run: |
ZIP_NAME="${{ steps.meta.outputs.zip_name }}"
cd build/package
zip -r "../${ZIP_NAME}" .
cd ..
SHA256=$(sha256sum "${ZIP_NAME}" | cut -d' ' -f1)
echo "sha256=${SHA256}" >> "$GITHUB_OUTPUT"
echo "ZIP: ${ZIP_NAME} (SHA: ${SHA256:0:16}...)"
- name: Create or replace Gitea release
id: release
run: |
TAG="${{ steps.meta.outputs.tag }}"
VERSION="${{ steps.meta.outputs.version }}"
STABILITY="${{ steps.meta.outputs.stability }}"
SHA256="${{ steps.zip.outputs.sha256 }}"
ZIP_NAME="${{ steps.meta.outputs.zip_name }}"
EXT_ELEMENT="${{ steps.meta.outputs.ext_element }}"
TOKEN="${{ secrets.GA_TOKEN }}"
API="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
BRANCH=$(git branch --show-current)
BODY="## ${VERSION} ($(date +%Y-%m-%d))
**Channel:** ${STABILITY}
**SHA-256:** \`${SHA256}\`"
# Delete existing release
EXISTING_ID=$(curl -sS -H "Authorization: token ${TOKEN}" \
"${API}/releases/tags/${TAG}" | jq -r '.id // empty' 2>/dev/null)
if [ -n "$EXISTING_ID" ]; then
curl -sS -X DELETE -H "Authorization: token ${TOKEN}" \
"${API}/releases/${EXISTING_ID}" 2>/dev/null || true
curl -sS -X DELETE -H "Authorization: token ${TOKEN}" \
"${API}/tags/${TAG}" 2>/dev/null || true
fi
# Create release
RELEASE_ID=$(curl -sS -X POST -H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
"${API}/releases" \
-d "$(jq -n \
--arg tag "$TAG" \
--arg target "$BRANCH" \
--arg name "${EXT_ELEMENT} ${VERSION} (${STABILITY})" \
--arg body "$BODY" \
'{tag_name: $tag, target_commitish: $target, name: $name, body: $body, prerelease: true}'
)" | jq -r '.id')
echo "release_id=${RELEASE_ID}" >> "$GITHUB_OUTPUT"
# Upload ZIP
curl -sS -X POST -H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/octet-stream" \
"${API}/releases/${RELEASE_ID}/assets?name=${ZIP_NAME}" \
--data-binary "@build/${ZIP_NAME}"
echo "Released: ${EXT_ELEMENT} ${VERSION} (${STABILITY})"
- name: Update updates.xml
if: steps.platform.outputs.platform == 'joomla'
run: |
STABILITY="${{ steps.meta.outputs.stability }}"
VERSION="${{ steps.meta.outputs.version }}"
SHA256="${{ steps.zip.outputs.sha256 }}"
ZIP_NAME="${{ steps.meta.outputs.zip_name }}"
TAG="${{ steps.meta.outputs.tag }}"
if [ ! -f "updates.xml" ]; then
echo "No updates.xml -- skipping"
exit 0
fi
# Map stability to XML tag name
case "$STABILITY" in
development) XML_TAG="development" ;;
alpha) XML_TAG="alpha" ;;
beta) XML_TAG="beta" ;;
release-candidate) XML_TAG="rc" ;;
*) XML_TAG="$STABILITY" ;;
esac
DOWNLOAD_URL="${GITEA_URL}/${GITEA_ORG}/${GITEA_REPO}/releases/download/${TAG}/${ZIP_NAME}"
# Use PHP to update the channel in updates.xml
php -r '
$xml_tag = $argv[1];
$version = $argv[2];
$sha256 = $argv[3];
$url = $argv[4];
$date = date("Y-m-d");
$content = file_get_contents("updates.xml");
$pattern = "/(<update>(?:(?!<\/update>).)*?<tag>" . preg_quote($xml_tag) . "<\/tag>.*?<\/update>)/s";
$content = preg_replace_callback($pattern, function($m) use ($version, $sha256, $url, $date) {
$block = $m[0];
$block = preg_replace("/<version>[^<]*<\/version>/", "<version>{$version}</version>", $block);
if (strpos($block, "<sha256>") !== false) {
$block = preg_replace("/<sha256>[^<]*<\/sha256>/", "<sha256>{$sha256}</sha256>", $block);
} else {
$block = str_replace("</downloads>", "</downloads>\n <sha256>{$sha256}</sha256>", $block);
}
$block = preg_replace("/(<downloadurl[^>]*>)[^<]*(<\/downloadurl>)/", "\${1}{$url}\${2}", $block);
return $block;
}, $content);
file_put_contents("updates.xml", $content);
echo "Updated {$xml_tag} channel: version={$version}\n";
' "$XML_TAG" "$VERSION" "$SHA256" "$DOWNLOAD_URL"
# Commit and push
if ! git diff --quiet updates.xml 2>/dev/null; then
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
git config --local user.name "gitea-actions[bot]"
git add updates.xml
git commit -m "chore: update ${STABILITY} channel ${VERSION} [skip ci]"
git push origin HEAD 2>&1 || echo "WARNING: push failed"
fi
- name: "Sync updates.xml to all branches"
if: steps.platform.outputs.platform == 'joomla'
run: |
CURRENT_BRANCH="${{ github.ref_name }}"
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
git config --local user.name "gitea-actions[bot]"
for BRANCH in main dev; do
[ "$BRANCH" = "$CURRENT_BRANCH" ] && continue
echo "Syncing updates.xml -> ${BRANCH}"
git fetch origin "${BRANCH}" 2>/dev/null || continue
git checkout "origin/${BRANCH}" -- . 2>/dev/null || continue
git checkout "${CURRENT_BRANCH}" -- updates.xml
if ! git diff --quiet updates.xml 2>/dev/null; then
git add updates.xml
git commit -m "chore: sync updates.xml from ${CURRENT_BRANCH} [skip ci]"
git push origin HEAD:refs/heads/${BRANCH} 2>&1 || echo "WARNING: push to ${BRANCH} failed"
fi
git checkout "${CURRENT_BRANCH}" 2>/dev/null
done
- name: "Delete lesser pre-release channels (cascade)"
continue-on-error: true
run: |
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
TOKEN="${{ secrets.GA_TOKEN }}"
php ${MOKO_CLI}/release_cascade.php \
--stability "${{ steps.meta.outputs.stability }}" \
--token "${TOKEN}" \
--api-base "${API_BASE}"
- name: Summary
if: always()
run: |
VERSION="${{ steps.meta.outputs.version }}"
STABILITY="${{ steps.meta.outputs.stability }}"
ZIP_NAME="${{ steps.meta.outputs.zip_name }}"
SHA256="${{ steps.zip.outputs.sha256 }}"
echo "## Pre-Release Complete" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
echo "|-------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| Version | \`${VERSION}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Channel | ${STABILITY} |" >> $GITHUB_STEP_SUMMARY
echo "| Package | \`${ZIP_NAME}\` |" >> $GITHUB_STEP_SUMMARY
echo "| SHA-256 | \`${SHA256:-n/a}\` |" >> $GITHUB_STEP_SUMMARY
+26
View File
@@ -18,6 +18,32 @@ Version format: `XX.YY.ZZ` (zero-padded semver).
## [Unreleased]
## [09.00.00] - 2026-05-26
### Added
- PHPDoc on Priority 1 Enterprise classes (CliFramework, adapters, ApiClient)
- Wiki: Coding-Standards page with PHPDoc standard, PHPCS exclusions, file patterns
- CI: PHPStan enforced at level 6 (was advisory), PHPUnit blocks on failure
### Fixed
- `updates_xml_build.php`: cascade entries down to lower channels — stable now writes all 5 entries instead of wiping them
- `updates_xml_build.php`: separate Joomla stability tags (`dev`, `rc`) from Gitea release tags (`development`, `release-candidate`) — download URLs now point to correct release assets
- `updates_xml_build.php`: only emit `<client>site</client>` for templates and modules, not packages or components
- `updates_xml_build.php`: preservation logic matches Joomla tag names when deciding which existing entries to keep
## [08.00.00] - 2026-05-26
### Changed
- PHPStan: level 5 → 6 (401 baselined, 0 new errors)
- Branch protection: 5 required checks enabled on main
- Workflows synced to all governed repos (72+ repos across 3 orgs)
- Flushed 44 stale runners from Gitea admin (3 active remain)
### Fixed
- PHPStan level 3→4: removed 13 dead properties, 41 defensive patterns baselined
- PHPStan level 4→5: fixed metrics `increment()` bug (labels passed as value param)
- PHPStan level 5→6: 360 missing array generic types baselined
## [07.00.00] - 2026-05-25
### Added
-2
View File
@@ -53,7 +53,6 @@ class BulkJoomlaTemplate extends CliFramework
public const VERSION = '04.06.10';
private GitPlatformAdapter $adapter;
private AuditLogger $logger;
private Config $config;
protected function configure(): void
@@ -85,7 +84,6 @@ class BulkJoomlaTemplate extends CliFramework
return 1;
}
$this->logger = new AuditLogger('joomla_template');
$org = $this->getArgument('--org', self::DEFAULT_ORG);
$platform = $this->adapter->getPlatformName();
$this->log("Platform: {$platform} | Organization: {$org}", 'INFO');
+1 -7
View File
@@ -66,9 +66,6 @@ class BulkSync extends CliFramework
private AuditLogger $logger;
private CheckpointManager $checkpoints;
private MetricsCollector $metrics;
private SecurityValidator $security;
private PluginFactory $pluginFactory;
private ProjectTypeDetector $typeDetector;
private Config $config;
/** Set to true by signal handler or rate-limit detection to abort the sync loop gracefully. */
@@ -204,7 +201,6 @@ class BulkSync extends CliFramework
$this->logger = new AuditLogger('bulk_sync');
$this->metrics = new MetricsCollector();
$this->checkpoints = new CheckpointManager('.checkpoints');
$this->security = new SecurityValidator();
$this->synchronizer = new RepositorySynchronizer(
$this->api,
$this->logger,
@@ -215,8 +211,6 @@ class BulkSync extends CliFramework
);
// Initialize plugin system
$this->pluginFactory = new PluginFactory($this->logger, $this->metrics);
$this->typeDetector = new ProjectTypeDetector($this->logger);
$this->log("✓ Enterprise components initialized for platform: {$platform}", 'INFO');
return true;
@@ -288,7 +282,7 @@ class BulkSync extends CliFramework
}
}
return array_values(array_merge($priority, $rest));
return array_merge($priority, $rest);
}
/**
-4
View File
@@ -58,8 +58,6 @@ class RepoCleanup extends CliFramework
private ApiClient $api;
private GitPlatformAdapter $adapter;
private AuditLogger $logger;
private MetricsCollector $metrics;
protected bool $dryRun = false;
private float $startTime;
@@ -99,8 +97,6 @@ class RepoCleanup extends CliFramework
return 1;
}
$this->logger = new AuditLogger('repo_cleanup');
$this->metrics = new MetricsCollector('repo_cleanup');
$this->logMsg("🧹 MokoStandards Repository Cleanup v" . self::VERSION);
$this->logMsg("Organization: {$org}");
-2
View File
@@ -48,7 +48,6 @@ class JoomlaRelease extends CliFramework
];
private ApiClient $api;
private AuditLogger $logger;
private \MokoEnterprise\GitPlatformAdapter $adapter;
protected function configure(): void
@@ -76,7 +75,6 @@ class JoomlaRelease extends CliFramework
$config = Config::load();
$this->adapter = PlatformAdapterFactory::create($config);
$this->api = $this->adapter->getApiClient();
$this->logger = new AuditLogger('joomla_release');
if ($repo !== '') {
$path = $this->cloneRepo($repo);
+47 -38
View File
@@ -194,29 +194,35 @@ $stabilitySuffixMap = [
'development' => '-dev',
];
// Joomla <tags><tag> values — maps to Joomla's stabilityTagToInteger()
$stabilityTagMap = [
'stable' => 'stable',
'rc' => 'rc',
'beta' => 'beta',
'alpha' => 'alpha',
'development' => 'dev',
];
// Gitea release tag names (used in download/info URLs)
$releaseTagMap = [
'stable' => 'stable',
'rc' => 'release-candidate',
'beta' => 'beta',
'alpha' => 'alpha',
'development' => 'development',
];
// -- Build update entries -----------------------------------------------------
$releaseTag = $stabilityTagMap[$stability] ?? $stability;
// For the primary entry: apply suffix if not stable
$primarySuffix = $stabilitySuffixMap[$stability] ?? '';
$primaryVersion = $version . $primarySuffix;
$downloadUrl = "{$giteaUrl}/{$org}/{$repo}/releases/download/{$releaseTag}/{$typePrefix}{$extElement}-{$primaryVersion}.zip";
$infoUrl = "{$giteaUrl}/{$org}/{$repo}/releases/tag/{$releaseTag}";
// Build client tag
// Build client tag — only needed for templates and modules (site vs admin).
// Packages and components don't use client; plugins use folder instead.
$clientTag = '';
if (!empty($extClient)) {
$clientTag = " <client>{$extClient}</client>";
} elseif ($extType === 'module' || $extType === 'plugin') {
} elseif (in_array($extType, ['template', 'module'])) {
$clientTag = ' <client>site</client>';
}
@@ -282,41 +288,44 @@ function buildEntry(
}
// -- Determine which channels to write ----------------------------------------
// Stable cascades to all channels; pre-releases only write their level and below
// Each channel gets its own suffixed version:
// development -> 04.01.00-dev
// alpha -> 04.01.00-alpha
// beta -> 04.01.00-beta
// rc -> 04.01.00-rc
// stable -> 04.01.00
// Stable cascades to all channels; pre-releases cascade down to lower channels.
// Each channel entry represents "latest release available at this stability or higher".
// When stable releases, ALL channels point to stable (it's the newest for everyone).
// When RC releases, rc/beta/alpha/dev point to RC; stable is preserved.
// When dev releases, only dev is updated; everything else is preserved.
$allChannels = ['development', 'alpha', 'beta', 'rc', 'stable'];
$stabilityIndex = array_search($stability === 'development' ? 'development' : $stability, $allChannels);
if ($stabilityIndex === false) $stabilityIndex = 4; // default to stable
// Write only the current channel entry (not cascade)
// Each channel release only creates its own entry; preserved entries handle other channels
// Write entries for the current channel AND all lower channels (cascade down)
// All cascaded entries point to the CURRENT release (the highest stability being built)
$entries = [];
$channelName = $allChannels[$stabilityIndex];
$channelSuffix = $stabilitySuffixMap[$channelName] ?? '';
$channelVersion = $version . $channelSuffix;
$channelTag = $stabilityTagMap[$channelName] ?? $channelName;
$channelDownloadUrl = "{$giteaUrl}/{$org}/{$repo}/releases/download/{$channelTag}/{$typePrefix}{$extElement}-{$channelVersion}.zip";
$channelInfoUrl = "{$giteaUrl}/{$org}/{$repo}/releases/tag/{$channelTag}";
$giteaTag = $releaseTagMap[$stability] ?? $stability;
$channelVersion = $version . ($stabilitySuffixMap[$stability] ?? '');
$channelDownloadUrl = "{$giteaUrl}/{$org}/{$repo}/releases/download/{$giteaTag}/{$typePrefix}{$extElement}-{$channelVersion}.zip";
$channelInfoUrl = "{$giteaUrl}/{$org}/{$repo}/releases/tag/{$giteaTag}";
$entries[] = buildEntry(
$channelName,
$channelVersion,
$channelDownloadUrl,
$extName,
$extElement,
$extType,
$clientTag,
$folderTag,
$channelInfoUrl,
$targetPlatform,
$phpTag,
$shaTag
);
for ($i = 0; $i <= $stabilityIndex; $i++) {
$channelName = $allChannels[$i];
$joomlaTag = $stabilityTagMap[$channelName] ?? $channelName;
// Only attach SHA to the primary channel entry
$entrySha = ($i === $stabilityIndex) ? $shaTag : '';
$entries[] = buildEntry(
$joomlaTag,
$channelVersion,
$channelDownloadUrl,
$extName,
$extElement,
$extType,
$clientTag,
$folderTag,
$channelInfoUrl,
$targetPlatform,
$phpTag,
$entrySha
);
}
// -- Preserve existing entries for channels not being updated -----------------
$dest = $outputFile ?? "{$root}/updates.xml";
@@ -325,10 +334,10 @@ $preservedEntries = [];
if (file_exists($dest)) {
$existingXml = @simplexml_load_file($dest);
if ($existingXml) {
// Channels we're writing — don't preserve these
// Joomla tags we're writing — don't preserve these
$writtenChannels = [];
for ($i = 0; $i <= $stabilityIndex; $i++) {
$writtenChannels[] = $allChannels[$i];
$writtenChannels[] = $stabilityTagMap[$allChannels[$i]] ?? $allChannels[$i];
}
foreach ($existingXml->update as $existingUpdate) {
+138
View File
@@ -0,0 +1,138 @@
#!/usr/bin/env php
<?php
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* FILE INFORMATION
* DEFGROUP: moko-platform.CLI
* INGROUP: moko-platform
* REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
* PATH: /cli/version_check.php
* VERSION: 05.00.00
* BRIEF: Validate version consistency across README, manifests, and sub-packages
*
* Usage:
* php version_check.php --path /repo
* php version_check.php --path /repo --strict # exit 1 on mismatch
* php version_check.php --path /repo --fix # fix mismatches to highest version
*/
declare(strict_types=1);
$path = '.';
$strict = false;
$fix = false;
foreach ($argv as $i => $arg) {
if ($arg === '--path' && isset($argv[$i + 1])) $path = $argv[$i + 1];
if ($arg === '--strict') $strict = true;
if ($arg === '--fix') $fix = true;
}
$root = realpath($path) ?: $path;
$errors = 0;
$versions = [];
// ── Read README.md version ───────────────────────────────────────────────────
$readme = "{$root}/README.md";
if (file_exists($readme)) {
$content = file_get_contents($readme);
if (preg_match('/VERSION:\s*(\d{2}\.\d{2}\.\d{2})/m', $content, $m)) {
$versions['README.md'] = $m[1];
}
}
// ── Read manifest XML versions ───────────────────────────────────────────────
$xmlGlobs = [
"{$root}/src/pkg_*.xml",
"{$root}/src/*.xml",
"{$root}/src/packages/*/*.xml",
"{$root}/*.xml",
];
foreach ($xmlGlobs as $glob) {
foreach (glob($glob) ?: [] as $file) {
// Skip updates.xml
if (basename($file) === 'updates.xml') continue;
$xmlContent = file_get_contents($file);
if (strpos($xmlContent, '<extension') === false) continue;
if (preg_match('|<version>(\d{2}\.\d{2}\.\d{2})(?:-[a-z]+)?</version>|', $xmlContent, $xm)) {
$relPath = str_replace($root . '/', '', $file);
$relPath = str_replace($root . '\\', '', $relPath);
$versions[$relPath] = $xm[1];
}
}
}
if (empty($versions)) {
fwrite(STDERR, "No version sources found\n");
exit(1);
}
// ── Compare versions ─────────────────────────────────────────────────────────
$uniqueVersions = array_unique(array_values($versions));
$highestVersion = '00.00.00';
foreach ($versions as $v) {
if (version_compare($v, $highestVersion, '>')) {
$highestVersion = $v;
}
}
echo "=== Version Consistency Check ===\n";
foreach ($versions as $source => $ver) {
$status = ($ver === $highestVersion) ? 'OK' : 'MISMATCH';
if ($status === 'MISMATCH') $errors++;
echo sprintf(" %-50s %s %s\n", $source, $ver, $status === 'OK' ? '' : "** MISMATCH (expected {$highestVersion})");
}
if (count($uniqueVersions) === 1) {
echo "\nAll {$ver} — consistent.\n";
} else {
echo "\n** {$errors} mismatch(es) found. Highest version: {$highestVersion}\n";
if ($fix) {
echo "\n=== Fixing mismatches to {$highestVersion} ===\n";
// Fix README.md
if (isset($versions['README.md']) && $versions['README.md'] !== $highestVersion) {
$content = file_get_contents($readme);
$content = preg_replace(
'/(VERSION:\s*)\d{2}\.\d{2}\.\d{2}/m',
'${1}' . $highestVersion,
$content,
1
);
file_put_contents($readme, $content);
echo " Fixed: README.md -> {$highestVersion}\n";
}
// Fix XML manifests
foreach ($versions as $source => $ver) {
if ($source === 'README.md') continue;
if ($ver === $highestVersion) continue;
$file = "{$root}/{$source}";
if (!file_exists($file)) continue;
$content = file_get_contents($file);
$content = preg_replace(
'|<version>[^<]*</version>|',
"<version>{$highestVersion}</version>",
$content
);
file_put_contents($file, $content);
echo " Fixed: {$source} -> {$highestVersion}\n";
}
echo "Done.\n";
}
}
if ($strict && $errors > 0) {
exit(1);
}
exit(0);
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "mokoconsulting-tech/enterprise",
"description": "MokoStandards Enterprise API \u2014 PHP implementation",
"type": "library",
"version": "07.00.00",
"version": "09.00.00",
"license": "GPL-3.0-or-later",
"authors": [
{
+2 -2
View File
@@ -92,6 +92,8 @@ class CircuitBreakerOpen extends RuntimeException
* );
* $response = $client->get('/repos/owner/repo');
* ```
*
* @since 04.00.00
*/
class ApiClient
{
@@ -124,7 +126,6 @@ class ApiClient
private ?DateTime $circuitLastFailure = null;
/** @var LoggerInterface|null Optional logger instance */
private ?LoggerInterface $logger = null;
/** @var array<string, mixed> Request metrics */
private array $metrics = [
@@ -179,7 +180,6 @@ class ApiClient
$this->circuitBreakerTimeout = $circuitBreakerTimeout;
$this->enableCaching = $enableCaching;
$this->userAgent = $userAgent;
$this->logger = $logger;
$this->authScheme = $authScheme;
// Initialize HTTP client
+13
View File
@@ -716,6 +716,9 @@ class ValidationCLI extends CLIApp
* Lifecycle: configure() -> parseArguments() -> printBanner() -> initialize() -> run()
*
* All new scripts must extend CliFramework and implement configure() + run().
*
* @since 04.00.15
* @see CLIApp Legacy base class (deprecated)
*/
abstract class CliFramework
{
@@ -932,6 +935,11 @@ abstract class CliFramework
// Argument parsing (internal)
// =========================================================================
/**
* Parse CLI arguments from $_SERVER['argv'] into registered argument definitions.
*
* @since 04.00.15
*/
private function parseArguments(): void
{
$argv = array_slice($_SERVER['argv'] ?? [], 1);
@@ -970,6 +978,11 @@ abstract class CliFramework
// Help screen
// =========================================================================
/**
* Print auto-generated help screen from registered arguments.
*
* @since 04.00.15
*/
protected function printHelp(): void
{
$w = $this->termWidth();
+7 -2
View File
@@ -32,12 +32,17 @@ use RuntimeException;
* - Workflow dir: .github/workflows
*
* @package MokoStandards\Enterprise
* @version 04.06.10
* @since 04.06.10
* @see GitPlatformAdapter
*/
class GitHubAdapter implements GitPlatformAdapter
{
/** @var ApiClient HTTP client for GitHub API calls. */
private ApiClient $apiClient;
/**
* @param ApiClient $apiClient Configured API client for api.github.com
*/
public function __construct(ApiClient $apiClient)
{
$this->apiClient = $apiClient;
@@ -405,7 +410,7 @@ class GitHubAdapter implements GitPlatformAdapter
$page++;
}
return $all;
return array_values($all);
}
// ──────────────────────────────────────────────
+7 -7
View File
@@ -175,7 +175,7 @@ interface GitPlatformAdapter
/**
* List all branches in a repository.
*
* @return array<int, array<string, mixed>>
* @return array<mixed>
*/
public function listBranches(string $org, string $repo): array;
@@ -202,7 +202,7 @@ interface GitPlatformAdapter
* @param string $repo Repository name
* @param string $path File path within the repository
* @param string|null $ref Branch/tag/SHA reference (null = default branch)
* @return array{content: string, sha: string, size: int, encoding: string} File data (content is base64-encoded)
* @return array<string, mixed> File data (content is base64-encoded)
*/
public function getFileContents(string $org, string $repo, string $path, ?string $ref = null): array;
@@ -258,7 +258,7 @@ interface GitPlatformAdapter
* @param string $org Organization name
* @param string $repo Repository name
* @param array<string, mixed> $filters Filters (state, head, base, sort, direction)
* @return array<int, array<string, mixed>> Pull request list
* @return array<mixed> Pull request list
*/
public function listPullRequests(string $org, string $repo, array $filters = []): array;
@@ -305,7 +305,7 @@ interface GitPlatformAdapter
* @param string $org Organization name
* @param string $repo Repository name
* @param array<string, mixed> $filters Filters (state, labels, assignee, etc.)
* @return array<int, array<string, mixed>> Issue list
* @return array<mixed> Issue list
*/
public function listIssues(string $org, string $repo, array $filters = []): array;
@@ -357,7 +357,7 @@ interface GitPlatformAdapter
*
* @param string $org Organization name
* @param string $repo Repository name
* @return array<int, array{name: string, color: string, description: string}> Label list
* @return array<mixed> Label list
*/
public function listLabels(string $org, string $repo): array;
@@ -406,7 +406,7 @@ interface GitPlatformAdapter
*
* @param string $org Organization name
* @param string $repo Repository name
* @return array<int, array<string, mixed>> Protection rules
* @return array<mixed> Protection rules
*/
public function listBranchProtections(string $org, string $repo): array;
@@ -445,7 +445,7 @@ interface GitPlatformAdapter
* @param string $endpoint API endpoint path
* @param array<string, mixed> $params Query parameters
* @param int $perPage Items per page (platform default if 0)
* @return array<int, array<string, mixed>> All items across all pages
* @return array<mixed> All items across all pages
*/
public function paginateAll(string $endpoint, array $params = [], int $perPage = 100): array;
+10 -2
View File
@@ -34,13 +34,21 @@ use RuntimeException;
* - Workflow dir: .mokogitea/workflows
*
* @package MokoStandards\Enterprise
* @version 04.06.10
* @since 04.06.10
* @see GitPlatformAdapter
*/
class MokoGiteaAdapter implements GitPlatformAdapter
{
/** @var ApiClient HTTP client for Gitea API calls. */
private ApiClient $apiClient;
/** @var string Base URL for Gitea API (e.g. https://git.mokoconsulting.tech/api/v1). */
private string $baseUrl;
/**
* @param ApiClient $apiClient Configured API client
* @param string $baseUrl Gitea API base URL
*/
public function __construct(ApiClient $apiClient, string $baseUrl = 'https://git.mokoconsulting.tech/api/v1')
{
$this->apiClient = $apiClient;
@@ -468,7 +476,7 @@ class MokoGiteaAdapter implements GitPlatformAdapter
$page++;
}
return $all;
return array_values($all);
}
// ──────────────────────────────────────────────
@@ -29,7 +29,6 @@ class RepositoryHealthChecker
{
private AuditLogger $logger;
private MetricsCollector $metrics;
private UnifiedValidator $validator;
private array $results = [
'categories' => [],
@@ -50,7 +49,6 @@ class RepositoryHealthChecker
) {
$this->logger = $logger ?? new AuditLogger('repo_health_checker');
$this->metrics = $metrics ?? new MetricsCollector();
$this->validator = $validator ?? new UnifiedValidator();
}
/**
+3 -5
View File
@@ -39,7 +39,6 @@ class RepositorySynchronizer
private const VERSION_BRANCH = 'version/' . self::STANDARDS_MAJOR;
private const SYNC_BRANCH = 'chore/sync-mokostandards-v' . self::STANDARDS_MINOR;
private ApiClient $apiClient;
private GitPlatformAdapter $adapter;
private AuditLogger $logger;
private MetricsCollector $metrics;
@@ -65,7 +64,6 @@ class RepositorySynchronizer
?DefinitionParser $definitionParser = null,
?GitPlatformAdapter $adapter = null
) {
$this->apiClient = $apiClient;
$this->adapter = $adapter ?? new MokoGiteaAdapter($apiClient);
$this->logger = $logger;
$this->metrics = $metrics;
@@ -1510,16 +1508,16 @@ HCL;
if ($updated) {
$results['success']++;
$this->metrics->increment('repos_updated_total', ['status' => 'success']);
$this->metrics->increment('repos_updated_total', 1, ['status' => 'success']);
$results['repositories'][$repoName] = 'updated';
} else {
$results['skipped']++;
$this->metrics->increment('repos_updated_total', ['status' => 'skipped']);
$this->metrics->increment('repos_updated_total', 1, ['status' => 'skipped']);
$results['repositories'][$repoName] = 'skipped';
}
} catch (Exception $e) {
$results['failed']++;
$this->metrics->increment('repos_updated_total', ['status' => 'failed']);
$this->metrics->increment('repos_updated_total', 1, ['status' => 'failed']);
$results['repositories'][$repoName] = 'failed: ' . $e->getMessage();
}
-2
View File
@@ -96,8 +96,6 @@ class TransactionStep
*/
class Transaction
{
private const VERSION = '04.06.00';
private string $name;
/** @var array<int, TransactionStep> */
private array $steps = [];
File diff suppressed because it is too large Load Diff
+4 -1
View File
@@ -6,7 +6,7 @@
# PHPStan configuration for moko-platform projects
parameters:
level: 2
level: 6
paths:
- lib
- validate
@@ -21,3 +21,6 @@ parameters:
checkFunctionNameCase: true
checkInternalClassCaseSensitivity: true
includes:
- phpstan-baseline.neon
+1 -1
View File
@@ -25,7 +25,7 @@ final class CheckFileIntegrity
private bool $verbose = false;
private bool $jsonOutput = false;
/** @var array{host: string, port: int, user: string, identity: string} */
/** @var array<string, mixed> */
private array $sftpConfig = [];
public function run(): int
-3
View File
@@ -35,10 +35,8 @@ use MokoEnterprise\{AuditLogger, CliFramework, MetricsCollector, PluginFactory};
class RepoHealthChecker extends CliFramework
{
private const DEFAULT_THRESHOLD = 70.0;
private AuditLogger $logger;
private MetricsCollector $metrics;
private PluginFactory $pluginFactory;
private string $apiBaseUrl = 'https://git.mokoconsulting.tech/api/v1';
private array $results = [
@@ -61,7 +59,6 @@ class RepoHealthChecker extends CliFramework
parent::initialize();
$this->logger = new AuditLogger('repo_health_checker');
$this->metrics = new MetricsCollector();
$this->pluginFactory = new PluginFactory($this->logger, $this->metrics);
$config = \MokoEnterprise\Config::load();
$this->apiBaseUrl = rtrim($config->getString('gitea.url', 'https://git.mokoconsulting.tech'), '/') . '/api/v1';
}
-2
View File
@@ -38,7 +38,6 @@ class DriftScanner extends CliFramework
private const DEFAULT_ORG = 'mokoconsulting-tech';
private ApiClient $apiClient;
private AuditLogger $logger;
private MetricsCollector $metrics;
private \MokoEnterprise\GitPlatformAdapter $adapter;
@@ -60,7 +59,6 @@ class DriftScanner extends CliFramework
{
parent::initialize();
$this->logger = new AuditLogger('drift_scanner');
$this->metrics = new MetricsCollector();
// Initialize API client via platform adapter