Compare commits

...

17 Commits

Author SHA1 Message Date
jmiller 670d26408d chore: sync auto-release.yml from Template-Go [skip ci]
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
2026-07-21 18:20:27 +00:00
jmiller ef0c22aecc Merge pull request 'chore(release): merge dev to main' (#855) from dev into main
Cascade Main -> Dev / Cascade main -> dev (push) Successful in 50s
Universal: Push Notifications / push-notify (push) Successful in 2s
Generic: Standards Compliance / Secret Scanning (push) Failing after 9s
Generic: Standards Compliance / License Header Validation (push) Successful in 7s
Generic: Standards Compliance / Repository Structure Validation (push) Successful in 9s
Generic: Standards Compliance / Coding Standards Check (push) Successful in 9s
Generic: Standards Compliance / Version Consistency Check (push) Successful in 1m40s
Generic: Standards Compliance / Workflow Configuration Check (push) Failing after 7s
Generic: Standards Compliance / Documentation Quality Check (push) Successful in 7s
Deploy (Prod) / Deploy to Prod (push) Successful in 3m22s
Generic: Standards Compliance / README Completeness Check (push) Failing after 5s
Generic: Standards Compliance / Script Integrity Validation (push) Successful in 7s
Generic: Standards Compliance / Line Length Check (push) Successful in 13s
Generic: Standards Compliance / File Naming Standards (push) Successful in 6s
Generic: Standards Compliance / Git Repository Hygiene (push) Successful in 32s
Generic: Standards Compliance / Insecure Code Pattern Detection (push) Successful in 5s
Generic: Standards Compliance / Code Complexity Analysis (push) Successful in 38s
Generic: Standards Compliance / Code Duplication Detection (push) Successful in 38s
Generic: Standards Compliance / Dead Code Detection (push) Successful in 7s
Generic: Standards Compliance / File Size Limits (push) Successful in 6s
Generic: Standards Compliance / TODO/FIXME Tracking (push) Successful in 5s
Generic: Standards Compliance / Dependency Vulnerability Scanning (push) Successful in 41s
Generic: Standards Compliance / Broken Link Detection (push) Successful in 8s
Generic: Standards Compliance / API Documentation Coverage (push) Successful in 6s
Generic: Standards Compliance / Accessibility Check (push) Successful in 6s
Generic: Standards Compliance / Binary File Detection (push) Successful in 1m16s
Generic: Standards Compliance / Performance Metrics (push) Successful in 5s
Generic: Standards Compliance / Unused Dependencies Check (push) Successful in 44s
Generic: Standards Compliance / Terraform Configuration Validation (push) Successful in 9s
Generic: Standards Compliance / Repository Health Check (push) Successful in 46s
Generic: Standards Compliance / Enterprise Readiness Check (push) Successful in 52s
Generic: Project CI / Lint & Validate (pull_request) Successful in 37s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Require Docs Update (pull_request) Has been skipped
Universal: PR Check / Wiki Update Reminder (pull_request) Has been skipped
Generic: Project CI / Tests (pull_request) Successful in 40s
Universal: PR Check / Validate PR (pull_request) Successful in 9s
Universal: PR Check / Secret Scan (pull_request) Successful in 47s
Generic: Standards Compliance / Compliance Summary (push) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
2026-07-21 16:51:24 +00:00
jmiller c6e0a45bb4 Merge pull request 'fix(release): skip source archive generation for Joomla repos (#853)' (#854) from fix/853-skip-joomla-source-archives into dev
Deploy (Dev) / Deploy to Dev (push) Successful in 2m50s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Generic: Project CI / Tests (pull_request) Successful in 33s
Generic: Project CI / Lint & Validate (pull_request) Successful in 35s
Universal: PR Check / Wiki Update Reminder (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Successful in 8s
Universal: PR Check / Require Docs Update (pull_request) Failing after 41s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Standards Compliance / Secret Scanning (pull_request) Failing after 8s
Generic: Standards Compliance / License Header Validation (pull_request) Successful in 7s
Generic: Standards Compliance / Repository Structure Validation (pull_request) Successful in 8s
Generic: Standards Compliance / Coding Standards Check (pull_request) Successful in 9s
Universal: Auto Version Bump / Version Bump (push) Has been skipped
Universal: Build & Release / Promote to RC (pull_request) Has been skipped
Generic: Standards Compliance / Workflow Configuration Check (pull_request) Failing after 8s
Universal: PR Check / Secret Scan (pull_request) Successful in 40s
Generic: Standards Compliance / Documentation Quality Check (pull_request) Successful in 7s
Generic: Standards Compliance / README Completeness Check (pull_request) Failing after 7s
Generic: Standards Compliance / Script Integrity Validation (pull_request) Successful in 10s
Universal: Build & Release / Build & Release Pipeline (pull_request) Failing after 43s
Generic: Standards Compliance / Line Length Check (pull_request) Successful in 17s
Generic: Standards Compliance / File Naming Standards (pull_request) Successful in 6s
Generic: Standards Compliance / Git Repository Hygiene (pull_request) Successful in 39s
Generic: Standards Compliance / Version Consistency Check (pull_request) Successful in 56s
Generic: Standards Compliance / Insecure Code Pattern Detection (pull_request) Successful in 6s
Generic: Standards Compliance / Dead Code Detection (pull_request) Successful in 9s
Generic: Standards Compliance / File Size Limits (pull_request) Successful in 7s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 37s
Generic: Standards Compliance / Code Complexity Analysis (pull_request) Successful in 44s
Generic: Standards Compliance / Code Duplication Detection (pull_request) Successful in 45s
Generic: Standards Compliance / TODO/FIXME Tracking (pull_request) Successful in 6s
Generic: Standards Compliance / Dependency Vulnerability Scanning (pull_request) Successful in 42s
Generic: Standards Compliance / Unused Dependencies Check (pull_request) Successful in 38s
Generic: Standards Compliance / API Documentation Coverage (pull_request) Successful in 6s
Generic: Standards Compliance / Binary File Detection (pull_request) Successful in 1m15s
Generic: Standards Compliance / Broken Link Detection (pull_request) Successful in 8s
Generic: Standards Compliance / Accessibility Check (pull_request) Successful in 6s
Generic: Standards Compliance / Performance Metrics (pull_request) Successful in 7s
Generic: Standards Compliance / Terraform Configuration Validation (pull_request) Successful in 8s
Generic: Standards Compliance / Enterprise Readiness Check (pull_request) Successful in 44s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
Universal: Workflow Sync Trigger / Sync workflows to live repos (pull_request) Has been skipped
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
Generic: Standards Compliance / Repository Health Check (pull_request) Successful in 42s
Deploy (RC) / Deploy to RC (push) Failing after 5m53s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report: Scripts Governance (pull_request) Has been cancelled
Generic: Repo Health / Report: Repository Health (pull_request) Has been cancelled
Generic: Standards Compliance / Compliance Summary (pull_request) Has been cancelled
fix(release): skip source archive generation for Joomla repos (#853)

Closes #853
2026-07-20 14:47:44 +00:00
jmiller 154c3f77e4 Merge pull request 'test(metadata): apiMetadata npm-fields round-trip test [#847]' (#848) from fix/apimetadata-npm-fields into dev
Universal: Auto Version Bump / Version Bump (push) Has been skipped
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 46s
Deploy (Dev) / Deploy to Dev (push) Successful in 2m40s
2026-07-20 14:37:41 +00:00
Moko Consulting c72d872557 fix(release): skip source archive generation for Joomla repos (#853)
Generic: Project CI / Lint & Validate (pull_request) Successful in 37s
Generic: Project CI / Tests (pull_request) Successful in 36s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 48s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Require Docs Update (pull_request) Has been skipped
Universal: PR Check / Wiki Update Reminder (pull_request) Has been skipped
Universal: PR Check / Validate PR (pull_request) Successful in 12s
Universal: PR Check / Secret Scan (pull_request) Successful in 1m1s
Branch Cleanup / Delete merged branch (pull_request) Successful in 2s
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Joomla repos are packaged by the CI pipeline (release_package.php),
which uploads the correct installable zip/tar.gz. The server-generated
source archives are redundant and confuse users about which file to
download.

Closes #853

Claude-Session: https://claude.ai/code/session_01CwLGvFJPjoPTp9BEnSjtJf
2026-07-20 09:34:01 -05:00
jmiller 02b0377b1d Merge pull request 'fix(deploy): migrate deploy/git compose templates to MOKOGIT__ + /data/mokogit' (#846) from feature/deploy-templates-mokogit-paths into dev
Universal: Auto Version Bump / Version Bump (push) Has been skipped
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 41s
Deploy (Dev) / Deploy to Dev (push) Successful in 3m13s
2026-07-20 14:33:57 +00:00
jmiller f27c73195f Merge pull request 'release: MokoGIT hard-fork disconnect to prod (rebrand + Option-B GPL + /data/mokogit)' (#852) from dev into main
Cascade Main -> Dev / Cascade main -> dev (push) Has been cancelled
Deploy (Prod) / Deploy to Prod (push) Has been cancelled
Universal: Push Notifications / push-notify (push) Has been cancelled
Generic: Standards Compliance / Secret Scanning (push) Has been cancelled
Generic: Standards Compliance / License Header Validation (push) Has been cancelled
Generic: Standards Compliance / Repository Structure Validation (push) Has been cancelled
Generic: Standards Compliance / Coding Standards Check (push) Has been cancelled
Generic: Standards Compliance / Version Consistency Check (push) Has been cancelled
Generic: Standards Compliance / Workflow Configuration Check (push) Has been cancelled
Generic: Standards Compliance / Documentation Quality Check (push) Has been cancelled
Generic: Standards Compliance / README Completeness Check (push) Has been cancelled
Generic: Standards Compliance / Git Repository Hygiene (push) Has been cancelled
Generic: Standards Compliance / Script Integrity Validation (push) Has been cancelled
Generic: Standards Compliance / Line Length Check (push) Has been cancelled
Generic: Standards Compliance / File Naming Standards (push) Has been cancelled
Generic: Standards Compliance / Insecure Code Pattern Detection (push) Has been cancelled
Generic: Standards Compliance / Code Complexity Analysis (push) Has been cancelled
Generic: Standards Compliance / Code Duplication Detection (push) Has been cancelled
Generic: Standards Compliance / Dead Code Detection (push) Has been cancelled
Generic: Standards Compliance / File Size Limits (push) Has been cancelled
Generic: Standards Compliance / Binary File Detection (push) Has been cancelled
Generic: Standards Compliance / TODO/FIXME Tracking (push) Has been cancelled
Generic: Standards Compliance / Dependency Vulnerability Scanning (push) Has been cancelled
Generic: Standards Compliance / Unused Dependencies Check (push) Has been cancelled
Generic: Standards Compliance / Broken Link Detection (push) Has been cancelled
Generic: Standards Compliance / API Documentation Coverage (push) Has been cancelled
Generic: Standards Compliance / Accessibility Check (push) Has been cancelled
Generic: Standards Compliance / Performance Metrics (push) Has been cancelled
Generic: Standards Compliance / Enterprise Readiness Check (push) Has been cancelled
Generic: Standards Compliance / Repository Health Check (push) Has been cancelled
Generic: Standards Compliance / Terraform Configuration Validation (push) Has been cancelled
Generic: Standards Compliance / Compliance Summary (push) Has been cancelled
2026-07-20 14:13:16 +00:00
jmiller c2b64de621 Merge pull request 'docs(changelog): Joomla update-server artifact-selection fix' (#851) from chore/changelog-updateserver into dev
Universal: Build & Release / Promote to RC (pull_request) Has been skipped
Universal: Build & Release / Build & Release Pipeline (pull_request) Failing after 47s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 47s
Deploy (Dev) / Deploy to Dev (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Successful in 44s
Generic: Project CI / Lint & Validate (pull_request) Successful in 47s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: PR Check / Wiki Update Reminder (pull_request) Successful in 1s
Generic: Repo Health / Access control (pull_request) Has been cancelled
Generic: Repo Health / Site Health (pull_request) Has been cancelled
Generic: Standards Compliance / Secret Scanning (pull_request) Has been cancelled
Generic: Standards Compliance / License Header Validation (pull_request) Has been cancelled
Generic: Standards Compliance / Repository Structure Validation (pull_request) Has been cancelled
Generic: Standards Compliance / Coding Standards Check (pull_request) Has been cancelled
Generic: Standards Compliance / Version Consistency Check (pull_request) Has been cancelled
Generic: Standards Compliance / Workflow Configuration Check (pull_request) Has been cancelled
Generic: Standards Compliance / Documentation Quality Check (pull_request) Has been cancelled
Generic: Standards Compliance / README Completeness Check (pull_request) Has been cancelled
Generic: Standards Compliance / Git Repository Hygiene (pull_request) Has been cancelled
Generic: Standards Compliance / Script Integrity Validation (pull_request) Has been cancelled
Generic: Standards Compliance / Line Length Check (pull_request) Has been cancelled
Generic: Standards Compliance / File Naming Standards (pull_request) Has been cancelled
Generic: Standards Compliance / Insecure Code Pattern Detection (pull_request) Has been cancelled
Generic: Standards Compliance / Code Complexity Analysis (pull_request) Has been cancelled
Generic: Standards Compliance / Code Duplication Detection (pull_request) Has been cancelled
Generic: Standards Compliance / Dead Code Detection (pull_request) Has been cancelled
Generic: Standards Compliance / File Size Limits (pull_request) Has been cancelled
Generic: Standards Compliance / Binary File Detection (pull_request) Has been cancelled
Generic: Standards Compliance / TODO/FIXME Tracking (pull_request) Has been cancelled
Generic: Standards Compliance / Dependency Vulnerability Scanning (pull_request) Has been cancelled
Generic: Standards Compliance / Unused Dependencies Check (pull_request) Has been cancelled
Generic: Standards Compliance / Broken Link Detection (pull_request) Has been cancelled
Generic: Standards Compliance / API Documentation Coverage (pull_request) Has been cancelled
Generic: Standards Compliance / Accessibility Check (pull_request) Has been cancelled
Generic: Standards Compliance / Performance Metrics (pull_request) Has been cancelled
Generic: Standards Compliance / Enterprise Readiness Check (pull_request) Has been cancelled
Generic: Standards Compliance / Repository Health Check (pull_request) Has been cancelled
Generic: Standards Compliance / Terraform Configuration Validation (pull_request) Has been cancelled
Branch Cleanup / Delete merged branch (pull_request) Has been cancelled
Universal: Workflow Sync Trigger / Sync workflows to live repos (pull_request) Has been cancelled
RC Revert / Rename rc/ back to dev/ (pull_request) Has been cancelled
Deploy (RC) / Deploy to RC (push) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report: Scripts Governance (pull_request) Has been cancelled
Generic: Repo Health / Report: Repository Health (pull_request) Has been cancelled
Generic: Standards Compliance / Compliance Summary (pull_request) Has been cancelled
Universal: PR Check / Validate PR (pull_request) Successful in 23s
Universal: PR Check / Secret Scan (pull_request) Successful in 1m4s
Universal: PR Check / Require Docs Update (pull_request) Successful in 1m7s
Universal: Auto Version Bump / Version Bump (push) Has been skipped
2026-07-20 14:09:12 +00:00
Moko Consulting d7d6662804 docs(changelog): record Joomla update-server artifact-selection fix
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Failing after 28s
Generic: Project CI / Lint & Validate (pull_request) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Universal: PR Check / Branch Policy (pull_request) Has been cancelled
Universal: PR Check / Require Docs Update (pull_request) Has been cancelled
Universal: PR Check / Wiki Update Reminder (pull_request) Has been cancelled
Universal: PR Check / Secret Scan (pull_request) Has been cancelled
Universal: PR Check / Validate PR (pull_request) Has been cancelled
Branch Cleanup / Delete merged branch (pull_request) Has been cancelled
RC Revert / Rename rc/ back to dev/ (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Authored-by: Moko Consulting
2026-07-20 09:08:21 -05:00
jmiller 2878699082 Merge pull request 'chore(sync): cascade main -> dev' (#845) from main into dev
Universal: Auto Version Bump / Version Bump (push) Has been skipped
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 50s
Deploy (Dev) / Deploy to Dev (push) Has been cancelled
2026-07-20 13:57:29 +00:00
jmiller b551493110 chore: sync deploy-{dev,rc,prod}.yml from Template-Go [skip ci]
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
Thin-trigger deploy: logic in mokocli (cli/deploy.php) + restricted per-repo deploy
pattern. No registry token / build script in CI. Onboarding-guarded.
Authored-by: Moko Consulting
2026-07-20 08:57:14 -05:00
jmiller 24e6e2b4a1 Merge pull request 'chore: ignore .claude + untrack .gemini (AI client dot-folders)' (#850) from chore/ignore-ai-folders into dev
Universal: Auto Version Bump / Version Bump (push) Has been skipped
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 1m25s
Deploy (Dev) / Build & Deploy to Dev (push) Failing after 57s
2026-07-20 13:47:02 +00:00
Moko Consulting 7f540b4510 chore: ignore .claude + untrack .gemini (AI client dot-folders)
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 49s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Require Docs Update (pull_request) Has been skipped
Universal: PR Check / Wiki Update Reminder (pull_request) Has been skipped
Generic: Project CI / Lint & Validate (pull_request) Successful in 33s
Universal: PR Check / Validate PR (pull_request) Successful in 10s
Generic: Project CI / Tests (pull_request) Successful in 29s
Universal: PR Check / Secret Scan (pull_request) Successful in 40s
Branch Cleanup / Delete merged branch (pull_request) Successful in 2s
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
AI-client working dirs must not be committed. Add .claude/ to .gitignore
(.gemini/ and .mokoai/ already present) and untrack .gemini/GEMINI.md.

Authored-by: Moko Consulting
2026-07-20 08:46:22 -05:00
Moko Consulting 92d7d5563b fix(metadata): serialize npm/mcp fields in apiMetadata (npm_package/node_minimum/publish_target) [#847]
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 44s
Generic: Project CI / Tests (pull_request) Successful in 29s
Generic: Project CI / Lint & Validate (pull_request) Successful in 34s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Require Docs Update (pull_request) Has been skipped
Universal: PR Check / Wiki Update Reminder (pull_request) Has been skipped
Universal: PR Check / Validate PR (pull_request) Successful in 9s
Branch Cleanup / Delete merged branch (pull_request) Successful in 2s
Universal: PR Check / Secret Scan (pull_request) Successful in 40s
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
The GET/PUT /api/v1/repos/{owner}/{repo}/metadata handler already declares
node_minimum, npm_package and publish_target on the apiMetadata struct and
wires both the GET-serialize and PUT-persist paths (commit 5f85b27, #363).
No round-trip test guarded that behavior, so a regression could silently
reintroduce #847 (from #827) where these DB columns are un-settable and
un-readable over the REST API.

Add an integration test that PUTs the three fields and asserts they are
echoed by the PUT response and read back by a subsequent GET.

Authored-by: Moko Consulting
2026-07-20 08:41:39 -05:00
Moko Consulting 00f3d5d6d8 fix(deploy): migrate compose templates to MOKOGIT__ prefix + /data/mokogit mounts [#839 follow-up]
Universal: Auto Version Bump / Version Bump (push) Successful in 11s
Generic: Project CI / Lint & Validate (pull_request) Successful in 28s
Generic: Project CI / Tests (pull_request) Successful in 29s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Require Docs Update (pull_request) Has been skipped
Universal: PR Check / Wiki Update Reminder (pull_request) Has been skipped
Universal: PR Check / Validate PR (pull_request) Successful in 8s
Universal: PR Check / Secret Scan (pull_request) Successful in 39s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
Branch Cleanup / Delete merged branch (pull_request) Successful in 1s
The image disconnect (#839) renamed the env prefix GITEA__ -> MOKOGIT__ and
moved the custom path to /data/mokogit (MOKOGIT_CUSTOM baked into the image,
no GITEA__ fallback in the binary). The deploy compose templates still used the
old GITEA__ prefix and a single :/data mount, so they produced a forge with no
config. Align dev/rc/prod templates with the validated clean running state:

- Rename all GITEA__section__key -> MOKOGIT__section__key (server + database).
- Replace the single ${GIT_DATA_DIR}:/data bind with the clean 3-mount layout:
  ${GIT_DATA_DIR}:/var/lib/gitea (WorkPath),
  ${GIT_DATA_DIR}:/data/mokogit (CustomPath),
  ${GIT_DATA_DIR}/conf:/data/mokogit/conf (app.ini, child after parent).

Ports, SSH, domain, container_name, image, healthcheck, and all ${GIT_*}
variable names are unchanged. .env.example files reference no GITEA_ vars or
old paths, so they need no changes.

Authored-by: Moko Consulting <hello@mokoconsulting.tech>
2026-07-20 07:37:44 -05:00
jmiller f6b43492e9 Merge pull request 'fix(updateserver): pick installable package zip, not source archive (prod hotfix)' (#844) from hotfix/joomla-artifact-selection into main
Universal: Push Notifications / push-notify (push) Successful in 2s
Generic: Standards Compliance / Secret Scanning (push) Failing after 8s
Generic: Standards Compliance / License Header Validation (push) Successful in 12s
Generic: Standards Compliance / Repository Structure Validation (push) Successful in 16s
Generic: Standards Compliance / Coding Standards Check (push) Successful in 14s
Cascade Main -> Dev / Cascade main -> dev (push) Successful in 1m5s
Generic: Standards Compliance / Workflow Configuration Check (push) Failing after 8s
Generic: Standards Compliance / Documentation Quality Check (push) Successful in 19s
Generic: Standards Compliance / README Completeness Check (push) Failing after 16s
Generic: Standards Compliance / Version Consistency Check (push) Successful in 2m2s
Generic: Standards Compliance / Script Integrity Validation (push) Successful in 17s
Generic: Standards Compliance / Line Length Check (push) Successful in 23s
Generic: Standards Compliance / File Naming Standards (push) Successful in 11s
Generic: Standards Compliance / Insecure Code Pattern Detection (push) Successful in 10s
Generic: Standards Compliance / Git Repository Hygiene (push) Successful in 2m54s
Generic: Standards Compliance / Code Complexity Analysis (push) Successful in 1m9s
Generic: Standards Compliance / Dead Code Detection (push) Successful in 8s
Generic: Standards Compliance / Code Duplication Detection (push) Successful in 54s
Generic: Standards Compliance / File Size Limits (push) Successful in 6s
Deploy (Prod) / Build & Deploy to Prod (push) Successful in 5m46s
Generic: Standards Compliance / TODO/FIXME Tracking (push) Successful in 6s
Generic: Standards Compliance / Unused Dependencies Check (push) Successful in 41s
Generic: Standards Compliance / Dependency Vulnerability Scanning (push) Successful in 46s
Generic: Standards Compliance / API Documentation Coverage (push) Successful in 6s
Generic: Standards Compliance / Broken Link Detection (push) Successful in 9s
Generic: Standards Compliance / Accessibility Check (push) Successful in 6s
Generic: Standards Compliance / Performance Metrics (push) Successful in 6s
Generic: Standards Compliance / Binary File Detection (push) Successful in 1m20s
Generic: Standards Compliance / Terraform Configuration Validation (push) Successful in 10s
Generic: Standards Compliance / Repository Health Check (push) Successful in 42s
Generic: Standards Compliance / Enterprise Readiness Check (push) Successful in 42s
Generic: Project CI / Lint & Validate (pull_request) Successful in 29s
Generic: Project CI / Tests (pull_request) Successful in 28s
Universal: PR Check / Require Docs Update (pull_request) Has been skipped
Universal: PR Check / Wiki Update Reminder (pull_request) Has been skipped
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Successful in 7s
Universal: PR Check / Secret Scan (pull_request) Successful in 35s
Generic: Standards Compliance / Compliance Summary (push) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
2026-07-20 11:53:14 +00:00
Moko Consulting 457a53f987 fix(updateserver): pick installable package zip, not the source archive
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 1m5s
Universal: Build & Release / Promote to RC (pull_request) Has been skipped
Universal: Build & Release / Build & Release Pipeline (pull_request) Failing after 1m8s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Generic: Project CI / Lint & Validate (pull_request) Successful in 34s
Universal: PR Check / Wiki Update Reminder (pull_request) Successful in 1s
Generic: Project CI / Tests (pull_request) Successful in 22s
Universal: PR Check / Validate PR (pull_request) Successful in 7s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Standards Compliance / Secret Scanning (pull_request) Failing after 8s
Universal: PR Check / Require Docs Update (pull_request) Failing after 35s
Generic: Standards Compliance / License Header Validation (pull_request) Successful in 7s
Generic: Standards Compliance / Repository Structure Validation (pull_request) Successful in 13s
Generic: Standards Compliance / Coding Standards Check (pull_request) Successful in 18s
Generic: Standards Compliance / Workflow Configuration Check (pull_request) Failing after 7s
Universal: PR Check / Secret Scan (pull_request) Successful in 54s
Generic: Standards Compliance / Documentation Quality Check (pull_request) Successful in 6s
Generic: Standards Compliance / README Completeness Check (pull_request) Failing after 7s
Generic: Standards Compliance / Script Integrity Validation (pull_request) Successful in 8s
Generic: Standards Compliance / Line Length Check (pull_request) Successful in 14s
Generic: Standards Compliance / Version Consistency Check (pull_request) Successful in 49s
Generic: Standards Compliance / File Naming Standards (pull_request) Successful in 9s
Generic: Standards Compliance / Git Repository Hygiene (pull_request) Successful in 45s
Generic: Standards Compliance / Insecure Code Pattern Detection (pull_request) Successful in 15s
Generic: Standards Compliance / Code Duplication Detection (pull_request) Successful in 47s
Generic: Standards Compliance / Code Complexity Analysis (pull_request) Successful in 1m15s
Generic: Standards Compliance / Dead Code Detection (pull_request) Successful in 25s
Generic: Standards Compliance / File Size Limits (pull_request) Successful in 20s
Generic: Standards Compliance / TODO/FIXME Tracking (pull_request) Successful in 21s
Generic: Standards Compliance / Dependency Vulnerability Scanning (pull_request) Successful in 1m6s
Generic: Standards Compliance / Unused Dependencies Check (pull_request) Successful in 49s
Generic: Standards Compliance / Broken Link Detection (pull_request) Successful in 8s
Generic: Standards Compliance / API Documentation Coverage (pull_request) Successful in 6s
Generic: Standards Compliance / Accessibility Check (pull_request) Successful in 6s
Generic: Standards Compliance / Performance Metrics (pull_request) Successful in 6s
Generic: Standards Compliance / Binary File Detection (pull_request) Successful in 2m3s
Generic: Standards Compliance / Terraform Configuration Validation (pull_request) Successful in 13s
Branch Cleanup / Delete merged branch (pull_request) Successful in 1s
Universal: Workflow Sync Trigger / Sync workflows to live repos (pull_request) Has been skipped
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
Generic: Standards Compliance / Enterprise Readiness Check (pull_request) Successful in 53s
Generic: Standards Compliance / Repository Health Check (pull_request) Successful in 51s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report: Scripts Governance (pull_request) Has been cancelled
Generic: Repo Health / Report: Repository Health (pull_request) Has been cancelled
Generic: Standards Compliance / Compliance Summary (pull_request) Has been cancelled
The Joomla update feed took the FIRST .zip attachment on a release as the
download URL. Releases that carry extra zips (e.g. <repo>-<channel>-source.zip
alongside pkg_*.zip) then advertised the raw SOURCE archive, so Joomla
downloaded a non-installable zip and failed with "Install path does not exist"
(affected prerelease/dev channels; stable had a single pkg_ zip so was fine).

Add selectJoomlaArtifact(): prefer an extension-prefixed zip
(pkg_/com_/mod_/plg_/tpl_/lib_) that is not a "-source" archive, then any
non-source zip, then any zip.

Authored-by: Moko Consulting
2026-07-20 06:51:55 -05:00
12 changed files with 253 additions and 309 deletions
View File
+1
View File
@@ -144,3 +144,4 @@ Makefile.local
# ============================================================
wiki/
docs/
.claude/
+55 -1
View File
@@ -7,7 +7,7 @@
# INGROUP: MokoCLI.Release
# REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Generic
# PATH: /.mokogit/workflows/auto-release.yml
# VERSION: 05.01.02
# VERSION: 05.02.00
# BRIEF: Universal build & release detects platform from metadata API
#
# +=======================================================================+
@@ -39,6 +39,12 @@ on:
- '.gitattributes'
- '.gitmessage'
- 'LICENSE'
# Daily safety-net: catch merges whose pull_request event never created a run
# (e.g. this workflow file being re-synced from the template concurrently with the
# merge). Off-round minute to avoid a fleet-wide spike. The safety-net job below
# only dispatches a release when main actually has unreleased changes.
schedule:
- cron: '37 8 * * *'
workflow_dispatch:
inputs:
action:
@@ -505,3 +511,51 @@ jobs:
echo "| Tag | \`${{ steps.version.outputs.tag }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Release | [View](${MOKOGIT_URL}/${GIT_ORG}/${GIT_REPO}/releases/tag/${{ steps.version.outputs.tag }}) |" >> $GITHUB_STEP_SUMMARY
fi
# ── Scheduled safety-net ─────────────────────────────────────────────────────────
# A merge to main normally fires the `release` job via the pull_request `closed`
# event. If that event never creates a run (observed when this workflow file is
# being re-synced from the template in the same window as the merge), the release
# is silently skipped. This daily job self-heals that: if main's CHANGELOG
# [Unreleased] section still has content — which the release job empties on a
# successful promote — it dispatches a normal release. Dependency-free (awk only)
# so it runs on any runner; never touches the release job's own conditions.
scheduled-safety-net:
name: Scheduled release safety-net
runs-on: ubuntu-latest
if: github.event_name == 'schedule' && !startsWith(github.event.repository.name, 'Template-')
permissions:
contents: read
steps:
- name: Checkout main
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
ref: main
fetch-depth: 1
- name: Dispatch release if main has unreleased changes
env:
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
run: |
# [Unreleased] is non-empty precisely when changes were merged but not yet
# released (the release job promotes it to a version and empties it).
NOTES=""
if [ -f CHANGELOG.md ]; then
NOTES=$(awk '/^## \[Unreleased\]/{f=1;next} /^## \[/{if(f)exit} f{print}' CHANGELOG.md)
fi
if [ -z "$(printf '%s' "$NOTES" | tr -d '[:space:]')" ]; then
echo "No unreleased changes on main — safety-net has nothing to do."
exit 0
fi
echo "Unreleased changes detected on main — a merge release was likely missed."
echo "Dispatching a release via the safety-net."
HTTP=$(curl -s -o /dev/null -w '%{http_code}' -X POST \
-H "Authorization: token ${MOKOGIT_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"ref":"main","inputs":{"action":"release"}}' \
"${MOKOGIT_URL}/api/v1/repos/${{ github.repository }}/actions/workflows/auto-release.yml/dispatches")
if [ "$HTTP" = "204" ] || [ "$HTTP" = "201" ] || [ "$HTTP" = "200" ]; then
echo "Release dispatched (HTTP $HTTP)."
else
echo "::warning::Safety-net release dispatch failed (HTTP $HTTP)"
fi
+26 -92
View File
@@ -1,24 +1,16 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
# SPDX-License-Identifier: GPL-3.0-or-later
# BRIEF: Build and deploy to the Dev environment on push to the dev branch.
# Portable across Go server repos: ALL deployment config comes from repo
# Actions variables (vars.*) and secrets (secrets.*), nothing hardcoded.
# The dev branch is the ongoing integration branch.
# OWNER: Template-Go (canonical source; syncs to the root workflows dir). See Template-Go#3.
# BRIEF: Deploy to the Dev environment on push to the dev branch. THIN TRIGGER —
# the deploy LOGIC lives in mokocli (cli/deploy.php) and server-side in the
# restricted per-repo deploy pattern (.vault system/deploy, runbook 16).
# This workflow validates + invokes only; it carries NO registry token and
# NO build script. A leaked DEPLOY_SSH_KEY can only redeploy this one repo.
# OWNER: Template-Go (canonical; syncs to each repo's .mokogit/workflows).
#
# Required repo VARIABLES (all tier-scoped so each environment is independent —
# a repo may host its rc/dev/prod tiers on different machines):
# DEV_SSH_HOST, DEV_SSH_PORT, DEV_SSH_USERNAME - SSH deploy target for the dev tier
# DEV_REGISTRY, DEV_REGISTRY_USER, DEV_IMAGE - container registry + login user + image
# DEV_CONTAINER - compose service/container to recreate
# DEV_COMPOSE_PROJECT - docker compose -p project name
# DEV_COMPOSE_DIR - dir containing docker-compose.yml on host
# DEV_SOURCE_DIR - build source checkout on host
# DEV_TAG_ENV - compose env-var name that pins the image tag
# DEV_HEALTH_URL - external URL to verify after deploy
# Required SECRETS (already configured org-wide; reused, not re-set):
# DEPLOY_SSH_KEY - deploy private key (repo/org secret)
# MOKOGIT_TOKEN - registry/API token (org secret)
# Required repo VARIABLES (tier-scoped): DEV_SSH_HOST, DEV_SSH_PORT, DEV_SSH_USERNAME.
# Required SECRET: DEPLOY_SSH_KEY (the deploy-<repo> private key).
# ONBOARDING: a repo joins the restricted deploy pattern when DEV_SSH_USERNAME is
# set to deploy-<repo>. Un-onboarded go repos skip the job (guards below).
name: Deploy (Dev)
@@ -26,21 +18,18 @@ on:
push:
branches:
- dev
# Manual trigger for isolated end-to-end tests.
# Runs on the ref it is dispatched from.
workflow_dispatch:
# No `concurrency:` block: it triggers a MokoGIT Actions run-creation bug that
# silently drops deploys on rapid pushes to the branch. Do not re-add until the
# upstream bug is confirmed fixed.
# No `concurrency:` block: triggers a MokoGIT run-creation bug that drops deploys.
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
deploy-dev:
name: "Build & Deploy to Dev"
name: "Deploy to Dev"
runs-on: ubuntu-latest
if: ${{ vars.DEV_SSH_USERNAME != '' }}
steps:
- name: Checkout source
uses: actions/checkout@v4
@@ -62,75 +51,20 @@ jobs:
echo "$DEPLOY_KEY" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
- name: Build and deploy to RC via SSH
- name: Set up mokocli (deploy logic)
env:
REGISTRY_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
TAG: ${{ steps.config.outputs.tag }}
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
run: |
# Runner-side values (TAG, REGISTRY_TOKEN) are injected into the remote shell
# via an env prefix; a *quoted* heredoc keeps every $var expanding once, on the
# remote. Repo variables (vars.*) are substituted inline by Actions before ssh.
ssh -i ~/.ssh/deploy_key -p ${{ vars.DEV_SSH_PORT }} \
-o ConnectTimeout=30 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
-o ServerAliveInterval=30 -o ServerAliveCountMax=10 \
${{ vars.DEV_SSH_USERNAME }}@${{ vars.DEV_SSH_HOST }} \
"TAG='$TAG' REGISTRY_TOKEN='$REGISTRY_TOKEN' bash -s" <<'DEPLOY_EOF'
set -e
echo 'SSH connected to Dev environment'
command -v php >/dev/null || { sudo apt-get update -qq && sudo apt-get install -y -qq php-cli; }
git clone --depth 1 "https://x-access-token:${MOKOGIT_TOKEN}@git.mokoconsulting.tech/MokoConsulting/MokoCLI.git" "$RUNNER_TEMP/mokocli"
echo "MOKO_CLI=$RUNNER_TEMP/mokocli/cli" >> $GITHUB_ENV
if [ -z "$TAG" ]; then
echo 'ERROR: TAG is empty; refusing to build an untagged image' >&2
exit 1
fi
HEALTH_FMT='{{.State.Health.Status}}'
echo 'Cleaning Docker build cache...'
docker builder prune -af 2>/dev/null || true
docker image prune -af 2>/dev/null || true
echo 'Pulling source...'
SOURCE_DIR='${{ vars.DEV_SOURCE_DIR }}'
if [ ! -d "$SOURCE_DIR/.git" ]; then
git clone -b dev https://x-access-token:${REGISTRY_TOKEN}@git.mokoconsulting.tech/${{ github.repository }}.git "$SOURCE_DIR"
fi
cd "$SOURCE_DIR"
git remote set-url origin https://x-access-token:${REGISTRY_TOKEN}@git.mokoconsulting.tech/${{ github.repository }}.git 2>/dev/null || true
git fetch origin dev
git reset --hard origin/dev
echo "Building image: ${{ vars.DEV_REGISTRY }}/${{ vars.DEV_IMAGE }}:$TAG"
docker build --no-cache --build-arg GOFLAGS='-p 1' \
--tag "${{ vars.DEV_REGISTRY }}/${{ vars.DEV_IMAGE }}:$TAG" \
-f Dockerfile .
echo 'Pushing to registry...'
echo "$REGISTRY_TOKEN" | docker login ${{ vars.DEV_REGISTRY }} -u ${{ vars.DEV_REGISTRY_USER }} --password-stdin
docker push "${{ vars.DEV_REGISTRY }}/${{ vars.DEV_IMAGE }}:$TAG"
echo 'Restarting Dev container...'
cd '${{ vars.DEV_COMPOSE_DIR }}'
# Drive the rc service image tag via its compose env-var (no sed on the shared
# file); remove any lingering fixed-name container first, then force-recreate.
docker rm -f '${{ vars.DEV_CONTAINER }}' 2>/dev/null || true
${{ vars.DEV_TAG_ENV }}="$TAG" docker compose -p '${{ vars.DEV_COMPOSE_PROJECT }}' up -d --force-recreate '${{ vars.DEV_CONTAINER }}'
echo 'Health check...'
for i in 1 2 3 4 5 6 7 8; do
sleep 15
if docker inspect --format="$HEALTH_FMT" '${{ vars.DEV_CONTAINER }}' 2>/dev/null | grep -q healthy; then
echo 'Dev container healthy!'
exit 0
fi
echo "Waiting... (attempt $i/8)"
done
echo 'Health check failed'
docker logs '${{ vars.DEV_CONTAINER }}' --tail 20
exit 1
DEPLOY_EOF
- name: Verify Dev instance
continue-on-error: true
- name: Deploy (mokocli triggers the restricted deploy pattern)
run: |
sleep 5
ssh -i ~/.ssh/deploy_key -p ${{ vars.DEV_SSH_PORT }} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ${{ vars.DEV_SSH_USERNAME }}@${{ vars.DEV_SSH_HOST }} "curl -sf '${{ vars.DEV_HEALTH_URL }}'" && echo " Dev API healthy"
if [ -z "${{ vars.DEV_SSH_USERNAME }}" ]; then
echo "DEV_SSH_USERNAME unset — repo not onboarded to the restricted deploy pattern; skipping."
exit 0
fi
php "$MOKO_CLI/deploy.php" --tier dev --tag "${{ steps.config.outputs.tag }}" \
--ssh-host "${{ vars.DEV_SSH_HOST }}" --ssh-port "${{ vars.DEV_SSH_PORT }}" \
--ssh-user "${{ vars.DEV_SSH_USERNAME }}" --ssh-key ~/.ssh/deploy_key
+26 -92
View File
@@ -1,24 +1,16 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
# SPDX-License-Identifier: GPL-3.0-or-later
# BRIEF: Build and deploy to the Prod environment on push to the main branch.
# Portable across Go server repos: ALL deployment config comes from repo
# Actions variables (vars.*) and secrets (secrets.*), nothing hardcoded.
# Prod deploys on merge to main (dev -> rc -> main pipeline).
# OWNER: Template-Go (canonical source; syncs to the root workflows dir). See Template-Go#3.
# BRIEF: Deploy to the Prod environment on push to the main branch. THIN TRIGGER —
# the deploy LOGIC lives in mokocli (cli/deploy.php) and server-side in the
# restricted per-repo deploy pattern (.vault system/deploy, runbook 16).
# This workflow validates + invokes only; it carries NO registry token and
# NO build script. A leaked DEPLOY_SSH_KEY can only redeploy this one repo.
# OWNER: Template-Go (canonical; syncs to each repo's .mokogit/workflows).
#
# Required repo VARIABLES (all tier-scoped so each environment is independent —
# a repo may host its rc/dev/prod tiers on different machines):
# PROD_SSH_HOST, PROD_SSH_PORT, PROD_SSH_USERNAME - SSH deploy target for the prod tier
# PROD_REGISTRY, PROD_REGISTRY_USER, PROD_IMAGE - container registry + login user + image
# PROD_CONTAINER - compose service/container to recreate
# PROD_COMPOSE_PROJECT - docker compose -p project name
# PROD_COMPOSE_DIR - dir containing docker-compose.yml on host
# PROD_SOURCE_DIR - build source checkout on host
# PROD_TAG_ENV - compose env-var name that pins the image tag
# PROD_HEALTH_URL - external URL to verify after deploy
# Required SECRETS (already configured org-wide; reused, not re-set):
# DEPLOY_SSH_KEY - deploy private key (repo/org secret)
# MOKOGIT_TOKEN - registry/API token (org secret)
# Required repo VARIABLES (tier-scoped): PROD_SSH_HOST, PROD_SSH_PORT, PROD_SSH_USERNAME.
# Required SECRET: DEPLOY_SSH_KEY (the deploy-<repo> private key).
# ONBOARDING: a repo joins the restricted deploy pattern when PROD_SSH_USERNAME is
# set to deploy-<repo>. Un-onboarded go repos skip the job (guards below).
name: Deploy (Prod)
@@ -26,21 +18,18 @@ on:
push:
branches:
- main
# Manual trigger for a prod re-deploy.
# Runs on the ref it is dispatched from (use main).
workflow_dispatch:
# No `concurrency:` block: it triggers a MokoGIT Actions run-creation bug that
# silently drops deploys on rapid pushes to the branch. Do not re-add until the
# upstream bug is confirmed fixed.
# No `concurrency:` block: triggers a MokoGIT run-creation bug that drops deploys.
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
deploy-prod:
name: "Build & Deploy to Prod"
name: "Deploy to Prod"
runs-on: ubuntu-latest
if: ${{ vars.PROD_SSH_USERNAME != '' }}
steps:
- name: Checkout source
uses: actions/checkout@v4
@@ -62,75 +51,20 @@ jobs:
echo "$DEPLOY_KEY" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
- name: Build and deploy to RC via SSH
- name: Set up mokocli (deploy logic)
env:
REGISTRY_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
TAG: ${{ steps.config.outputs.tag }}
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
run: |
# Runner-side values (TAG, REGISTRY_TOKEN) are injected into the remote shell
# via an env prefix; a *quoted* heredoc keeps every $var expanding once, on the
# remote. Repo variables (vars.*) are substituted inline by Actions before ssh.
ssh -i ~/.ssh/deploy_key -p ${{ vars.PROD_SSH_PORT }} \
-o ConnectTimeout=30 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
-o ServerAliveInterval=30 -o ServerAliveCountMax=10 \
${{ vars.PROD_SSH_USERNAME }}@${{ vars.PROD_SSH_HOST }} \
"TAG='$TAG' REGISTRY_TOKEN='$REGISTRY_TOKEN' bash -s" <<'DEPLOY_EOF'
set -e
echo 'SSH connected to Prod environment'
command -v php >/dev/null || { sudo apt-get update -qq && sudo apt-get install -y -qq php-cli; }
git clone --depth 1 "https://x-access-token:${MOKOGIT_TOKEN}@git.mokoconsulting.tech/MokoConsulting/MokoCLI.git" "$RUNNER_TEMP/mokocli"
echo "MOKO_CLI=$RUNNER_TEMP/mokocli/cli" >> $GITHUB_ENV
if [ -z "$TAG" ]; then
echo 'ERROR: TAG is empty; refusing to build an untagged image' >&2
exit 1
fi
HEALTH_FMT='{{.State.Health.Status}}'
echo 'Cleaning Docker build cache...'
docker builder prune -af 2>/dev/null || true
docker image prune -af 2>/dev/null || true
echo 'Pulling source...'
SOURCE_DIR='${{ vars.PROD_SOURCE_DIR }}'
if [ ! -d "$SOURCE_DIR/.git" ]; then
git clone -b main https://x-access-token:${REGISTRY_TOKEN}@git.mokoconsulting.tech/${{ github.repository }}.git "$SOURCE_DIR"
fi
cd "$SOURCE_DIR"
git remote set-url origin https://x-access-token:${REGISTRY_TOKEN}@git.mokoconsulting.tech/${{ github.repository }}.git 2>/dev/null || true
git fetch origin main
git reset --hard origin/main
echo "Building image: ${{ vars.PROD_REGISTRY }}/${{ vars.PROD_IMAGE }}:$TAG"
docker build --no-cache --build-arg GOFLAGS='-p 1' \
--tag "${{ vars.PROD_REGISTRY }}/${{ vars.PROD_IMAGE }}:$TAG" \
-f Dockerfile .
echo 'Pushing to registry...'
echo "$REGISTRY_TOKEN" | docker login ${{ vars.PROD_REGISTRY }} -u ${{ vars.PROD_REGISTRY_USER }} --password-stdin
docker push "${{ vars.PROD_REGISTRY }}/${{ vars.PROD_IMAGE }}:$TAG"
echo 'Restarting Prod container...'
cd '${{ vars.PROD_COMPOSE_DIR }}'
# Drive the rc service image tag via its compose env-var (no sed on the shared
# file); remove any lingering fixed-name container first, then force-recreate.
docker rm -f '${{ vars.PROD_CONTAINER }}' 2>/dev/null || true
${{ vars.PROD_TAG_ENV }}="$TAG" docker compose -p '${{ vars.PROD_COMPOSE_PROJECT }}' up -d --force-recreate '${{ vars.PROD_CONTAINER }}'
echo 'Health check...'
for i in 1 2 3 4 5 6 7 8; do
sleep 15
if docker inspect --format="$HEALTH_FMT" '${{ vars.PROD_CONTAINER }}' 2>/dev/null | grep -q healthy; then
echo 'Prod container healthy!'
exit 0
fi
echo "Waiting... (attempt $i/8)"
done
echo 'Health check failed'
docker logs '${{ vars.PROD_CONTAINER }}' --tail 20
exit 1
DEPLOY_EOF
- name: Verify Prod instance
continue-on-error: true
- name: Deploy (mokocli triggers the restricted deploy pattern)
run: |
sleep 5
ssh -i ~/.ssh/deploy_key -p ${{ vars.PROD_SSH_PORT }} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ${{ vars.PROD_SSH_USERNAME }}@${{ vars.PROD_SSH_HOST }} "curl -sf '${{ vars.PROD_HEALTH_URL }}'" && echo " Prod API healthy"
if [ -z "${{ vars.PROD_SSH_USERNAME }}" ]; then
echo "PROD_SSH_USERNAME unset — repo not onboarded to the restricted deploy pattern; skipping."
exit 0
fi
php "$MOKO_CLI/deploy.php" --tier prod --tag "${{ steps.config.outputs.tag }}" \
--ssh-host "${{ vars.PROD_SSH_HOST }}" --ssh-port "${{ vars.PROD_SSH_PORT }}" \
--ssh-user "${{ vars.PROD_SSH_USERNAME }}" --ssh-key ~/.ssh/deploy_key
+29 -94
View File
@@ -1,24 +1,17 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
# SPDX-License-Identifier: GPL-3.0-or-later
# BRIEF: Build and deploy to the RC environment on push to the rc branch.
# Portable across Go server repos: ALL deployment config comes from repo
# Actions variables (vars.*) and secrets (secrets.*), nothing hardcoded.
# The rc branch is created by promote-rc when a PR to main opens.
# OWNER: Template-Go (canonical source; syncs to the root workflows dir). See Template-Go#3.
# BRIEF: Deploy to the RC environment on push to the rc branch. THIN TRIGGER —
# the deploy LOGIC lives in mokocli (cli/deploy.php) and server-side in the
# restricted per-repo deploy pattern (.vault system/deploy, runbook 16).
# This workflow validates + invokes only; it carries NO registry token and
# NO build script. A leaked DEPLOY_SSH_KEY can only redeploy this one repo.
# OWNER: Template-Go (canonical; syncs to each repo's .mokogit/workflows).
#
# Required repo VARIABLES (all tier-scoped so each environment is independent —
# a repo may host its rc/dev/prod tiers on different machines):
# RC_SSH_HOST, RC_SSH_PORT, RC_SSH_USERNAME - SSH deploy target for the rc tier
# RC_REGISTRY, RC_REGISTRY_USER, RC_IMAGE - container registry + login user + image
# RC_CONTAINER - compose service/container to recreate
# RC_COMPOSE_PROJECT - docker compose -p project name
# RC_COMPOSE_DIR - dir containing docker-compose.yml on host
# RC_SOURCE_DIR - build source checkout on host
# RC_TAG_ENV - compose env-var name that pins the image tag
# RC_HEALTH_URL - external URL to verify after deploy
# Required SECRETS (already configured org-wide; reused, not re-set):
# DEPLOY_SSH_KEY - deploy private key (repo/org secret)
# MOKOGIT_TOKEN - registry/API token (org secret)
# Required repo VARIABLES (tier-scoped): RC_SSH_HOST, RC_SSH_PORT, RC_SSH_USERNAME.
# Required SECRET: DEPLOY_SSH_KEY (the deploy-<repo> private key).
# ONBOARDING: a repo joins the restricted deploy pattern when RC_SSH_USERNAME is
# set to deploy-<repo>. Un-onboarded go repos skip the job (guards below), so this
# template is safe to cascade to every go repo.
name: Deploy (RC)
@@ -26,23 +19,19 @@ on:
push:
branches:
- rc
# Manual trigger for isolated end-to-end tests without a full RC promotion.
# Runs on the ref it is dispatched from; that ref must carry current source
# (>= the RC database migration version) or the rebuilt image will refuse the
# newer DB. Dispatch from `rc` once `rc` is current.
workflow_dispatch:
# No `concurrency:` block: it triggers a MokoGIT Actions run-creation bug that
# silently drops deploys on rapid pushes to the branch. Do not re-add until the
# upstream bug is confirmed fixed.
# No `concurrency:` block: triggers a MokoGIT run-creation bug that drops deploys.
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
deploy-rc:
name: "Build & Deploy to RC"
name: "Deploy to RC"
runs-on: ubuntu-latest
# Guard 1 (job-level): skip entirely unless onboarded.
if: ${{ vars.RC_SSH_USERNAME != '' }}
steps:
- name: Checkout source
uses: actions/checkout@v4
@@ -64,75 +53,21 @@ jobs:
echo "$DEPLOY_KEY" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
- name: Build and deploy to RC via SSH
- name: Set up mokocli (deploy logic)
env:
REGISTRY_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
TAG: ${{ steps.config.outputs.tag }}
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
run: |
# Runner-side values (TAG, REGISTRY_TOKEN) are injected into the remote shell
# via an env prefix; a *quoted* heredoc keeps every $var expanding once, on the
# remote. Repo variables (vars.*) are substituted inline by Actions before ssh.
ssh -i ~/.ssh/deploy_key -p ${{ vars.RC_SSH_PORT }} \
-o ConnectTimeout=30 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
-o ServerAliveInterval=30 -o ServerAliveCountMax=10 \
${{ vars.RC_SSH_USERNAME }}@${{ vars.RC_SSH_HOST }} \
"TAG='$TAG' REGISTRY_TOKEN='$REGISTRY_TOKEN' bash -s" <<'DEPLOY_EOF'
set -e
echo 'SSH connected to RC environment'
command -v php >/dev/null || { sudo apt-get update -qq && sudo apt-get install -y -qq php-cli; }
git clone --depth 1 "https://x-access-token:${MOKOGIT_TOKEN}@git.mokoconsulting.tech/MokoConsulting/MokoCLI.git" "$RUNNER_TEMP/mokocli"
echo "MOKO_CLI=$RUNNER_TEMP/mokocli/cli" >> $GITHUB_ENV
if [ -z "$TAG" ]; then
echo 'ERROR: TAG is empty; refusing to build an untagged image' >&2
exit 1
fi
HEALTH_FMT='{{.State.Health.Status}}'
echo 'Cleaning Docker build cache...'
docker builder prune -af 2>/dev/null || true
docker image prune -af 2>/dev/null || true
echo 'Pulling source...'
SOURCE_DIR='${{ vars.RC_SOURCE_DIR }}'
if [ ! -d "$SOURCE_DIR/.git" ]; then
git clone -b rc https://x-access-token:${REGISTRY_TOKEN}@git.mokoconsulting.tech/${{ github.repository }}.git "$SOURCE_DIR"
fi
cd "$SOURCE_DIR"
git remote set-url origin https://x-access-token:${REGISTRY_TOKEN}@git.mokoconsulting.tech/${{ github.repository }}.git 2>/dev/null || true
git fetch origin rc
git reset --hard origin/rc
echo "Building image: ${{ vars.RC_REGISTRY }}/${{ vars.RC_IMAGE }}:$TAG"
docker build --no-cache --build-arg GOFLAGS='-p 1' \
--tag "${{ vars.RC_REGISTRY }}/${{ vars.RC_IMAGE }}:$TAG" \
-f Dockerfile .
echo 'Pushing to registry...'
echo "$REGISTRY_TOKEN" | docker login ${{ vars.RC_REGISTRY }} -u ${{ vars.RC_REGISTRY_USER }} --password-stdin
docker push "${{ vars.RC_REGISTRY }}/${{ vars.RC_IMAGE }}:$TAG"
echo 'Restarting RC container...'
cd '${{ vars.RC_COMPOSE_DIR }}'
# Drive the rc service image tag via its compose env-var (no sed on the shared
# file); remove any lingering fixed-name container first, then force-recreate.
docker rm -f '${{ vars.RC_CONTAINER }}' 2>/dev/null || true
${{ vars.RC_TAG_ENV }}="$TAG" docker compose -p '${{ vars.RC_COMPOSE_PROJECT }}' up -d --force-recreate '${{ vars.RC_CONTAINER }}'
echo 'Health check...'
for i in 1 2 3 4 5 6 7 8; do
sleep 15
if docker inspect --format="$HEALTH_FMT" '${{ vars.RC_CONTAINER }}' 2>/dev/null | grep -q healthy; then
echo 'RC container healthy!'
exit 0
fi
echo "Waiting... (attempt $i/8)"
done
echo 'Health check failed'
docker logs '${{ vars.RC_CONTAINER }}' --tail 20
exit 1
DEPLOY_EOF
- name: Verify RC instance
continue-on-error: true
- name: Deploy (mokocli triggers the restricted deploy pattern)
run: |
sleep 5
ssh -i ~/.ssh/deploy_key -p ${{ vars.RC_SSH_PORT }} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ${{ vars.RC_SSH_USERNAME }}@${{ vars.RC_SSH_HOST }} "curl -sf '${{ vars.RC_HEALTH_URL }}'" && echo " RC API healthy"
# Guard 2 (step-level, reliable): no-op if not onboarded.
if [ -z "${{ vars.RC_SSH_USERNAME }}" ]; then
echo "RC_SSH_USERNAME unset — repo not onboarded to the restricted deploy pattern; skipping."
exit 0
fi
php "$MOKO_CLI/deploy.php" --tier rc --tag "${{ steps.config.outputs.tag }}" \
--ssh-host "${{ vars.RC_SSH_HOST }}" --ssh-port "${{ vars.RC_SSH_PORT }}" \
--ssh-user "${{ vars.RC_SSH_USERNAME }}" --ssh-key ~/.ssh/deploy_key
+1
View File
@@ -3,6 +3,7 @@
## [Unreleased]
### Fixed
- **Update server (Joomla): serve the installable package, not the source archive** — `GenerateJoomlaXML` selected the first `.zip` attachment on a release, so releases carrying extra zips (e.g. `<repo>-<channel>-source.zip` ahead of `pkg_*.zip`) advertised the raw source archive; Joomla then downloaded a non-installable zip and failed with "Install path does not exist" (prerelease/dev channels). New `selectJoomlaArtifact()` prefers an extension-prefixed package (`pkg_`/`com_`/`mod_`/`plg_`/`tpl_`/`lib_`) and never a `-source` archive (hotfixed to prod)
- **Actions: `.mokogit/workflows` custom-path detection restored** — `WorkflowDirs` now scans `.mokogit/workflows`; the legacy `.mokogitea/workflows` is fully retired. Workflow indexing, push-triggered CI/deploys, and `workflow_dispatch` work again (#798)
- **Issue custom-status dropdown shows its options again** — the status `<select>` carried the `ui compact dropdown` class, so fomantic turned it into an overlay menu that painted behind the page content (options were present in the DOM but invisible); it is now a plain native `<select>` with its inline styles moved to a stylesheet (`web_src/css/repo/issue-status.css`)
- Restored the repo's `.mokogit/workflows/` (deploy + org CI, ~20 workflows) from Template-Go after the workflow sync had dropped them
+14 -10
View File
@@ -13,18 +13,22 @@ services:
environment:
- USER_UID=${GIT_UID}
- USER_GID=${GIT_GID}
- GITEA__server__DOMAIN=${GIT_DOMAIN}
- GITEA__server__ROOT_URL=${GIT_ROOT_URL}
- GITEA__server__SSH_DOMAIN=${GIT_SSH_DOMAIN}
- GITEA__server__SSH_PORT=${GIT_SSH_PUBLIC_PORT}
- GITEA__database__DB_TYPE=mysql
- GITEA__database__HOST=${GIT_DB_HOST}
- GITEA__database__NAME=${GIT_DB_NAME}
- GITEA__database__USER=${GIT_DB_USER}
- GITEA__database__PASSWD=${GIT_DB_PASSWD}
- MOKOGIT__server__DOMAIN=${GIT_DOMAIN}
- MOKOGIT__server__ROOT_URL=${GIT_ROOT_URL}
- MOKOGIT__server__SSH_DOMAIN=${GIT_SSH_DOMAIN}
- MOKOGIT__server__SSH_PORT=${GIT_SSH_PUBLIC_PORT}
- MOKOGIT__database__DB_TYPE=mysql
- MOKOGIT__database__HOST=${GIT_DB_HOST}
- MOKOGIT__database__NAME=${GIT_DB_NAME}
- MOKOGIT__database__USER=${GIT_DB_USER}
- MOKOGIT__database__PASSWD=${GIT_DB_PASSWD}
volumes:
# RECONCILE: live app.ini at ${GIT_DATA_DIR}/conf/app.ini (/opt/mokogit/dev/conf).
- "${GIT_DATA_DIR}:/data"
# Clean disconnect layout (#839): MOKOGIT_CUSTOM=/data/mokogit is baked into the image.
# Parent (/data/mokogit) listed before child (/data/mokogit/conf) so Docker attaches it first.
- "${GIT_DATA_DIR}:/var/lib/gitea"
- "${GIT_DATA_DIR}:/data/mokogit"
- "${GIT_DATA_DIR}/conf:/data/mokogit/conf"
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
+14 -10
View File
@@ -17,19 +17,23 @@ services:
environment:
- USER_UID=${GIT_UID}
- USER_GID=${GIT_GID}
- GITEA__server__DOMAIN=${GIT_DOMAIN}
- GITEA__server__ROOT_URL=${GIT_ROOT_URL}
- GITEA__server__SSH_DOMAIN=${GIT_SSH_DOMAIN}
- GITEA__server__SSH_PORT=${GIT_SSH_PUBLIC_PORT}
- MOKOGIT__server__DOMAIN=${GIT_DOMAIN}
- MOKOGIT__server__ROOT_URL=${GIT_ROOT_URL}
- MOKOGIT__server__SSH_DOMAIN=${GIT_SSH_DOMAIN}
- MOKOGIT__server__SSH_PORT=${GIT_SSH_PUBLIC_PORT}
# DB is HOST MySQL (RECONCILE host reachability: host-gateway / socket / LAN IP).
- GITEA__database__DB_TYPE=mysql
- GITEA__database__HOST=${GIT_DB_HOST}
- GITEA__database__NAME=${GIT_DB_NAME}
- GITEA__database__USER=${GIT_DB_USER}
- GITEA__database__PASSWD=${GIT_DB_PASSWD}
- MOKOGIT__database__DB_TYPE=mysql
- MOKOGIT__database__HOST=${GIT_DB_HOST}
- MOKOGIT__database__NAME=${GIT_DB_NAME}
- MOKOGIT__database__USER=${GIT_DB_USER}
- MOKOGIT__database__PASSWD=${GIT_DB_PASSWD}
volumes:
# RECONCILE: live app.ini is at ${GIT_DATA_DIR}/conf/app.ini (/opt/mokogit/prod/conf).
- "${GIT_DATA_DIR}:/data"
# Clean disconnect layout (#839): MOKOGIT_CUSTOM=/data/mokogit is baked into the image.
# Parent (/data/mokogit) listed before child (/data/mokogit/conf) so Docker attaches it first.
- "${GIT_DATA_DIR}:/var/lib/gitea"
- "${GIT_DATA_DIR}:/data/mokogit"
- "${GIT_DATA_DIR}/conf:/data/mokogit/conf"
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
+14 -10
View File
@@ -13,18 +13,22 @@ services:
environment:
- USER_UID=${GIT_UID}
- USER_GID=${GIT_GID}
- GITEA__server__DOMAIN=${GIT_DOMAIN}
- GITEA__server__ROOT_URL=${GIT_ROOT_URL}
- GITEA__server__SSH_DOMAIN=${GIT_SSH_DOMAIN}
- GITEA__server__SSH_PORT=${GIT_SSH_PUBLIC_PORT}
- GITEA__database__DB_TYPE=mysql
- GITEA__database__HOST=${GIT_DB_HOST}
- GITEA__database__NAME=${GIT_DB_NAME}
- GITEA__database__USER=${GIT_DB_USER}
- GITEA__database__PASSWD=${GIT_DB_PASSWD}
- MOKOGIT__server__DOMAIN=${GIT_DOMAIN}
- MOKOGIT__server__ROOT_URL=${GIT_ROOT_URL}
- MOKOGIT__server__SSH_DOMAIN=${GIT_SSH_DOMAIN}
- MOKOGIT__server__SSH_PORT=${GIT_SSH_PUBLIC_PORT}
- MOKOGIT__database__DB_TYPE=mysql
- MOKOGIT__database__HOST=${GIT_DB_HOST}
- MOKOGIT__database__NAME=${GIT_DB_NAME}
- MOKOGIT__database__USER=${GIT_DB_USER}
- MOKOGIT__database__PASSWD=${GIT_DB_PASSWD}
volumes:
# RECONCILE: live app.ini at ${GIT_DATA_DIR}/conf/app.ini (/opt/mokogit/rc/conf).
- "${GIT_DATA_DIR}:/data"
# Clean disconnect layout (#839): MOKOGIT_CUSTOM=/data/mokogit is baked into the image.
# Parent (/data/mokogit) listed before child (/data/mokogit/conf) so Docker attaches it first.
- "${GIT_DATA_DIR}:/var/lib/gitea"
- "${GIT_DATA_DIR}:/data/mokogit"
- "${GIT_DATA_DIR}/conf:/data/mokogit/conf"
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
+10
View File
@@ -200,6 +200,16 @@ func GenerateReleaseArtifacts(ctx context.Context, rel *repo_model.Release) erro
} else if meta != nil {
entryPoint = meta.EntryPoint
}
// Joomla repos are packaged by the CI pipeline (release_package.php),
// which uploads the correct installable zip/tar.gz. Server-generated
// source archives are redundant and confuse users about which file to
// download, so skip them entirely.
if meta != nil && strings.EqualFold(meta.Platform, "joomla") {
log.Info("GenerateReleaseArtifacts: skipping source archives for Joomla repo %d (CI pipeline packages)", rel.RepoID)
return nil
}
wantSource := !isRootEntryPoint(entryPoint)
// Serialize the delete+attach sequence per-release so concurrent
@@ -0,0 +1,63 @@
// Copyright 2026 Moko Consulting <hello@mokoconsulting.tech>
// SPDX-License-Identifier: GPL-3.0-or-later
package integration
import (
"net/http"
"net/url"
"testing"
auth_model "code.mokoconsulting.tech/MokoConsulting/MokoGIT/models/auth"
"github.com/stretchr/testify/assert"
)
// apiMetadataResponse mirrors the subset of the repo manifest/metadata API
// payload exercised by this test. The handler struct (routers/api/v1/repo)
// is unexported, so the fields are re-declared here by their JSON tags.
type apiMetadataResponse struct {
Name string `json:"name"`
NodeMinimum string `json:"node_minimum"`
NpmPackage string `json:"npm_package"`
PublishTarget string `json:"publish_target"`
}
// TestAPIRepoMetadataNpmFieldsRoundTrip guards against regression of issue #847
// (from #827): the npm/mcp fields node_minimum, npm_package and publish_target
// must be persisted via PUT and returned via GET on the metadata endpoint,
// rather than being silently dropped by the apiMetadata struct.
func TestAPIRepoMetadataNpmFieldsRoundTrip(t *testing.T) {
onGiteaRun(t, func(t *testing.T, u *url.URL) {
// user1 is the site admin in the fixtures; the PUT route requires admin.
session := loginUser(t, "user1")
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
const owner, repo = "user2", "repo1"
// PUT the three npm/mcp fields.
req := NewRequestWithJSON(t, "PUT", "/api/v1/repos/"+owner+"/"+repo+"/metadata", map[string]string{
"node_minimum": "18",
"npm_package": "@moko/foo",
"publish_target": "npm",
}).AddTokenAuth(token)
resp := session.MakeRequest(t, req, http.StatusOK)
// The PUT response should echo the persisted fields.
var put apiMetadataResponse
DecodeJSON(t, resp, &put)
assert.Equal(t, "18", put.NodeMinimum)
assert.Equal(t, "@moko/foo", put.NpmPackage)
assert.Equal(t, "npm", put.PublishTarget)
// A subsequent GET should read the same values back from the DB.
req = NewRequest(t, "GET", "/api/v1/repos/"+owner+"/"+repo+"/metadata").AddTokenAuth(token)
resp = session.MakeRequest(t, req, http.StatusOK)
var got apiMetadataResponse
DecodeJSON(t, resp, &got)
assert.Equal(t, "18", got.NodeMinimum)
assert.Equal(t, "@moko/foo", got.NpmPackage)
assert.Equal(t, "npm", got.PublishTarget)
})
}