416 Commits

Author SHA1 Message Date
Moko Consulting 0a1a44699e chore(ci): sync CI issue reporter from Template-Joomla
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Generic: Repo Health / Release configuration (push) Has been cancelled
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
2026-06-02 21:29:22 +00:00
Moko Consulting cbf6ced4af chore(ci): sync CI issue reporter from Template-Joomla
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Generic: Repo Health / Release configuration (push) Has been cancelled
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
2026-06-02 21:29:21 +00:00
Moko Consulting e913d4eba9 chore(ci): sync CI issue reporter from Template-Joomla
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 2s
Generic: Repo Health / Release configuration (push) Has been cancelled
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
2026-06-02 21:29:20 +00:00
Moko Consulting 06b265a247 chore(ci): add CI issue reporter for auto-filing gate failures
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Generic: Repo Health / Release configuration (push) Has been cancelled
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
2026-06-02 20:36:57 +00:00
Moko Consulting d08f720d40 chore(ci): add CI issue reporter for auto-filing gate failures
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Generic: Repo Health / Release configuration (push) Has been cancelled
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
2026-06-02 20:36:56 +00:00
Moko Consulting 814637123e chore(ci): add CI issue reporter for auto-filing gate failures
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 2s
Generic: Repo Health / Release configuration (push) Has been cancelled
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
2026-06-02 20:36:55 +00:00
jmiller f97742986e chore: sync .mokogitea/workflows/cascade-dev.yml from moko-platform [skip ci] 2026-05-31 01:41:54 +00:00
jmiller 14dd2c403a chore: sync CONTRIBUTING.md from moko-platform [skip ci] 2026-05-31 01:10:05 +00:00
jmiller 5e1efd85ba feat: add display-name to manifest.xml [skip ci] 2026-05-30 19:14:18 +00:00
jmiller d57309d6b3 chore: sync .mokogitea/workflows/pr-check.yml from moko-platform [skip ci] 2026-05-30 16:01:33 +00:00
jmiller 54cdbe3256 chore: sync CONTRIBUTING.md from moko-platform [skip ci] 2026-05-30 14:59:33 +00:00
jmiller 05fa5d0b26 chore: sync .mokogitea/workflows/auto-release.yml from moko-platform [skip ci] 2026-05-30 14:56:01 +00:00
jmiller 58f45492d3 chore: sync .mokogitea/workflows/auto-bump.yml from moko-platform [skip ci] 2026-05-30 14:54:09 +00:00
jmiller 4ca946586b chore: sync .mokogitea/workflows/auto-release.yml from moko-platform [skip ci] 2026-05-30 05:53:09 +00:00
jmiller ec42b4e6c1 chore: sync .mokogitea/workflows/auto-bump.yml from moko-platform [skip ci] 2026-05-30 05:51:13 +00:00
jmiller 6cd0392e10 chore: sync .mokogitea/workflows/auto-release.yml from moko-platform [skip ci] 2026-05-30 03:40:59 +00:00
jmiller 0c76915796 chore: sync .mokogitea/workflows/auto-release.yml from moko-platform [skip ci] 2026-05-30 01:14:53 +00:00
jmiller 9e6d0a2c55 chore: add .mokogitea/branch-protection.yml from moko-platform [skip ci] 2026-05-29 10:30:09 +00:00
jmiller 936c5e715d chore: sync CONTRIBUTING.md from moko-platform [skip ci] 2026-05-29 10:27:37 +00:00
jmiller 90acd8e89c chore: sync .mokogitea/workflows/branch-cleanup.yml from moko-platform [skip ci] 2026-05-29 10:26:00 +00:00
jmiller 26de75ff60 chore: sync .mokogitea/workflows/auto-release.yml from moko-platform [skip ci] 2026-05-29 10:24:31 +00:00
jmiller 693e45a66f chore: sync .mokogitea/workflows/auto-bump.yml from moko-platform [skip ci] 2026-05-29 10:23:02 +00:00
jmiller ca68e65794 chore: sync .mokogitea/workflows/pre-release.yml from moko-platform [skip ci] 2026-05-28 20:53:19 +00:00
jmiller 6bd1a34fd9 chore: sync .mokogitea/workflows/update-server.yml from moko-platform [skip ci] 2026-05-28 20:48:26 +00:00
jmiller 1ca3774148 chore: sync .mokogitea/workflows/auto-release.yml from moko-platform [skip ci] 2026-05-28 20:43:15 +00:00
jmiller 03b67a12d4 chore: sync .mokogitea/workflows/auto-release.yml from moko-platform [skip ci] 2026-05-28 20:37:51 +00:00
jmiller bcf39442eb docs: add infrastructure changes to CHANGELOG [skip ci] 2026-05-27 05:46:14 +00:00
jmiller dac228a9a3 chore: add branch-cleanup workflow [skip ci] 2026-05-27 03:52:44 +00:00
gitea-actions[bot] beab2455f2 feat(ci): add version branch creation on stable release [skip ci] 2026-05-27 02:18:55 +00:00
jmiller 07f9e077e0 chore(ci): update pre-release.yml from moko-platform [skip ci] 2026-05-26 22:50:56 +00:00
jmiller b32bdbdb3a chore(ci): update auto-bump.yml from moko-platform [skip ci] 2026-05-26 22:49:44 +00:00
jmiller 1cc294a411 chore(ci): update auto-release.yml from moko-platform [skip ci] 2026-05-26 22:48:31 +00:00
jmiller f0b0c6b6da chore(ci): update pre-release.yml from moko-platform [skip ci] 2026-05-26 22:37:00 +00:00
jmiller 8133785fb5 chore(ci): update auto-release.yml from moko-platform [skip ci] 2026-05-26 22:35:38 +00:00
jmiller 77b4344bdd chore(ci): update auto-bump.yml from moko-platform [skip ci] 2026-05-26 22:25:15 +00:00
jmiller 49065c35a4 chore(ci): update auto-release.yml from moko-platform [skip ci] 2026-05-26 22:23:59 +00:00
jmiller 6069e73bdb chore(ci): update pre-release.yml from moko-platform [skip ci] 2026-05-26 22:13:22 +00:00
jmiller 456cddd114 chore(ci): add auto-bump.yml from moko-platform [skip ci] 2026-05-26 22:12:10 +00:00
jmiller 02c24ad32d chore: sync .mokogitea/workflows/update-server.yml from moko-platform [skip ci] 2026-05-26 20:12:40 +00:00
jmiller 41e464aa0a chore: sync .mokogitea/workflows/pre-release.yml from moko-platform [skip ci] 2026-05-26 20:10:46 +00:00
jmiller 451f6e85b1 fix(ci): use release_package.php for Joomla package builds [skip ci] 2026-05-26 19:54:32 +00:00
jmiller 4c5af4388a chore(ci): update pre-release.yml from moko-platform [skip ci] 2026-05-26 19:34:39 +00:00
jmiller d5b8ee1d5e chore(ci): update auto-release.yml from moko-platform [skip ci] 2026-05-26 19:34:38 +00:00
jmiller a8ea7ad1fd chore: sync .mokogitea/workflows/update-server.yml from moko-platform [skip ci] 2026-05-26 19:04:06 +00:00
jmiller c17c5df12b sync: update-server.yml with updates.xml integrity check [skip ci] 2026-05-26 04:47:45 +00:00
gitea-actions[bot] 4f7c0d7b0d fix(ci): update workflows — tag dev, client site, version_check [skip ci] 2026-05-25 22:56:18 -05:00
jmiller 7bbcbc8998 fix: updates.xml tag dev not development + client site [skip ci] 2026-05-26 03:54:07 +00:00
jmiller 94d0b8afd7 fix(updates): broaden targetplatform to match Joomla 5.x and 6.x [skip ci] 2026-05-26 03:42:38 +00:00
jmiller 3091e6655b chore: sync .mokogitea/workflows/auto-release.yml from moko-platform [skip ci] 2026-05-26 03:07:28 +00:00
jmiller 63583ededc chore: sync .mokogitea/workflows/pre-release.yml from moko-platform [skip ci] 2026-05-26 03:05:35 +00:00
jmiller ba17a831fa feat(ci): add issue-branch.yml [skip ci] 2026-05-25 05:12:37 +00:00
jmiller 3222722e47 fix(ci): update pre-release.yml - PHP CLI tools, fix broken platform detection [skip ci] 2026-05-25 04:13:05 +00:00
jmiller 9b12979a60 Merge pull request 'chore: merge dev into main [skip ci]' (#14) from dev into main
chore: cascade main → dev [skip ci]
2026-05-24 22:57:54 +00:00
jmiller 2fd4772c06 Add RC pre-release trigger to CI workflow
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 2s
Universal: Cascade Main → Dev / Cascade main → branches (push) Successful in 6s
Generic: Repo Health / Release configuration (push) Failing after 5s
Generic: Repo Health / Scripts governance (push) Successful in 5s
Generic: Repo Health / Repository health (push) Failing after 5s
Automatically triggers a release-candidate build when CI lint+tests
pass on a pull request.

Authored-by: Moko Consulting
2026-05-24 22:55:28 +00:00
jmiller 26a85f332d Add RC pre-release trigger to PR check workflow
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 2s
Universal: Cascade Main → Dev / Cascade main → branches (push) Successful in 3s
Generic: Repo Health / Release configuration (push) Failing after 4s
Generic: Repo Health / Scripts governance (push) Successful in 7s
Generic: Repo Health / Repository health (push) Failing after 7s
Automatically triggers a release-candidate build when a PR passes
branch policy and validation checks.

Authored-by: Moko Consulting
2026-05-24 22:54:38 +00:00
Jonathan Miller 3f57a3c7aa chore: cascade main -> dev, resolve conflicts [skip ci] 2026-05-24 14:49:14 -05:00
Moko Consulting dc2e0d42f7 chore: update CHANGELOG for deploy workflow removal
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 2s
Universal: Cascade Main → Dev / Cascade main → branches (push) Successful in 3s
Generic: Repo Health / Release configuration (push) Failing after 5s
Generic: Repo Health / Scripts governance (push) Successful in 4s
Generic: Repo Health / Repository health (push) Failing after 5s
2026-05-24 04:09:56 +00:00
jmiller d41ff35074 chore: remove deploy workflow — switching to Joomla update server method
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
Generic: Repo Health / Release configuration (push) Successful in 4s
Generic: Repo Health / Scripts governance (push) Successful in 4s
Generic: Repo Health / Repository health (push) Failing after 4s
2026-05-24 03:44:11 +00:00
jmiller bebd55d874 fix(ci): add branch output to auto-release [skip ci] 2026-05-23 19:47:30 +00:00
jmiller 68ac2d40ef fix(ci): pre-release php-curl + continue-on-error + CLI updates.xml [skip ci] 2026-05-22 03:30:53 +00:00
jmiller 0df24b619a refactor(ci): sync auto-release.yml — CLI-based workflow [skip ci] 2026-05-22 02:55:54 +00:00
jmiller d60f8c06fc refactor(ci): pre-release uses CLI tools [skip ci] 2026-05-22 02:49:14 +00:00
jmiller f22fc7312a fix(ci): sync pre-release.yml — CLI-based updates.xml sync [skip ci] 2026-05-22 02:39:45 +00:00
jmiller acb6622737 fix(ci): sync pre-release.yml — updates.xml API sync (#34) [skip ci] 2026-05-22 02:35:30 +00:00
jmiller 7c796ec2a8 chore: sync security-audit.yml from moko-platform [skip ci] 2026-05-21 22:25:54 +00:00
jmiller b434bb1ec3 chore: sync repo-health.yml from moko-platform [skip ci] 2026-05-21 22:25:53 +00:00
jmiller 6574679c68 chore: sync pre-release.yml from moko-platform [skip ci] 2026-05-21 22:25:52 +00:00
jmiller 109e7cbb1a chore: sync pr-check.yml from moko-platform [skip ci] 2026-05-21 22:25:51 +00:00
jmiller ee38a547ed chore: sync notify.yml from moko-platform [skip ci] 2026-05-21 22:25:50 +00:00
jmiller 8ac5089bc0 chore: sync gitleaks.yml from moko-platform [skip ci] 2026-05-21 22:25:49 +00:00
jmiller 826b33001e chore: sync deploy-manual.yml from moko-platform [skip ci] 2026-05-21 22:25:48 +00:00
jmiller 5ebb08cd69 chore: sync cleanup.yml from moko-platform [skip ci] 2026-05-21 22:25:48 +00:00
jmiller b862a8befe chore: sync cascade-dev.yml from moko-platform [skip ci] 2026-05-21 22:25:47 +00:00
jmiller 5b1ec76936 chore: sync auto-release.yml from moko-platform [skip ci] 2026-05-21 22:25:46 +00:00
Jonathan Miller 45cc7d3080 chore(ci): use manifest.xml for platform detection, remove .moko-platform
Authored-by: Moko Consulting

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-21 17:19:05 -05:00
Jonathan Miller 2ec6a5f6b0 chore(ci): resolve merge — .gitea to .mokogitea migration complete
Authored-by: Moko Consulting

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-21 15:59:03 -05:00
Jonathan Miller 31efe86b1e chore(ci): migrate .gitea to .mokogitea and update workflows
Synced release workflows from Template-Joomla with package type support.

Authored-by: Moko Consulting

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-21 15:57:02 -05:00
Jonathan Miller d2f774db48 chore(ci): update release workflows with package type support
Synced from Template-Joomla: pre-release.yml and auto-release.yml now
handle Joomla package extensions (type="package" with sub-extensions).

Authored-by: Moko Consulting

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-21 15:52:55 -05:00
jmiller 44035da711 chore: update CLAUDE.md to reference .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 20:08:52 +00:00
jmiller 69705efd62 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:31 +00:00
jmiller a03538f1ed chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:30 +00:00
jmiller cb1e244e10 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:30 +00:00
jmiller e26af481d0 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:29 +00:00
jmiller 05dd2398f9 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:29 +00:00
jmiller c231dd5010 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:28 +00:00
jmiller e9c4e69d9b chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:28 +00:00
jmiller d3e4c98e8d chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:27 +00:00
jmiller e3ff8cfd93 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:27 +00:00
jmiller e3a87ceea2 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:26 +00:00
jmiller a4871571b0 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:26 +00:00
jmiller bf0d0a256a chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:25 +00:00
jmiller 1f8cb89ba2 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:24 +00:00
jmiller 571a2ceaba chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:24 +00:00
jmiller afeda847a0 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:23 +00:00
jmiller f8022553e1 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:23 +00:00
jmiller 975ec8b393 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:22 +00:00
jmiller 0a360b74c3 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:22 +00:00
jmiller 075a656ffb chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:21 +00:00
jmiller c6d2493006 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:21 +00:00
jmiller 69eeb1274e chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:20 +00:00
jmiller 7fb94c7399 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:20 +00:00
jmiller c2e5d4209f chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:19 +00:00
jmiller 533a0e81d9 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:19 +00:00
jmiller c3a475bddb chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:18 +00:00
jmiller 239468559d chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:17 +00:00
jmiller 8f4744382a chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:17 +00:00
jmiller e63228e062 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:16 +00:00
jmiller 37e3cf24ed chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:16 +00:00
jmiller 807ff35bc7 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:15 +00:00
jmiller 21dd88a51f chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:15 +00:00
jmiller 5397d36ce4 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:14 +00:00
jmiller 34887c4cd0 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:14 +00:00
jmiller 16c57fb5fa chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:13 +00:00
jmiller f7b4bb30f6 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:13 +00:00
jmiller 4b2e6764c3 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:12 +00:00
jmiller 94a81d0bea chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:12 +00:00
jmiller 581d95dea5 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:11 +00:00
jmiller 73bb39ae5b chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:11 +00:00
jmiller 5b299d19f8 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:10 +00:00
jmiller 2cc204d288 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:10 +00:00
jmiller ada3555f4b chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:09 +00:00
jmiller f4c1abf688 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:08 +00:00
jmiller 68da1b95b4 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:08 +00:00
jmiller dff481a53d chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:07 +00:00
jmiller 333a16b8a3 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:07 +00:00
jmiller ac387ef04a chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:06 +00:00
jmiller 5ee0b9e516 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:06 +00:00
jmiller a3bf34a31d chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:05 +00:00
jmiller ad6ac42f9f chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:05 +00:00
jmiller 21e91364ec chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:04 +00:00
jmiller 176176a191 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:04 +00:00
jmiller aa0a15fbd9 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:03 +00:00
jmiller 0bb0269a3a chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:03 +00:00
jmiller 93595173f4 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:02 +00:00
jmiller 25a72151bf chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:02 +00:00
jmiller 5ae97e91df chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:01 +00:00
jmiller c1cf9fffe2 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:01 +00:00
jmiller 8d0a80d82e chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:00 +00:00
jmiller 8b30eeca51 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:54:00 +00:00
jmiller 461a05b3a6 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:53:59 +00:00
jmiller 3588242ac5 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:53:59 +00:00
jmiller 96d1f077ec chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:53:58 +00:00
jmiller 3137dd99e1 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:53:57 +00:00
jmiller ab98c994c1 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:53:57 +00:00
jmiller 75b76502f8 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:53:57 +00:00
jmiller 571c75ffaf chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:53:56 +00:00
jmiller db52cc84d8 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:53:56 +00:00
jmiller f0269e1122 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:53:55 +00:00
jmiller f649659f98 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:53:54 +00:00
jmiller 00e61dbf56 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:53:54 +00:00
jmiller 84c89f1ed2 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:53:53 +00:00
jmiller 8653943794 chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:53:53 +00:00
jmiller da4cc0fdcd chore: rename .gitea/ to .mokogitea/ [skip ci]
Authored-by: Moko Consulting
2026-05-21 16:53:52 +00:00
jmiller 572ade05f6 chore: sync issue templates from template repo [skip ci] 2026-05-20 00:33:39 +00:00
jmiller 7a7282571b chore: sync issue templates from template repo [skip ci] 2026-05-20 00:33:38 +00:00
jmiller b879d6260f chore: sync issue templates from template repo [skip ci] 2026-05-20 00:33:36 +00:00
jmiller 646a5aede7 chore: sync issue templates from template repo [skip ci] 2026-05-20 00:33:35 +00:00
jmiller 9d8a738480 chore: sync issue templates from template repo [skip ci] 2026-05-20 00:33:33 +00:00
jmiller 5f227bf719 chore: sync issue templates from template repo [skip ci] 2026-05-20 00:33:32 +00:00
jmiller e5ef2623f7 chore: sync issue templates from template repo [skip ci] 2026-05-20 00:33:31 +00:00
jmiller 3a31d84a86 chore: sync issue templates from template repo [skip ci] 2026-05-20 00:33:29 +00:00
jmiller d8a74ffa69 chore: sync issue templates from template repo [skip ci] 2026-05-20 00:33:28 +00:00
jmiller 7d1ba20882 chore: rename Setup step to moko-platform [skip ci] 2026-05-16 22:19:22 +00:00
jmiller b7c53cdfaa chore: add manifest.xml [skip ci] 2026-05-16 19:21:02 +00:00
jmiller 1a1399f6b8 feat(ci): CB plugin detection + platform auto-sense + remove GitHub mirror [skip ci] 2026-05-16 18:57:56 +00:00
jmiller 532c217051 chore: remove .mokogitea/workflows/update-server.yml (moved to .gitea/) [skip ci] 2026-05-16 18:38:15 +00:00
jmiller f583d68a3c chore: move .mokogitea/workflows/update-server.yml to .gitea/workflows/update-server.yml [skip ci] 2026-05-16 18:38:15 +00:00
jmiller 146489a9ae chore: remove .mokogitea/workflows/security-audit.yml (moved to .gitea/) [skip ci] 2026-05-16 18:38:14 +00:00
jmiller 8f96efda9c chore: move .mokogitea/workflows/security-audit.yml to .gitea/workflows/security-audit.yml [skip ci] 2026-05-16 18:38:14 +00:00
jmiller 67c054ebe1 chore: remove .mokogitea/workflows/repo-health.yml (moved to .gitea/) [skip ci] 2026-05-16 18:38:13 +00:00
jmiller 114b00f05d chore: move .mokogitea/workflows/repo-health.yml to .gitea/workflows/repo-health.yml [skip ci] 2026-05-16 18:38:13 +00:00
jmiller ee3d5693bd chore: remove .mokogitea/workflows/pre-release.yml (moved to .gitea/) [skip ci] 2026-05-16 18:38:13 +00:00
jmiller 3991021883 chore: move .mokogitea/workflows/pre-release.yml to .gitea/workflows/pre-release.yml [skip ci] 2026-05-16 18:38:12 +00:00
jmiller 19d647005e chore: remove .mokogitea/workflows/pr-check.yml (moved to .gitea/) [skip ci] 2026-05-16 18:38:12 +00:00
jmiller 48e7328038 chore: move .mokogitea/workflows/pr-check.yml to .gitea/workflows/pr-check.yml [skip ci] 2026-05-16 18:38:11 +00:00
jmiller fb2bfaa282 chore: remove .mokogitea/workflows/notify.yml (moved to .gitea/) [skip ci] 2026-05-16 18:38:11 +00:00
jmiller 45d21f1b5e chore: move .mokogitea/workflows/notify.yml to .gitea/workflows/notify.yml [skip ci] 2026-05-16 18:38:10 +00:00
jmiller 507189bee9 chore: remove .mokogitea/workflows/gitleaks.yml (moved to .gitea/) [skip ci] 2026-05-16 18:38:10 +00:00
jmiller dcac514773 chore: move .mokogitea/workflows/gitleaks.yml to .gitea/workflows/gitleaks.yml [skip ci] 2026-05-16 18:38:09 +00:00
jmiller 4988510a09 chore: remove .mokogitea/workflows/deploy-manual.yml (moved to .gitea/) [skip ci] 2026-05-16 18:38:09 +00:00
jmiller 608b71042c chore: move .mokogitea/workflows/deploy-manual.yml to .gitea/workflows/deploy-manual.yml [skip ci] 2026-05-16 18:38:09 +00:00
jmiller 6f0beb9763 chore: remove .mokogitea/workflows/cleanup.yml (moved to .gitea/) [skip ci] 2026-05-16 18:38:08 +00:00
jmiller ee3ba5a8eb chore: move .mokogitea/workflows/cleanup.yml to .gitea/workflows/cleanup.yml [skip ci] 2026-05-16 18:38:08 +00:00
jmiller faa0a40024 chore: remove .mokogitea/workflows/ci-joomla.yml (moved to .gitea/) [skip ci] 2026-05-16 18:38:07 +00:00
jmiller efeabc5cde chore: move .mokogitea/workflows/ci-joomla.yml to .gitea/workflows/ci-joomla.yml [skip ci] 2026-05-16 18:38:07 +00:00
jmiller 8694ab1b81 chore: remove .mokogitea/workflows/cascade-dev.yml (moved to .gitea/) [skip ci] 2026-05-16 18:38:06 +00:00
jmiller 1e39df8af5 chore: move .mokogitea/workflows/cascade-dev.yml to .gitea/workflows/cascade-dev.yml [skip ci] 2026-05-16 18:38:06 +00:00
jmiller fb91ec85fc chore: remove .mokogitea/workflows/auto-release.yml (exists in .gitea/) [skip ci] 2026-05-16 18:38:05 +00:00
jmiller c323fd3f07 chore: remove .mokogitea/update-server.yml (moved to .gitea/) [skip ci] 2026-05-16 18:38:05 +00:00
jmiller 5067f27b87 chore: move .mokogitea/update-server.yml to .gitea/update-server.yml [skip ci] 2026-05-16 18:38:04 +00:00
jmiller 833cf5b544 chore: remove .mokogitea/sync-roadmap-wiki.yml (moved to .gitea/) [skip ci] 2026-05-16 18:38:04 +00:00
jmiller 1b86674b26 chore: move .mokogitea/sync-roadmap-wiki.yml to .gitea/sync-roadmap-wiki.yml [skip ci] 2026-05-16 18:38:04 +00:00
jmiller 0fd2d2ba1b chore: remove .mokogitea/security-audit.yml (moved to .gitea/) [skip ci] 2026-05-16 18:38:03 +00:00
jmiller 8b3a238c48 chore: move .mokogitea/security-audit.yml to .gitea/security-audit.yml [skip ci] 2026-05-16 18:38:03 +00:00
jmiller 236669e8bd chore: remove .mokogitea/repo-health.yml (moved to .gitea/) [skip ci] 2026-05-16 18:38:02 +00:00
jmiller 60ac9c807c chore: move .mokogitea/repo-health.yml to .gitea/repo-health.yml [skip ci] 2026-05-16 18:38:02 +00:00
jmiller e3eca2296a chore: remove .mokogitea/pre-release.yml (moved to .gitea/) [skip ci] 2026-05-16 18:38:01 +00:00
jmiller 4eb64ca890 chore: move .mokogitea/pre-release.yml to .gitea/pre-release.yml [skip ci] 2026-05-16 18:38:01 +00:00
jmiller b783af913c chore: remove .mokogitea/pr-check.yml (moved to .gitea/) [skip ci] 2026-05-16 18:38:00 +00:00
jmiller 21a184576a chore: move .mokogitea/pr-check.yml to .gitea/pr-check.yml [skip ci] 2026-05-16 18:38:00 +00:00
jmiller 6af7479542 chore: remove .mokogitea/pr-branch-check.yml (moved to .gitea/) [skip ci] 2026-05-16 18:38:00 +00:00
jmiller cfee137685 chore: move .mokogitea/pr-branch-check.yml to .gitea/pr-branch-check.yml [skip ci] 2026-05-16 18:37:59 +00:00
jmiller b3665dfe3b chore: remove .mokogitea/notify.yml (moved to .gitea/) [skip ci] 2026-05-16 18:37:59 +00:00
jmiller 5175b30c1c chore: move .mokogitea/notify.yml to .gitea/notify.yml [skip ci] 2026-05-16 18:37:58 +00:00
jmiller cfe552dd64 chore: remove .mokogitea/gitleaks.yml (moved to .gitea/) [skip ci] 2026-05-16 18:37:58 +00:00
jmiller 26f80aafbc chore: move .mokogitea/gitleaks.yml to .gitea/gitleaks.yml [skip ci] 2026-05-16 18:37:58 +00:00
jmiller 3c72252ab5 chore: remove .mokogitea/deploy-manual.yml (moved to .gitea/) [skip ci] 2026-05-16 18:37:57 +00:00
jmiller 61a98ee393 chore: move .mokogitea/deploy-manual.yml to .gitea/deploy-manual.yml [skip ci] 2026-05-16 18:37:57 +00:00
jmiller c97ca5dca5 chore: remove .mokogitea/cleanup.yml (moved to .gitea/) [skip ci] 2026-05-16 18:37:56 +00:00
jmiller ea42677b61 chore: move .mokogitea/cleanup.yml to .gitea/cleanup.yml [skip ci] 2026-05-16 18:37:56 +00:00
jmiller 9cf7f89b64 chore: remove .mokogitea/ci-joomla.yml (moved to .gitea/) [skip ci] 2026-05-16 18:37:55 +00:00
jmiller 7290d6e19b chore: move .mokogitea/ci-joomla.yml to .gitea/ci-joomla.yml [skip ci] 2026-05-16 18:37:55 +00:00
jmiller 64cc1186a7 chore: remove .mokogitea/cascade-dev.yml (moved to .gitea/) [skip ci] 2026-05-16 18:37:54 +00:00
jmiller 0d3341558a chore: move .mokogitea/cascade-dev.yml to .gitea/cascade-dev.yml [skip ci] 2026-05-16 18:37:54 +00:00
jmiller 5513961c91 chore: remove .mokogitea/auto-release.yml (moved to .gitea/) [skip ci] 2026-05-16 18:37:54 +00:00
jmiller fe800ff6c0 chore: move .mokogitea/auto-release.yml to .gitea/auto-release.yml [skip ci] 2026-05-16 18:37:53 +00:00
jmiller 7f8930d388 chore: remove .mokogitea/ISSUE_TEMPLATE/version.md (moved to .gitea/) [skip ci] 2026-05-16 18:37:53 +00:00
jmiller 850cf197f8 chore: move .mokogitea/ISSUE_TEMPLATE/version.md to .gitea/ISSUE_TEMPLATE/version.md [skip ci] 2026-05-16 18:37:52 +00:00
jmiller c8e5cda9b4 chore: remove .mokogitea/ISSUE_TEMPLATE/security.md (moved to .gitea/) [skip ci] 2026-05-16 18:37:52 +00:00
jmiller 255ab24bb7 chore: move .mokogitea/ISSUE_TEMPLATE/security.md to .gitea/ISSUE_TEMPLATE/security.md [skip ci] 2026-05-16 18:37:51 +00:00
jmiller de3da37e61 chore: remove .mokogitea/ISSUE_TEMPLATE/rfc.md (moved to .gitea/) [skip ci] 2026-05-16 18:37:51 +00:00
jmiller e1a7e1ab81 chore: move .mokogitea/ISSUE_TEMPLATE/rfc.md to .gitea/ISSUE_TEMPLATE/rfc.md [skip ci] 2026-05-16 18:37:51 +00:00
jmiller 57bced4bd8 chore: remove .mokogitea/ISSUE_TEMPLATE/question.md (moved to .gitea/) [skip ci] 2026-05-16 18:37:50 +00:00
jmiller d3242702e1 chore: move .mokogitea/ISSUE_TEMPLATE/question.md to .gitea/ISSUE_TEMPLATE/question.md [skip ci] 2026-05-16 18:37:50 +00:00
jmiller 165c5d3722 chore: remove .mokogitea/ISSUE_TEMPLATE/joomla_issue.md (moved to .gitea/) [skip ci] 2026-05-16 18:37:49 +00:00
jmiller 7d75015e1c chore: move .mokogitea/ISSUE_TEMPLATE/joomla_issue.md to .gitea/ISSUE_TEMPLATE/joomla_issue.md [skip ci] 2026-05-16 18:37:49 +00:00
jmiller d9ea63bf0a chore: remove .mokogitea/ISSUE_TEMPLATE/feature_request.md (moved to .gitea/) [skip ci] 2026-05-16 18:37:49 +00:00
jmiller 5a1ca2a554 chore: move .mokogitea/ISSUE_TEMPLATE/feature_request.md to .gitea/ISSUE_TEMPLATE/feature_request.md [skip ci] 2026-05-16 18:37:48 +00:00
jmiller 58a6c7e4ec chore: remove .mokogitea/ISSUE_TEMPLATE/documentation.md (moved to .gitea/) [skip ci] 2026-05-16 18:37:48 +00:00
jmiller 7b1d49c02b chore: move .mokogitea/ISSUE_TEMPLATE/documentation.md to .gitea/ISSUE_TEMPLATE/documentation.md [skip ci] 2026-05-16 18:37:47 +00:00
jmiller 625124f5c7 chore: remove .mokogitea/ISSUE_TEMPLATE/config.yml (moved to .gitea/) [skip ci] 2026-05-16 18:37:47 +00:00
jmiller 4cb64e3d55 chore: move .mokogitea/ISSUE_TEMPLATE/config.yml to .gitea/ISSUE_TEMPLATE/config.yml [skip ci] 2026-05-16 18:37:46 +00:00
jmiller e9d5246c06 chore: remove .mokogitea/ISSUE_TEMPLATE/bug_report.md (moved to .gitea/) [skip ci] 2026-05-16 18:37:46 +00:00
jmiller df504bb6dd chore: move .mokogitea/ISSUE_TEMPLATE/bug_report.md to .gitea/ISSUE_TEMPLATE/bug_report.md [skip ci] 2026-05-16 18:37:46 +00:00
jmiller 071ea4757f chore: remove .mokogitea/ISSUE_TEMPLATE/adr.md (moved to .gitea/) [skip ci] 2026-05-16 18:37:45 +00:00
jmiller 569b9a8631 chore: move .mokogitea/ISSUE_TEMPLATE/adr.md to .gitea/ISSUE_TEMPLATE/adr.md [skip ci] 2026-05-16 18:37:45 +00:00
jmiller b85d10257d fix(ci): platform auto-sense, .mokogitea precedence, remove GitHub mirror [skip ci] 2026-05-16 18:27:14 +00:00
jmiller 5acc86b2e1 fix(ci): auto-release on PR merge + dispatch, bump dev after [skip ci] 2026-05-16 18:00:39 +00:00
jmiller 6300095f54 fix(ci): restrict auto-release to workflow_dispatch only [skip ci] 2026-05-16 17:57:21 +00:00
jmiller 76411fc6e6 fix(ci): deploy auto-release with new version bump protocol [skip ci] 2026-05-16 17:41:45 +00:00
Jonathan Miller 4ab1d2ba61 feat(ci): add changelog gate to PR checks [skip ci]
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-16 09:09:17 -05:00
Jonathan Miller ef648d0582 chore(ci): version bump targets dev branch instead of main [skip ci]
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-16 09:04:18 -05:00
jmiller 511c98a2b4 chore: force-sync .mokogitea/ISSUE_TEMPLATE/version.md [skip ci] 2026-05-12 19:16:33 +00:00
jmiller 04d874bf55 chore: force-sync .mokogitea/ISSUE_TEMPLATE/security.md [skip ci] 2026-05-12 19:16:33 +00:00
jmiller beabd97294 chore: force-sync .mokogitea/ISSUE_TEMPLATE/rfc.md [skip ci] 2026-05-12 19:16:32 +00:00
jmiller 59f189c9dd chore: force-sync .mokogitea/ISSUE_TEMPLATE/question.md [skip ci] 2026-05-12 19:16:32 +00:00
jmiller e43bd1db82 chore: force-sync .mokogitea/ISSUE_TEMPLATE/joomla_issue.md [skip ci] 2026-05-12 19:16:32 +00:00
jmiller 2f8d5635f6 chore: force-sync .mokogitea/ISSUE_TEMPLATE/feature_request.md [skip ci] 2026-05-12 19:16:31 +00:00
jmiller 1e05f60cd8 chore: force-sync .mokogitea/ISSUE_TEMPLATE/documentation.md [skip ci] 2026-05-12 19:16:31 +00:00
jmiller ac0b3eb233 chore: force-sync .mokogitea/ISSUE_TEMPLATE/config.yml [skip ci] 2026-05-12 19:16:30 +00:00
jmiller ab4e31d7c8 chore: force-sync .mokogitea/ISSUE_TEMPLATE/bug_report.md [skip ci] 2026-05-12 19:16:30 +00:00
jmiller dc4342142b chore: force-sync .mokogitea/ISSUE_TEMPLATE/adr.md [skip ci] 2026-05-12 19:16:30 +00:00
jmiller ec3b3e44a3 chore: force-sync .mokogitea/workflows/update-server.yml [skip ci] 2026-05-12 19:16:29 +00:00
jmiller b37c3c6c32 chore: force-sync .mokogitea/workflows/security-audit.yml [skip ci] 2026-05-12 19:16:29 +00:00
jmiller 481388e793 chore: force-sync .mokogitea/workflows/repo-health.yml [skip ci] 2026-05-12 19:16:28 +00:00
jmiller 490c0769b5 chore: force-sync .mokogitea/workflows/pre-release.yml [skip ci] 2026-05-12 19:16:28 +00:00
jmiller 5206a96ae4 chore: force-sync .mokogitea/workflows/pr-check.yml [skip ci] 2026-05-12 19:16:28 +00:00
jmiller cd3f0ec5da chore: force-sync .mokogitea/workflows/notify.yml [skip ci] 2026-05-12 19:16:27 +00:00
jmiller 08f5bc0bf9 chore: force-sync .mokogitea/workflows/gitleaks.yml [skip ci] 2026-05-12 19:16:27 +00:00
jmiller 5efbae0994 chore: force-sync .mokogitea/workflows/deploy-manual.yml [skip ci] 2026-05-12 19:16:27 +00:00
jmiller 5ae3b07e16 chore: force-sync .mokogitea/workflows/cleanup.yml [skip ci] 2026-05-12 19:16:26 +00:00
jmiller dce6ba7748 chore: force-sync .mokogitea/workflows/ci-joomla.yml [skip ci] 2026-05-12 19:16:26 +00:00
jmiller b61c2a75d9 chore: force-sync .mokogitea/workflows/cascade-dev.yml [skip ci] 2026-05-12 19:16:25 +00:00
jmiller f6a6bc39eb chore: force-sync .mokogitea/workflows/auto-release.yml [skip ci] 2026-05-12 19:16:25 +00:00
jmiller c8b4772341 chore: force-sync .mokogitea/ISSUE_TEMPLATE/version.md [skip ci] 2026-05-12 19:11:23 +00:00
jmiller 870e2c071b chore: force-sync .mokogitea/ISSUE_TEMPLATE/security.md [skip ci] 2026-05-12 19:11:22 +00:00
jmiller 584cd60db8 chore: force-sync .mokogitea/ISSUE_TEMPLATE/rfc.md [skip ci] 2026-05-12 19:11:22 +00:00
jmiller feea10173a chore: force-sync .mokogitea/ISSUE_TEMPLATE/question.md [skip ci] 2026-05-12 19:11:21 +00:00
jmiller ea0b9e462a chore: force-sync .mokogitea/ISSUE_TEMPLATE/joomla_issue.md [skip ci] 2026-05-12 19:11:21 +00:00
jmiller a128cdde42 chore: force-sync .mokogitea/ISSUE_TEMPLATE/feature_request.md [skip ci] 2026-05-12 19:11:21 +00:00
jmiller fe51b7638c chore: force-sync .mokogitea/ISSUE_TEMPLATE/documentation.md [skip ci] 2026-05-12 19:11:20 +00:00
jmiller c90c015814 chore: force-sync .mokogitea/ISSUE_TEMPLATE/config.yml [skip ci] 2026-05-12 19:11:20 +00:00
jmiller 87d59df3e1 chore: force-sync .mokogitea/ISSUE_TEMPLATE/bug_report.md [skip ci] 2026-05-12 19:11:19 +00:00
jmiller cc92296fd5 chore: force-sync .mokogitea/ISSUE_TEMPLATE/adr.md [skip ci] 2026-05-12 19:11:19 +00:00
jmiller 8f6c66fd2c chore: force-sync .mokogitea/workflows/update-server.yml [skip ci] 2026-05-12 19:11:18 +00:00
jmiller 2bd95a8914 chore: force-sync .mokogitea/workflows/security-audit.yml [skip ci] 2026-05-12 19:11:18 +00:00
jmiller 2af99417f4 chore: force-sync .mokogitea/workflows/repo-health.yml [skip ci] 2026-05-12 19:11:18 +00:00
jmiller 4411949b49 chore: force-sync .mokogitea/workflows/pre-release.yml [skip ci] 2026-05-12 19:11:17 +00:00
jmiller 1bad61d155 chore: force-sync .mokogitea/workflows/pr-check.yml [skip ci] 2026-05-12 19:11:17 +00:00
jmiller 3582ca6336 chore: force-sync .mokogitea/workflows/notify.yml [skip ci] 2026-05-12 19:11:17 +00:00
jmiller 2e70a2f2ad chore: force-sync .mokogitea/workflows/gitleaks.yml [skip ci] 2026-05-12 19:11:16 +00:00
jmiller c1fbc1905e chore: force-sync .mokogitea/workflows/deploy-manual.yml [skip ci] 2026-05-12 19:11:16 +00:00
jmiller 50d8af7bd7 chore: force-sync .mokogitea/workflows/cleanup.yml [skip ci] 2026-05-12 19:11:15 +00:00
jmiller 7a6f2e0125 chore: force-sync .mokogitea/workflows/ci-joomla.yml [skip ci] 2026-05-12 19:11:15 +00:00
jmiller 09c0e84936 chore: force-sync .mokogitea/workflows/cascade-dev.yml [skip ci] 2026-05-12 19:11:15 +00:00
jmiller 983f32631d chore: force-sync .mokogitea/workflows/auto-release.yml [skip ci] 2026-05-12 19:11:14 +00:00
jmiller cc798c0fd3 chore: remove .mokogitea/.moko-platform [skip ci] 2026-05-12 19:08:46 +00:00
jmiller f8ea5f7698 chore: force-sync .mokogitea/ISSUE_TEMPLATE/version.md [skip ci] 2026-05-12 19:08:45 +00:00
jmiller 65678e7a7b chore: force-sync .mokogitea/ISSUE_TEMPLATE/security.md [skip ci] 2026-05-12 19:08:45 +00:00
jmiller 432e520544 chore: force-sync .mokogitea/ISSUE_TEMPLATE/rfc.md [skip ci] 2026-05-12 19:08:44 +00:00
jmiller c437e671ed chore: force-sync .mokogitea/ISSUE_TEMPLATE/question.md [skip ci] 2026-05-12 19:08:44 +00:00
jmiller bf6b0a2ab0 chore: force-sync .mokogitea/ISSUE_TEMPLATE/joomla_issue.md [skip ci] 2026-05-12 19:08:44 +00:00
jmiller b2400c4ef7 chore: force-sync .mokogitea/ISSUE_TEMPLATE/feature_request.md [skip ci] 2026-05-12 19:08:43 +00:00
jmiller 9c04d6c84a chore: force-sync .mokogitea/ISSUE_TEMPLATE/documentation.md [skip ci] 2026-05-12 19:08:43 +00:00
jmiller ba929326ff chore: force-sync .mokogitea/ISSUE_TEMPLATE/config.yml [skip ci] 2026-05-12 19:08:42 +00:00
jmiller 95e4f89256 chore: force-sync .mokogitea/ISSUE_TEMPLATE/bug_report.md [skip ci] 2026-05-12 19:08:42 +00:00
jmiller 9052778091 chore: force-sync .mokogitea/ISSUE_TEMPLATE/adr.md [skip ci] 2026-05-12 19:08:42 +00:00
jmiller f5d5fef1bb chore: force-sync .mokogitea/workflows/update-server.yml [skip ci] 2026-05-12 19:08:41 +00:00
jmiller ca6998c9f6 chore: force-sync .mokogitea/workflows/security-audit.yml [skip ci] 2026-05-12 19:08:41 +00:00
jmiller 9f55fe2264 chore: force-sync .mokogitea/workflows/repo-health.yml [skip ci] 2026-05-12 19:08:40 +00:00
jmiller 3862eff934 chore: force-sync .mokogitea/workflows/pre-release.yml [skip ci] 2026-05-12 19:08:40 +00:00
jmiller b40a649e8b chore: force-sync .mokogitea/workflows/pr-check.yml [skip ci] 2026-05-12 19:08:40 +00:00
jmiller a35f6a839b chore: force-sync .mokogitea/workflows/notify.yml [skip ci] 2026-05-12 19:08:39 +00:00
jmiller 52c18f1b90 chore: force-sync .mokogitea/workflows/gitleaks.yml [skip ci] 2026-05-12 19:08:39 +00:00
jmiller 7ef7298cdd chore: force-sync .mokogitea/workflows/deploy-manual.yml [skip ci] 2026-05-12 19:08:39 +00:00
jmiller 730bad5f77 chore: force-sync .mokogitea/workflows/cleanup.yml [skip ci] 2026-05-12 19:08:38 +00:00
jmiller 78873d6187 chore: force-sync .mokogitea/workflows/ci-joomla.yml [skip ci] 2026-05-12 19:08:38 +00:00
jmiller 7cd2a817fa chore: force-sync .mokogitea/workflows/cascade-dev.yml [skip ci] 2026-05-12 19:08:37 +00:00
jmiller 2188eca5d5 chore: force-sync .mokogitea/workflows/auto-release.yml [skip ci] 2026-05-12 19:08:37 +00:00
jmiller 95eee47151 chore: sync .mokogitea/ISSUE_TEMPLATE/version.md from template [skip ci] 2026-05-12 18:46:56 +00:00
jmiller cff9acb79a chore: sync .mokogitea/ISSUE_TEMPLATE/security.md from template [skip ci] 2026-05-12 18:46:56 +00:00
jmiller 632bb1f1b5 chore: sync .mokogitea/ISSUE_TEMPLATE/rfc.md from template [skip ci] 2026-05-12 18:46:55 +00:00
jmiller 0e71dc25c7 chore: sync .mokogitea/ISSUE_TEMPLATE/question.md from template [skip ci] 2026-05-12 18:46:55 +00:00
jmiller d180994dc3 chore: sync .mokogitea/ISSUE_TEMPLATE/joomla_issue.md from template [skip ci] 2026-05-12 18:46:55 +00:00
jmiller 73966f7da6 chore: sync .mokogitea/ISSUE_TEMPLATE/feature_request.md from template [skip ci] 2026-05-12 18:46:54 +00:00
jmiller 5a10145dec chore: sync .mokogitea/ISSUE_TEMPLATE/documentation.md from template [skip ci] 2026-05-12 18:46:54 +00:00
jmiller 5c586b1c61 chore: sync .mokogitea/ISSUE_TEMPLATE/config.yml from template [skip ci] 2026-05-12 18:46:53 +00:00
jmiller d52fb497ac chore: sync .mokogitea/ISSUE_TEMPLATE/bug_report.md from template [skip ci] 2026-05-12 18:46:53 +00:00
jmiller a8a4cf7cd4 chore: sync .mokogitea/ISSUE_TEMPLATE/adr.md from template [skip ci] 2026-05-12 18:46:53 +00:00
jmiller 36e8dbeb52 chore: sync .mokogitea/workflows/update-server.yml from template [skip ci] 2026-05-12 18:46:52 +00:00
jmiller 3819a132f4 chore: sync .mokogitea/workflows/security-audit.yml from template [skip ci] 2026-05-12 18:46:52 +00:00
jmiller 5a74095ec7 chore: sync .mokogitea/workflows/repo-health.yml from template [skip ci] 2026-05-12 18:46:51 +00:00
jmiller ace1603fce chore: sync .mokogitea/workflows/pre-release.yml from template [skip ci] 2026-05-12 18:46:51 +00:00
jmiller 5271cc3699 chore: sync .mokogitea/workflows/pr-check.yml from template [skip ci] 2026-05-12 18:46:51 +00:00
jmiller 695c85df5c chore: sync .mokogitea/workflows/notify.yml from template [skip ci] 2026-05-12 18:46:50 +00:00
jmiller 656073cfba chore: sync .mokogitea/workflows/gitleaks.yml from template [skip ci] 2026-05-12 18:46:50 +00:00
jmiller 6c98b3c403 chore: sync .mokogitea/workflows/deploy-manual.yml from template [skip ci] 2026-05-12 18:46:50 +00:00
jmiller 77a1f84f86 chore: sync .mokogitea/workflows/cleanup.yml from template [skip ci] 2026-05-12 18:46:49 +00:00
jmiller d9b93ceec2 chore: sync .mokogitea/workflows/ci-joomla.yml from template [skip ci] 2026-05-12 18:46:49 +00:00
jmiller acad220640 chore: sync .mokogitea/workflows/cascade-dev.yml from template [skip ci] 2026-05-12 18:46:48 +00:00
jmiller a57e060d65 chore: sync .mokogitea/workflows/auto-release.yml from template [skip ci] 2026-05-12 18:46:48 +00:00
jmiller dec5fdf040 chore: sync .mokogitea/ISSUE_TEMPLATE/version.md from template [skip ci] 2026-05-12 18:37:26 +00:00
jmiller aec4e04bf0 chore: sync .mokogitea/ISSUE_TEMPLATE/security.md from template [skip ci] 2026-05-12 18:37:25 +00:00
jmiller 3892f5523d chore: sync .mokogitea/ISSUE_TEMPLATE/rfc.md from template [skip ci] 2026-05-12 18:37:25 +00:00
jmiller 4c8a927585 chore: sync .mokogitea/ISSUE_TEMPLATE/question.md from template [skip ci] 2026-05-12 18:37:25 +00:00
jmiller 45eacb425d chore: sync .mokogitea/ISSUE_TEMPLATE/joomla_issue.md from template [skip ci] 2026-05-12 18:37:24 +00:00
jmiller 7924fd9248 chore: sync .mokogitea/ISSUE_TEMPLATE/feature_request.md from template [skip ci] 2026-05-12 18:37:24 +00:00
jmiller 3a6fa0393b chore: sync .mokogitea/ISSUE_TEMPLATE/documentation.md from template [skip ci] 2026-05-12 18:37:23 +00:00
jmiller 743447c3a9 chore: sync .mokogitea/ISSUE_TEMPLATE/config.yml from template [skip ci] 2026-05-12 18:37:23 +00:00
jmiller b07c4e57bf chore: sync .mokogitea/ISSUE_TEMPLATE/bug_report.md from template [skip ci] 2026-05-12 18:37:22 +00:00
jmiller 1d332e958b chore: sync .mokogitea/ISSUE_TEMPLATE/adr.md from template [skip ci] 2026-05-12 18:37:22 +00:00
jmiller 96e03775ae chore: sync .mokogitea/workflows/update-server.yml from template [skip ci] 2026-05-12 18:37:22 +00:00
jmiller 5aa915b533 chore: sync .mokogitea/workflows/security-audit.yml from template [skip ci] 2026-05-12 18:37:21 +00:00
jmiller 6650eb3ef8 chore: sync .mokogitea/workflows/repo-health.yml from template [skip ci] 2026-05-12 18:37:21 +00:00
jmiller 8441454d39 chore: sync .mokogitea/workflows/pre-release.yml from template [skip ci] 2026-05-12 18:37:20 +00:00
jmiller 2d536d9dfe chore: sync .mokogitea/workflows/pr-check.yml from template [skip ci] 2026-05-12 18:37:20 +00:00
jmiller 33c7fc225a chore: sync .mokogitea/workflows/notify.yml from template [skip ci] 2026-05-12 18:37:20 +00:00
jmiller 29a765b0d5 chore: sync .mokogitea/workflows/gitleaks.yml from template [skip ci] 2026-05-12 18:37:19 +00:00
jmiller 30947d8a43 chore: sync .mokogitea/workflows/deploy-manual.yml from template [skip ci] 2026-05-12 18:37:19 +00:00
jmiller 713dc72a21 chore: sync .mokogitea/workflows/cleanup.yml from template [skip ci] 2026-05-12 18:37:18 +00:00
jmiller ef289d2366 chore: sync .mokogitea/workflows/ci-joomla.yml from template [skip ci] 2026-05-12 18:37:18 +00:00
jmiller e7bc3511f2 chore: sync .mokogitea/workflows/cascade-dev.yml from template [skip ci] 2026-05-12 18:37:18 +00:00
jmiller aad2e17eed chore: sync .mokogitea/workflows/auto-release.yml from template [skip ci] 2026-05-12 18:37:17 +00:00
jmiller 559c48363f chore: sync .mokogitea/workflows/update-server.yml from template [skip ci] 2026-05-12 05:31:02 +00:00
jmiller c81e483366 chore: sync .mokogitea/workflows/security-audit.yml from template [skip ci] 2026-05-12 05:31:02 +00:00
jmiller fc92366acc chore: sync .mokogitea/workflows/repo-health.yml from template [skip ci] 2026-05-12 05:31:02 +00:00
jmiller 80922179de chore: sync .mokogitea/workflows/pre-release.yml from template [skip ci] 2026-05-12 05:31:01 +00:00
jmiller 70b28cdf0b chore: sync .mokogitea/workflows/pr-check.yml from template [skip ci] 2026-05-12 05:31:01 +00:00
jmiller 57d477149f chore: sync .mokogitea/workflows/notify.yml from template [skip ci] 2026-05-12 05:31:01 +00:00
jmiller 9b7f2a3514 chore: sync .mokogitea/workflows/gitleaks.yml from template [skip ci] 2026-05-12 05:31:00 +00:00
jmiller a975d3b7eb chore: sync .mokogitea/workflows/deploy-manual.yml from template [skip ci] 2026-05-12 05:31:00 +00:00
jmiller 58f536bffc chore: sync .mokogitea/workflows/cleanup.yml from template [skip ci] 2026-05-12 05:30:59 +00:00
jmiller 94eeb1dab1 chore: sync .mokogitea/workflows/ci-joomla.yml from template [skip ci] 2026-05-12 05:30:59 +00:00
jmiller 1c776d3a0f chore: sync .mokogitea/workflows/cascade-dev.yml from template [skip ci] 2026-05-12 05:30:59 +00:00
jmiller 5f061c0e2f chore: sync .mokogitea/workflows/auto-release.yml from template [skip ci] 2026-05-12 05:30:58 +00:00
jmiller 30b12bd1de chore: sync .mokogitea/ISSUE_TEMPLATE/version.md from template [skip ci] 2026-05-12 05:30:58 +00:00
jmiller d95ffb02c0 chore: sync .mokogitea/ISSUE_TEMPLATE/security.md from template [skip ci] 2026-05-12 05:30:58 +00:00
jmiller eb9b7ac25d chore: sync .mokogitea/ISSUE_TEMPLATE/rfc.md from template [skip ci] 2026-05-12 05:30:57 +00:00
jmiller 8ede04c284 chore: sync .mokogitea/ISSUE_TEMPLATE/question.md from template [skip ci] 2026-05-12 05:30:57 +00:00
jmiller b913b36232 chore: sync .mokogitea/ISSUE_TEMPLATE/joomla_issue.md from template [skip ci] 2026-05-12 05:30:57 +00:00
jmiller 21b1771380 chore: sync .mokogitea/ISSUE_TEMPLATE/feature_request.md from template [skip ci] 2026-05-12 05:30:56 +00:00
jmiller e24c21e123 chore: sync .mokogitea/ISSUE_TEMPLATE/documentation.md from template [skip ci] 2026-05-12 05:30:56 +00:00
jmiller 2bfd19fa63 chore: sync .mokogitea/ISSUE_TEMPLATE/config.yml from template [skip ci] 2026-05-12 05:30:56 +00:00
jmiller adc44004be chore: sync .mokogitea/ISSUE_TEMPLATE/bug_report.md from template [skip ci] 2026-05-12 05:30:55 +00:00
jmiller 5000d38294 chore: sync .mokogitea/ISSUE_TEMPLATE/adr.md from template [skip ci] 2026-05-12 05:30:55 +00:00
jmiller 51674d4b04 chore: sync .mokogitea/.moko-platform from template [skip ci] 2026-05-12 05:30:55 +00:00
jmiller 3f6a1d2278 chore: remove .gitea/workflows/update-server.yml (moved to .mokogitea/) [skip ci] 2026-05-12 04:58:08 +00:00
jmiller b61b9aac37 chore: move .gitea/workflows/update-server.yml to .mokogitea/update-server.yml [skip ci] 2026-05-12 04:58:08 +00:00
jmiller 7ed55a577f chore: remove .gitea/workflows/sync-roadmap-wiki.yml (moved to .mokogitea/) [skip ci] 2026-05-12 04:58:08 +00:00
jmiller 924fe39a7b chore: move .gitea/workflows/sync-roadmap-wiki.yml to .mokogitea/sync-roadmap-wiki.yml [skip ci] 2026-05-12 04:58:07 +00:00
jmiller 64d7b4a93c chore: remove .gitea/workflows/security-audit.yml (moved to .mokogitea/) [skip ci] 2026-05-12 04:58:07 +00:00
jmiller c7427325b7 chore: move .gitea/workflows/security-audit.yml to .mokogitea/security-audit.yml [skip ci] 2026-05-12 04:58:07 +00:00
jmiller 21f4e7c655 chore: remove .gitea/workflows/repo-health.yml (moved to .mokogitea/) [skip ci] 2026-05-12 04:58:06 +00:00
jmiller 978e88dfb1 chore: move .gitea/workflows/repo-health.yml to .mokogitea/repo-health.yml [skip ci] 2026-05-12 04:58:06 +00:00
jmiller decab5f80e chore: remove .gitea/workflows/pre-release.yml (moved to .mokogitea/) [skip ci] 2026-05-12 04:58:05 +00:00
jmiller 594c5ebb48 chore: move .gitea/workflows/pre-release.yml to .mokogitea/pre-release.yml [skip ci] 2026-05-12 04:58:05 +00:00
jmiller bbf89e9f61 chore: remove .gitea/workflows/pr-check.yml (moved to .mokogitea/) [skip ci] 2026-05-12 04:58:05 +00:00
jmiller e0dd66c1f7 chore: move .gitea/workflows/pr-check.yml to .mokogitea/pr-check.yml [skip ci] 2026-05-12 04:58:04 +00:00
jmiller a0f83db86e chore: remove .gitea/workflows/pr-branch-check.yml (moved to .mokogitea/) [skip ci] 2026-05-12 04:58:04 +00:00
jmiller afbcfc7f07 chore: move .gitea/workflows/pr-branch-check.yml to .mokogitea/pr-branch-check.yml [skip ci] 2026-05-12 04:58:04 +00:00
jmiller 8bd22a53e4 chore: remove .gitea/workflows/notify.yml (moved to .mokogitea/) [skip ci] 2026-05-12 04:58:03 +00:00
jmiller 69d9335ad6 chore: move .gitea/workflows/notify.yml to .mokogitea/notify.yml [skip ci] 2026-05-12 04:58:03 +00:00
jmiller 987e137db3 chore: remove .gitea/workflows/gitleaks.yml (moved to .mokogitea/) [skip ci] 2026-05-12 04:58:03 +00:00
jmiller 5a68945b96 chore: move .gitea/workflows/gitleaks.yml to .mokogitea/gitleaks.yml [skip ci] 2026-05-12 04:58:02 +00:00
jmiller 29f7ad8459 chore: remove .gitea/workflows/deploy-manual.yml (moved to .mokogitea/) [skip ci] 2026-05-12 04:58:02 +00:00
jmiller 90fee9905a chore: move .gitea/workflows/deploy-manual.yml to .mokogitea/deploy-manual.yml [skip ci] 2026-05-12 04:58:02 +00:00
jmiller d19c1efd40 chore: remove .gitea/workflows/cleanup.yml (moved to .mokogitea/) [skip ci] 2026-05-12 04:58:01 +00:00
jmiller 301f861431 chore: move .gitea/workflows/cleanup.yml to .mokogitea/cleanup.yml [skip ci] 2026-05-12 04:58:01 +00:00
jmiller 866b7c86df chore: remove .gitea/workflows/ci-joomla.yml (moved to .mokogitea/) [skip ci] 2026-05-12 04:58:00 +00:00
jmiller 25f7e7bfe5 chore: move .gitea/workflows/ci-joomla.yml to .mokogitea/ci-joomla.yml [skip ci] 2026-05-12 04:58:00 +00:00
jmiller 2eed2e88f3 chore: remove .gitea/workflows/cascade-dev.yml (moved to .mokogitea/) [skip ci] 2026-05-12 04:58:00 +00:00
jmiller 153ad6cc28 chore: move .gitea/workflows/cascade-dev.yml to .mokogitea/cascade-dev.yml [skip ci] 2026-05-12 04:57:59 +00:00
jmiller 994974e6c9 chore: remove .gitea/workflows/auto-release.yml (moved to .mokogitea/) [skip ci] 2026-05-12 04:57:59 +00:00
jmiller 24d866e2c0 chore: move .gitea/workflows/auto-release.yml to .mokogitea/auto-release.yml [skip ci] 2026-05-12 04:57:59 +00:00
jmiller 8bbe2cae21 chore: remove .gitea/.moko-platform (moved to .mokogitea/) [skip ci] 2026-05-12 04:57:58 +00:00
jmiller 71997cd9fa chore: move .gitea/.moko-platform to .mokogitea/.moko-platform [skip ci] 2026-05-12 04:57:58 +00:00
jmiller e985ea2e2b chore: sync repo-health.yml from Template-Joomla [skip ci] 2026-05-11 21:23:05 +00:00
jmiller bd7cebe762 chore: sync pre-release.yml from Template-Joomla [skip ci] 2026-05-11 21:23:04 +00:00
jmiller 2f9f4b562b chore: sync notify.yml from Template-Joomla [skip ci] 2026-05-11 21:23:00 +00:00
jmiller bdc073b285 chore: sync auto-release.yml from Template-Joomla [skip ci] 2026-05-11 21:22:54 +00:00
jmiller 672f4c423a chore: add PR branch policy check workflow [skip ci] 2026-05-11 17:15:38 +00:00
jmiller 2ed90b5116 chore: sync auto-release.yml with changelog+SHA+pretty-name fixes [skip ci] 2026-05-11 16:43:31 +00:00
jmiller da0a202e8b chore: sync auto-release.yml from MokoGalleryCalendar [skip ci] 2026-05-11 16:41:19 +00:00
jmiller 009b5b7c3c chore: remove renovate.json [skip ci] 2026-05-10 19:57:27 +00:00
jmiller 061e8daa34 docs: add CLAUDE.md for Claude Code context [skip ci] 2026-05-10 19:55:23 +00:00
jmiller edf1e16fee chore: remove .claude/ from version control [skip ci] 2026-05-10 19:48:19 +00:00
24 changed files with 2693 additions and 3915 deletions
-59
View File
@@ -1,59 +0,0 @@
{
"permissions": {
"allow": [
"Bash(cd:*)",
"mcp__joomla-api__joomla_plugins_list",
"mcp__gitea-moko__get_repository_tree",
"mcp__joomla-api__joomla_api_request",
"Bash(curl:*)",
"mcp__gitea-moko__search_repos",
"Bash(TOKEN=\"29367101e6edf28375e0a03cef30a7dfc7eb2186\"\ncurl -sS -H \"Authorization: token $TOKEN\" \"https://git.mokoconsulting.tech/api/v1/repos/MokoConsulting/MokoOnyx/contents/.gitea/workflows/release.yml?ref=main\" | head -200)",
"mcp__gitea-moko__list_releases",
"mcp__gitea-moko__delete_release",
"mcp__gitea-moko__get_latest_release",
"mcp__gitea-moko__actions_run_read",
"Read(//a/MokoStandards-API/.gitea/**)",
"Read(//a/MokoStandards-API/**)",
"Read(//a/MokoStandards-Template-Joomla-Template/.gitea/workflows/**)",
"Read(//a/MokoStandards-Template-Joomla-Module/.gitea/workflows/**)",
"Read(//a/MokoStandards-Template-Joomla-Component/.gitea/workflows/**)",
"Read(//a/MokoStandards-Template-Joomla-Package/.gitea/workflows/**)",
"Read(//a/MokoStandards-Template-Joomla-Library/.gitea/workflows/**)",
"Read(//a/MokoJGDPC/.gitea/workflows/**)",
"Read(//a/MokoCassiopeia/.gitea/workflows/**)",
"Read(//a/MokoJoomHero/.gitea/workflows/**)",
"Read(//a/MokoJoomTOS/.gitea/workflows/**)",
"Read(//a/MokoWaaS/.gitea/workflows/**)",
"Read(//a/MokoWaaSAnnounce/.gitea/workflows/**)",
"Bash(REPOS=\"MokoDPCalendarAPI MokoJGDPC MokoCassiopeia MokoJoomHero MokoJoomTOS MokoWaaS MokoWaaSAnnounce\"\n\nfor REPO in $REPOS; do\n echo \"=== $REPO ===\"\n cd \"A:/$REPO\"\n git pull --rebase origin main 2>&1 | tail -1\n rm -f .gitea/workflows/*.yml\n cp A:/MokoOnyx/.gitea/workflows/*.yml .gitea/workflows/\n git add .gitea/workflows/\n if git diff --cached --quiet; then\n echo \" No changes\"\n else\n git commit -m \"feat: expand workflow suite \\(10 workflows from MokoOnyx\\)\n\nCo-Authored-By: Claude Opus 4.6 \\(1M context\\) <noreply@anthropic.com>\"\n git push origin main 2>&1 | tail -1\n fi\n echo \"\"\ndone)",
"mcp__gitea-moko__actions_config_read",
"mcp__gitea-moko__actions_config_write",
"Bash(REPOS=\"MokoDPCalendarAPI MokoJGDPC MokoCassiopeia MokoJoomHero MokoJoomTOS MokoWaaS MokoWaaSAnnounce MokoStandards-Template-Joomla-Plugin MokoStandards-Template-Joomla-Template MokoStandards-Template-Joomla-Module MokoStandards-Template-Joomla-Component MokoStandards-Template-Joomla-Package MokoStandards-Template-Joomla-Library MokoStandards-API\"\n\nfor REPO in $REPOS; do\n echo \"=== $REPO ===\"\n cd \"A:/$REPO\"\n git pull --rebase origin main 2>&1 | tail -1\n cp A:/MokoOnyx/.gitea/workflows/pre-release.yml .gitea/workflows/pre-release.yml\n git add .gitea/workflows/pre-release.yml\n if git diff --cached --quiet; then\n echo \" No changes\"\n else\n git commit -m \"feat: add pre-release workflow for manual dev/alpha/beta/rc builds\n\nCo-Authored-By: Claude Opus 4.6 \\(1M context\\) <noreply@anthropic.com>\"\n git push origin main 2>&1 | tail -1\n fi\n echo \"\"\ndone)",
"Bash(tail -1 rm .gitea/workflows/deploy.yml git add .gitea/workflows/deploy.yml git commit -m \"chore: remove auto-deploy workflow \\(deploy is manual only\\):*)",
"mcp__gitea-moko__pull_request_write",
"mcp__gitea-moko__actions_run_write",
"Bash(REPOS=\"MokoDPCalendarAPI MokoJGDPC MokoCassiopeia MokoJoomHero MokoJoomTOS MokoWaaS MokoWaaSAnnounce MokoStandards-Template-Joomla-Plugin MokoStandards-Template-Joomla-Template MokoStandards-Template-Joomla-Module MokoStandards-Template-Joomla-Component MokoStandards-Template-Joomla-Package MokoStandards-Template-Joomla-Library MokoStandards-API\" __NEW_LINE_0c05a93337c7dba4__ for REPO in $REPOS)",
"Bash(do cd:*)",
"Bash(then echo \"$REPO: no changes\" else git commit -m \"fix: add patch version bump to pre-release workflow:*)",
"Bash(for REPO in client-clarksvillefurs client-kiddieland)",
"Bash(do echo:*)",
"Read(//a/MokoStandards-Template-Client/.gitea/workflows/**)",
"Bash(then echo \" No changes\" else git commit -m \"feat: add standard client workflow suite + media sync:*)",
"Bash(for:*)",
"mcp__gitea-moko__create_repo",
"Bash(REPOS=\"MokoDPCalendarAPI MokoJGDPC MokoCassiopeia MokoJoomHero MokoJoomTOS MokoWaaS MokoWaaSAnnounce MokoStandards-Template-Joomla\" __NEW_LINE_ef3af20e9774ebe9__ for REPO in $REPOS)",
"Bash(then echo \"$REPO: no changes\" else git commit -m \"fix: version bump logic — stable=minor, pre-release=patch:*)",
"Bash(then continue fi git commit -m \"fix: version bump logic — pre-release=patch with rollover:*)",
"Bash(REPOS=\"MokoDPCalendarAPI MokoJGDPC MokoCassiopeia MokoJoomHero MokoJoomTOS MokoWaaS MokoWaaSAnnounce MokoStandards-Template-Joomla\" __NEW_LINE_a82c045e0ae69651__ for REPO in $REPOS)",
"Bash(then continue:*)",
"Bash(fi git commit -m \"fix: stable release = major version bump \\(XX+1.00.00\\):*)",
"mcp__gitea-moko__get_release",
"Bash(ALL_REPOS=\"MokoDPCalendarAPI MokoJGDPC MokoCassiopeia MokoJoomHero MokoJoomTOS MokoWaaS MokoWaaSAnnounce MokoStandards-Template-Joomla\" __NEW_LINE_fbd28532f2d35636__ for REPO in $ALL_REPOS)",
"Bash(fi git commit -m \"fix: include element name in stable release title:*)"
]
},
"enableAllProjectMcpServers": true,
"enabledMcpjsonServers": [
"joomla-api"
]
}
File diff suppressed because it is too large Load Diff
+251
View File
@@ -0,0 +1,251 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
# SPDX-License-Identifier: GPL-3.0-or-later
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.Automation
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
# PATH: /.gitea/workflows/branch-protection.yml
# BRIEF: Apply standardised branch protection rules to all governed repositories
#
# +========================================================================+
# | BRANCH PROTECTION SETUP |
# +========================================================================+
# | |
# | Applies protection rules for: main, dev, rc, beta, alpha |
# | |
# | main — Require PR, block rejected reviews, no force push |
# | dev — Allow push, no force push, no delete |
# | rc — Allow push, no force push, no delete |
# | beta — Allow push, no force push, no delete |
# | alpha — Allow push, no force push, no delete |
# | |
# | jmiller has override authority on all branches. |
# | |
# +========================================================================+
name: Branch Protection Setup
on:
schedule:
- cron: '0 2 * * 1' # Weekly Monday 02:00 UTC
workflow_dispatch:
inputs:
dry_run:
description: 'Preview mode (no changes)'
required: false
type: boolean
default: false
repos:
description: 'Comma-separated repo names (empty = all governed repos)'
required: false
type: string
default: ''
env:
GITEA_URL: https://git.mokoconsulting.tech
GITEA_ORG: MokoConsulting
permissions:
contents: read
jobs:
protect:
name: Apply Branch Protection Rules
runs-on: ubuntu-latest
steps:
- name: Determine target repos
id: repos
env:
GA_TOKEN: ${{ secrets.GA_TOKEN }}
run: |
API="${GITEA_URL}/api/v1"
# Platform/standards/infra repos to exclude
EXCLUDE="gitea-org-config org-profile gitea-private .mokogitea-private MokoStandards moko-platform MokoTesting"
EXCLUDE="$EXCLUDE MokoStandards-Template-Client MokoStandards-Template-Dolibarr MokoStandards-Template-Generic MokoStandards-Template-Joomla MokoDoliProjTemplate"
if [ -n "${{ inputs.repos }}" ]; then
# User-specified repos
REPOS=$(echo "${{ inputs.repos }}" | tr ',' ' ')
else
# Fetch all org repos
PAGE=1
REPOS=""
while true; do
BATCH=$(curl -sS \
-H "Authorization: token ${GA_TOKEN}" \
"${API}/orgs/${GITEA_ORG}/repos?page=${PAGE}&limit=50" \
| jq -r '.[].name // empty')
[ -z "$BATCH" ] && break
REPOS="$REPOS $BATCH"
PAGE=$((PAGE + 1))
done
# Filter out excluded repos
FILTERED=""
for REPO in $REPOS; do
SKIP=false
for EX in $EXCLUDE; do
if [ "$REPO" = "$EX" ]; then
SKIP=true
break
fi
done
if [ "$SKIP" = "false" ]; then
FILTERED="$FILTERED $REPO"
fi
done
REPOS="$FILTERED"
fi
echo "repos=$REPOS" >> "$GITHUB_OUTPUT"
COUNT=$(echo "$REPOS" | wc -w)
echo "📋 Target repos (${COUNT}): $REPOS"
- name: Apply protection rules
env:
GA_TOKEN: ${{ secrets.GA_TOKEN }}
DRY_RUN: ${{ inputs.dry_run || 'false' }}
run: |
API="${GITEA_URL}/api/v1"
REPOS="${{ steps.repos.outputs.repos }}"
SUCCESS=0
FAILED=0
SKIPPED=0
# ── Rule definitions ──────────────────────────────────────
# Only the CI bot (jmiller token) can push directly.
# All human contributors must use PRs.
# Force push disabled on all branches.
RULE_MAIN='{
"rule_name": "main",
"enable_push": true,
"enable_push_whitelist": true,
"push_whitelist_usernames": ["jmiller"],
"enable_force_push": false,
"enable_force_push_allowlist": false,
"force_push_allowlist_usernames": [],
"enable_merge_whitelist": false,
"required_approvals": 0,
"dismiss_stale_approvals": true,
"block_on_rejected_reviews": true,
"block_on_outdated_branch": false,
"priority": 1
}'
RULE_DEV='{
"rule_name": "dev",
"enable_push": true,
"enable_push_whitelist": true,
"push_whitelist_usernames": ["jmiller"],
"enable_force_push": false,
"enable_force_push_allowlist": false,
"force_push_allowlist_usernames": [],
"enable_merge_whitelist": false,
"required_approvals": 0,
"block_on_rejected_reviews": false,
"priority": 2
}'
RULE_RC='{
"rule_name": "rc",
"enable_push": true,
"enable_push_whitelist": true,
"push_whitelist_usernames": ["jmiller"],
"enable_force_push": false,
"enable_force_push_allowlist": false,
"force_push_allowlist_usernames": [],
"enable_merge_whitelist": false,
"required_approvals": 0,
"block_on_rejected_reviews": false,
"priority": 3
}'
RULE_BETA='{
"rule_name": "beta",
"enable_push": true,
"enable_push_whitelist": true,
"push_whitelist_usernames": ["jmiller"],
"enable_force_push": false,
"enable_force_push_allowlist": false,
"force_push_allowlist_usernames": [],
"enable_merge_whitelist": false,
"required_approvals": 0,
"block_on_rejected_reviews": false,
"priority": 4
}'
RULE_ALPHA='{
"rule_name": "alpha",
"enable_push": true,
"enable_push_whitelist": true,
"push_whitelist_usernames": ["jmiller"],
"enable_force_push": false,
"enable_force_push_allowlist": false,
"force_push_allowlist_usernames": [],
"enable_merge_whitelist": false,
"required_approvals": 0,
"block_on_rejected_reviews": false,
"priority": 5
}'
RULES=("$RULE_MAIN" "$RULE_DEV" "$RULE_RC" "$RULE_BETA" "$RULE_ALPHA")
RULE_NAMES=("main" "dev" "rc" "beta" "alpha")
# ── Apply rules to each repo ──────────────────────────────
for REPO in $REPOS; do
echo ""
echo "═══ ${REPO} ═══"
for i in "${!RULES[@]}"; do
RULE="${RULES[$i]}"
NAME="${RULE_NAMES[$i]}"
if [ "$DRY_RUN" = "true" ]; then
echo " [DRY RUN] Would apply rule: ${NAME}"
SKIPPED=$((SKIPPED + 1))
continue
fi
# Delete existing rule if present (idempotent recreate)
ENCODED_NAME=$(echo "$NAME" | sed 's|/|%2F|g')
curl -sS -o /dev/null -w "" \
-X DELETE \
-H "Authorization: token ${GA_TOKEN}" \
"${API}/repos/${GITEA_ORG}/${REPO}/branch_protections/${ENCODED_NAME}" 2>/dev/null || true
# Create rule
RESPONSE=$(curl -sS -w "\n%{http_code}" \
-X POST \
-H "Authorization: token ${GA_TOKEN}" \
-H "Content-Type: application/json" \
-d "$RULE" \
"${API}/repos/${GITEA_ORG}/${REPO}/branch_protections")
HTTP=$(echo "$RESPONSE" | tail -1)
BODY=$(echo "$RESPONSE" | sed '$d')
if [ "$HTTP" = "201" ]; then
echo " ✅ ${NAME}"
SUCCESS=$((SUCCESS + 1))
else
echo " ❌ ${NAME} (HTTP ${HTTP}): $(echo "$BODY" | jq -r '.message // .' 2>/dev/null | head -1)"
FAILED=$((FAILED + 1))
fi
done
done
# ── Summary ───────────────────────────────────────────────
echo ""
echo "════════════════════════════════════════"
echo " ✅ Success: ${SUCCESS}"
echo " ❌ Failed: ${FAILED}"
echo " ⏭️ Skipped: ${SKIPPED}"
echo "════════════════════════════════════════"
if [ "$FAILED" -gt 0 ]; then
echo "::warning::${FAILED} rule(s) failed to apply"
fi
+20
View File
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<moko-platform xmlns="https://standards.mokoconsulting.tech/moko-platform/1.0" schema-version="1.0">
<identity>
<name>MokoDPCalendarAPI</name>
<display-name>Plugin - MokoDPCalendarAPI</display-name>
<org>MokoConsulting</org>
<description>Joomla Web Services plugin exposing DPCalendar events, calendars, and locations via REST API</description>
<license spdx="GPL-3.0-or-later">GNU General Public License v3</license>
</identity>
<governance>
<platform>joomla</platform>
<standards-version>04.07.00</standards-version>
<standards-source>https://git.mokoconsulting.tech/MokoConsulting/moko-platform</standards-source>
</governance>
<build>
<language>PHP</language>
<package-type>joomla</package-type>
<entry-point>src/</entry-point>
</build>
</moko-platform>
+121 -34
View File
@@ -6,11 +6,11 @@
# DEFGROUP: Gitea.Workflow
# INGROUP: MokoStandards.Release
# REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards
# PATH: /.gitea/workflows/pre-release.yml
# VERSION: 01.00.00
# PATH: /templates/workflows/universal/pre-release.yml.template
# VERSION: 05.00.00
# BRIEF: Manual pre-release — builds dev/alpha/beta/rc packages from any branch
name: Pre-Release
name: "Universal: Pre-Release"
on:
workflow_dispatch:
@@ -52,6 +52,20 @@ jobs:
sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip >/dev/null 2>&1
fi
- name: Detect platform
id: platform
run: |
PLATFORM=$(cat .mokogitea/.moko-platform 2>/dev/null | tr -d '[:space:]')
[ -z "$PLATFORM" ] && PLATFORM="generic"
echo "platform=$PLATFORM" >> "$GITHUB_OUTPUT"
# For packages: prefer pkg_*.xml in src/; fallback to any manifest
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
id: meta
run: |
@@ -94,13 +108,36 @@ jobs:
# Update README.md
sed -i "s/VERSION:[[:space:]]*${CURRENT}/VERSION: ${VERSION}/" README.md
# Update manifest
MANIFEST=$(find . -maxdepth 3 -name "*.xml" ! -path "./.git/*" -exec grep -l '<extension' {} \; 2>/dev/null | head -1)
if [ -n "$MANIFEST" ]; then
MANIFEST_VER=$(sed -n 's/.*<version>\([^<]*\)<\/version>.*/\1/p' "$MANIFEST" | head -1)
sed -i "s|<version>${MANIFEST_VER}</version>|<version>${VERSION}</version>|" "$MANIFEST"
sed -i "s|<creationDate>[^<]*</creationDate>|<creationDate>${TODAY}</creationDate>|" "$MANIFEST"
fi
# Update platform-specific manifest
PLATFORM="${{ steps.platform.outputs.platform }}"
MANIFEST="${{ steps.platform.outputs.manifest }}"
MOD_FILE="${{ steps.platform.outputs.mod_file }}"
case "$PLATFORM" in
joomla)
if [ -n "$MANIFEST" ]; then
MANIFEST_VER=$(sed -n 's/.*<version>\([^<]*\)<\/version>.*/\1/p' "$MANIFEST" | head -1)
sed -i "s|<version>${MANIFEST_VER}</version>|<version>${VERSION}</version>|" "$MANIFEST"
sed -i "s|<creationDate>[^<]*</creationDate>|<creationDate>${TODAY}</creationDate>|" "$MANIFEST"
fi
# For packages: also bump version in all sub-extension manifests
if [ -d "src/packages" ]; then
for SUB_MANIFEST in $(find src/packages -maxdepth 2 -name "*.xml" -exec grep -l '<extension' {} \; 2>/dev/null); do
SUB_VER=$(sed -n 's/.*<version>\([^<]*\)<\/version>.*/\1/p' "$SUB_MANIFEST" | head -1)
if [ -n "$SUB_VER" ]; then
sed -i "s|<version>${SUB_VER}</version>|<version>${VERSION}</version>|" "$SUB_MANIFEST"
sed -i "s|<creationDate>[^<]*</creationDate>|<creationDate>${TODAY}</creationDate>|" "$SUB_MANIFEST"
echo " Bumped sub-extension: $(basename $SUB_MANIFEST) ${SUB_VER} → ${VERSION}"
fi
done
fi
;;
dolibarr)
if [ -n "$MOD_FILE" ]; then
sed -i "s/\$this->version = '[^']*'/\$this->version = '${VERSION}'/" "$MOD_FILE"
fi
;;
*) ;;
esac
# Commit version bump
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
@@ -112,20 +149,36 @@ jobs:
git push origin HEAD 2>&1
}
# Auto-detect element from manifest
MANIFEST=$(find . -maxdepth 3 -name "*.xml" ! -path "./.git/*" -exec grep -l '<extension' {} \; 2>/dev/null | head -1)
EXT_ELEMENT=""
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
# Auto-detect element (platform-aware)
case "$PLATFORM" in
joomla)
MANIFEST="${{ steps.platform.outputs.manifest }}"
EXT_ELEMENT=""
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)
MOD_FILE="${{ steps.platform.outputs.mod_file }}"
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"
@@ -148,17 +201,49 @@ jobs:
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
rsync -a \
--exclude='sftp-config*' \
--exclude='.ftpignore' \
--exclude='*.ppk' \
--exclude='*.pem' \
--exclude='*.key' \
--exclude='.env*' \
--exclude='*.local' \
--exclude='.build-trigger' \
"${SOURCE_DIR}/" build/package/
if [ "$EXT_TYPE" = "package" ] && [ -d "${SOURCE_DIR}/packages" ]; then
echo "=== Building Joomla PACKAGE (multi-extension) ==="
# 1) ZIP each sub-extension in src/packages/
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
# 2) Copy package-level files (manifest, script, etc.)
for f in "${SOURCE_DIR}"/*.xml "${SOURCE_DIR}"/*.php; do
[ -f "$f" ] && cp "$f" build/package/
done
echo "Package contents:"
ls -la build/package/
else
echo "=== Building standard Joomla 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
@@ -222,6 +307,7 @@ jobs:
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 }}"
@@ -288,6 +374,7 @@ jobs:
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"
+66
View File
@@ -0,0 +1,66 @@
# 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: /.mokogitea/workflows/auto-bump.yml
# VERSION: 09.02.00
# BRIEF: Auto patch-bump version on every push to dev (skips merge commits)
name: "Universal: Auto Version Bump"
on:
push:
branches:
- dev
- rc
- 'feature/**'
- 'patch/**'
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
permissions:
contents: write
jobs:
bump:
name: Version Bump
runs-on: release
if: >-
!contains(github.event.head_commit.message, '[skip ci]') &&
!contains(github.event.head_commit.message, '[skip bump]') &&
!startsWith(github.event.head_commit.message, 'Merge pull request')
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
token: ${{ secrets.MOKOGITEA_TOKEN }}
fetch-depth: 1
- name: Setup moko-platform tools
run: |
if ! command -v composer &> /dev/null; then
sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer >/dev/null 2>&1
fi
if [ -d "/opt/moko-platform/cli" ]; then
echo "MOKO_CLI=/opt/moko-platform/cli" >> "$GITHUB_ENV"
else
git clone --depth 1 --branch main --quiet \
"https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/MokoConsulting/moko-platform.git" \
/tmp/moko-platform-api
cd /tmp/moko-platform-api && composer install --no-dev --no-interaction --quiet
echo "MOKO_CLI=/tmp/moko-platform-api/cli" >> "$GITHUB_ENV"
fi
- name: Bump version
run: |
php ${MOKO_CLI}/version_auto_bump.php \
--path . --branch "${GITHUB_REF_NAME}" \
--token "${{ secrets.MOKOGITEA_TOKEN }}" \
--repo-url "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
File diff suppressed because it is too large Load Diff
+48
View File
@@ -0,0 +1,48 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: MokoStandards.Universal
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
# PATH: /.mokogitea/workflows/branch-cleanup.yml
# VERSION: 01.00.00
# BRIEF: Delete feature branches after PR merge
name: "Branch Cleanup"
on:
pull_request:
types: [closed]
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
cleanup:
name: Delete merged branch
runs-on: ubuntu-latest
if: >-
github.event.pull_request.merged == true &&
github.event.pull_request.head.ref != 'dev' &&
github.event.pull_request.head.ref != 'main'
steps:
- name: Delete source branch
run: |
BRANCH="${{ github.event.pull_request.head.ref }}"
API="${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}/api/v1/repos/${{ github.repository }}/branches"
ENCODED=$(php -r "echo rawurlencode('${BRANCH}');")
STATUS=$(curl -sf -o /dev/null -w "%{http_code}" -X DELETE \
-H "Authorization: token ${{ secrets.MOKOGITEA_TOKEN }}" \
"${API}/${ENCODED}" 2>/dev/null || true)
if [ "$STATUS" = "204" ]; then
echo "Deleted branch: ${BRANCH}" >> $GITHUB_STEP_SUMMARY
elif [ "$STATUS" = "404" ]; then
echo "Branch already deleted: ${BRANCH}" >> $GITHUB_STEP_SUMMARY
else
echo "::warning::Failed to delete branch ${BRANCH} (HTTP ${STATUS})"
fi
+7 -210
View File
@@ -1,213 +1,10 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: MokoStandards.Maintenance
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
# PATH: /templates/workflows/cascade-dev.yml.template
# VERSION: 02.00.00
# BRIEF: Forward-merge main → all open branches after every push to main
#
# +========================================================================+
# | CASCADE MAIN → ALL BRANCHES |
# +========================================================================+
# | |
# | Triggers on every push to main (PR merges, bot commits, etc.) |
# | |
# | 1. List all branches matching: dev, rc/*, beta/*, alpha/* |
# | 2. For each: create PR (main → branch), auto-merge if clean |
# | 3. On conflict: leave PR open for manual resolution |
# | |
# +========================================================================+
name: "Universal: Cascade Main → Dev"
on:
push:
branches:
- main
workflow_dispatch:
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
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 }}
permissions:
contents: write
pull-requests: write
# DISABLED — auto-release Step 11 recreates dev from main after every release.
# Cascade-dev is redundant and causes version conflicts when both main and dev
# have different version numbers in templateDetails.xml / manifest.xml.
name: "Cascade Main → Dev (DISABLED)"
on: workflow_dispatch
jobs:
cascade:
name: Cascade main → branches
noop:
runs-on: ubuntu-latest
if: >-
!contains(github.event.head_commit.message, '[skip ci]') &&
!contains(github.event.head_commit.message, '[skip cascade]')
steps:
- name: Discover target branches
id: branches
env:
GA_TOKEN: ${{ secrets.GA_TOKEN }}
run: |
API="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
# Fetch all branches (paginated)
PAGE=1
ALL_BRANCHES=""
while true; do
BATCH=$(curl -sS \
-H "Authorization: token ${GA_TOKEN}" \
"${API}/branches?page=${PAGE}&limit=50" \
| jq -r '.[].name // empty')
[ -z "$BATCH" ] && break
ALL_BRANCHES="$ALL_BRANCHES $BATCH"
PAGE=$((PAGE + 1))
done
# Filter to cascade targets: dev, dev/*, rc/*, beta/*, alpha/*
TARGETS=""
for BRANCH in $ALL_BRANCHES; do
case "$BRANCH" in
dev|dev/*|rc/*|beta/*|alpha/*)
TARGETS="$TARGETS $BRANCH"
;;
esac
done
TARGETS=$(echo "$TARGETS" | xargs) # trim whitespace
if [ -z "$TARGETS" ]; then
echo "targets=" >> "$GITHUB_OUTPUT"
echo "️ No cascade target branches found"
else
echo "targets=$TARGETS" >> "$GITHUB_OUTPUT"
COUNT=$(echo "$TARGETS" | wc -w)
echo "📋 Found ${COUNT} target branch(es): ${TARGETS}"
fi
- name: Cascade to all target branches
if: steps.branches.outputs.targets != ''
env:
GA_TOKEN: ${{ secrets.GA_TOKEN }}
run: |
API="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
SHORT_SHA="${GITHUB_SHA:0:7}"
TARGETS="${{ steps.branches.outputs.targets }}"
SUCCESS=0
CONFLICTS=0
SKIPPED=0
FAILED=0
for BRANCH in $TARGETS; do
echo ""
echo "═══ main → ${BRANCH} ═══"
# Check if branch is already up to date
ENCODED_BRANCH=$(echo "$BRANCH" | sed 's|/|%2F|g')
RESPONSE=$(curl -sS \
-H "Authorization: token ${GA_TOKEN}" \
"${API}/compare/${ENCODED_BRANCH}...main")
AHEAD=$(echo "$RESPONSE" | jq '.total_commits // 0')
if [ "$AHEAD" -eq 0 ]; then
echo " ✅ Already up to date"
SKIPPED=$((SKIPPED + 1))
continue
fi
echo " ️ main is ${AHEAD} commit(s) ahead"
# Check for existing cascade PR
EXISTING=$(curl -sS \
-H "Authorization: token ${GA_TOKEN}" \
"${API}/pulls?state=open&head=${GITEA_ORG}:main&base=${ENCODED_BRANCH}&limit=1")
EXISTING_COUNT=$(echo "$EXISTING" | jq 'length')
PR_NUMBER=""
if [ "$EXISTING_COUNT" -gt 0 ]; then
PR_NUMBER=$(echo "$EXISTING" | jq -r '.[0].number')
echo " ️ Reusing existing PR #${PR_NUMBER}"
else
# Create cascade PR
PR_RESPONSE=$(curl -sS -w "\n%{http_code}" \
-X POST \
-H "Authorization: token ${GA_TOKEN}" \
-H "Content-Type: application/json" \
-d "{
\"title\": \"chore: cascade main → ${BRANCH} (${SHORT_SHA}) [skip ci]\",
\"body\": \"## Automatic cascade\\n\\nForward-merging \`main\` (${SHORT_SHA}) into \`${BRANCH}\`.\\n\\nIf conflicts exist, resolve manually and merge.\\n\\n> Auto-created by **Cascade Main → Dev**.\",
\"head\": \"main\",
\"base\": \"${BRANCH}\"
}" \
"${API}/pulls")
HTTP_CODE=$(echo "$PR_RESPONSE" | tail -1)
BODY=$(echo "$PR_RESPONSE" | sed '$d')
PR_NUMBER=$(echo "$BODY" | jq -r '.number // empty')
if [ "$HTTP_CODE" != "201" ] || [ -z "$PR_NUMBER" ]; then
MSG=$(echo "$BODY" | jq -r '.message // .' 2>/dev/null | head -1)
echo " ❌ Failed to create PR (HTTP ${HTTP_CODE}): ${MSG}"
FAILED=$((FAILED + 1))
continue
fi
echo " ✅ Created PR #${PR_NUMBER}"
fi
# Try auto-merge
PR_DATA=$(curl -sS \
-H "Authorization: token ${GA_TOKEN}" \
"${API}/pulls/${PR_NUMBER}")
MERGEABLE=$(echo "$PR_DATA" | jq -r '.mergeable // false')
if [ "$MERGEABLE" != "true" ]; then
echo " ⚠️ Conflicts — PR #${PR_NUMBER} left open"
CONFLICTS=$((CONFLICTS + 1))
continue
fi
MERGE_RESPONSE=$(curl -sS -w "\n%{http_code}" \
-X POST \
-H "Authorization: token ${GA_TOKEN}" \
-H "Content-Type: application/json" \
-d "{
\"Do\": \"merge\",
\"merge_message_field\": \"chore: cascade main → ${BRANCH} [skip ci]\",
\"delete_branch_after_merge\": false
}" \
"${API}/pulls/${PR_NUMBER}/merge")
MERGE_HTTP=$(echo "$MERGE_RESPONSE" | tail -1)
if [ "$MERGE_HTTP" = "200" ] || [ "$MERGE_HTTP" = "204" ]; then
echo " ✅ Merged — ${BRANCH} is in sync"
SUCCESS=$((SUCCESS + 1))
else
MERGE_BODY=$(echo "$MERGE_RESPONSE" | sed '$d')
echo " ⚠️ Merge failed (HTTP ${MERGE_HTTP}) — PR #${PR_NUMBER} left open"
CONFLICTS=$((CONFLICTS + 1))
fi
done
# Summary
echo ""
echo "════════════════════════════════════════"
echo " ✅ Merged: ${SUCCESS}"
echo " ⚠️ Conflicts: ${CONFLICTS}"
echo " ⏭️ Up to date: ${SKIPPED}"
echo " ❌ Failed: ${FAILED}"
echo "════════════════════════════════════════"
if [ "$FAILED" -gt 0 ]; then
exit 1
fi
- run: echo "Cascade disabled — auto-release handles dev recreation"
+17
View File
@@ -448,3 +448,20 @@ jobs:
echo '```' >> $GITHUB_STEP_SUMMARY
fi
exit $EXIT
pre-release:
name: Build RC Pre-Release
runs-on: ubuntu-latest
needs: [lint-and-validate, test]
if: github.event_name == 'pull_request'
steps:
- name: Trigger pre-release build
env:
GA_TOKEN: ${{ secrets.GA_TOKEN }}
REPO: ${{ github.repository }}
BRANCH: ${{ github.head_ref }}
run: |
curl -s -X POST "${GITEA_URL:-https://git.mokoconsulting.tech}/api/v1/repos/${REPO}/actions/workflows/pre-release.yml/dispatches" -H "Authorization: token ${GA_TOKEN}" -H "Content-Type: application/json" -d "{\"ref\":\"${BRANCH}\",\"inputs\":{\"stability\":\"release-candidate\"}}"
echo "### Pre-Release" >> $GITHUB_STEP_SUMMARY
echo "Triggered RC build on branch \`${BRANCH}\`" >> $GITHUB_STEP_SUMMARY
+2 -2
View File
@@ -4,8 +4,8 @@
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: MokoStandards.Maintenance
# REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards
# INGROUP: moko-platform.Maintenance
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
# PATH: /.gitea/workflows/cleanup.yml
# VERSION: 01.00.00
# BRIEF: Scheduled cleanup — delete merged branches and old workflow runs
+2 -2
View File
@@ -4,8 +4,8 @@
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: MokoStandards.Security
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
# INGROUP: moko-platform.Security
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/moko-platform
# PATH: /templates/workflows/gitleaks.yml.template
# VERSION: 01.00.00
# BRIEF: Secret scanning — detect leaked credentials, API keys, and tokens
+73
View File
@@ -0,0 +1,73 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.Automation
# VERSION: 01.00.00
# BRIEF: Auto-create feature branch when an issue is opened
name: "Universal: Issue Branch"
on:
issues:
types: [opened]
permissions:
contents: write
issues: write
env:
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
jobs:
create-branch:
name: Create feature branch
runs-on: ubuntu-latest
steps:
- name: Create branch and comment
run: |
TOKEN="${{ secrets.GA_TOKEN }}"
API="${GITEA_URL}/api/v1/repos/${{ github.repository }}"
ISSUE_NUM="${{ github.event.issue.number }}"
ISSUE_TITLE="${{ github.event.issue.title }}"
# Build slug from title: lowercase, replace non-alnum with dash, trim
SLUG=$(echo "${ISSUE_TITLE}" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-//;s/-$//' | cut -c1-40)
BRANCH="feature/${ISSUE_NUM}-${SLUG}"
# Check dev branch exists
DEV_EXISTS=$(curl -sf -o /dev/null -w '%{http_code}' \
-H "Authorization: token ${TOKEN}" \
"${API}/branches/dev" 2>/dev/null || echo "000")
if [ "${DEV_EXISTS}" != "200" ]; then
echo "No dev branch -- skipping"
exit 0
fi
# Create branch from dev
HTTP=$(curl -sf -o /dev/null -w '%{http_code}' -X POST \
-H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
"${API}/branches" \
-d "{\"new_branch_name\":\"${BRANCH}\",\"old_branch_name\":\"dev\"}" 2>/dev/null || echo "000")
if [ "${HTTP}" = "201" ]; then
echo "Created branch: ${BRANCH}"
# Comment on issue with branch link
REPO_URL="${GITEA_URL}/${{ github.repository }}"
BODY="Branch created: [\`${BRANCH}\`](${REPO_URL}/src/branch/${BRANCH})\n\n\`\`\`bash\ngit fetch origin\ngit checkout ${BRANCH}\n\`\`\`"
curl -sf -X POST \
-H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
"${API}/issues/${ISSUE_NUM}/comments" \
-d "{\"body\":\"${BODY}\"}" > /dev/null 2>&1
echo "Commented on issue #${ISSUE_NUM}"
else
echo "Failed to create branch (HTTP ${HTTP}) -- may already exist"
fi
+2 -3
View File
@@ -4,8 +4,8 @@
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: MokoStandards.Notifications
# REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards
# INGROUP: moko-platform.Notifications
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
# PATH: /.gitea/workflows/notify.yml
# VERSION: 01.00.00
# BRIEF: Push notifications via ntfy on release success or workflow failure
@@ -18,7 +18,6 @@ on:
- "Joomla Build & Release"
- "Joomla Extension CI"
- "Deploy"
- "Cascade Main → Dev"
types:
- completed
+264 -196
View File
@@ -1,196 +1,264 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: MokoStandards.CI
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
# PATH: /templates/workflows/universal/pr-check.yml.template
# VERSION: 05.00.00
# BRIEF: PR gate — branch policy + code validation before merge
name: "Universal: PR Check"
on:
pull_request:
types: [opened, synchronize, reopened, edited]
permissions:
contents: read
pull-requests: write
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
# ── Branch Policy ──────────────────────────────────────────────────────
branch-policy:
name: Branch Policy
runs-on: ubuntu-latest
steps:
- name: Check branch merge target
run: |
HEAD="${{ github.head_ref }}"
BASE="${{ github.base_ref }}"
echo "PR: ${HEAD} → ${BASE}"
ALLOWED=true
REASON=""
case "$HEAD" in
feature/*|feat/*)
if [ "$BASE" != "dev" ]; then
ALLOWED=false
REASON="Feature branches must target 'dev', not '${BASE}'"
fi
;;
fix/*|bugfix/*)
if [ "$BASE" != "dev" ]; then
ALLOWED=false
REASON="Fix branches must target 'dev', not '${BASE}'"
fi
;;
hotfix/*)
if [ "$BASE" != "dev" ] && [ "$BASE" != "main" ]; then
ALLOWED=false
REASON="Hotfix branches can only target 'dev' or 'main', not '${BASE}'"
fi
;;
alpha/*|beta/*)
if [ "$BASE" != "dev" ]; then
ALLOWED=false
REASON="Pre-release branches must target 'dev', not '${BASE}'"
fi
;;
rc/*)
if [ "$BASE" != "main" ]; then
ALLOWED=false
REASON="Release candidate branches must target 'main', not '${BASE}'"
fi
;;
dev)
if [ "$BASE" != "main" ]; then
ALLOWED=false
REASON="Dev branch can only merge into 'main', not '${BASE}'"
fi
;;
esac
if [ "$ALLOWED" = false ]; then
echo "::error::${REASON}"
echo "## Branch Policy Violation" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "${REASON}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Allowed merge paths:" >> $GITHUB_STEP_SUMMARY
echo "- \`feature/*\` → \`dev\`" >> $GITHUB_STEP_SUMMARY
echo "- \`fix/*\` → \`dev\`" >> $GITHUB_STEP_SUMMARY
echo "- \`hotfix/*\` → \`dev\` or \`main\`" >> $GITHUB_STEP_SUMMARY
echo "- \`dev\` → \`main\`" >> $GITHUB_STEP_SUMMARY
echo "- \`rc/*\` → \`main\`" >> $GITHUB_STEP_SUMMARY
exit 1
fi
echo "Branch policy: OK (${HEAD} → ${BASE})"
echo "## Branch Policy: Passed" >> $GITHUB_STEP_SUMMARY
# ── Code Validation ────────────────────────────────────────────────────
validate:
name: Validate PR
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Detect platform
id: platform
run: |
# Read platform from XML manifest (<platform> tag) or plain text fallback
PLATFORM=$(sed -n 's/.*<platform>\([^<]*\)<\/platform>.*/\1/p' .mokogitea/manifest.xml 2>/dev/null | head -1)
[ -z "$PLATFORM" ] && PLATFORM=$(cat .mokogitea/manifest.xml 2>/dev/null | tr -d '[:space:]')
[ -z "$PLATFORM" ] && PLATFORM="generic"
echo "platform=$PLATFORM" >> "$GITHUB_OUTPUT"
- name: Setup PHP
if: steps.platform.outputs.platform == 'joomla' || steps.platform.outputs.platform == 'dolibarr'
run: |
if ! command -v php &> /dev/null; then
sudo apt-get update -qq
sudo apt-get install -y -qq php-cli php-mbstring php-xml >/dev/null 2>&1
fi
- name: PHP syntax check
if: steps.platform.outputs.platform == 'joomla' || steps.platform.outputs.platform == 'dolibarr'
run: |
ERRORS=0
while IFS= read -r -d '' file; do
if ! php -l "$file" 2>&1 | grep -q "No syntax errors"; then
ERRORS=$((ERRORS + 1))
fi
done < <(find . -name "*.php" -not -path "./.git/*" -not -path "./vendor/*" -print0)
echo "PHP lint: ${ERRORS} error(s)"
[ "$ERRORS" -eq 0 ] || { echo "::error::PHP syntax errors found"; exit 1; }
- name: Validate platform manifest
run: |
PLATFORM="${{ steps.platform.outputs.platform }}"
case "$PLATFORM" in
joomla)
MANIFEST=$(find . -maxdepth 3 -name "*.xml" ! -path "./.git/*" -exec grep -l '<extension' {} \; 2>/dev/null | head -1)
if [ -z "$MANIFEST" ]; then
echo "::warning::No Joomla manifest found (WaaS site)"
exit 0
fi
echo "Manifest: ${MANIFEST}"
if command -v php &> /dev/null; then
php -r "libxml_use_internal_errors(true); \$x = simplexml_load_file('$MANIFEST'); if(!\$x){foreach(libxml_get_errors() as \$e) echo \$e->message; exit(1);}" || { echo "::error::Manifest XML is malformed"; exit 1; }
fi
for ELEMENT in name version description; do
grep -q "<${ELEMENT}>" "$MANIFEST" || { echo "::error::Missing <${ELEMENT}> in manifest"; exit 1; }
done
echo "Joomla manifest valid"
;;
dolibarr)
MOD_FILE=$(find . -maxdepth 4 -name "mod*.class.php" ! -path "./.git/*" -exec grep -l 'extends DolibarrModules' {} \; 2>/dev/null | head -1)
if [ -z "$MOD_FILE" ]; then
echo "::error::No mod*.class.php found"
exit 1
fi
echo "Dolibarr module: ${MOD_FILE}"
;;
*)
echo "Generic platform — no manifest validation"
;;
esac
- name: Check update stream format
run: |
PLATFORM="${{ steps.platform.outputs.platform }}"
case "$PLATFORM" in
joomla)
if [ -f "updates.xml" ]; then
if command -v php &> /dev/null; then
php -r "libxml_use_internal_errors(true); \$x = simplexml_load_file('updates.xml'); if(!\$x){foreach(libxml_get_errors() as \$e) echo \$e->message; exit(1);}" || { echo "::error::updates.xml is malformed"; exit 1; }
fi
echo "updates.xml valid"
fi
;;
dolibarr)
[ -f "update.txt" ] && echo "update.txt present" || echo "::warning::No update.txt"
;;
esac
- name: Verify package source
run: |
SOURCE_DIR="src"
[ ! -d "$SOURCE_DIR" ] && SOURCE_DIR="htdocs"
if [ ! -d "$SOURCE_DIR" ]; then
echo "::warning::No src/ or htdocs/ directory"
exit 0
fi
FILE_COUNT=$(find "$SOURCE_DIR" -type f | wc -l)
echo "Source: ${FILE_COUNT} files"
[ "$FILE_COUNT" -gt 0 ] || { echo "::error::Source directory is empty"; exit 1; }
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.CI
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/moko-platform
# PATH: /templates/workflows/universal/pr-check.yml.template
# VERSION: 09.23.00
# BRIEF: PR gate — branch policy + code validation before merge
name: "Universal: PR Check"
on:
pull_request:
types: [opened, synchronize, reopened, edited]
permissions:
contents: read
pull-requests: write
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
# ── Branch Policy ──────────────────────────────────────────────────────
branch-policy:
name: Branch Policy
runs-on: ubuntu-latest
steps:
- name: Check branch merge target
run: |
HEAD="${{ github.head_ref }}"
BASE="${{ github.base_ref }}"
echo "PR: ${HEAD} → ${BASE}"
ALLOWED=true
REASON=""
case "$HEAD" in
feature/*|feat/*)
if [ "$BASE" != "dev" ]; then
ALLOWED=false
REASON="Feature branches must target 'dev', not '${BASE}'"
fi
;;
fix/*|bugfix/*)
if [ "$BASE" != "dev" ]; then
ALLOWED=false
REASON="Fix branches must target 'dev', not '${BASE}'"
fi
;;
patch/*)
if [ "$BASE" != "dev" ] && [ "$BASE" != "rc" ]; then
ALLOWED=false
REASON="Patch branches must target 'dev' or 'rc', not '${BASE}'"
fi
;;
hotfix/*)
if [ "$BASE" != "dev" ] && [ "$BASE" != "main" ]; then
ALLOWED=false
REASON="Hotfix branches can only target 'dev' or 'main', not '${BASE}'"
fi
;;
rc)
if [ "$BASE" != "main" ]; then
ALLOWED=false
REASON="RC branch can only merge into 'main', not '${BASE}'"
fi
;;
dev)
if [ "$BASE" != "main" ]; then
ALLOWED=false
REASON="Dev branch can only merge into 'main', not '${BASE}'"
fi
;;
esac
if [ "$ALLOWED" = false ]; then
echo "::error::${REASON}"
echo "## Branch Policy Violation" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "${REASON}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Allowed merge paths:" >> $GITHUB_STEP_SUMMARY
echo "- \`feature/*\` → \`dev\`" >> $GITHUB_STEP_SUMMARY
echo "- \`fix/*\` → \`dev\`" >> $GITHUB_STEP_SUMMARY
echo "- \`hotfix/*\` → \`dev\` or \`main\`" >> $GITHUB_STEP_SUMMARY
echo "- \`dev\` → \`main\`" >> $GITHUB_STEP_SUMMARY
echo "- \`rc/*\` → \`main\`" >> $GITHUB_STEP_SUMMARY
exit 1
fi
echo "Branch policy: OK (${HEAD} → ${BASE})"
echo "## Branch Policy: Passed" >> $GITHUB_STEP_SUMMARY
# ── Code Validation ────────────────────────────────────────────────────
validate:
name: Validate PR
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Detect platform
id: platform
run: |
# Read platform from XML manifest (<platform> tag) or plain text fallback
PLATFORM=$(sed -n 's/.*<platform>\([^<]*\)<\/platform>.*/\1/p' .mokogitea/manifest.xml 2>/dev/null | head -1)
[ -z "$PLATFORM" ] && PLATFORM=$(cat .mokogitea/manifest.xml 2>/dev/null | tr -d '[:space:]')
[ -z "$PLATFORM" ] && PLATFORM="generic"
echo "platform=$PLATFORM" >> "$GITHUB_OUTPUT"
- name: Setup PHP
if: steps.platform.outputs.platform == 'joomla' || steps.platform.outputs.platform == 'dolibarr'
run: |
if ! command -v php &> /dev/null; then
sudo apt-get update -qq
sudo apt-get install -y -qq php-cli php-mbstring php-xml >/dev/null 2>&1
fi
- name: PHP syntax check
if: steps.platform.outputs.platform == 'joomla' || steps.platform.outputs.platform == 'dolibarr'
run: |
ERRORS=0
while IFS= read -r -d '' file; do
if ! php -l "$file" 2>&1 | grep -q "No syntax errors"; then
ERRORS=$((ERRORS + 1))
fi
done < <(find . -name "*.php" -not -path "./.git/*" -not -path "./vendor/*" -print0)
echo "PHP lint: ${ERRORS} error(s)"
[ "$ERRORS" -eq 0 ] || { echo "::error::PHP syntax errors found"; exit 1; }
- name: Validate platform manifest
run: |
PLATFORM="${{ steps.platform.outputs.platform }}"
case "$PLATFORM" in
joomla)
MANIFEST=$(find . -maxdepth 3 -name "*.xml" ! -path "./.git/*" -exec grep -l '<extension' {} \; 2>/dev/null | head -1)
if [ -z "$MANIFEST" ]; then
echo "::warning::No Joomla manifest found (WaaS site)"
exit 0
fi
echo "Manifest: ${MANIFEST}"
if command -v php &> /dev/null; then
php -r "libxml_use_internal_errors(true); \$x = simplexml_load_file('$MANIFEST'); if(!\$x){foreach(libxml_get_errors() as \$e) echo \$e->message; exit(1);}" || { echo "::error::Manifest XML is malformed"; exit 1; }
fi
for ELEMENT in name version description; do
grep -q "<${ELEMENT}>" "$MANIFEST" || { echo "::error::Missing <${ELEMENT}> in manifest"; exit 1; }
done
echo "Joomla manifest valid"
;;
dolibarr)
MOD_FILE=$(find . -maxdepth 4 -name "mod*.class.php" ! -path "./.git/*" -exec grep -l 'extends DolibarrModules' {} \; 2>/dev/null | head -1)
if [ -z "$MOD_FILE" ]; then
echo "::error::No mod*.class.php found"
exit 1
fi
echo "Dolibarr module: ${MOD_FILE}"
;;
*)
echo "Generic platform — no manifest validation"
;;
esac
- name: Check update stream format
run: |
PLATFORM="${{ steps.platform.outputs.platform }}"
case "$PLATFORM" in
joomla)
if [ -f "updates.xml" ]; then
if command -v php &> /dev/null; then
php -r "libxml_use_internal_errors(true); \$x = simplexml_load_file('updates.xml'); if(!\$x){foreach(libxml_get_errors() as \$e) echo \$e->message; exit(1);}" || { echo "::error::updates.xml is malformed"; exit 1; }
fi
echo "updates.xml valid"
fi
;;
dolibarr)
[ -f "update.txt" ] && echo "update.txt present" || echo "::warning::No update.txt"
;;
esac
- name: Check changelog has unreleased entry
run: |
if [ ! -f "CHANGELOG.md" ]; then
echo "::warning::No CHANGELOG.md found"
exit 0
fi
# Check for content under [Unreleased] section
if ! grep -q "## \[Unreleased\]" CHANGELOG.md; then
echo "::error::CHANGELOG.md missing [Unreleased] section"
exit 1
fi
# Check there's at least one entry (Added/Changed/Fixed/Removed) under Unreleased
UNRELEASED_CONTENT=$(sed -n '/## \[Unreleased\]/,/## \[/p' CHANGELOG.md | grep -cE '^\s*-\s' || true)
if [ "$UNRELEASED_CONTENT" -eq 0 ]; then
echo "::error::CHANGELOG.md [Unreleased] section has no entries. Add a changelog entry describing your changes."
echo "## Changelog Check: Failed" >> $GITHUB_STEP_SUMMARY
echo "The \`[Unreleased]\` section in CHANGELOG.md has no entries." >> $GITHUB_STEP_SUMMARY
echo "Add a line like \`- Description of your change\` under a heading (\`### Added\`, \`### Changed\`, \`### Fixed\`, etc.)" >> $GITHUB_STEP_SUMMARY
exit 1
fi
echo "Changelog: ${UNRELEASED_CONTENT} entry/entries in [Unreleased]"
- name: Verify package source
run: |
SOURCE_DIR="src"
[ ! -d "$SOURCE_DIR" ] && SOURCE_DIR="htdocs"
if [ ! -d "$SOURCE_DIR" ]; then
echo "::warning::No src/ or htdocs/ directory"
exit 0
fi
FILE_COUNT=$(find "$SOURCE_DIR" -type f | wc -l)
echo "Source: ${FILE_COUNT} files"
[ "$FILE_COUNT" -gt 0 ] || { echo "::error::Source directory is empty"; exit 1; }
# ── Pre-Release RC Build ─────────────────────────────────────────────────
pre-release:
name: Build RC Package
runs-on: ubuntu-latest
needs: [branch-policy, validate]
steps:
- name: Trigger RC pre-release
env:
GA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
REPO: ${{ github.repository }}
BRANCH: ${{ github.head_ref }}
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
run: |
curl -s -X POST "${GITEA_URL}/api/v1/repos/${REPO}/actions/workflows/pre-release.yml/dispatches" -H "Authorization: token ${GITEA_TOKEN}" -H "Content-Type: application/json" -d "{\"ref\":\"${BRANCH}\",\"inputs\":{\"stability\":\"release-candidate\"}}"
echo "### Pre-Release" >> $GITHUB_STEP_SUMMARY
echo "Triggered RC build on branch \`${BRANCH}\`" >> $GITHUB_STEP_SUMMARY
# ── Issue Reporter ──────────────────────────────────────────────────────
report-issues:
name: Report Issues
runs-on: ubuntu-latest
needs: [branch-policy, validate]
if: >-
always() &&
needs.validate.result == 'failure'
steps:
- name: Checkout
uses: actions/checkout@v4
with:
sparse-checkout: automation/ci-issue-reporter.sh
sparse-checkout-cone-mode: false
- name: "File issue for PR validation failure"
env:
GITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
run: |
chmod +x automation/ci-issue-reporter.sh
./automation/ci-issue-reporter.sh \
--gate "PR Validation" \
--workflow "PR Check" \
--severity error \
--details "PR validation failed (syntax, manifest, changelog, or source checks). See the CI run for the specific check that failed."
+102 -253
View File
@@ -4,15 +4,19 @@
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: MokoStandards.Release
# REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards
# INGROUP: moko-platform.Release
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
# PATH: /templates/workflows/universal/pre-release.yml.template
# VERSION: 05.00.00
# BRIEF: Manual pre-release builds dev/alpha/beta/rc packages from any branch
# VERSION: 05.01.00
# BRIEF: Manual pre-release -- builds dev/alpha/beta/rc packages from any branch
name: "Universal: Pre-Release"
on:
pull_request:
types: [closed]
branches:
- dev
workflow_dispatch:
inputs:
stability:
@@ -35,40 +39,44 @@ env:
jobs:
build:
name: "Build Pre-Release (${{ inputs.stability }})"
name: "Build Pre-Release (${{ inputs.stability || 'development' }})"
runs-on: release
if: >-
github.event_name == 'workflow_dispatch' ||
(github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'dev')
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GA_TOKEN }}
token: ${{ secrets.MOKOGITEA_TOKEN }}
- name: Setup PHP
- name: Setup moko-platform tools
env:
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
run: |
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 >/dev/null 2>&1
if ! command -v composer &> /dev/null; then
sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer >/dev/null 2>&1
fi
# Always fetch latest CLI tools — never use stale cache from previous runs
rm -rf /tmp/moko-platform-api
git clone --depth 1 --branch main --quiet \
"https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/moko-platform.git" \
/tmp/moko-platform-api
cd /tmp/moko-platform-api && composer install --no-dev --no-interaction --quiet
echo "MOKO_CLI=/tmp/moko-platform-api/cli" >> "$GITHUB_ENV"
- name: Detect platform
id: platform
run: |
# Read platform from XML manifest (<platform> tag) or plain text fallback
PLATFORM=$(sed -n 's/.*<platform>\([^<]*\)<\/platform>.*/\1/p' .mokogitea/manifest.xml 2>/dev/null | head -1)
[ -z "$PLATFORM" ] && PLATFORM=$(cat .mokogitea/manifest.xml 2>/dev/null | tr -d '[:space:]')
[ -z "$PLATFORM" ] && PLATFORM="generic"
echo "platform=$PLATFORM" >> "$GITHUB_OUTPUT"
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"
php ${MOKO_CLI}/manifest_read.php --path . --github-output
- name: Resolve metadata
- name: Resolve metadata and bump version
id: meta
run: |
STABILITY="${{ inputs.stability }}"
STABILITY="${{ inputs.stability || 'development' }}"
case "$STABILITY" in
development) SUFFIX="-dev"; TAG="development" ;;
@@ -77,98 +85,44 @@ jobs:
release-candidate) SUFFIX="-rc"; TAG="release-candidate" ;;
esac
# Read and bump patch version (with rollover)
CURRENT=$(sed -n 's/.*VERSION:[[:space:]]*\([0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\).*/\1/p' README.md 2>/dev/null | head -1)
[ -z "$CURRENT" ] && CURRENT="00.00.00"
# Read current version (bump already handled by push workflow)
VERSION=$(php ${MOKO_CLI}/version_read.php --path . 2>/dev/null)
[ -z "$VERSION" ] && VERSION="00.00.01"
MAJOR=$(echo "$CURRENT" | cut -d. -f1)
MINOR=$(echo "$CURRENT" | cut -d. -f2)
PATCH=$(echo "$CURRENT" | cut -d. -f3)
# Strip any existing suffix from version before applying stability
VERSION=$(echo "$VERSION" | sed 's/-\(dev\|alpha\|beta\|rc\)$//')
# Patch bump with rollover: ZZ=99 → bump minor, YY=99 → bump major
NEW_PATCH=$((10#$PATCH + 1))
NEW_MINOR=$((10#$MINOR))
NEW_MAJOR=$((10#$MAJOR))
php ${MOKO_CLI}/version_set_platform.php \
--path . --version "$VERSION" --branch "${{ github.ref_name }}" --stability "$STABILITY" 2>/dev/null || true
if [ $NEW_PATCH -gt 99 ]; then
NEW_PATCH=0
NEW_MINOR=$((NEW_MINOR + 1))
# Verify version consistency across all files
php ${MOKO_CLI}/version_check.php --path . --fix 2>/dev/null || true
# Update VERSION variable with suffix
if [ -n "$SUFFIX" ]; then
VERSION="${VERSION}${SUFFIX}"
fi
if [ $NEW_MINOR -gt 99 ]; then
NEW_MINOR=0
NEW_MAJOR=$((NEW_MAJOR + 1))
fi
VERSION=$(printf "%02d.%02d.%02d" $NEW_MAJOR $NEW_MINOR $NEW_PATCH)
TODAY=$(date +%Y-%m-%d)
echo "Bumping: ${CURRENT} → ${VERSION} (patch)"
# Update README.md
sed -i "s/VERSION:[[:space:]]*${CURRENT}/VERSION: ${VERSION}/" README.md
# Update platform-specific manifest
PLATFORM="${{ steps.platform.outputs.platform }}"
MANIFEST="${{ steps.platform.outputs.manifest }}"
MOD_FILE="${{ steps.platform.outputs.mod_file }}"
case "$PLATFORM" in
joomla)
if [ -n "$MANIFEST" ]; then
MANIFEST_VER=$(sed -n 's/.*<version>\([^<]*\)<\/version>.*/\1/p' "$MANIFEST" | head -1)
sed -i "s|<version>${MANIFEST_VER}</version>|<version>${VERSION}</version>|" "$MANIFEST"
sed -i "s|<creationDate>[^<]*</creationDate>|<creationDate>${TODAY}</creationDate>|" "$MANIFEST"
fi
;;
dolibarr)
if [ -n "$MOD_FILE" ]; then
sed -i "s/\$this->version = '[^']*'/\$this->version = '${VERSION}'/" "$MOD_FILE"
fi
;;
*) ;;
esac
# 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 remote set-url origin "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
git add -A
git diff --cached --quiet || {
git commit -m "chore(version): bump ${CURRENT} → ${VERSION} [skip ci]"
git commit -m "chore(version): pre-release bump to ${VERSION} [skip ci]"
git push origin HEAD 2>&1
}
# Auto-detect element (platform-aware)
case "$PLATFORM" in
joomla)
MANIFEST="${{ steps.platform.outputs.manifest }}"
EXT_ELEMENT=""
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)
MOD_FILE="${{ steps.platform.outputs.mod_file }}"
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
# Auto-detect element via manifest_element.php
php ${MOKO_CLI}/manifest_element.php \
--path . --version "$VERSION" --stability "$STABILITY" \
--repo "${GITEA_REPO}" --github-output
ZIP_NAME="${EXT_ELEMENT}-${VERSION}${SUFFIX}.zip"
# Read back element outputs
EXT_ELEMENT=$(grep '^ext_element=' "$GITHUB_OUTPUT" | tail -1 | cut -d= -f2)
ZIP_NAME=$(grep '^zip_name=' "$GITHUB_OUTPUT" | tail -1 | cut -d= -f2)
[ -z "$EXT_ELEMENT" ] && EXT_ELEMENT=$(echo "${GITEA_REPO}" | tr '[:upper:]' '[:lower:]' | tr -d ' -')
[ -z "$ZIP_NAME" ] && ZIP_NAME="${EXT_ELEMENT}-${VERSION}.zip"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
echo "stability=${STABILITY}" >> "$GITHUB_OUTPUT"
@@ -176,151 +130,52 @@ jobs:
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
mkdir -p build/package
rsync -a \
--exclude='sftp-config*' \
--exclude='.ftpignore' \
--exclude='*.ppk' \
--exclude='*.pem' \
--exclude='*.key' \
--exclude='.env*' \
--exclude='*.local' \
--exclude='.build-trigger' \
"${SOURCE_DIR}/" build/package/
- 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
- name: Create 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)
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
php ${MOKO_CLI}/release_create.php \
--path . --version "$VERSION" --tag "$TAG" \
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \
--repo "${GITEA_REPO}" --branch dev --prerelease
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: Build package and upload
id: package
run: |
VERSION="${{ steps.meta.outputs.version }}"
TAG="${{ steps.meta.outputs.tag }}"
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
php ${MOKO_CLI}/release_package.php \
--path . --version "$VERSION" --tag "$TAG" \
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \
--repo "${GITEA_REPO}" --output /tmp || true
- 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 }}"
DATE=$(date +%Y-%m-%d)
STABILITY="${{ steps.meta.outputs.stability }}"
SHA256="${{ steps.package.outputs.sha256_zip }}"
if [ ! -f "updates.xml" ]; then
echo "No updates.xml skipping"
echo "No updates.xml -- skipping"
exit 0
fi
export PY_STABILITY="$STABILITY" PY_VERSION="$VERSION" PY_SHA256="$SHA256" \
PY_ZIP_NAME="$ZIP_NAME" PY_TAG="$TAG" PY_DATE="$DATE" \
PY_GITEA_ORG="$GITEA_ORG" PY_GITEA_REPO="$GITEA_REPO"
python3 << 'PYEOF'
import re, os
SHA_FLAG=""
[ -n "$SHA256" ] && SHA_FLAG="--sha ${SHA256}"
stability = os.environ["PY_STABILITY"]
version = os.environ["PY_VERSION"]
sha256 = os.environ["PY_SHA256"]
zip_name = os.environ["PY_ZIP_NAME"]
tag = os.environ["PY_TAG"]
date = os.environ["PY_DATE"]
gitea_org = os.environ["PY_GITEA_ORG"]
gitea_repo = os.environ["PY_GITEA_REPO"]
download_url = f"https://git.mokoconsulting.tech/{gitea_org}/{gitea_repo}/releases/download/{tag}/{zip_name}"
php ${MOKO_CLI}/updates_xml_build.php \
--path . --version "${VERSION}" --stability "${STABILITY}" \
--gitea-url "${GITEA_URL}" --org "${GITEA_ORG}" --repo "${GITEA_REPO}" \
${SHA_FLAG}
with open("updates.xml", "r") as f:
content = f.read()
# Map stability to XML tag name
tag_map = {"development": "development", "alpha": "alpha", "beta": "beta", "release-candidate": "rc"}
xml_tag = tag_map.get(stability, stability)
pattern = r"(<update>(?:(?!</update>).)*?<tag>" + re.escape(xml_tag) + r"</tag>.*?</update>)"
match = re.search(pattern, content, re.DOTALL)
if match:
block = match.group(1)
updated = re.sub(r"<version>[^<]*</version>", f"<version>{version}</version>", block)
updated = re.sub(r"<creationDate>[^<]*</creationDate>", f"<creationDate>{date}</creationDate>", updated)
if "<sha256>" in updated:
updated = re.sub(r"<sha256>[^<]*</sha256>", f"<sha256>{sha256}</sha256>", updated)
else:
updated = updated.replace("</downloads>", f"</downloads>\n <sha256>{sha256}</sha256>")
updated = re.sub(r"(<downloadurl[^>]*>)[^<]*(</downloadurl>)", rf"\g<1>{download_url}\g<2>", updated)
content = content.replace(block, updated)
print(f"Updated {xml_tag} channel: version={version}")
else:
print(f"WARNING: No <tag>{xml_tag}</tag> block in updates.xml")
with open("updates.xml", "w") as f:
f.write(content)
PYEOF
# Commit and push to current branch
# 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]"
@@ -336,13 +191,11 @@ jobs:
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
git config --local user.name "gitea-actions[bot]"
# Sync updates.xml to main and dev (whichever isn't current)
for BRANCH in main dev; do
[ "$BRANCH" = "$CURRENT_BRANCH" ] && continue
echo "Syncing updates.xml → ${BRANCH}"
echo "Syncing updates.xml -> ${BRANCH}"
git fetch origin "${BRANCH}" 2>/dev/null || continue
git checkout "origin/${BRANCH}" -- . 2>/dev/null || continue
git checkout "origin/${BRANCH}" -- updates.xml 2>/dev/null || continue
git checkout "${CURRENT_BRANCH}" -- updates.xml
if ! git diff --quiet updates.xml 2>/dev/null; then
git add updates.xml
@@ -356,29 +209,25 @@ jobs:
continue-on-error: true
run: |
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
TOKEN="${{ secrets.GA_TOKEN }}"
TOKEN="${{ secrets.MOKOGITEA_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 }}"
# Cascade: rc → beta,alpha,dev | beta → alpha,dev | alpha → dev | dev → nothing
case "$STABILITY" in
release-candidate) TAGS_TO_DELETE="beta alpha development" ;;
beta) TAGS_TO_DELETE="alpha development" ;;
alpha) TAGS_TO_DELETE="development" ;;
*) TAGS_TO_DELETE="" ;;
esac
[ -z "$TAGS_TO_DELETE" ] && exit 0
for TAG in $TAGS_TO_DELETE; do
RELEASE_ID=$(curl -sS -H "Authorization: token ${TOKEN}" \
"${API_BASE}/releases/tags/${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
curl -sS -X DELETE -H "Authorization: token ${TOKEN}" \
"${API_BASE}/releases/${RELEASE_ID}" 2>/dev/null || true
curl -sS -X DELETE -H "Authorization: token ${TOKEN}" \
"${API_BASE}/tags/${TAG}" 2>/dev/null || true
echo "Deleted: ${TAG} (id: ${RELEASE_ID})"
fi
done
ZIP_NAME="${{ steps.meta.outputs.zip_name }}"
SHA256="${{ steps.package.outputs.sha256_zip }}"
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
File diff suppressed because it is too large Load Diff
+18 -2
View File
@@ -4,8 +4,8 @@
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: MokoStandards.Security
# REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards
# INGROUP: moko-platform.Security
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
# PATH: /.gitea/workflows/security-audit.yml
# VERSION: 01.00.00
# BRIEF: Dependency vulnerability scanning for composer and npm packages
@@ -80,3 +80,19 @@ jobs:
-H "Priority: high" \
-d "Security audit found vulnerabilities. Review dependency updates." \
"${NTFY_URL}/${NTFY_TOPIC}" || true
- name: Joomla version audit
if: always()
run: |
if [ -f "monitoring/joomla-version-audit.php" ] && [ -n "$JOOMLA_SITES" ]; then
echo "$JOOMLA_SITES" > /tmp/sites.json
php monitoring/joomla-version-audit.php --sites /tmp/sites.json || true
echo "### Joomla Version Audit" >> $GITHUB_STEP_SUMMARY
rm -f /tmp/sites.json
else
echo "Joomla audit skipped (no script or JOOMLA_SITES_JSON not configured)"
fi
env:
JOOMLA_SITES: ${{ vars.JOOMLA_SITES_JSON }}
+150 -302
View File
@@ -4,20 +4,18 @@
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: MokoStandards.Joomla
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
# PATH: /templates/workflows/joomla/update-server.yml.template
# VERSION: 04.06.00
# BRIEF: Update Joomla update server XML feed with stable/rc/dev entries
# INGROUP: moko-platform.Universal
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
# PATH: /templates/workflows/update-server.yml
# VERSION: 05.00.00
# BRIEF: Pre-release build + update server XML for dev/alpha/beta/rc branches
#
# Writes updates.xml with multiple <update> entries:
# - <tag>stable</tag> on push to main (from auto-release)
# - <tag>rc</tag> on push to rc/**
# - <tag>development</tag> on push to dev or dev/**
# Thin wrapper around moko-platform CLI tools.
# Builds packages, updates updates.xml, and optionally deploys via SFTP.
#
# Joomla filters by user's "Minimum Stability" setting.
# Joomla filters update entries by the user's "Minimum Stability" setting.
name: "Joomla: Update Server"
name: "Update Server"
on:
push:
@@ -66,55 +64,60 @@ permissions:
jobs:
update-xml:
name: Update updates.xml
name: Update Server
runs-on: release
if: >-
github.event.pull_request.merged == true || github.event_name == 'workflow_dispatch' || github.event_name == 'push'
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@v4
with:
token: ${{ secrets.GA_TOKEN }}
token: ${{ secrets.MOKOGITEA_TOKEN }}
fetch-depth: 0
- name: Setup MokoStandards tools
- name: Setup moko-platform tools
env:
MOKO_CLONE_TOKEN: ${{ secrets.GA_TOKEN }}
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
COMPOSER_AUTH: '{"http-basic":{"git.mokoconsulting.tech":{"username":"token","password":"${{ secrets.GA_TOKEN }}"}}}'
COMPOSER_AUTH: '{"http-basic":{"git.mokoconsulting.tech":{"username":"token","password":"${{ secrets.MOKOGITEA_TOKEN }}"}}}'
run: |
if ! command -v composer &> /dev/null; then
sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer >/dev/null 2>&1
fi
# Always fetch latest CLI tools — never use stale cache from previous runs
rm -rf /tmp/moko-platform
git clone --depth 1 --branch main --quiet \
"https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/MokoStandards-API.git" \
/tmp/mokostandards-api 2>/dev/null || true
if [ -d "/tmp/mokostandards-api" ] && [ -f "/tmp/mokostandards-api/composer.json" ]; then
cd /tmp/mokostandards-api && composer install --no-dev --no-interaction --quiet 2>/dev/null || true
"https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/moko-platform.git" \
/tmp/moko-platform 2>/dev/null || true
if [ -d "/tmp/moko-platform" ] && [ -f "/tmp/moko-platform/composer.json" ]; then
cd /tmp/moko-platform && composer install --no-dev --no-interaction --quiet 2>/dev/null || true
fi
echo "MOKO_CLI=/tmp/moko-platform/cli" >> "$GITHUB_ENV"
- name: Generate updates.xml entry
id: update
- name: Detect platform
id: platform
run: php ${MOKO_CLI}/manifest_read.php --path . --github-output
- name: Resolve stability and bump version
id: meta
run: |
BRANCH="${{ github.ref_name }}"
REPO="${{ github.repository }}"
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
VERSION=$(php /tmp/mokostandards-api/cli/version_read.php --path . 2>/dev/null || echo "0.0.0")
# Auto-bump patch on all branches (dev, alpha, beta, rc)
# Configure git for bot pushes
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
git config --local user.name "gitea-actions[bot]"
BUMPED=$(php /tmp/mokostandards-api/cli/version_bump.php --path . 2>/dev/null || true)
if [ -n "$BUMPED" ]; then
VERSION=$(php /tmp/mokostandards-api/cli/version_read.php --path . 2>/dev/null || echo "$VERSION")
git add -A
git commit -m "chore(version): auto-bump patch ${VERSION} [skip ci]" \
--author="gitea-actions[bot] <gitea-actions[bot]@mokoconsulting.tech>" 2>/dev/null || true
git push 2>/dev/null || true
fi
git remote set-url origin "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
# Determine stability from branch or input
# Auto-bump patch version
php ${MOKO_CLI}/version_bump.php --path . 2>/dev/null || true
VERSION=$(php ${MOKO_CLI}/version_read.php --path . 2>/dev/null || echo "0.0.0")
# Strip any existing suffix before applying stability
VERSION=$(echo "$VERSION" | sed 's/-\(dev\|alpha\|beta\|rc\)$//')
# Determine stability from branch or manual input
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
STABILITY="${{ inputs.stability }}"
elif [[ "$BRANCH" == rc/* ]]; then
@@ -123,277 +126,122 @@ jobs:
STABILITY="beta"
elif [[ "$BRANCH" == alpha/* ]]; then
STABILITY="alpha"
elif [[ "$BRANCH" == dev/* ]] || [[ "$BRANCH" == "dev" ]]; then
else
STABILITY="development"
else
STABILITY="stable"
fi
# Version suffix per stability stream
case "$STABILITY" in
development) SUFFIX="-dev"; TAG="development" ;;
alpha) SUFFIX="-alpha"; TAG="alpha" ;;
beta) SUFFIX="-beta"; TAG="beta" ;;
rc) SUFFIX="-rc"; TAG="release-candidate" ;;
*) SUFFIX=""; TAG="stable" ;;
esac
# Propagate version with stability suffix to all manifest files
php ${MOKO_CLI}/version_set_platform.php \
--path . --version "$VERSION" --branch "$BRANCH" --stability "$STABILITY" 2>/dev/null || true
php ${MOKO_CLI}/version_check.php --path . --fix 2>/dev/null || true
# Re-read version (now includes suffix from version_set_platform)
if [ -n "$SUFFIX" ]; then
VERSION="${VERSION}${SUFFIX}"
fi
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
echo "stability=${STABILITY}" >> "$GITHUB_OUTPUT"
echo "suffix=${SUFFIX}" >> "$GITHUB_OUTPUT"
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
echo "display_version=${VERSION}" >> "$GITHUB_OUTPUT"
# Parse manifest (portable — no grep -P)
MANIFEST=$(find . -maxdepth 3 -name "*.xml" ! -path "./.git/*" ! -path "./build/*" -exec grep -l '<extension' {} \; 2>/dev/null | head -1)
if [ -z "$MANIFEST" ]; then
echo "No Joomla manifest found — skipping"
exit 0
fi
# Extract fields using sed (works on all runners)
EXT_NAME=$(sed -n 's/.*<name>\([^<]*\)<\/name>.*/\1/p' "$MANIFEST" | head -1)
EXT_TYPE=$(sed -n 's/.*<extension[^>]*type="\([^"]*\)".*/\1/p' "$MANIFEST" | head -1)
EXT_ELEMENT=$(sed -n 's/.*<element>\([^<]*\)<\/element>.*/\1/p' "$MANIFEST" | head -1)
EXT_CLIENT=$(sed -n 's/.*<extension[^>]*client="\([^"]*\)".*/\1/p' "$MANIFEST" | head -1)
EXT_FOLDER=$(sed -n 's/.*<extension[^>]*group="\([^"]*\)".*/\1/p' "$MANIFEST" | head -1)
EXT_VERSION=$(sed -n 's/.*<version>\([^<]*\)<\/version>.*/\1/p' "$MANIFEST" | head -1)
TARGET_PLATFORM=$(sed -n 's/.*\(<targetplatform[^/]*\/>\).*/\1/p' "$MANIFEST" | head -1)
PHP_MINIMUM=$(sed -n 's/.*<php_minimum>\([^<]*\)<\/php_minimum>.*/\1/p' "$MANIFEST" | head -1)
# Fallbacks
[ -z "$EXT_NAME" ] && EXT_NAME="${{ github.event.repository.name }}"
[ -z "$EXT_TYPE" ] && EXT_TYPE="component"
# Derive element if not in manifest: try XML filename, then repo name
if [ -z "$EXT_ELEMENT" ]; then
EXT_ELEMENT=$(basename "$MANIFEST" .xml | tr '[:upper:]' '[:lower:]')
case "$EXT_ELEMENT" in
templatedetails|manifest|*.xml) EXT_ELEMENT=$(echo "${{ github.event.repository.name }}" | tr '[:upper:]' '[:lower:]' | tr -d ' -') ;;
esac
fi
# Use manifest version if README version is empty
[ "$VERSION" = "0.0.0" ] && [ -n "$EXT_VERSION" ] && VERSION="$EXT_VERSION"
[ -z "$TARGET_PLATFORM" ] && TARGET_PLATFORM=$(printf '<targetplatform name="joomla" version="((5.[0-9])|(6.[0-9]))" %s>' "/")
CLIENT_TAG=""
[ -n "$EXT_CLIENT" ] && CLIENT_TAG="<client>${EXT_CLIENT}</client>"
[ -z "$CLIENT_TAG" ] && ([ "$EXT_TYPE" = "module" ] || [ "$EXT_TYPE" = "plugin" ]) && CLIENT_TAG="<client>site</client>"
FOLDER_TAG=""
[ -n "$EXT_FOLDER" ] && [ "$EXT_TYPE" = "plugin" ] && FOLDER_TAG="<folder>${EXT_FOLDER}</folder>"
PHP_TAG=""
[ -n "$PHP_MINIMUM" ] && PHP_TAG="<php_minimum>${PHP_MINIMUM}</php_minimum>"
# Version suffix for non-stable
DISPLAY_VERSION="$VERSION"
case "$STABILITY" in
development) DISPLAY_VERSION="${VERSION}-dev" ;;
alpha) DISPLAY_VERSION="${VERSION}-alpha" ;;
beta) DISPLAY_VERSION="${VERSION}-beta" ;;
rc) DISPLAY_VERSION="${VERSION}-rc" ;;
esac
MAJOR=$(echo "$VERSION" | awk -F. '{print $1}')
# Each stability level has its own release tag
case "$STABILITY" in
development) RELEASE_TAG="development" ;;
alpha) RELEASE_TAG="alpha" ;;
beta) RELEASE_TAG="beta" ;;
rc) RELEASE_TAG="release-candidate" ;;
*) RELEASE_TAG="v${MAJOR}" ;;
esac
PACKAGE_NAME="${EXT_ELEMENT}-${DISPLAY_VERSION}.zip"
DOWNLOAD_URL="${GITEA_URL}/${GITEA_ORG}/${GITEA_REPO}/releases/download/${RELEASE_TAG}/${PACKAGE_NAME}"
INFO_URL="${GITEA_URL}/${GITEA_ORG}/${GITEA_REPO}"
# -- Build install packages (ZIP + tar.gz) --------------------
SOURCE_DIR="src"
[ ! -d "$SOURCE_DIR" ] && SOURCE_DIR="htdocs"
if [ -d "$SOURCE_DIR" ]; then
EXCLUDES=".ftpignore sftp-config* *.ppk *.pem *.key .env*"
TAR_NAME="${EXT_ELEMENT}-${DISPLAY_VERSION}.tar.gz"
cd "$SOURCE_DIR"
zip -r "/tmp/${PACKAGE_NAME}" . -x $EXCLUDES
cd ..
tar -czf "/tmp/${TAR_NAME}" -C "$SOURCE_DIR" \
--exclude='.ftpignore' --exclude='sftp-config*' \
--exclude='*.ppk' --exclude='*.pem' --exclude='*.key' --exclude='.env*' .
SHA256=$(sha256sum "/tmp/${PACKAGE_NAME}" | cut -d' ' -f1)
# Ensure release exists on Gitea
RELEASE_JSON=$(curl -sf -H "Authorization: token ${{ secrets.GA_TOKEN }}" \
"${API_BASE}/releases/tags/${RELEASE_TAG}" 2>/dev/null || true)
RELEASE_ID=$(echo "$RELEASE_JSON" | python3 -c "import sys,json; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true)
if [ -z "$RELEASE_ID" ]; then
# Create release
RELEASE_JSON=$(curl -sf -X POST -H "Authorization: token ${{ secrets.GA_TOKEN }}" \
-H "Content-Type: application/json" \
"${API_BASE}/releases" \
-d "$(python3 -c "import json; print(json.dumps({
'tag_name': '${RELEASE_TAG}',
'name': '${RELEASE_TAG} (${DISPLAY_VERSION})',
'body': '${STABILITY} release',
'prerelease': True,
'target_commitish': 'main'
}))")" 2>/dev/null || true)
RELEASE_ID=$(echo "$RELEASE_JSON" | python3 -c "import sys,json; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true)
fi
if [ -n "$RELEASE_ID" ]; then
# Delete existing assets with same name before uploading
ASSETS=$(curl -sf -H "Authorization: token ${{ secrets.GA_TOKEN }}" \
"${API_BASE}/releases/${RELEASE_ID}/assets" 2>/dev/null || echo "[]")
for ASSET_FILE in "$PACKAGE_NAME" "$TAR_NAME"; do
ASSET_ID=$(echo "$ASSETS" | python3 -c "
import sys,json
assets = json.load(sys.stdin)
for a in assets:
if a['name'] == '${ASSET_FILE}':
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
done
# Upload both formats
curl -sf -X POST -H "Authorization: token ${{ secrets.GA_TOKEN }}" \
-H "Content-Type: application/octet-stream" \
--data-binary @"/tmp/${PACKAGE_NAME}" \
"${API_BASE}/releases/${RELEASE_ID}/assets?name=${PACKAGE_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
fi
echo "Packages: ${PACKAGE_NAME} + ${TAR_NAME} (SHA: ${SHA256})" >> $GITHUB_STEP_SUMMARY
else
SHA256=""
fi
# -- Build the new entry (canonical format matching release.yml) --
NEW_ENTRY=""
NEW_ENTRY="${NEW_ENTRY} <update>\n"
NEW_ENTRY="${NEW_ENTRY} <name>${EXT_NAME}</name>\n"
NEW_ENTRY="${NEW_ENTRY} <description>${EXT_NAME} ${STABILITY} build.</description>\n"
NEW_ENTRY="${NEW_ENTRY} <element>${EXT_ELEMENT}</element>\n"
NEW_ENTRY="${NEW_ENTRY} <type>${EXT_TYPE}</type>\n"
[ -n "$CLIENT_TAG" ] && NEW_ENTRY="${NEW_ENTRY} ${CLIENT_TAG}\n"
[ -n "$FOLDER_TAG" ] && NEW_ENTRY="${NEW_ENTRY} ${FOLDER_TAG}\n"
NEW_ENTRY="${NEW_ENTRY} <version>${VERSION}</version>\n"
NEW_ENTRY="${NEW_ENTRY} <creationDate>$(date +%Y-%m-%d)</creationDate>\n"
NEW_ENTRY="${NEW_ENTRY} <infourl title='${EXT_NAME}'>https://git.mokoconsulting.tech/${GITEA_ORG}/${GITEA_REPO}/releases/tag/${RELEASE_TAG}</infourl>\n"
NEW_ENTRY="${NEW_ENTRY} <downloads>\n"
NEW_ENTRY="${NEW_ENTRY} <downloadurl type='full' format='zip'>${DOWNLOAD_URL}</downloadurl>\n"
NEW_ENTRY="${NEW_ENTRY} </downloads>\n"
[ -n "$SHA256" ] && NEW_ENTRY="${NEW_ENTRY} <sha256>${SHA256}</sha256>\n"
NEW_ENTRY="${NEW_ENTRY} <tags><tag>${STABILITY}</tag></tags>\n"
NEW_ENTRY="${NEW_ENTRY} <maintainer>Moko Consulting</maintainer>\n"
NEW_ENTRY="${NEW_ENTRY} <maintainerurl>https://mokoconsulting.tech</maintainerurl>\n"
NEW_ENTRY="${NEW_ENTRY} <targetplatform name='joomla' version='(5|6).*'/>\n"
[ -n "$PHP_MINIMUM" ] && NEW_ENTRY="${NEW_ENTRY} <php_minimum>${PHP_MINIMUM}</php_minimum>\n"
NEW_ENTRY="${NEW_ENTRY} </update>"
# -- Write new entry to temp file --------------------------------
printf '%b' "$NEW_ENTRY" > /tmp/new_entry.xml
# -- Merge into updates.xml ----------------------------------------
# Cascade: stable→all | rc→rc+lower | beta→beta+lower | alpha→alpha+dev | dev→dev
CASCADE_MAP="stable:development,alpha,beta,rc,stable rc:development,alpha,beta,rc beta:development,alpha,beta alpha:development,alpha development:development"
TARGETS=""
for entry in $CASCADE_MAP; do
key="${entry%%:*}"
vals="${entry#*:}"
if [ "$key" = "${STABILITY}" ]; then
TARGETS="$vals"
break
fi
done
[ -z "$TARGETS" ] && TARGETS="${STABILITY}"
echo "Cascade: ${STABILITY} → ${TARGETS}"
# Create updates.xml if missing
if [ ! -f "updates.xml" ]; then
printf '%s\n' "<?xml version='1.0' encoding='UTF-8'?>" > updates.xml
printf '%s\n' "<!-- Copyright (C) $(date +%Y) Moko Consulting -->" >> updates.xml
printf '%s\n' "<updates>" >> updates.xml
printf '%s\n' "</updates>" >> updates.xml
fi
# Update existing blocks or create missing ones
export PY_TARGETS="$TARGETS" PY_VERSION="$VERSION" PY_DATE="$(date +%Y-%m-%d)"
python3 << 'PYEOF'
import re, os
targets = os.environ["PY_TARGETS"].split(",")
version = os.environ["PY_VERSION"]
date = os.environ["PY_DATE"]
with open("updates.xml") as f:
content = f.read()
with open("/tmp/new_entry.xml") as f:
new_entry_template = f.read()
for tag in targets:
tag = tag.strip()
# Build entry with this tag's name
new_entry = re.sub(r"<tag>[^<]*</tag>", f"<tag>{tag}</tag>", new_entry_template)
# Try to find existing block (handles both single-line and multi-line <tags>)
block_pattern = r"(<update>(?:(?!</update>).)*?<tag>" + re.escape(tag) + r"</tag>.*?</update>)"
match = re.search(block_pattern, content, re.DOTALL)
if match:
# Update in place — replace entire block
content = content.replace(match.group(1), new_entry.strip())
print(f" UPDATED: <tag>{tag}</tag> → {version}")
else:
# Create — insert before </updates>
content = content.replace("</updates>", "\n" + new_entry.strip() + "\n\n</updates>")
print(f" CREATED: <tag>{tag}</tag> → {version}")
# Clean up excessive blank lines
content = re.sub(r"\n{3,}", "\n\n", content)
with open("updates.xml", "w") as f:
f.write(content)
PYEOF
# Commit
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
git config --local user.name "gitea-actions[bot]"
git add updates.xml
# Commit version bump if changed
git add -A
git diff --cached --quiet || {
git commit -m "chore: update updates.xml (${STABILITY}: ${DISPLAY_VERSION}) [skip ci]" \
git commit -m "chore(version): auto-bump ${VERSION} [skip ci]" \
--author="gitea-actions[bot] <gitea-actions[bot]@mokoconsulting.tech>"
git push
}
# -- Sync updates.xml to main (for non-main branches) ----------------------
- name: Create release and upload package
id: package
run: |
VERSION="${{ steps.meta.outputs.version }}"
TAG="${{ steps.meta.outputs.tag }}"
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
# Create or update Gitea release
php ${MOKO_CLI}/release_create.php \
--path . --version "$VERSION" --tag "$TAG" \
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \
--repo "${GITEA_REPO}" --branch "${{ github.ref_name }}" --prerelease
# Build package and upload
php ${MOKO_CLI}/release_package.php \
--path . --version "$VERSION" --tag "$TAG" \
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \
--repo "${GITEA_REPO}" --output /tmp || true
- name: Update updates.xml
if: steps.platform.outputs.platform == 'joomla'
run: |
VERSION="${{ steps.meta.outputs.version }}"
STABILITY="${{ steps.meta.outputs.stability }}"
SHA256="${{ steps.package.outputs.sha256_zip }}"
if [ ! -f "updates.xml" ]; then
echo "No updates.xml — skipping"
exit 0
fi
SHA_FLAG=""
[ -n "$SHA256" ] && SHA_FLAG="--sha ${SHA256}"
php ${MOKO_CLI}/updates_xml_build.php \
--path . --version "${VERSION}" --stability "${STABILITY}" \
--gitea-url "${GITEA_URL}" --org "${GITEA_ORG}" --repo "${GITEA_REPO}" \
${SHA_FLAG}
# Commit and push updates.xml
git add updates.xml
git diff --cached --quiet || {
git commit -m "chore: update ${STABILITY} channel ${VERSION} [skip ci]"
git push
}
- name: Sync updates.xml to main
if: github.ref_name != 'main'
if: github.ref_name != 'main' && steps.platform.outputs.platform == 'joomla'
run: |
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
GA_TOKEN="${{ secrets.GA_TOKEN }}"
GITEA_TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
FILE_SHA=$(curl -sf -H "Authorization: token ${GA_TOKEN}" \
FILE_SHA=$(curl -sf -H "Authorization: token ${GITEA_TOKEN}" \
"${API_BASE}/contents/updates.xml?ref=main" | python3 -c "import sys,json; print(json.load(sys.stdin).get('sha',''))" 2>/dev/null || true)
if [ -n "$FILE_SHA" ] && [ -f "updates.xml" ]; then
CONTENT=$(base64 -w0 updates.xml)
curl -sf -X PUT -H "Authorization: token ${GA_TOKEN}" \
-H "Content-Type: application/json" \
"${API_BASE}/contents/updates.xml" \
-d "$(python3 -c "import json; print(json.dumps({
'content': '${CONTENT}',
'sha': '${FILE_SHA}',
'message': 'chore: sync updates.xml from ${STABILITY} [skip ci]',
'branch': 'main'
}))")" > /dev/null 2>&1 \
&& echo "updates.xml synced to main (${STABILITY})" >> $GITHUB_STEP_SUMMARY \
|| echo "WARNING: failed to sync updates.xml to main" >> $GITHUB_STEP_SUMMARY
else
echo "WARNING: could not get updates.xml SHA from main" >> $GITHUB_STEP_SUMMARY
python3 -c "
import base64, json, urllib.request, sys
with open('updates.xml', 'rb') as f:
content = base64.b64encode(f.read()).decode()
payload = json.dumps({
'content': content,
'sha': '${FILE_SHA}',
'message': 'chore: sync updates.xml from ${{ steps.meta.outputs.stability }} [skip ci]',
'branch': 'main'
}).encode()
req = urllib.request.Request(
'${API_BASE}/contents/updates.xml',
data=payload, method='PUT',
headers={
'Authorization': 'token ${GITEA_TOKEN}',
'Content-Type': 'application/json'
})
try:
urllib.request.urlopen(req)
print('updates.xml synced to main')
except Exception as e:
print(f'WARNING: sync to main failed: {e}', file=sys.stderr)
"
fi
- name: SFTP deploy to dev server
@@ -407,12 +255,11 @@ jobs:
DEV_KEY: ${{ secrets.DEV_FTP_KEY }}
DEV_PASS: ${{ secrets.DEV_FTP_PASSWORD }}
run: |
# -- Permission check: admin or maintain role required --------
# Permission check: admin or maintain role required
ACTOR="${{ github.actor }}"
REPO="${{ github.repository }}"
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
PERMISSION=$(curl -sf -H "Authorization: token ${{ secrets.GA_TOKEN }}" \
PERMISSION=$(curl -sf -H "Authorization: token ${{ secrets.MOKOGITEA_TOKEN }}" \
"${API_BASE}/collaborators/${ACTOR}/permission" 2>/dev/null | \
python3 -c "import sys,json; print(json.load(sys.stdin).get('permission','read'))" 2>/dev/null || echo "read")
case "$PERMISSION" in
@@ -442,11 +289,11 @@ jobs:
printf ',"password":"%s"}' "$DEV_PASS" >> /tmp/sftp-config.json
fi
PLATFORM=$(php /tmp/mokostandards-api/cli/platform_detect.php --path . 2>/dev/null || true)
if [ "$PLATFORM" = "waas-component" ] && [ -f "/tmp/mokostandards-api/deploy/deploy-joomla.php" ]; then
php /tmp/mokostandards-api/deploy/deploy-joomla.php --path . --src-dir "$SOURCE_DIR" --config /tmp/sftp-config.json
elif [ -f "/tmp/mokostandards-api/deploy/deploy-sftp.php" ]; then
php /tmp/mokostandards-api/deploy/deploy-sftp.php --path . --src-dir "$SOURCE_DIR" --config /tmp/sftp-config.json
PLATFORM=$(php ${MOKO_CLI}/platform_detect.php --path . 2>/dev/null || true)
if [ "$PLATFORM" = "waas-component" ] && [ -f "${MOKO_CLI}/../deploy/deploy-joomla.php" ]; then
php ${MOKO_CLI}/../deploy/deploy-joomla.php --path . --src-dir "$SOURCE_DIR" --config /tmp/sftp-config.json
elif [ -f "${MOKO_CLI}/../deploy/deploy-sftp.php" ]; then
php ${MOKO_CLI}/../deploy/deploy-sftp.php --path . --src-dir "$SOURCE_DIR" --config /tmp/sftp-config.json
fi
rm -f /tmp/deploy_key /tmp/sftp-config.json
echo "SFTP deploy to dev complete" >> $GITHUB_STEP_SUMMARY
@@ -454,11 +301,12 @@ jobs:
- name: Summary
if: always()
run: |
echo "## Joomla Update Server" >> $GITHUB_STEP_SUMMARY
VERSION="${{ steps.meta.outputs.version }}"
STABILITY="${{ steps.meta.outputs.stability }}"
DISPLAY="${{ steps.meta.outputs.display_version }}"
echo "## Update Server" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
echo "|-------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| Stability | \`${STABILITY}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Version | \`${DISPLAY_VERSION}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Element | \`${EXT_ELEMENT}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Download | [ZIP](${DOWNLOAD_URL}) |" >> $GITHUB_STEP_SUMMARY
echo "| Version | \`${DISPLAY}\` |" >> $GITHUB_STEP_SUMMARY
+17
View File
@@ -8,6 +8,23 @@
# CHANGELOG - MokoDPCalendarAPI
## [Unreleased]
### Changed
- Migrated all workflow and template paths from `.github/` to `.mokogitea/`
- Template source paths updated: `templates/gitea/` to `templates/mokogitea/`
- HCL definition files removed -- Template repos are now the canonical source
### Added
- `branch-cleanup.yml`: auto-delete merged feature branches after PR merge
— 2026-05-23
### Removed
- Removed deploy-manual.yml workflow — switching to Joomla update server method for extension distribution
- Removed deploy variables and secrets (RS_FTP_PATH_SUFFIX, DEV_FTP_KEY)
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
+42
View File
@@ -0,0 +1,42 @@
# CLAUDE.md
This file provides guidance to Claude Code when working with this repository.
## Project Overview
**MokoDPCalendarAPI** -- Joomla Web Services plugin exposing DPCalendar events, calendars, and locations via REST API
| Field | Value |
|---|---|
| **Platform** | joomla |
| **Language** | PHP |
| **Default branch** | main |
| **License** | GPL-3.0-or-later |
| **Wiki** | [MokoDPCalendarAPI Wiki](https://git.mokoconsulting.tech/MokoConsulting/MokoDPCalendarAPI/wiki) |
| **Standards** | [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/Home) |
## Common Commands
```bash
composer install # Install PHP dependencies
```
## Architecture
This is a Joomla extension. Key directories:
- `src/` -- extension source (deployed to Joomla)
- `src/*.xml` -- manifest file (version, files, params)
- `src/src/` or `src/services/` -- PHP classes
- `src/language/` -- translation strings
- `src/media/` -- CSS/JS/images
## Rules
- **Workflow directory**: `.mokogitea/` (not `.gitea/` or `.github/`)
- **Never commit** `.claude/`, `.mcp.json`, `TODO.md`, or `*.min.css`/`*.min.js`
- **Attribution**: use `Authored-by: Moko Consulting` in commits
- **Branch strategy**: develop on `dev`, merge to `main` for release
- **Minification**: handled at build time (CI) and runtime (MokoMinifyHelper for Joomla templates)
- **Wiki**: documentation lives in the Gitea wiki, not in `docs/` files
- **Standards**: this repo follows [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/Home)
+161 -39
View File
@@ -1,39 +1,161 @@
<!--
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
SPDX-LICENSE-IDENTIFIER: GPL-3.0-or-later
REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoDPCalendarAPI
VERSION: 01.00.00
PATH: ./CONTRIBUTING.md
-->
# Contributing to MokoDPCalendarAPI
Thank you for your interest in contributing.
## Getting Started
1. Fork the repository
2. Create a feature branch from `main`
3. Make your changes in `src/`
4. Test by installing the plugin on a Joomla site with DPCalendar
5. Submit a pull request
## Development Setup
- Joomla 5.x or 6.x with DPCalendar installed
- PHP 8.1+
- A valid Joomla API token for testing
## Code Standards
- Follow MokoStandards file header format
- Use Joomla's namespace conventions (`Moko\Plugin\WebServices\MokoDPCalendarAPI`)
- All files must include the GPL-3.0-or-later license header
## Reporting Issues
Use the issue tracker on Gitea. Include:
- Joomla version
- DPCalendar version
- PHP version
- Steps to reproduce
# Contributing to Moko Consulting Projects
Thank you for your interest in contributing. All Moko Consulting repositories follow this universal workflow and version policy.
## Branching Workflow
```
feature/* ──PR──> dev ──draft PR──> (renamed to rc) ──merge──> main
```
### Step by step
1. **Create a feature branch** from `dev`:
```bash
git checkout dev && git pull
git checkout -b feature/my-change
```
2. **Work and commit** on your feature branch. Push to origin.
3. **Open a PR**: `feature/my-change` → `dev`. After review and checks, merge it.
4. **When ready for release**, open a **draft PR**: `dev` → `main`.
- This automatically renames the source branch to `rc` (release candidate)
- An RC pre-release is built and uploaded
5. **Alpha and beta branches** are created by manually renaming the branch before the RC stage:
- Rename `dev` to `alpha` for early testing → alpha pre-release is built
- Rename `alpha` to `beta` for feature-complete testing → beta pre-release is built
- When the draft PR is created, the branch is renamed to `rc`
6. **Once PR checks pass** on the `rc` branch, mark the PR as ready and merge to `main`.
7. **Merging to main** triggers the stable release pipeline:
- Minor version bump (e.g., `02.09.xx` → `02.10.00`)
- Stability suffix stripped (clean version)
- Gitea release created with ZIP/tar.gz packages
- `updates.xml` updated (Joomla extensions)
- `dev` branch recreated from `main`
### Branch summary
| Branch | Purpose | Created by |
|--------|---------|-----------|
| `feature/*` | New features and fixes | Developer |
| `dev` | Integration branch | Auto-recreated after release |
| `alpha` | Alpha pre-release testing | Manual rename from `dev` |
| `beta` | Beta pre-release testing | Manual rename from `alpha` |
| `rc` | Release candidate | Auto-renamed on draft PR to main |
| `main` | Stable releases | Protected, merge only |
| `version/XX.YY.ZZ` | Archived release snapshots | Auto-created by CI |
### Protected branches
| Branch | Direct push | Merge via |
|--------|------------|-----------|
| `main` | Blocked (CI bot whitelisted) | PR merge only |
| `dev` | Blocked (CI bot whitelisted) | PR merge from feature/* |
| `rc` | Blocked (CI bot whitelisted) | Auto-created on draft PR |
| `alpha` | Blocked (CI bot whitelisted) | Manual rename |
| `beta` | Blocked (CI bot whitelisted) | Manual rename |
| `feature/*` | Open | N/A (source branch) |
## Version Policy
### Format
All versions use `XX.YY.ZZ` — three two-digit segments, zero-padded:
- **XX** — Major version (breaking changes)
- **YY** — Minor version (new features, bumped on release to main)
- **ZZ** — Patch version (auto-incremented on every push to dev/feature branches)
Rollover: patch `99` → `00` increments minor; minor `99` → `00` increments major.
### Stability suffixes
Each branch appends a suffix to indicate stability:
| Branch | Suffix | Example |
|--------|--------|---------|
| `main` | (none) | `02.09.00` |
| `dev` | `-dev` | `02.09.01-dev` |
| `feature/*` | `-dev` | `02.09.01-dev` |
| `alpha` | `-alpha` | `02.09.01-alpha` |
| `beta` | `-beta` | `02.09.01-beta` |
| `rc` | `-rc` | `02.09.01-rc` |
### Auto version bump
On every push to `dev`, `feature/*`, or `patch/*`:
1. Patch version incremented
2. Stability suffix `-dev` applied
3. All version-bearing files updated (manifests, CHANGELOG, PHP headers, etc.)
4. Commit created with `[skip ci]` to avoid loops
### Release version flow
Version bumps happen at specific release events:
| Event | Bump | Example |
|-------|------|---------|
| Feature merged to dev | Patch bump after dev release | `02.09.01-dev` → release → `02.09.02-dev` |
| Dev promoted to RC | Minor bump | `02.09.02-dev` → `02.10.00-rc` |
| RC merged to main | Minor bump | `02.10.00-rc` → `02.11.00` (stable) |
| Dev recreated from main | Patch bump | `02.11.00` → `02.11.01-dev` |
### Release stream copies
When a higher-stability release is published, copies are created for all lesser streams with the same base version:
- **RC `02.10.00-rc`** also creates: `02.10.00-dev`, `02.10.00-alpha`, `02.10.00-beta`
- **Stable `02.11.00`** also creates: `02.11.00-dev`, `02.11.00-alpha`, `02.11.00-beta`, `02.11.00-rc`
This ensures Joomla sites on ANY stability channel see the update (Joomla only shows versions higher than what's installed).
### Version files
The version tools update all files containing version stamps:
- `.mokogitea/manifest.xml` (canonical source)
- Joomla XML manifests (`<version>` tag)
- `README.md`, `CHANGELOG.md` (`VERSION:` pattern)
- `package.json`, `pyproject.toml`
- Any text file with a `VERSION: XX.YY.ZZ` label
Files synced from other repos (with a `# REPO:` header) are not touched.
## Code Standards
- **PHP**: PSR-12, tabs for indentation
- **Copyright**: all files must include the Moko Consulting copyright header
- **License**: SPDX identifier `GPL-3.0-or-later` (or as specified per repo)
- **Attribution**: use `Authored-by: Moko Consulting` in commits, not individual names
## Commit Messages
Use conventional commit format:
```
type(scope): short description
Optional body with context.
Authored-by: Moko Consulting
```
Types: `feat`, `fix`, `chore`, `docs`, `style`, `refactor`, `test`, `ci`
Special flags in commit messages:
- `[skip ci]` — skip all CI workflows
- `[skip bump]` — skip auto version bump only
## Reporting Issues
Use the repository's issue tracker with the appropriate template.
---
*Moko Consulting <hello@mokoconsulting.tech>*
+237
View File
@@ -0,0 +1,237 @@
#!/usr/bin/env bash
# ============================================================================
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Automation.CI
# INGROUP: moko-platform.Automation
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
# PATH: /automation/ci-issue-reporter.sh
# VERSION: 09.23.00
# BRIEF: Creates or updates a Gitea issue when a CI gate fails.
# Deduplicates by searching open issues with the "ci-auto" label
# whose title matches the gate. If a matching issue exists, a comment
# is appended instead of opening a duplicate.
# ============================================================================
set -euo pipefail
# ── Defaults ────────────────────────────────────────────────────────────────
GITEA_URL="${GITEA_URL:-https://git.mokoconsulting.tech}"
GITEA_TOKEN="${GITEA_TOKEN:-}"
REPO="${GITHUB_REPOSITORY:-}"
RUN_URL="${GITHUB_SERVER_URL:-${GITEA_URL}}/${REPO}/actions/runs/${GITHUB_RUN_ID:-0}"
LABEL_NAME="ci-auto"
LABEL_COLOR="#e11d48"
GATE=""
DETAILS=""
SEVERITY="error"
WORKFLOW=""
# ── Parse arguments ─────────────────────────────────────────────────────────
usage() {
cat <<EOF
Usage: ci-issue-reporter.sh --gate NAME --details TEXT [OPTIONS]
Required:
--gate CI gate name (e.g. "Code Quality", "Self-Health")
--details Human-readable failure description
Optional:
--severity "error" (default) or "warning"
--workflow Workflow name for the issue title
--repo owner/repo (default: \$GITHUB_REPOSITORY)
--run-url URL to the CI run (auto-detected from env)
--token Gitea API token (default: \$GITEA_TOKEN)
--url Gitea base URL (default: \$GITEA_URL)
EOF
exit 1
}
while [[ $# -gt 0 ]]; do
case "$1" in
--gate) GATE="$2"; shift 2 ;;
--details) DETAILS="$2"; shift 2 ;;
--severity) SEVERITY="$2"; shift 2 ;;
--workflow) WORKFLOW="$2"; shift 2 ;;
--repo) REPO="$2"; shift 2 ;;
--run-url) RUN_URL="$2"; shift 2 ;;
--token) GITEA_TOKEN="$2"; shift 2 ;;
--url) GITEA_URL="$2"; shift 2 ;;
-h|--help) usage ;;
*) echo "Unknown option: $1"; usage ;;
esac
done
[[ -z "$GATE" ]] && { echo "ERROR: --gate is required"; usage; }
[[ -z "$DETAILS" ]] && { echo "ERROR: --details is required"; usage; }
[[ -z "$GITEA_TOKEN" ]] && { echo "ERROR: GITEA_TOKEN not set"; exit 1; }
[[ -z "$REPO" ]] && { echo "ERROR: GITHUB_REPOSITORY not set"; exit 1; }
API="${GITEA_URL}/api/v1/repos/${REPO}"
# ── Build title ─────────────────────────────────────────────────────────────
if [[ -n "$WORKFLOW" ]]; then
TITLE="[CI] ${WORKFLOW}: ${GATE} failed"
else
TITLE="[CI] ${GATE} failed"
fi
# ── Ensure label exists ─────────────────────────────────────────────────────
ensure_label() {
local exists
exists=$(curl -sf -o /dev/null -w '%{http_code}' \
-H "Authorization: token ${GITEA_TOKEN}" \
"${API}/labels" 2>/dev/null || echo "000")
if [[ "$exists" == "200" ]]; then
# Check if label already exists
local found
found=$(curl -sf \
-H "Authorization: token ${GITEA_TOKEN}" \
"${API}/labels" 2>/dev/null \
| grep -o "\"name\":\"${LABEL_NAME}\"" || true)
if [[ -z "$found" ]]; then
curl -sf -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"${API}/labels" \
-d "{\"name\":\"${LABEL_NAME}\",\"color\":\"${LABEL_COLOR}\",\"description\":\"Auto-created by CI issue reporter\"}" \
> /dev/null 2>&1 || true
fi
fi
}
# ── Search for existing open issue ──────────────────────────────────────────
find_existing_issue() {
# URL-encode the gate name for the query
local query
query=$(printf '%s' "[CI] ${GATE}" | sed 's/ /%20/g; s/\[/%5B/g; s/\]/%5D/g')
local response
response=$(curl -sf \
-H "Authorization: token ${GITEA_TOKEN}" \
"${API}/issues?type=issues&state=open&labels=${LABEL_NAME}&q=${query}&limit=5" \
2>/dev/null || echo "[]")
# Extract the first matching issue number
echo "$response" \
| grep -oP '"number":\s*\K[0-9]+' \
| head -1
}
# ── Build issue body ────────────────────────────────────────────────────────
build_body() {
local severity_badge
if [[ "$SEVERITY" == "error" ]]; then
severity_badge="**Severity:** Error"
else
severity_badge="**Severity:** Warning"
fi
cat <<BODY
## CI Gate Failure: ${GATE}
${severity_badge}
**Workflow:** ${WORKFLOW:-unknown}
**Branch:** ${GITHUB_REF_NAME:-unknown}
**Commit:** \`${GITHUB_SHA:0:8}\`
**Run:** [View CI run](${RUN_URL})
### Details
${DETAILS}
### Resolution
Fix the issue described above and push a new commit. This issue will be closed automatically when the gate passes, or can be closed manually.
---
*Auto-created by [ci-issue-reporter](${GITEA_URL}/${REPO}/src/branch/main/automation/ci-issue-reporter.sh)*
BODY
}
# ── Build comment body (for existing issues) ────────────────────────────────
build_comment() {
cat <<COMMENT
### CI failure recurrence
**Branch:** ${GITHUB_REF_NAME:-unknown}
**Commit:** \`${GITHUB_SHA:0:8}\`
**Run:** [View CI run](${RUN_URL})
${DETAILS}
COMMENT
}
# ── Main ────────────────────────────────────────────────────────────────────
ensure_label
EXISTING=$(find_existing_issue)
if [[ -n "$EXISTING" ]]; then
# Append comment to existing issue
COMMENT_BODY=$(build_comment)
COMMENT_JSON=$(printf '%s' "$COMMENT_BODY" | python3 -c "
import sys, json
print(json.dumps({'body': sys.stdin.read()}))" 2>/dev/null)
HTTP=$(curl -sf -o /dev/null -w '%{http_code}' -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"${API}/issues/${EXISTING}/comments" \
-d "${COMMENT_JSON}" 2>/dev/null || echo "000")
if [[ "$HTTP" == "201" ]]; then
echo "Commented on existing issue #${EXISTING}"
else
echo "WARNING: Failed to comment on issue #${EXISTING} (HTTP ${HTTP})"
fi
else
# Create new issue
ISSUE_BODY=$(build_body)
ISSUE_JSON=$(python3 -c "
import sys, json
body = sys.stdin.read()
print(json.dumps({
'title': sys.argv[1],
'body': body,
'labels': []
}))" "$TITLE" <<< "$ISSUE_BODY" 2>/dev/null)
# Create the issue
RESPONSE=$(curl -sf -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"${API}/issues" \
-d "${ISSUE_JSON}" 2>/dev/null || echo "{}")
ISSUE_NUM=$(echo "$RESPONSE" | grep -oP '"number":\s*\K[0-9]+' | head -1)
if [[ -n "$ISSUE_NUM" ]]; then
# Apply label (separate call — more reliable across Gitea versions)
LABEL_ID=$(curl -sf \
-H "Authorization: token ${GITEA_TOKEN}" \
"${API}/labels" 2>/dev/null \
| grep -oP "\"id\":\s*\K[0-9]+(?=[^}]*\"name\":\s*\"${LABEL_NAME}\")" \
| head -1 || true)
if [[ -n "$LABEL_ID" ]]; then
curl -sf -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"${API}/issues/${ISSUE_NUM}/labels" \
-d "{\"labels\":[${LABEL_ID}]}" \
> /dev/null 2>&1 || true
fi
echo "Created issue #${ISSUE_NUM}: ${TITLE}"
else
echo "WARNING: Failed to create issue"
echo "Response: ${RESPONSE}"
fi
fi
+6 -6
View File
@@ -13,13 +13,13 @@
<version>03.02.00</version>
<client>site</client>
<folder>webservices</folder>
<tags><tag>development</tag></tags>
<tags><tag>dev</tag></tags>
<infourl title="Moko Web Services - DPCalendar API">https://git.mokoconsulting.tech/MokoConsulting/MokoDPCalendarAPI/releases/tag/stable</infourl>
<downloads>
<downloadurl type="full" format="zip">https://git.mokoconsulting.tech/MokoConsulting/MokoDPCalendarAPI/releases/download/stable/-03.02.00.zip</downloadurl>
</downloads>
<sha256>652b87468d39eb4a513b6b0aae3a563abf7662f0ee3b837b724ee3b6e19a08fb</sha256>
<targetplatform name="joomla" version="((5.[0-9])|(6.[0-9]))" />
<targetplatform name="joomla" version="(5|6)\..*" />
<maintainer>Moko Consulting</maintainer>
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
</update>
@@ -37,7 +37,7 @@
<downloadurl type="full" format="zip">https://git.mokoconsulting.tech/MokoConsulting/MokoDPCalendarAPI/releases/download/stable/-03.02.00.zip</downloadurl>
</downloads>
<sha256>652b87468d39eb4a513b6b0aae3a563abf7662f0ee3b837b724ee3b6e19a08fb</sha256>
<targetplatform name="joomla" version="((5.[0-9])|(6.[0-9]))" />
<targetplatform name="joomla" version="(5|6)\..*" />
<maintainer>Moko Consulting</maintainer>
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
</update>
@@ -55,7 +55,7 @@
<downloadurl type="full" format="zip">https://git.mokoconsulting.tech/MokoConsulting/MokoDPCalendarAPI/releases/download/stable/-03.02.00.zip</downloadurl>
</downloads>
<sha256>652b87468d39eb4a513b6b0aae3a563abf7662f0ee3b837b724ee3b6e19a08fb</sha256>
<targetplatform name="joomla" version="((5.[0-9])|(6.[0-9]))" />
<targetplatform name="joomla" version="(5|6)\..*" />
<maintainer>Moko Consulting</maintainer>
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
</update>
@@ -73,7 +73,7 @@
<downloadurl type="full" format="zip">https://git.mokoconsulting.tech/MokoConsulting/MokoDPCalendarAPI/releases/download/stable/-03.02.00.zip</downloadurl>
</downloads>
<sha256>652b87468d39eb4a513b6b0aae3a563abf7662f0ee3b837b724ee3b6e19a08fb</sha256>
<targetplatform name="joomla" version="((5.[0-9])|(6.[0-9]))" />
<targetplatform name="joomla" version="(5|6)\..*" />
<maintainer>Moko Consulting</maintainer>
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
</update>
@@ -91,7 +91,7 @@
<downloadurl type="full" format="zip">https://git.mokoconsulting.tech/MokoConsulting/MokoDPCalendarAPI/releases/download/stable/-03.02.00.zip</downloadurl>
</downloads>
<sha256>652b87468d39eb4a513b6b0aae3a563abf7662f0ee3b837b724ee3b6e19a08fb</sha256>
<targetplatform name="joomla" version="((5.[0-9])|(6.[0-9]))" />
<targetplatform name="joomla" version="(5|6)\..*" />
<maintainer>Moko Consulting</maintainer>
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
</update>