Compare commits

..

125 Commits

Author SHA1 Message Date
jmiller 3231ac2707 chore: sync .mokogitea/workflows/pr-check.yml from moko-platform [skip ci] 2026-06-02 21:51:52 +00:00
Jonathan Miller 963fa6d384 fix(licenses): always allow anonymous download path access on licensed repos
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Universal: PR Check / Report Issues (pull_request) Blocked by required conditions
Generic: Repo Health / Release configuration (pull_request) Blocked by required conditions
Generic: Repo Health / Scripts governance (pull_request) Blocked by required conditions
Generic: Repo Health / Repository health (pull_request) Blocked by required conditions
Generic: Repo Health / Report Issues (pull_request) Blocked by required conditions
Generic: Repo Health / Site Health (pull_request) Has been skipped
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Generic: Repo Health / Release configuration (push) Blocked by required conditions
Generic: Repo Health / Scripts governance (push) Blocked by required conditions
Generic: Repo Health / Repository health (push) Blocked by required conditions
Generic: Repo Health / Report Issues (push) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 2s
PR RC Release / Build RC Release (pull_request) Successful in 23s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
RepoAssignment now always grants LicensedReadOnly for download
paths (/releases/, /archive/) on licensed repos. The actual
download gating (none/prerelease/all) is enforced by
CheckDownloadGating in the handler.

Previously only download_gating=none allowed anonymous access.
Now prerelease gating also allows through (CheckDownloadGating
blocks non-stable downloads without a key).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 15:50:23 -05:00
Jonathan Miller 48ff05d4b3 fix(updates): feed always public, downloads gated separately
Generic: Repo Health / Release configuration (push) Blocked by required conditions
Generic: Repo Health / Scripts governance (push) Blocked by required conditions
Generic: Repo Health / Repository health (push) Blocked by required conditions
Generic: Repo Health / Report Issues (push) Blocked by required conditions
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Universal: PR Check / Report Issues (pull_request) Blocked by required conditions
Generic: Repo Health / Release configuration (pull_request) Blocked by required conditions
Generic: Repo Health / Scripts governance (pull_request) Blocked by required conditions
Generic: Repo Health / Repository health (pull_request) Blocked by required conditions
Generic: Repo Health / Report Issues (pull_request) Blocked by required conditions
Generic: Repo Health / Access control (push) Successful in 1s
Generic: Repo Health / Site Health (push) Has been skipped
Branch Policy Check / Verify merge target (pull_request) Successful in 2s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Failing after 24s
The updates.xml/JSON feed is now always fully public with versions
and download URLs visible. The actual file downloads are what get
blocked by CheckDownloadGating (none/prerelease/all).

Previously require_key and feed_visibility controlled the XML
feed visibility. Now the feed is informational only — Joomla can
always see what versions are available. The download gating
setting controls whether the files can actually be downloaded.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 15:45:00 -05:00
Moko Consulting 70699b4f2a chore(ci): add CI issue reporter for auto-filing gate failures
Generic: Repo Health / Release configuration (push) Blocked by required conditions
Generic: Repo Health / Scripts governance (push) Blocked by required conditions
Generic: Repo Health / Repository health (push) Blocked by required conditions
Generic: Repo Health / Report Issues (push) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
2026-06-02 20:38:03 +00:00
Moko Consulting 99f5833c25 chore(ci): add CI issue reporter for auto-filing gate failures
Generic: Repo Health / Release configuration (push) Blocked by required conditions
Generic: Repo Health / Scripts governance (push) Blocked by required conditions
Generic: Repo Health / Repository health (push) Blocked by required conditions
Generic: Repo Health / Report Issues (push) Blocked by required conditions
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 2s
2026-06-02 20:37:54 +00:00
Moko Consulting 241596361e chore(ci): add CI issue reporter for auto-filing gate failures
Generic: Repo Health / Release configuration (push) Blocked by required conditions
Generic: Repo Health / Scripts governance (push) Blocked by required conditions
Generic: Repo Health / Repository health (push) Blocked by required conditions
Generic: Repo Health / Report Issues (push) Blocked by required conditions
Generic: Repo Health / Access control (push) Successful in 3s
Generic: Repo Health / Site Health (push) Has been skipped
2026-06-02 20:37:45 +00:00
Jonathan Miller 6405163e60 fix(licenses): restrict downloadsPublic to release/download paths only
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Branch Policy Check / Verify merge target (pull_request) Successful in 2s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
PR RC Release / Build RC Release (pull_request) Successful in 21s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
The downloadsPublic flag was granting LicensedReadOnly to all
routes including the main repo page, causing 404 on private repos.
Now only applies to paths containing /releases/ or /archive/.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 15:30:23 -05:00
Jonathan Miller 01011f6115 fix(licenses): allow anonymous downloads when download_gating=none on private repos
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Branch Policy Check / Verify merge target (pull_request) Successful in 2s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
PR RC Release / Build RC Release (pull_request) Successful in 21s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
RepoAssignment now checks the download_gating setting. When set to
"none" (all downloads public), anonymous users can access release
downloads on licensed private repos without a key.

Previously, anonymous users always got 403 on private repos even
when download gating was set to public.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 15:25:28 -05:00
Jonathan Miller ea10e8500c fix(ui): replace invalid octicon-settings with octicon-gear
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
PR RC Release / Build RC Release (pull_request) Successful in 23s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 14:45:37 -05:00
Jonathan Miller 92bd3f7dc0 fix(ui): clean section headers with dividers instead of accordions, icons on all navbar items
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Successful in 22s
Advanced settings: replace collapsible accordions with clean h5
section headers (icon + bold text) separated by dividers. All
sections always visible — no clicking to expand.

Navbar: add octicon icons to every menu item — Options (settings),
Advanced (tools), Licensing (key), Public Access (eye),
Collaboration (people), Webhooks (webhook), Branches (git-branch),
Tags (tag), Git Hooks (terminal), Deploy Keys (key-asterisk),
LFS (file-binary), Actions (play).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 14:33:23 -05:00
Jonathan Miller 89fcbda623 feat(settings): move advanced settings to dedicated /settings/advanced page
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
PR RC Release / Build RC Release (pull_request) Failing after 18s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
Extract all feature unit settings (Code, Wiki, Issues, Projects,
Releases, Packages, Pull Requests) from options.tmpl into a
separate advanced.tmpl with its own route at /settings/advanced.

Options page now only contains: basic repo settings, avatar,
mirror config, signing settings, and danger zone.

Navbar updated: Advanced Settings link points to /settings/advanced.
Form posts still go through the existing SettingsPost handler.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 14:23:49 -05:00
Jonathan Miller dd6ee750f0 fix(build): remove extra {{end}} in settings accordion template
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 14:17:47 -05:00
Jonathan Miller ffb9363e3e feat(settings): accordion layout for advanced settings sections
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Successful in 21s
Each feature section (Code, Wiki, Issues, Projects, Releases,
Packages, Pull Requests) is now wrapped in a collapsible <details>
accordion with an icon and bold title.

Code section is open by default; others are collapsed. This
reduces visual clutter and lets admins focus on the section
they need.

Licensing section removed from advanced settings (now on its
own /settings/licensing page).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 14:13:32 -05:00
Jonathan Miller a1ceac6396 feat(settings): separate licensing settings page with navbar entry
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Successful in 23s
Extract licensing/update feed settings to its own page at
/settings/licensing with dedicated template and handler.

Navbar additions:
- Advanced Settings link (points to existing options page)
- Licensing link with key icon (when licensing enabled)

New handler: LicensingSettings/LicensingSettingsPost serves the
standalone licensing form with all fields (platform, gating,
metadata, extensions).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 14:02:53 -05:00
Jonathan Miller a22fa57ab1 fix(ui): embed login form on 403 Access Denied page
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Failing after 19s
Anonymous users seeing the 403 page now get an inline login form
with username, password, and submit button. After login, redirects
back to the page they were trying to access.

Compact form centered with tw-max-w-sm, includes CSRF token and
redirect_to hidden field pointing to CurrentURL.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 13:55:52 -05:00
Jonathan Miller 68736c78a1 fix(ui): float visibility badge to right of title label
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 13:51:31 -05:00
Jonathan Miller cfea80d3ca fix(build): use UpdateRepositoryColsWithAutoTime for is_hidden
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Failing after 21s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 13:46:26 -05:00
Jonathan Miller e2c738a8d8 feat(repos): three-level visibility — Public, Private, Hidden
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Failing after 22s
Add IsHidden field to Repository model. Three visibility modes:

- Public: visible to everyone (green label)
- Private: members only, non-members see 403 Access Denied (orange)
- Hidden: members only, non-members see 404 Not Found (red)

Private mode is for commercial repos — customers know the repo
exists and see a styled 403 page with sign-in button. Licensed
update feeds and key-gated downloads still work.

Hidden mode is for internal/secret repos — complete stealth, as
if the repo doesn't exist.

Settings UI: radio button selector in danger zone replaces the
old binary toggle. Each option shows a colored label with
description.

Migration v342: adds is_hidden column to repository table.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 13:42:25 -05:00
Jonathan Miller 6c7a6e4061 fix(licenses): RequireUnitReader allows LicensedReadOnly access
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Branch Policy Check / Verify merge target (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Failing after 7s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Failing after 21s
RequireUnitReader now checks for LicensedReadOnly context flag
before checking standard permissions. This lets the releases
download route pass through for licensed private repos where
RepoAssignment granted read-only access via license key.

Fixes the 404 on /releases/download/ with valid dlid= param.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 10:23:38 -05:00
Jonathan Miller 95d93da2bc fix(licenses): bypass attachment permission check for licensed downloads
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Failing after 20s
ServeAttachment checks perm.CanRead(unitType) which fails for
licensed read-only access on private repos. Now skips the check
when LicensedReadOnly is set in context (from RepoAssignment).

This allows Joomla/WordPress clients with valid dlid= params to
download release files from private licensed repos.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 10:17:06 -05:00
Jonathan Miller 02424c3f75 fix(licenses): allow download access on private licensed repos with license key
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 4s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Successful in 20s
RepoAssignment now checks for dlid/key/download_key query params
when licensing is enabled. Anonymous Joomla/WordPress clients with
valid license keys can access release download routes on private
repos without being signed in.

Access flow for licensed private repos:
- Anonymous + no key → 403 (styled page)
- Anonymous + valid dlid → access granted (CheckDownloadGating validates)
- Signed in + no membership → access granted (releases visible, downloads hidden)
- Org member → full access

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 10:12:45 -05:00
Jonathan Miller 449af83e2b fix(ui): styled 403 Access Denied page matching the 404 page layout
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Failing after 21s
Add templates/status/403.tmpl mirroring the 404 page design with
a centered error message and sign-in button for anonymous users.

New Forbidden() method on Context renders the styled 403 template
for HTML requests, falls back to plain text for API/non-HTML.

RepoAssignment now calls ctx.Forbidden() instead of raw HTTPError
for both anonymous and signed-in users without access.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 10:05:24 -05:00
Jonathan Miller 3ad37e48e1 fix(security): return 403 for all users on private repos, not 404
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Successful in 21s
Both anonymous and signed-in users now get 403 Access Denied when
accessing a private repo they lack permission for. Previously
anonymous users got 404 which hid the repo's existence.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 09:57:29 -05:00
Jonathan Miller 021a054348 fix(licenses): licensed private repos allow signed-in users to view releases
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 4s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Successful in 19s
When licensing is enabled on a private repo, signed-in users who
are not repo members can now view the releases page (with downloads
hidden). The RepoAssignment permission check detects licensing and
grants read-only access instead of returning 403.

This enables the commercial pattern: private source code, but
release notes visible to any authenticated user. Download files
are gated by license key via HideReleaseDownloads.

Anonymous users still get 404 (no information leak).
Non-licensed private repos still return 403 for non-members.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 09:52:05 -05:00
Jonathan Miller ead620daf9 fix(updates): allow update feeds on private repos via lightweight repo loader
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Successful in 20s
Update feed endpoints (updates.xml, dolibarr.json, wordpress.json,
packages.json, prestashop.xml, drupal.xml, whmcs.json, changelog.xml)
now use RepoAssignmentPublicFeed instead of the full RepoAssignment.

The lightweight loader fetches the repo by owner/name without checking
user permissions. Feed handlers gate access via license keys, not repo
membership. This allows private repos to serve update feeds to
anonymous Joomla/WordPress/Composer clients with valid license keys.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 09:36:06 -05:00
Jonathan Miller 0add8bda72 fix(security): show 403 Access Denied instead of 404 for signed-in users on private repos
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Successful in 19s
Signed-in users who lack permission to a private repo now see a
403 "You do not have permission" instead of a misleading 404.
Anonymous users still get 404 to prevent repo enumeration.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 09:26:21 -05:00
Jonathan Miller bd81616432 fix(build): remove unused time import in drupal.go
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Branch Policy Check / Verify merge target (pull_request) Successful in 2s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Failing after 20s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 09:10:11 -05:00
Jonathan Miller 02f3ed88f1 feat(updates): PrestaShop (#352), Drupal (#353), WHMCS (#355) update feeds
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Failing after 18s
PrestaShop: GET /updates/prestashop.xml — module update XML with
name, version, download URL, author, SHA256. Serves stable only.

Drupal: GET /updates/drupal.xml — update status XML per Drupal API
spec. Includes project metadata, all releases with status, download
links, SHA256. Uses TargetVersion config for api_version field.

WHMCS: GET /updates/whmcs.json — simple JSON with latest stable
version, download URL (with dlid), changelog, author. License key
embedded in download URL when provided.

All three use ResolveReleaseStream for manual/auto stream mapping,
readSHA256FromSidecar for integrity hashes, and extractVersion with
stream-name tag fallback.

Routes registered under the update server group alongside Joomla,
Dolibarr, WordPress, and Composer feeds.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 09:08:03 -05:00
Jonathan Miller 0fb0aea719 feat(updates): Composer packages.json feed (#354), hide menu items for guests
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Successful in 20s
Composer feed: new endpoint GET /updates/packages.json serving
Composer/Packagist-compatible packages.json. Includes version,
dist URL with SHA256, authors, PHP requirement. License key
embedded in download URL when provided.

Menu visibility: Actions and Licenses tabs in repo header now
require .IsSigned — anonymous users no longer see tabs they
can't access. Previously the tabs were visible but clicking
redirected to login (confusing UX).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 09:02:00 -05:00
Jonathan Miller eca929f680 feat(licenses): configurable key prefix (#406), header button (#408), open feed button (#409)
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
PR RC Release / Build RC Release (pull_request) Failing after 18s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
#406: Add KeyPrefix field to UpdateStreamConfig. GenerateKeyString
now accepts a prefix parameter, looked up from org config. Default
remains MOKO if not set. Auto-uppercased, max 20 chars.

#408: Move "New Package" button into the packages header bar,
right-aligned. Uses details/summary pattern — clicking the button
expands the create form below. Cleaner layout on both repo and org.

#409: Add open-in-new-tab button (external link icon) next to every
copy button on feed URLs. All four feeds: Joomla XML, Dolibarr JSON,
WordPress JSON, Changelog XML.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 08:51:55 -05:00
Jonathan Miller b65b155446 SECURITY: fix release download gating and require login for actions
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Successful in 21s
Release gating: HideReleaseDownloads now checks download_gating
setting in addition to feed_visibility. When licensing is enabled
and download_gating != "none", anonymous users see "Sign in to
download" instead of download links on the release page.

Actions: changed from optSignIn to reqSignIn on the repo actions
route group. Anonymous users can no longer view CI/CD runs, logs,
or artifacts. This is a MokoGitea policy override — upstream Gitea
allows public actions on public repos.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 08:40:40 -05:00
Jonathan Miller de52ad0fbc fix(build): permanent fixes for recurring build errors
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Branch Policy Check / Verify merge target (pull_request) Successful in 2s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 11s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Failing after 26s
- AI migration 339: replaced with noopMigration placeholder
- feed/file.go: add missing comma in struct literal
- license_key.go: remove unused org_model import

These were being applied as server-side hotfixes on every deploy.
Now committed to dev so they persist through merges.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 08:34:14 -05:00
Jonathan Miller 1dfa5d8079 SECURITY: require login for licenses page — was accessible anonymously
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Branch Policy Check / Verify merge target (pull_request) Successful in 2s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Successful in 21s
The repo licenses route used optSignIn (login optional), allowing
anonymous users to view license packages and keys. Changed to
reqSignIn to require authentication.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 08:25:31 -05:00
Jonathan Miller 70793075fc fix(build): use db.Find for org list, remove unused org_model import
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Successful in 22s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 08:21:39 -05:00
Jonathan Miller 2799558040 feat(orgs): enterprise sub-org hierarchy with parent-child relationships (#410)
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Successful in 26s
Add ParentOrgID field to User model for org hierarchy. Parent orgs
can have child orgs, enabling enterprise structures like
MokoConsulting → client orgs.

Model changes:
- ParentOrgID int64 on User (INDEX, DEFAULT 0)
- GetChildOrgs, GetAncestorOrgIDs, GetParentOrg helpers
- Max 10 hierarchy levels with cycle detection

License integration:
- ListLicensePackagesWithAncestors — shows packages from parent orgs
- ListLicenseKeysWithAncestors — shows keys from parent orgs
- SearchLicenseKeysWithAncestors — searches across hierarchy
- Master keys from parent orgs validate for child org repos

UI:
- Parent org dropdown in org settings (owners/admins only)
- Shows all orgs user owns except self

Migration v341: adds parent_org_id column to user table.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 08:14:08 -05:00
Jonathan Miller d85ae6aa21 fix(build): add UpdateStream to EditReleaseForm
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Branch Policy Check / Verify merge target (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Failing after 19s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 07:56:11 -05:00
Jonathan Miller 1b9b82d59a fix(build): pass ctx to buildWordPressChangelog for ResolveReleaseStream
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Successful in 24s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 07:47:42 -05:00
Jonathan Miller 37322e4212 feat(updates): manual release-to-stream mapping
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Successful in 22s
Add release_stream_map table for explicitly assigning releases to
update streams. When a mapping exists, it overrides automatic tag
detection. When absent, falls back to tag name/suffix matching.

New model: ReleaseStreamMap with SetReleaseStream, GetReleaseStream,
ResolveReleaseStream (manual first, auto fallback).

UI: stream selector dropdown on release create/edit page, shown when
licensing is enabled. Options: auto-detect (default) or any
configured stream (stable, release-candidate, beta, etc.).

All three feed generators (Joomla, Dolibarr, WordPress) now use
ResolveReleaseStream instead of MatchStreamFromTag.

Migration v340 updated with release_stream_map table creation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 07:37:02 -05:00
Jonathan Miller 2f9097a254 fix(updates): check tag name not extracted version for stream name detection
isStreamName was checking the extracted version (empty for stream
tags) instead of the original tag name. Now checks rel.TagName
directly, and also falls through when extractVersion returns empty.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 07:29:43 -05:00
Jonathan Miller ce3af35c40 fix(updates): extract version numbers from release titles via regex
When tags are stream names, extractVersion falls back to finding a
version pattern (digits.digits.digits) anywhere in the release title.
Handles titles like "Package - MokoWaaS (VERSION: 02.31.00)".

Previously the full title was used as the version, producing invalid
entries like "Package - MokoWaaS (VERSION: 02.31.00)" in the XML.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 07:27:06 -05:00
Jonathan Miller 0a3cd3115f feat(updates): support stream-name tags alongside version tags
MatchStreamFromTag now checks if the tag name directly matches a
stream name (e.g. "stable", "release-candidate", "development")
before falling back to suffix matching. Supports both conventions:

1. Stream-name tags: tag IS the stream (MokoWaaS style)
2. Version tags: tag has version + suffix (v1.0.0-rc1 style)

When a stream-name tag is detected, the version number is extracted
from the release title instead of the tag. Falls back to tag name
if no version found in title.

Applied across all feed generators: Joomla XML, Dolibarr JSON,
WordPress JSON, and Changelog XML.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 07:21:02 -05:00
Jonathan Miller 3e31b662a6 fix(licenses): remove UNIQUE constraint on PaymentRef, use tw-max-w-lg
PaymentRef UNIQUE constraint causes Error 1062 when creating keys
without a payment reference — empty strings collide. Remove the
DB constraint; idempotency is enforced in code via
GetLicenseKeyByPaymentRef which already filters empty strings.

Also replace inline style with tw-max-w-lg class on search box.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 07:12:13 -05:00
Jonathan Miller 774ea3842b fix(ui): constrain license key search box width to 400px
The search input was spanning full width (tw-w-full) making it
disproportionately large. Cap at 400px to match other search
inputs in the Gitea UI.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 07:10:43 -05:00
Jonathan Miller 0e7d3c4a34 fix(security): ownership guards, RepoScope parsing, CSRF tokens, XSS escaping
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
PR RC Release / Build RC Release (pull_request) Failing after 17s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
SECURITY: Add verifyPackageOwnership/verifyKeyOwnership checks to
all API handlers that accept ID parameters. Prevents cross-org
access where an admin of org A could modify org B's license data.

FIX: RepoScope validation now properly parses JSON arrays using
json.Unmarshal instead of strings.Contains. The old approach matched
substrings (repo ID "2" matched inside "12"). Now uses typed int64
comparison.

FIX: Add {{$.CsrfTokenHtml}} to both delete confirmation modal
forms (package and key) in repo and org templates. Without CSRF
tokens, the form-fetch-action POST requests would be rejected.

FIX: HTML-escape release notes in WordPress changelog to prevent
XSS via malicious release note content reaching WP admin dashboards.

FIX: Parse AllowedChannels JSON format before comma-split fallback
to avoid garbage values from splitting JSON arrays by comma.

FIX: Add missing third return value (false) on error path in
validateUpdateKey to prevent compile error.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 06:59:29 -05:00
Jonathan Miller 913e919fba docs: update CHANGELOG and wiki for v1.26.1-moko.06.02.00
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
PR RC Release / Build RC Release (pull_request) Successful in 19s
Add changelog entry for full license management system release.
Update wiki with WordPress feed status, feed visibility modes,
and revision 1.4.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 06:47:09 -05:00
Jonathan Miller a20153a0e0 fix(licenses): no-download mode shows release notes but hides files
In "no-download" feed visibility mode, anonymous users can browse
the release listing page and read release notes, but the download
section (attachments, source archives) is replaced with a "Sign in
to download" message.

Only "hidden" mode redirects anonymous users to login entirely.
"no-download" keeps the page public — release notes, changelogs,
and version info are all visible. Just the actual files are gated.

This matches the commercial pattern: let users see what's available
to motivate purchase, while protecting the actual deliverables.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 06:42:44 -05:00
Jonathan Miller a149edccd3 feat(licenses): feed visibility modes and login-required releases
Add FeedVisibility field to UpdateStreamConfig with three modes:
- public: full feed with download URLs (default)
- no-download: version info visible but download URLs stripped
- hidden: empty feed returned without a valid license key

The "no-download" mode is the key commercial pattern — customers
see updates exist (motivating purchase/renewal) but cannot download
without a valid key. Joomla shows "update available" in admin.

Applied consistently across all update feed endpoints (Joomla XML,
Dolibarr JSON, WordPress JSON) via the shared validateUpdateKey()
which now returns a stripDownloads flag.

Also: when licensing is enabled, the release listing page requires
login. Anonymous users are redirected to the login page. This
prevents browsing release notes and download links without auth.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 06:38:09 -05:00
Jonathan Miller 01eb9944ca feat(licenses): replace channel checkboxes with combolist picker
Use the existing shared/combolist.tmpl component for channel
selection in create and edit package forms. This mimics the
issue label picker UI — a searchable dropdown with checkmarks
and a selected-items list below.

Replaces raw checkboxes (repo + org templates) and Fomantic
multiple selection dropdowns (edit templates) with the
combo-multiselect component that has proper JS for toggle,
search, and clear functionality.

Handler parsing updated: combolist sends comma-separated values
in a single hidden input (vs multiple checkbox form values).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 06:30:59 -05:00
Jonathan Miller e3a8ae2595 feat(settings): add extension metadata to repo settings (#335)
Repo settings now include extension metadata fields (element name,
display name, type, target version, maintainer, PHP minimum) under
the Licensing section. These override org-level defaults per-repo.

Empty fields inherit from the organization's update stream config.
Extension type dropdown includes: package, component, module,
plugin, template, library — plus an "(inherit from org)" option.

Also adds form fields to the RepoSettingsForm struct for all
metadata fields.

Closes #335

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 06:19:48 -05:00
Jonathan Miller 1fabdb94ec feat(updates): WordPress PUC-compatible update feed (#351)
New endpoint: GET /{owner}/{repo}/updates/wordpress.json

Generates JSON compatible with the YahnisElsts plugin-update-checker
library — the standard for commercial WordPress plugin self-hosted
updates. Returns name, slug, version, download_url, homepage,
requires_php, author, sections (changelog HTML), icons, and banners.

License key validation: reads from ?license_key=, ?dlid=, or ?key=
query params (PUC sends these via addQueryArgFilter). When RequireKey
is enabled, returns minimal empty response without download_url.

Changelog section built from release notes (last 10 stable releases),
converting markdown list items to HTML <ul>/<li> elements.

Icon/banner URLs point to conventional paths in the repo:
  assets/icon-128x128.png, assets/icon-256x256.png
  assets/banner-772x250.png, assets/banner-1544x500.png

Route registered at /updates/wordpress.json alongside existing
/updates.xml (Joomla) and /updates/dolibarr.json.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 00:01:16 -05:00
Jonathan Miller d204ecb9f0 fix(licenses): enforce RepoScope validation and add API revoke endpoint
SECURITY: ValidateLicenseKeyForRepo() now checks the package's
RepoScope field against the requesting repo ID. A package scoped
to repo A will reject keys when accessed from repo B's update feed.
Update server and download gating both use the new function.

Master/internal keys bypass repo scope checks.

RepoScope supports: "all" (any repo), single repo ID string,
or JSON array of repo IDs like ["1","5","12"].

Also adds POST /license-keys/{id}/revoke API endpoint that was
missing from the API but existed in web handlers.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-01 05:33:26 -05:00
Jonathan Miller 93d18ab25f feat(licenses): double confirmation modals for permanent deletion (#391)
Replace link-action delete buttons with show-modal pattern that opens
a Fomantic UI modal with a form. Package deletion requires typing
the package name in a required field before the submit button works.
Key deletion shows a warning modal with confirmation.

Uses Gitea's existing form-fetch-action + modal_actions_confirm
pattern, matching how repo deletion works in settings.

Both repo and org templates updated with matching modals.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-01 05:23:56 -05:00
Jonathan Miller 3e8124a2b7 feat(licenses): API package CRUD, settings API, and repo scope UI
API package endpoints (#388):
- PATCH /license-packages/{id} — edit package (master protected)
- DELETE /license-packages/{id} — delete package (master protected)
- POST /license-packages/{id}/archive — archive package
- POST /license-packages/{id}/unarchive — restore package

Settings API (#349):
- GET /license-settings — read licensing/update stream config
- PUT /license-settings — update config (all metadata fields)
- New LicenseSettings struct in API types

Repo scope UI (#395):
- Dropdown in create/edit package forms listing org repos
- "All repositories" default option
- RepoScope read from form in both repo and org handlers
- OrgRepos loaded via GetOrgRepositories in Licenses handlers

Refs #341, #346, #349, #388, #395

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-01 05:21:09 -05:00
Jonathan Miller 7c9215de05 test(licenses): add integration tests for license key API endpoints
Tests cover:
- Package CRUD (list, create, create without name)
- Key CRUD (create, list, edit, renew, delete)
- Purchase webhook (new key, idempotent duplicate)
- Public validation (valid key, invalid key, domain check)

Tests follow existing Gitea integration test patterns using
unittest fixtures, user tokens, and DecodeJSON assertions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-01 05:09:14 -05:00
Jonathan Miller 7da0e025da feat(updates): include SHA256 from sidecar files in Joomla updates.xml
Read the .sha256 sidecar attachment (generated by
GenerateReleaseChecksums) and populate the <sha256> element in the
update XML. This matches the pattern used by Akeeba (sha512) and
JCE (sha256 + sha384 + sha512) for integrity verification.

Also fix zip attachment filter to skip .sha256 sidecar files when
selecting the download URL.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-01 05:04:24 -05:00
Jonathan Miller 0e09723d2a fix(updates): map stream names to Joomla-standard tag values
Joomla only recognizes: dev, alpha, beta, rc, stable. Our internal
stream names use longer forms (development, release-candidate).
Add joomlaTagName() to map between conventions in the <tags><tag>
XML element.

Without this, Joomla's update channel filter ignores entries with
non-standard tag values like "release-candidate" or "development".

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-01 05:01:59 -05:00
Jonathan Miller 53a5d0b97b feat(licenses): domain lock timer, infourl fix, Akeeba-compatible XML format
Domain lock timer: add DomainLockHours to LicensePackage and
FirstUsedUnix to LicenseKey. During the grace period after first
use, any domain is accepted and auto-added to the restriction list.
After the grace period, only listed domains are allowed. Set 0 for
immediate lock-on-first-use (default).

Fix infourl: default to /releases listing page instead of specific
tag page. Falls back to SupportURL or InfoURL if configured.

Match Akeeba Backup Pro XML format: downloadkey prefix is "dlid="
(not "&dlid="), matching how Joomla stores extra_query. Verified
against production Akeeba/JCE/AdminTools manifests via SSH.

Update migration v340 with FirstUsedUnix and DomainLockHours columns.

Add DomainLockHours field to create/edit package forms for both
repo and org levels with help text.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-01 05:00:50 -05:00
Jonathan Miller 448b7d3ab0 feat(licenses): archive, search, download gating, changelog XML, and expanded permissions
Migration v340: sync all missing columns (key_raw, payment_ref,
last_heartbeat_unix, is_archived, licensing_enabled, download_gating,
support_url, and all extension metadata fields).

Package archiving (#384): add IsArchived field with archive/unarchive
handlers and collapsible "Archived Packages" section in templates.
Existing keys from archived packages continue to work.

Expanded delete permissions (#385): org owners and site admins can
permanently delete packages and keys (previously site admin only).

Search (#392): server-side search across key_prefix, key_raw,
licensee_name, licensee_email, domain_restriction, and payment_ref
via ?q= query parameter on both repo and org licenses pages.

Sortable tables (#390): Fomantic UI sortable class on keys table
with new Domain column showing DomainRestriction per key.

Download gating (#347): three modes — none, prerelease-only, and
all downloads. CheckDownloadGating() intercepts both release
attachment and git archive download handlers.

Support URL (#393): configurable SupportURL field on
UpdateStreamConfig for wiki or external site links.

Changelog XML (#343): ServeChangelogXML endpoint at /changelog.xml
generates Joomla-compatible changelog from release notes. Parses
Keep-a-Changelog markdown sections into <security>, <fix>,
<addition>, <change>, <remove>, <note> XML elements.

API renew (#387): POST /license-keys/{id}/renew endpoint extends
key expiration by package duration.

Closes #384, #385, #386, #387, #389, #390, #392, #393
Refs #343, #346, #347

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-01 04:45:20 -05:00
Jonathan Miller e998c494b2 fix: resolve tech-debt batch 7 — dead routes, stale FIXMEs, feed revision
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
PR RC Release / Build RC Release (pull_request) Successful in 20s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
- chore: remove stale mustNotBeArchived FIXME (CanEnableEditor no longer exists)
- fix(routes): remove dead /cherry-pick/{sha} route — replaced by /_cherrypick/
- fix(feed): use full ref name instead of ShortName for file feed revision

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 13:46:06 -05:00
Jonathan Miller eafd5320e3 fix(build): remove unused imports causing compile errors
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 13:41:35 -05:00
Jonathan Miller 1ed8e463df chore: remove stale TODO comments (#328, #332)
Branch Policy Check / Verify merge target (pull_request) Successful in 9s
Universal: PR Check / Branch Policy (pull_request) Successful in 9s
Universal: PR Check / Validate PR (pull_request) Failing after 17s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Successful in 34s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
- Remove TODO from OAuth2 regenerate secret template — the
  functionality was already fully implemented
- Remove stub TODO test comments for TestMerge, TestNewPullRequest,
  TestAddTestPullRequestTask — stale for years
- Remove stale GetProjectsMode TODO — method is needed by templates

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 13:38:18 -05:00
Jonathan Miller cd0a803341 fix(issues): deprecate Issue.Ref branch selector UI (#307)
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 8s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Failing after 24s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Remove the branch/tag selector from the issue sidebar and new issue
form. The Issue.Ref field was added 8 years ago and provides minimal
value — it only saves a branch name and optionally restricts which
branch's commits can auto-close the issue.

Removed:
- Branch selector template (branch_selector_field.tmpl)
- Sidebar and new-form includes
- Ref badge from issue lists
- POST /{index}/ref web route and UpdateIssueRef handler
- GetRefEndNamesAndURLs calls from list renderers
- JS handler for branch selector dropdown

Preserved:
- DB column (Issue.Ref) — still used by commit-close logic
- API response still includes ref for backward compatibility

Closes #307

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 13:31:11 -05:00
Jonathan Miller 278645113b fix(cron): add missing translation for cleanup_expired_license_keys
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 13:14:45 -05:00
Jonathan Miller 7e312077e7 fix(docker): disable openssh s6 service in Dockerfile
Branch Policy Check / Verify merge target (pull_request) Successful in 9s
Universal: PR Check / Branch Policy (pull_request) Successful in 8s
Universal: PR Check / Validate PR (pull_request) Failing after 18s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Failing after 43s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Bake the noop script directly into the image layer so openssh never
starts. We use external SSH (port 2222) via host networking, not the
container's sshd.

Fixes: #372

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 12:13:21 -05:00
Jonathan Miller 40130d1793 docs: update CHANGELOG for v05.15.00 dev cycle
Branch Policy Check / Verify merge target (pull_request) Successful in 2s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
PR RC Release / Build RC Release (pull_request) Successful in 20s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 11:55:21 -05:00
Jonathan Miller 79724b5bc9 feat(ui): add generic combo-multiselect component
Add a reusable multiselect dropdown component inspired by the issue
sidebar label picker, but decoupled from issue-specific logic.

Components:
- templates/shared/combolist.tmpl — generic template accepting Items,
  Name, Title, SelectedValues parameters
- web_src/js/features/combo-multiselect.ts — lightweight JS init that
  handles check/uncheck, search, and hidden input updates
- web_src/css/modules/combo-multiselect.css — check-mark visibility
  and selected-items list styling

Usage in any template:
  {{template "shared/combolist" dict
    "Name" "channels"
    "Title" "Update Channels"
    "Items" .AvailableChannels
    "SelectedValues" .SelectedChannelIDs
  }}

Items must have .Value and .Label fields.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 11:41:08 -05:00
Jonathan Miller 88e210bffb fix(build): use slices.Collect for maps.Values (Go 1.23+ compat)
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
Universal: PR Check / Validate PR (pull_request) Failing after 6s
PR RC Release / Build RC Release (pull_request) Failing after 25s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
In Go 1.23+, maps.Values returns iter.Seq not a slice.
Use slices.Collect() to materialize the iterator.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 11:38:00 -05:00
jmiller f73f628403 Merge pull request 'fix: tech-debt batch 5 — CSS cleanup' (#361) from fix/tech-debt-batch-5 into dev
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Failing after 21s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
2026-05-31 16:19:35 +00:00
Jonathan Miller c07443aa87 fix: resolve tech-debt batch 5 — CSS cleanup
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
PR RC Release / Build RC Release (pull_request) Successful in 3s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
Branch Cleanup / Delete merged branch (pull_request) Successful in 1s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
- fix(css): use calc(infinity * 1px) for --border-radius-full instead
  of magic 99999px value (supported in all modern browsers)
- fix(css): remove legacy .center class from 2015, replace 6 usages
  with tw-text-center utility class

Refs #318

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 11:19:01 -05:00
jmiller c1c7556916 Merge pull request 'fix: tech-debt batch 4 — parseIssueHref, job limit, stale TODOs' (#360) from fix/tech-debt-batch-4 into dev 2026-05-31 16:13:34 +00:00
Jonathan Miller 889f64009b fix: resolve tech-debt batch 4 — parseIssueHref, job limit, stale TODOs
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Branch Policy Check / Verify merge target (pull_request) Successful in 2s
PR RC Release / Build RC Release (pull_request) Successful in 3s
Universal: PR Check / Validate PR (pull_request) Failing after 8s
Branch Cleanup / Delete merged branch (pull_request) Successful in 2s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
- fix(ts): parseIssueHref now uses URL pathname and trims appSubUrl
  for correct issue link parsing with sub-path deployments
- fix(actions): enforce MaxJobNumPerRun (256) limit when creating jobs,
  rejecting workflows that exceed the GitHub-compatible limit
- chore: remove stale TODO comment on OAuth redirect route

Refs #325, #334

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 11:12:44 -05:00
Jonathan Miller 27c4d176f4 fix(licenses): remove duplicate DeleteLicenseKey declaration
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Successful in 26s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 11:06:41 -05:00
jmiller 53bcb3cdf9 Merge pull request 'fix: tech-debt batch 3 — remove deprecated functions, use stdlib' (#357) from fix/tech-debt-batch-3 into dev 2026-05-31 16:05:15 +00:00
Jonathan Miller b9b3026122 fix: resolve tech-debt batch 3 — remove deprecated functions, use stdlib
Branch Policy Check / Verify merge target (pull_request) Successful in 3s
Universal: PR Check / Branch Policy (pull_request) Successful in 3s
PR RC Release / Build RC Release (pull_request) Successful in 4s
Universal: PR Check / Validate PR (pull_request) Failing after 12s
Branch Cleanup / Delete merged branch (pull_request) Successful in 3s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
- refactor(go): replace ValuesRepository with maps.Values (Go 1.21+)
- refactor(go): remove CanEnableEditor wrapper, use CanContentChange directly
- chore: remove stale TODO comments about project column route naming

Refs #311, #317

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 11:03:42 -05:00
Jonathan Miller d30e7d7a5a feat(updates): extension metadata settings for update feed generation
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
Universal: PR Check / Validate PR (pull_request) Failing after 7s
PR RC Release / Build RC Release (pull_request) Failing after 27s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
- Add configurable fields: element name, display name, description,
  extension type, maintainer, maintainer URL, info URL, target version,
  PHP minimum
- Add platform dropdown: joomla, dolibarr, wordpress, prestashop,
  drupal, composer, both
- Update Joomla XML generator to use metadata from config (falls back
  to repo-derived values when not set)
- Add GetEffectiveConfig() for resolving repo → org → nil config chain
- Add locale keys for all new settings fields

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 10:58:45 -05:00
Jonathan Miller e0c69d792c fix(licenses): only show licenses tab when licensing is enabled
Uses LicensingEnabled (org config) instead of EnableLicenses/IsRepoAdmin.
Tab is now hidden when the org hasn't enabled the licensing system.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 10:53:06 -05:00
jmiller d4bb976544 Merge pull request 'fix: tech-debt batch 2 — dropdown validation, editor cleanup, rename' (#350) from fix/tech-debt-batch-2 into dev 2026-05-31 15:52:26 +00:00
Jonathan Miller d74ae92e5b fix: resolve tech-debt batch 2 — dropdown validation, editor cleanup, rename
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
PR RC Release / Build RC Release (pull_request) Successful in 3s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Branch Cleanup / Delete merged branch (pull_request) Successful in 2s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
- fix(templates): add required validation to issue dropdown fields
- refactor(ts): remove redundant `handled` field from MarkdownHandleIndentionResult
- refactor(go): rename HasOrgOrUserVisible to IsOwnerVisibleToDoer for clarity

Refs #311, #334

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 10:50:33 -05:00
jmiller 2982d2d445 Merge pull request 'fix: tech-debt batch 1 + full namespace migration to code.mokoconsulting.tech' (#344) from fix/tech-debt-batch-1 into dev
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Successful in 24s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
2026-05-31 15:35:31 +00:00
Jonathan Miller b3488e2715 fix(updates): correct dlid prefix and align XML with Joomla standard
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
Universal: PR Check / Validate PR (pull_request) Failing after 6s
PR RC Release / Build RC Release (pull_request) Successful in 24s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
- Fix downloadkey prefix: "&dlid=" → "dlid=" (Joomla handles the separator)
- Reorder XML fields to match Akeeba/Joomla convention
- Add sha512 and php_minimum optional fields to update XML struct

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 10:30:31 -05:00
Jonathan Miller 9a5720e8ad chore: rename Go module from git. to code.mokoconsulting.tech (#336)
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
PR RC Release / Build RC Release (pull_request) Successful in 3s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Branch Cleanup / Delete merged branch (pull_request) Successful in 1s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Full namespace migration: update the Go module path and all import
statements from git.mokoconsulting.tech to code.mokoconsulting.tech.
Also updates all URL references in templates, workflows, configs,
tests, and documentation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 10:28:25 -05:00
Jonathan Miller 5e4ac1617e fix(updates): correct dlid prefix and align XML with Joomla standard
- Fix downloadkey prefix: "&dlid=" → "dlid=" (Joomla handles the separator)
- Reorder XML fields to match Akeeba/Joomla convention
- Add sha512 and php_minimum optional fields to update XML struct

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 10:23:20 -05:00
Jonathan Miller 682ab42888 fix: resolve three tech-debt FIXME/TODO items
- fix(blame): set HasSourceRenderedToggle for renderable files so that
  permalinks include ?display=source for correct line-number linking
- fix(settings): translate team permission strings using data-locale
  attributes instead of raw API values
- fix(dropzone): use relative path for non-image attachment markdown
  links for consistency with image attachments

Refs #318, #334

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 10:13:51 -05:00
Jonathan Miller 809c387054 feat(licenses): store keys in plaintext, show full key with copy button
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
Universal: PR Check / Validate PR (pull_request) Failing after 8s
PR RC Release / Build RC Release (pull_request) Successful in 27s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
License keys are domain-locked so hashing is unnecessary. Store the
full key in KeyRaw column for permanent visibility. Keys table now
shows the complete key with a clipboard copy button per row.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 10:07:20 -05:00
Jonathan Miller 4efc679c8b feat(licenses): platform enforcement, key deletion, expired key cleanup
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Successful in 24s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
- Block update feed endpoints based on repo platform setting:
  Joomla-only repos return 404 on /updates/dolibarr.json and vice versa
- Show feed URLs section only when licensing is enabled
- Add delete button for license keys (site admin only)
- Add weekly cron job to purge expired keys older than 1 year
- Add DeleteLicenseKey and DeleteExpiredKeys model functions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 10:03:23 -05:00
Jonathan Miller 68ee152cfc fix(licenses): show feed URLs based on repo update platform setting
Only show Joomla XML URL when platform is joomla/both/empty.
Only show Dolibarr JSON URL when platform is dolibarr/both.
Also gate the entire feed URLs section behind LicensingEnabled.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 09:54:38 -05:00
jmiller 18510b0da3 Merge pull request 'fix(licenses): remove repo unit requirement causing 404s' (#338) from fix/admin-delete-only into dev
Branch Policy Check / Verify merge target (pull_request) Successful in 2s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
Universal: PR Check / Validate PR (pull_request) Failing after 9s
PR RC Release / Build RC Release (pull_request) Successful in 31s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
2026-05-31 14:48:15 +00:00
Jonathan Miller 1bf51f3aa5 fix(licenses): remove repo unit requirement from licenses routes
Universal: PR Check / Branch Policy (pull_request) Successful in 13s
Branch Policy Check / Verify merge target (pull_request) Successful in 14s
Branch Cleanup / Delete merged branch (pull_request) Successful in 7s
PR RC Release / Build RC Release (pull_request) Successful in 15s
Universal: PR Check / Validate PR (pull_request) Failing after 22s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
The licenses feature is gated by org-level LicensingEnabled config,
not by per-repo unit enablement. Requiring TypeLicenses unit on repos
caused 404s since it wasn't in DefaultRepoUnits.

Write permissions are still enforced in handlers via
CanWrite(TypeLicenses). Org routes retain reqUnitAccess for
team-level permission control.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 09:47:51 -05:00
Jonathan Miller 80be67b2ef chore: migrate namespace from git. to code.mokoconsulting.tech (#336)
Update all URLs in manifest.xml and updates.xml to use the new
code.mokoconsulting.tech domain.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 09:37:42 -05:00
jmiller e6afc9f8c3 Merge pull request 'feat(licenses): UI/UX cleanup, permissions system, and key management improvements' (#305) from fix/admin-delete-only into dev
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 7s
PR RC Release / Build RC Release (pull_request) Successful in 26s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
2026-05-31 14:21:02 +00:00
Jonathan Miller c20139393d fix(licenses): pass IsOrganizationOwner to org licenses template
Branch Policy Check / Verify merge target (pull_request) Successful in 2s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
PR RC Release / Build RC Release (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
Branch Cleanup / Delete merged branch (pull_request) Successful in 1s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Required for the custom key input field visibility check.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 09:04:12 -05:00
Jonathan Miller 1a4d0739db fix(permissions): admin teams implicitly inherit access to all unit types
Admin-level teams (team.authorize >= Admin) now implicitly get admin
access to all unit types in UnitMaxAccess(), even without explicit
TeamUnit records. This resolves the long-standing TEAM-UNIT-PERMISSION
issue where adding new units (like TypeLicenses) left existing admin
teams without access.

Resolves: #304

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 09:00:49 -05:00
Jonathan Miller ed79a48119 feat(licenses): UI/UX cleanup, permissions, renew, auto-domain, custom keys
- Replace confirm() with Gitea modal system (link-action + data-modal-confirm)
- Add confirmation modal to revoke key action
- Fix clipboard copy to use data-clipboard-target with tooltip feedback
- Localize all hardcoded English strings (feed labels, "unlimited", "Master")
- Improve key creation flash with security-focused message + copy button
- Add count badge to org licenses nav tab
- Add icon to org settings navbar for update streams
- Add help text to "Active" checkboxes explaining deactivation impact
- Fix empty state message to reference UI creation (not just API)
- Compact tables for denser license data display
- Add orange "Master" label to master package rows
- Conditional feed buttons on release page (only when licensing enabled)
- Add TypeLicenses unit type with Read/Write/Admin team permissions
- Route-level permission enforcement via RequireUnitReader/Writer
- Add "Renew" action for license keys (extends by package duration)
- Auto-associate domain on first heartbeat (lock-on-first-use)
- Enforce max_sites limit during domain auto-association
- Allow site admins and org owners to set custom license key values

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 08:54:29 -05:00
Jonathan Miller b77da17f38 feat(licenses): implement full commercial license management system
Add key editing, domain enforcement, purchase webhooks, public
validation API, channels multiselect, Joomla downloadkey element,
licensing feature toggle, unified update system, release tag
enforcement, heartbeat tracking, and improved settings UX.

Phase 1: Full key display with AbsoluteShort dates, master package
protection (hide edit/delete in UI, reject in handlers).

Phase 2: Key edit page with template, handlers, and routes for both
repo and org levels. Master keys redirect away.

Phase 3: Domain restriction checking against CSV allowlist,
MaxSites enforcement via CountUniqueDomainsByKey and
IsDomainKnownForKey, dlid query param support for Joomla.

Phase 4: Purchase webhook (POST /license-keys/purchase) with
PaymentRef idempotency. Public validation endpoint
(POST /license-keys/validate) outside auth middleware.
PATCH /license-keys/{id} for API key editing.

Phase 5: Channels multiselect using org UpdateStreamConfig streams
rendered as checkboxes, stored as JSON arrays.

Additional: downloadkey XML element, LicensingEnabled toggle on
UpdateStreamConfig, Dolibarr endpoint unified with key validation,
release tag suffix enforcement, LastHeartbeatUnix field with
TouchHeartbeat, and cleaned-up settings pages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 01:31:51 -05:00
jmiller bec7b70ff5 Merge branch 'main' into dev
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
PR RC Release / Build RC Release (pull_request) Successful in 23s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
2026-05-31 04:22:29 +00:00
jmiller 92b4cd61c2 Merge pull request 'fix(ui): details/summary toggle for create package' (#294) from fix/admin-delete-only into dev
Branch Policy Check / Verify merge target (pull_request) Successful in 5s
Universal: PR Check / Branch Policy (pull_request) Successful in 6s
Universal: PR Check / Validate PR (pull_request) Failing after 18s
PR RC Release / Build RC Release (pull_request) Successful in 32s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
2026-05-31 04:22:08 +00:00
Jonathan Miller dc2647977c fix(ui): use HTML details/summary for package create toggle
Branch Policy Check / Verify merge target (pull_request) Successful in 2s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
PR RC Release / Build RC Release (pull_request) Successful in 5s
Universal: PR Check / Validate PR (pull_request) Failing after 11s
Branch Cleanup / Delete merged branch (pull_request) Successful in 4s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Replace broken JavaScript onclick toggle with native HTML
<details>/<summary> element. Works without JS, accessible,
and styled as a Fomantic UI button.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 23:21:42 -05:00
jmiller 685d89acf9 Merge pull request 'chore: merge dev into main — admin permissions' (#293) from dev into main
Deploy MokoGitea / deploy (push) Failing after 4m9s
2026-05-31 04:19:17 +00:00
jmiller 8ceddefbdb Merge branch 'main' into dev
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 7s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Successful in 25s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
2026-05-31 04:19:04 +00:00
jmiller ea2666948e Merge pull request 'feat(permissions): site admin only for delete' (#292) from fix/admin-delete-only into dev
Branch Policy Check / Verify merge target (pull_request) Successful in 2s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
PR RC Release / Build RC Release (pull_request) Successful in 25s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
2026-05-31 04:18:53 +00:00
Jonathan Miller 3aabd1b1f9 feat(permissions): only site admins can delete license packages
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
PR RC Release / Build RC Release (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Branch Cleanup / Delete merged branch (pull_request) Successful in 1s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
- Delete button only visible to site admins (super admins)
- Delete handler checks ctx.IsUserSiteAdmin() and returns 404 otherwise
- Repo admins can still create, edit, revoke — but not delete
- IsSiteAdmin set in both repo and org context data

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 23:18:31 -05:00
jmiller 0328258529 Merge pull request 'chore: merge dev into main — org update streams' (#291) from dev into main
Deploy MokoGitea / deploy (push) Failing after 4m3s
2026-05-31 04:09:53 +00:00
jmiller e6ff9a99f9 Merge branch 'main' into dev
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Successful in 24s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
2026-05-31 04:09:42 +00:00
jmiller 4138ab7d47 Merge pull request 'feat(org): Update Streams settings page + package edit/delete' (#290) from feat/repo-update-settings into dev
Branch Policy Check / Verify merge target (pull_request) Successful in 2s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 7s
PR RC Release / Build RC Release (pull_request) Successful in 25s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
2026-05-31 04:09:30 +00:00
Jonathan Miller d75e648970 feat(org): add Update Streams settings page in org settings
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
PR RC Release / Build RC Release (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
Branch Cleanup / Delete merged branch (pull_request) Successful in 2s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Add "Licenses & Update Streams" tab to org settings sidebar with:
- Stream mode: Joomla standard or Custom
- Active streams table showing name, suffix, description
- Custom streams JSON editor
- Saves org-level defaults that repos inherit

Ref #265

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 23:09:07 -05:00
jmiller 06a382e82e Merge pull request 'chore: merge dev into main — package edit/delete' (#289) from dev into main
Deploy MokoGitea / deploy (push) Failing after 3m39s
2026-05-31 04:04:41 +00:00
jmiller 0ff4b12f27 Merge branch 'main' into dev
Branch Policy Check / Verify merge target (pull_request) Successful in 2s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 7s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Successful in 23s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
2026-05-31 04:04:29 +00:00
jmiller 53f0472e4f Merge pull request 'feat(licenses): edit and delete packages via web UI' (#288) from feat/repo-update-settings into dev
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
PR RC Release / Build RC Release (pull_request) Successful in 21s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
2026-05-31 04:04:18 +00:00
Jonathan Miller 021ddbb17a feat(licenses): edit and delete license packages via web UI
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
PR RC Release / Build RC Release (pull_request) Successful in 3s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Branch Cleanup / Delete merged branch (pull_request) Successful in 2s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Add edit and delete actions for license packages:
- Edit button (pencil icon) opens edit form with all package fields
- Delete button (trash icon) with confirmation dialog
- Edit form includes active/inactive toggle
- Routes: GET/POST /licenses/packages/{id}/edit, POST /licenses/packages/{id}/delete

Ref #239

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 23:03:44 -05:00
jmiller 12f78e8feb Merge pull request 'chore: merge dev into main — platform settings' (#287) from dev into main
Deploy MokoGitea / deploy (push) Failing after 4m8s
2026-05-31 03:57:18 +00:00
jmiller b72d419fb1 Merge branch 'main' into dev
Branch Policy Check / Verify merge target (pull_request) Successful in 2s
Universal: PR Check / Branch Policy (pull_request) Successful in 3s
Universal: PR Check / Validate PR (pull_request) Failing after 9s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Successful in 28s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
2026-05-31 03:57:06 +00:00
jmiller 865e8b9bfa Merge pull request 'feat(updates): per-repo platform + require-key + platform buttons' (#286) from feat/repo-update-settings into dev
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
PR RC Release / Build RC Release (pull_request) Successful in 24s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
2026-05-31 03:56:56 +00:00
Jonathan Miller 3a5ca580db feat(updates): per-repo platform, require-key, platform-aware buttons
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
PR RC Release / Build RC Release (pull_request) Successful in 3s
Universal: PR Check / Validate PR (pull_request) Failing after 5s
Branch Cleanup / Delete merged branch (pull_request) Successful in 1s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
- Repo settings: platform dropdown (Joomla/Dolibarr/Both) + require key
- Releases page buttons change based on platform setting
- Update feed enforces require-key (empty response without valid key)
- key_plain column stores full key for copy functionality
- DB migrations v337 (key_plain) + v338 (platform, require_key)

Ref #239

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 22:55:55 -05:00
jmiller 93f186bd1d Merge pull request 'chore: merge dev into main — UI fixes' (#285) from dev into main
Deploy MokoGitea / deploy (push) Failing after 4m40s
2026-05-31 03:48:29 +00:00
jmiller 56988e810e Merge branch 'main' into dev
Branch Policy Check / Verify merge target (pull_request) Successful in 2s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Failing after 11s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Successful in 47s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
2026-05-31 03:48:11 +00:00
jmiller f8b7af30d9 Merge pull request 'fix(ui): always-visible create package form + org locale strings' (#284) from fix/licenses-ui-v3 into dev
Branch Policy Check / Verify merge target (pull_request) Successful in 2s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Failing after 8s
PR RC Release / Build RC Release (pull_request) Successful in 39s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
2026-05-31 03:47:53 +00:00
Jonathan Miller df06e11704 fix(ui): always-visible create package form + clearer labels + org locale strings
Universal: PR Check / Branch Policy (pull_request) Successful in 3s
Branch Policy Check / Verify merge target (pull_request) Successful in 3s
PR RC Release / Build RC Release (pull_request) Successful in 10s
Branch Cleanup / Delete merged branch (pull_request) Successful in 4s
Universal: PR Check / Validate PR (pull_request) Failing after 20s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Replace toggle button with always-visible "Create New License Package"
section. Added org settings locale strings for Update Streams page.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-30 22:47:29 -05:00
gitea-actions[bot] 51517a5275 chore: update channels for 05.14.00 [skip ci] 2026-05-31 03:46:14 +00:00
gitea-actions[bot] 336338b541 chore(ci): remove update-server.yml for update server migration [skip ci] 2026-05-31 03:46:11 +00:00
gitea-actions[bot] 8f537df6c5 chore(ci): remove cascade-dev.yml for update server migration [skip ci] 2026-05-31 03:46:02 +00:00
gitea-actions[bot] 7ac8c3d0a1 chore(ci): remove auto-bump.yml for update server migration [skip ci] 2026-05-31 03:45:51 +00:00
gitea-actions[bot] 3465b4fa01 chore(ci): remove pre-release.yml for update server migration [skip ci] 2026-05-31 03:45:42 +00:00
gitea-actions[bot] 0b4e7575eb chore(ci): remove auto-release.yml for update server migration [skip ci] 2026-05-31 03:45:33 +00:00
gitea-actions[bot] 508185f7ad chore(release): build 05.14.00 [skip ci] 2026-05-31 03:45:25 +00:00
jmiller c8ba0647d3 Merge pull request 'chore: merge dev into main' (#283) from dev into main
Deploy MokoGitea / deploy (push) Successful in 5m56s
2026-05-31 03:44:31 +00:00
2353 changed files with 19713 additions and 13755 deletions
+4 -4
View File
@@ -44,7 +44,7 @@ linters:
desc: use os or io instead desc: use os or io instead
- pkg: golang.org/x/exp - pkg: golang.org/x/exp
desc: it's experimental and unreliable desc: it's experimental and unreliable
- pkg: git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/git/internal - pkg: code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/git/internal
desc: do not use the internal package, use AddXxx function instead desc: do not use the internal package, use AddXxx function instead
- pkg: gopkg.in/ini.v1 - pkg: gopkg.in/ini.v1
desc: do not use the ini package, use gitea's config system instead desc: do not use the ini package, use gitea's config system instead
@@ -56,9 +56,9 @@ linters:
files: files:
- '**/models/migrations/**/*.go' - '**/models/migrations/**/*.go'
deny: deny:
- pkg: git.mokoconsulting.tech/MokoConsulting/MokoGitea/models$ - pkg: code.mokoconsulting.tech/MokoConsulting/MokoGitea/models$
desc: migrations must not depend on the models package desc: migrations must not depend on the models package
- pkg: git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/structs - pkg: code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/structs
desc: migrations must not depend on modules/structs (API structures change over time) desc: migrations must not depend on modules/structs (API structures change over time)
nolintlint: nolintlint:
allow-unused: false allow-unused: false
@@ -179,7 +179,7 @@ formatters:
custom-order: true custom-order: true
sections: sections:
- standard - standard
- prefix(git.mokoconsulting.tech/MokoConsulting/MokoGitea) - prefix(code.mokoconsulting.tech/MokoConsulting/MokoGitea)
- blank - blank
- default - default
gofumpt: gofumpt:
+2 -2
View File
@@ -8,10 +8,10 @@ contact_links:
url: https://mokoconsulting.tech/ url: https://mokoconsulting.tech/
about: Get help or ask questions through our website about: Get help or ask questions through our website
- name: 📚 MokoStandards Documentation - name: 📚 MokoStandards Documentation
url: https://git.mokoconsulting.tech/MokoConsulting/moko-platform url: https://code.mokoconsulting.tech/MokoConsulting/moko-platform
about: View our coding standards and best practices about: View our coding standards and best practices
- name: 🔒 Report a Security Vulnerability - name: 🔒 Report a Security Vulnerability
url: https://git.mokoconsulting.tech/mokoconsulting-tech/.github-private/security/advisories/new url: https://code.mokoconsulting.tech/mokoconsulting-tech/.github-private/security/advisories/new
about: Report security vulnerabilities privately (for critical issues) about: Report security vulnerabilities privately (for critical issues)
- name: 💡 Community Discussions - name: 💡 Community Discussions
url: https://github.com/orgs/mokoconsulting-tech/discussions url: https://github.com/orgs/mokoconsulting-tech/discussions
+1 -1
View File
@@ -37,7 +37,7 @@ If you have ideas about how this could be implemented, share them here:
Add any other context, mockups, or screenshots about the feature request here. Add any other context, mockups, or screenshots about the feature request here.
## Relevant Standards ## Relevant Standards
Does this relate to any standards in [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/MokoStandards)? Does this relate to any standards in [MokoStandards](https://code.mokoconsulting.tech/MokoConsulting/MokoStandards)?
- [ ] Accessibility (WCAG 2.1 AA) - [ ] Accessibility (WCAG 2.1 AA)
- [ ] Localization (en_US/en_GB) - [ ] Localization (en_US/en_GB)
- [ ] Security best practices - [ ] Security best practices
+1 -1
View File
@@ -35,7 +35,7 @@ Use this template only for:
<!-- Describe how this could be addressed --> <!-- Describe how this could be addressed -->
## Standards Reference ## Standards Reference
Does this relate to security standards in [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/MokoStandards)? Does this relate to security standards in [MokoStandards](https://code.mokoconsulting.tech/MokoConsulting/MokoStandards)?
- [ ] SPDX license identifiers - [ ] SPDX license identifiers
- [ ] Secret management - [ ] Secret management
- [ ] Dependency security - [ ] Dependency security
+2 -2
View File
@@ -3,7 +3,7 @@
# FILE INFORMATION # FILE INFORMATION
# DEFGROUP: Gitea.Workflow # DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.Automation # INGROUP: moko-platform.Automation
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform # REPO: https://code.mokoconsulting.tech/MokoConsulting/moko-platform
# PATH: /.gitea/workflows/branch-protection.yml # PATH: /.gitea/workflows/branch-protection.yml
# BRIEF: Apply standardised branch protection rules to all governed repositories # BRIEF: Apply standardised branch protection rules to all governed repositories
# #
@@ -42,7 +42,7 @@ on:
default: '' default: ''
env: env:
GITEA_URL: https://git.mokoconsulting.tech GITEA_URL: https://code.mokoconsulting.tech
GITEA_ORG: MokoConsulting GITEA_ORG: MokoConsulting
permissions: permissions:
+2 -2
View File
@@ -4,13 +4,13 @@
<name>MokoGitea</name> <name>MokoGitea</name>
<org>MokoConsulting</org> <org>MokoConsulting</org>
<description>Moko fork of Gitea — adding project board REST API endpoints and custom enhancements</description> <description>Moko fork of Gitea — adding project board REST API endpoints and custom enhancements</description>
<version>05.13.00</version> <version>05.14.00</version>
<license spdx="GPL-3.0-or-later">GNU General Public License v3</license> <license spdx="GPL-3.0-or-later">GNU General Public License v3</license>
</identity> </identity>
<governance> <governance>
<platform>go</platform> <platform>go</platform>
<standards-version>05.00.00</standards-version> <standards-version>05.00.00</standards-version>
<standards-source>https://git.mokoconsulting.tech/MokoConsulting/moko-platform</standards-source> <standards-source>https://code.mokoconsulting.tech/MokoConsulting/moko-platform</standards-source>
</governance> </governance>
<build> <build>
<language>Go</language> <language>Go</language>
-66
View File
@@ -1,66 +0,0 @@
# 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"
-270
View File
@@ -1,270 +0,0 @@
# 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-tech/moko-platform
# PATH: /templates/workflows/universal/auto-release.yml.template
# VERSION: 05.00.00
# BRIEF: Universal build & release detects platform from manifest.xml
#
# +========================================================================+
# | UNIVERSAL BUILD & RELEASE PIPELINE |
# +========================================================================+
# | |
# | Reads manifest.xml (joomla|dolibarr|generic) to branch logic. |
# | |
# | Platform-specific: |
# | joomla: XML manifest, updates.xml, type-prefixed packages |
# | dolibarr: mod*.class.php, update.txt, dev version reset |
# | generic: README-only, no update stream |
# | |
# +========================================================================+
name: "Universal: Build & Release"
on:
pull_request:
types: [opened, closed]
branches:
- main
workflow_dispatch:
inputs:
action:
description: 'Action to perform'
required: false
type: choice
default: release
options:
- release
- promote-rc
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
jobs:
# ── PR Opened → Rename branch to RC and build RC release ─────────────────────
promote-rc:
name: Promote to RC
runs-on: release
if: >-
(github.event.action == 'opened' && github.event.pull_request.merged != true) ||
(github.event_name == 'workflow_dispatch' && inputs.action == 'promote-rc')
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
token: ${{ secrets.MOKOGITEA_TOKEN }}
fetch-depth: 1
- name: Setup moko-platform tools
env:
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
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-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
- name: Rename branch to rc
run: |
php /tmp/moko-platform-api/cli/branch_rename.php \
--from "${{ github.event.pull_request.head.ref || 'dev' }}" --to rc \
--token "${{ secrets.MOKOGITEA_TOKEN }}" \
--api-base "${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" \
--pr "${{ github.event.pull_request.number }}"
- name: Checkout rc and configure git
run: |
git fetch origin rc
git checkout rc
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
git config --local user.name "gitea-actions[bot]"
git remote set-url origin "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
- name: Publish RC release
run: |
php /tmp/moko-platform-api/cli/release_publish.php \
--path . --stability rc --bump minor --branch rc \
--token "${{ secrets.MOKOGITEA_TOKEN }}"
- name: Summary
if: always()
run: |
echo "## Promoted to Release Candidate" >> $GITHUB_STEP_SUMMARY
echo "Branch renamed to rc, minor bump, RC + lesser stream releases built, updates.xml synced" >> $GITHUB_STEP_SUMMARY
# ── Merged PR → Build & Release (or promote RC to stable) ────────────────────
release:
name: Build & Release Pipeline
runs-on: release
if: >-
github.event.pull_request.merged == true ||
(github.event_name == 'workflow_dispatch' && inputs.action != 'promote-rc')
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
token: ${{ secrets.MOKOGITEA_TOKEN }}
fetch-depth: 0
- name: Configure git for bot pushes
run: |
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
git config --local user.name "gitea-actions[bot]"
git remote set-url origin "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
- name: Setup moko-platform tools
env:
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_MIRROR_TOKEN }}"}}'
run: |
# Ensure PHP + Composer are available
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
- name: "Publish stable release"
run: |
php /tmp/moko-platform-api/cli/release_publish.php \
--path . --stability stable --bump minor --branch main \
--token "${{ secrets.MOKOGITEA_TOKEN }}"
# -- STEP 9: Mirror to GitHub (stable only) --------------------------------
- name: "Step 9: Mirror release to GitHub"
if: >-
steps.version.outputs.skip != 'true' &&
secrets.GH_MIRROR_TOKEN != ''
continue-on-error: true
run: |
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
RELEASE_TAG="${{ steps.version.outputs.release_tag }}"
GH_REPO="${{ vars.GH_MIRROR_REPO || github.repository }}"
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
php /tmp/moko-platform-api/cli/release_mirror.php \
--version "$VERSION" --tag "$RELEASE_TAG" \
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \
--gh-token "${{ secrets.GH_MIRROR_TOKEN }}" --gh-repo "$GH_REPO" \
--branch main 2>&1 || true
echo "GitHub mirror updated" >> $GITHUB_STEP_SUMMARY
# -- STEP 10: Sync main branch to GitHub mirror ----------------------------
- name: "Step 10: Push main to GitHub mirror"
if: >-
steps.version.outputs.skip != 'true' &&
secrets.GH_MIRROR_TOKEN != ''
continue-on-error: true
run: |
GH_REPO="${{ vars.GH_MIRROR_REPO || github.repository }}"
GH_ORG=$(echo "$GH_REPO" | cut -d/ -f1)
GH_NAME=$(echo "$GH_REPO" | cut -d/ -f2)
git remote add github "https://x-access-token:${{ secrets.GH_MIRROR_TOKEN }}@github.com/${GH_ORG}/${GH_NAME}.git" 2>/dev/null || \
git remote set-url github "https://x-access-token:${{ secrets.GH_MIRROR_TOKEN }}@github.com/${GH_ORG}/${GH_NAME}.git"
git fetch origin main --depth=1
git push github origin/main:refs/heads/main --force 2>/dev/null \
&& echo "main branch pushed to GitHub mirror" \
|| echo "WARNING: GitHub mirror push failed"
- name: "Step 11: Delete rc branch and recreate dev from main"
if: steps.version.outputs.skip != 'true'
continue-on-error: true
run: |
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
# Delete rc branch (ephemeral — created by promote-rc)
curl -sf -X DELETE -H "Authorization: token ${TOKEN}" \
"${API_BASE}/branches/rc" 2>/dev/null \
&& echo "Deleted rc branch" || echo "rc branch not found"
# Delete dev branch
curl -sf -X DELETE -H "Authorization: token ${TOKEN}" \
"${API_BASE}/branches/dev" 2>/dev/null && echo "Deleted dev branch"
# Recreate dev from main (now includes version bump + changelog promotion)
curl -sf -X POST -H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
"${API_BASE}/branches" \
-d '{"new_branch_name":"dev","old_branch_name":"main"}' 2>/dev/null && echo "Recreated dev from main"
echo "Pre-release branches cleaned, dev reset from main" >> $GITHUB_STEP_SUMMARY
- name: "Step 12: Create version branch from main"
if: steps.version.outputs.skip != 'true'
continue-on-error: true
run: |
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
BRANCH_NAME="version/${VERSION}"
MAIN_SHA=$(git rev-parse HEAD)
# Delete old version branch if it exists (same version re-release)
curl -sf -X DELETE -H "Authorization: token ${TOKEN}" "${API_BASE}/branches/${BRANCH_NAME}" 2>/dev/null && echo "Deleted old ${BRANCH_NAME}"
# Create version/XX.YY.ZZ from main
curl -sf -X POST -H "Authorization: token ${TOKEN}" -H "Content-Type: application/json" "${API_BASE}/branches" -d "{\"new_branch_name\":\"${BRANCH_NAME}\",\"old_branch_name\":\"main\"}" 2>/dev/null && echo "Created ${BRANCH_NAME} from main (${MAIN_SHA})" || echo "WARNING: ${BRANCH_NAME} creation failed"
echo "Version branch created: ${BRANCH_NAME} (${MAIN_SHA})" >> $GITHUB_STEP_SUMMARY
# -- Dolibarr post-release: Reset dev version -----------------------------
- name: "Post-release: Reset dev version"
if: steps.version.outputs.skip != 'true'
continue-on-error: true
run: |
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
php /tmp/moko-platform-api/cli/version_reset_dev.php \
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "${API_BASE}" \
--branch dev --path . 2>&1 || true
# -- Summary --------------------------------------------------------------
- name: Pipeline Summary
if: always()
run: |
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
PLATFORM="${{ steps.platform.outputs.platform }}"
if [ "${{ steps.version.outputs.skip }}" = "true" ]; then
echo "## Release Skipped" >> $GITHUB_STEP_SUMMARY
echo "No VERSION in README.md" >> $GITHUB_STEP_SUMMARY
elif [ "${{ steps.check.outputs.already_released }}" = "true" ]; then
echo "## Already Released — ${VERSION}" >> $GITHUB_STEP_SUMMARY
else
echo "" >> $GITHUB_STEP_SUMMARY
echo "## Build & Release Complete (${PLATFORM})" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Step | Result |" >> $GITHUB_STEP_SUMMARY
echo "|------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| Platform | \`${PLATFORM}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Version | \`${VERSION}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Branch | \`${{ steps.version.outputs.branch }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Tag | \`${{ steps.version.outputs.tag }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Release | [View](${GITEA_URL}/${GITEA_ORG}/${GITEA_REPO}/releases/tag/${{ steps.version.outputs.tag }}) |" >> $GITHUB_STEP_SUMMARY
fi
+2 -2
View File
@@ -5,7 +5,7 @@
# FILE INFORMATION # FILE INFORMATION
# DEFGROUP: Gitea.Workflow # DEFGROUP: Gitea.Workflow
# INGROUP: MokoStandards.Universal # INGROUP: MokoStandards.Universal
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform # REPO: https://code.mokoconsulting.tech/MokoConsulting/moko-platform
# PATH: /.mokogitea/workflows/branch-cleanup.yml # PATH: /.mokogitea/workflows/branch-cleanup.yml
# VERSION: 01.00.00 # VERSION: 01.00.00
# BRIEF: Delete feature branches after PR merge # BRIEF: Delete feature branches after PR merge
@@ -32,7 +32,7 @@ jobs:
- name: Delete source branch - name: Delete source branch
run: | run: |
BRANCH="${{ github.event.pull_request.head.ref }}" BRANCH="${{ github.event.pull_request.head.ref }}"
API="${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}/api/v1/repos/${{ github.repository }}/branches" API="${{ vars.GITEA_URL || 'https://code.mokoconsulting.tech' }}/api/v1/repos/${{ github.repository }}/branches"
ENCODED=$(php -r "echo rawurlencode('${BRANCH}');") ENCODED=$(php -r "echo rawurlencode('${BRANCH}');")
STATUS=$(curl -sf -o /dev/null -w "%{http_code}" -X DELETE \ STATUS=$(curl -sf -o /dev/null -w "%{http_code}" -X DELETE \
-10
View File
@@ -1,10 +0,0 @@
# 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:
noop:
runs-on: ubuntu-latest
steps:
- run: echo "Cascade disabled — auto-release handles dev recreation"
+4 -4
View File
@@ -28,9 +28,9 @@ concurrency:
cancel-in-progress: false cancel-in-progress: false
env: env:
REGISTRY: git.mokoconsulting.tech REGISTRY: code.mokoconsulting.tech
IMAGE: mokoconsulting/mokogitea IMAGE: mokoconsulting/mokogitea
DEPLOY_HOST: git.mokoconsulting.tech DEPLOY_HOST: code.mokoconsulting.tech
DEPLOY_PORT: 2918 DEPLOY_PORT: 2918
DEPLOY_USER: mokoconsulting DEPLOY_USER: mokoconsulting
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
@@ -63,7 +63,7 @@ jobs:
echo "source_dir=/opt/gitea/source" >> $GITHUB_OUTPUT echo "source_dir=/opt/gitea/source" >> $GITHUB_OUTPUT
echo "branch=main" >> $GITHUB_OUTPUT echo "branch=main" >> $GITHUB_OUTPUT
echo "tag=${VERSION}" >> $GITHUB_OUTPUT echo "tag=${VERSION}" >> $GITHUB_OUTPUT
echo "instance_url=https://git.mokoconsulting.tech" >> $GITHUB_OUTPUT echo "instance_url=https://code.mokoconsulting.tech" >> $GITHUB_OUTPUT
else else
echo "compose_dir=/opt/gitea-dev" >> $GITHUB_OUTPUT echo "compose_dir=/opt/gitea-dev" >> $GITHUB_OUTPUT
echo "container=mokogitea-dev" >> $GITHUB_OUTPUT echo "container=mokogitea-dev" >> $GITHUB_OUTPUT
@@ -118,7 +118,7 @@ jobs:
$SSH_CMD " $SSH_CMD "
set -e set -e
if [ ! -d ${SOURCE_DIR}/.git ]; then if [ ! -d ${SOURCE_DIR}/.git ]; then
git clone -b ${BRANCH} https://git.mokoconsulting.tech/MokoConsulting/MokoGitea.git ${SOURCE_DIR} git clone -b ${BRANCH} https://code.mokoconsulting.tech/MokoConsulting/MokoGitea.git ${SOURCE_DIR}
fi fi
cd ${SOURCE_DIR} cd ${SOURCE_DIR}
git fetch origin ${BRANCH} git fetch origin ${BRANCH}
+2 -2
View File
@@ -5,7 +5,7 @@
# FILE INFORMATION # FILE INFORMATION
# DEFGROUP: Gitea.Workflow # DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.Automation # INGROUP: moko-platform.Automation
# VERSION: 05.13.00 # VERSION: 05.14.00
# BRIEF: Auto-create feature branch when an issue is opened # BRIEF: Auto-create feature branch when an issue is opened
name: "Universal: Issue Branch" name: "Universal: Issue Branch"
@@ -19,7 +19,7 @@ permissions:
issues: write issues: write
env: env:
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }} GITEA_URL: ${{ vars.GITEA_URL || 'https://code.mokoconsulting.tech' }}
jobs: jobs:
create-branch: create-branch:
+277 -236
View File
@@ -1,236 +1,277 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech> # Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
# #
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
# #
# FILE INFORMATION # FILE INFORMATION
# DEFGROUP: Gitea.Workflow # DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.CI # INGROUP: moko-platform.CI
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/moko-platform # REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/moko-platform
# PATH: /templates/workflows/universal/pr-check.yml.template # PATH: /templates/workflows/universal/pr-check.yml.template
# VERSION: 05.00.00 # VERSION: 09.23.00
# BRIEF: PR gate — branch policy + code validation before merge # BRIEF: PR gate — branch policy + code validation before merge
name: "Universal: PR Check" name: "Universal: PR Check"
on: on:
pull_request: pull_request:
types: [opened, synchronize, reopened, edited] types: [opened, synchronize, reopened, edited]
permissions: permissions:
contents: read contents: read
pull-requests: write pull-requests: write
env: env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs: jobs:
# ── Branch Policy ────────────────────────────────────────────────────── # ── Branch Policy ──────────────────────────────────────────────────────
branch-policy: branch-policy:
name: Branch Policy name: Branch Policy
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Check branch merge target - name: Check branch merge target
run: | run: |
HEAD="${{ github.head_ref }}" HEAD="${{ github.head_ref }}"
BASE="${{ github.base_ref }}" BASE="${{ github.base_ref }}"
echo "PR: ${HEAD} → ${BASE}" echo "PR: ${HEAD} → ${BASE}"
ALLOWED=true ALLOWED=true
REASON="" REASON=""
case "$HEAD" in case "$HEAD" in
feature/*|feat/*) feature/*|feat/*)
if [ "$BASE" != "dev" ]; then if [ "$BASE" != "dev" ]; then
ALLOWED=false ALLOWED=false
REASON="Feature branches must target 'dev', not '${BASE}'" REASON="Feature branches must target 'dev', not '${BASE}'"
fi fi
;; ;;
fix/*|bugfix/*) fix/*|bugfix/*)
if [ "$BASE" != "dev" ]; then if [ "$BASE" != "dev" ]; then
ALLOWED=false ALLOWED=false
REASON="Fix branches must target 'dev', not '${BASE}'" REASON="Fix branches must target 'dev', not '${BASE}'"
fi fi
;; ;;
patch/*) patch/*)
if [ "$BASE" != "dev" ] && [ "$BASE" != "rc" ]; then if [ "$BASE" != "dev" ] && [ "$BASE" != "rc" ]; then
ALLOWED=false ALLOWED=false
REASON="Patch branches must target 'dev' or 'rc', not '${BASE}'" REASON="Patch branches must target 'dev' or 'rc', not '${BASE}'"
fi fi
;; ;;
hotfix/*) hotfix/*)
if [ "$BASE" != "dev" ] && [ "$BASE" != "main" ]; then if [ "$BASE" != "dev" ] && [ "$BASE" != "main" ]; then
ALLOWED=false ALLOWED=false
REASON="Hotfix branches can only target 'dev' or 'main', not '${BASE}'" REASON="Hotfix branches can only target 'dev' or 'main', not '${BASE}'"
fi fi
;; ;;
rc) rc)
if [ "$BASE" != "main" ]; then if [ "$BASE" != "main" ]; then
ALLOWED=false ALLOWED=false
REASON="RC branch can only merge into 'main', not '${BASE}'" REASON="RC branch can only merge into 'main', not '${BASE}'"
fi fi
;; ;;
dev) dev)
if [ "$BASE" != "main" ]; then if [ "$BASE" != "main" ]; then
ALLOWED=false ALLOWED=false
REASON="Dev branch can only merge into 'main', not '${BASE}'" REASON="Dev branch can only merge into 'main', not '${BASE}'"
fi fi
;; ;;
esac esac
if [ "$ALLOWED" = false ]; then if [ "$ALLOWED" = false ]; then
echo "::error::${REASON}" echo "::error::${REASON}"
echo "## Branch Policy Violation" >> $GITHUB_STEP_SUMMARY echo "## Branch Policy Violation" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
echo "${REASON}" >> $GITHUB_STEP_SUMMARY echo "${REASON}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
echo "### Allowed merge paths:" >> $GITHUB_STEP_SUMMARY echo "### Allowed merge paths:" >> $GITHUB_STEP_SUMMARY
echo "- \`feature/*\` → \`dev\`" >> $GITHUB_STEP_SUMMARY echo "- \`feature/*\` → \`dev\`" >> $GITHUB_STEP_SUMMARY
echo "- \`fix/*\` → \`dev\`" >> $GITHUB_STEP_SUMMARY echo "- \`fix/*\` → \`dev\`" >> $GITHUB_STEP_SUMMARY
echo "- \`hotfix/*\` → \`dev\` or \`main\`" >> $GITHUB_STEP_SUMMARY echo "- \`hotfix/*\` → \`dev\` or \`main\`" >> $GITHUB_STEP_SUMMARY
echo "- \`dev\` → \`main\`" >> $GITHUB_STEP_SUMMARY echo "- \`dev\` → \`main\`" >> $GITHUB_STEP_SUMMARY
echo "- \`rc/*\` → \`main\`" >> $GITHUB_STEP_SUMMARY echo "- \`rc/*\` → \`main\`" >> $GITHUB_STEP_SUMMARY
exit 1 exit 1
fi fi
echo "Branch policy: OK (${HEAD} → ${BASE})" echo "Branch policy: OK (${HEAD} → ${BASE})"
echo "## Branch Policy: Passed" >> $GITHUB_STEP_SUMMARY echo "## Branch Policy: Passed" >> $GITHUB_STEP_SUMMARY
# ── Code Validation ──────────────────────────────────────────────────── # ── Code Validation ────────────────────────────────────────────────────
validate: validate:
name: Validate PR name: Validate PR
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Detect platform - name: Check for merge conflict markers
id: platform run: |
run: | CONFLICTS=$(grep -rn '<<<<<<< \|>>>>>>> \|^=======$' --include='*.php' --include='*.xml' --include='*.css' --include='*.js' --include='*.json' --include='*.md' --include='*.yml' --include='*.yaml' --include='*.ini' --include='*.txt' . 2>/dev/null | grep -v '.git/' || true)
# Read platform from XML manifest (<platform> tag) or plain text fallback if [ -n "$CONFLICTS" ]; then
PLATFORM=$(sed -n 's/.*<platform>\([^<]*\)<\/platform>.*/\1/p' .mokogitea/manifest.xml 2>/dev/null | head -1) echo "::error::Merge conflict markers found in source files"
[ -z "$PLATFORM" ] && PLATFORM=$(cat .mokogitea/manifest.xml 2>/dev/null | tr -d '[:space:]') echo "## Conflict Markers Found" >> $GITHUB_STEP_SUMMARY
[ -z "$PLATFORM" ] && PLATFORM="generic" echo '```' >> $GITHUB_STEP_SUMMARY
echo "platform=$PLATFORM" >> "$GITHUB_OUTPUT" echo "$CONFLICTS" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
- name: Setup PHP exit 1
if: steps.platform.outputs.platform == 'joomla' || steps.platform.outputs.platform == 'dolibarr' fi
run: | echo "No conflict markers found"
if ! command -v php &> /dev/null; then
sudo apt-get update -qq - name: Detect platform
sudo apt-get install -y -qq php-cli php-mbstring php-xml >/dev/null 2>&1 id: platform
fi run: |
# Read platform from XML manifest (<platform> tag) or plain text fallback
- name: PHP syntax check PLATFORM=$(sed -n 's/.*<platform>\([^<]*\)<\/platform>.*/\1/p' .mokogitea/manifest.xml 2>/dev/null | head -1)
if: steps.platform.outputs.platform == 'joomla' || steps.platform.outputs.platform == 'dolibarr' [ -z "$PLATFORM" ] && PLATFORM=$(cat .mokogitea/manifest.xml 2>/dev/null | tr -d '[:space:]')
run: | [ -z "$PLATFORM" ] && PLATFORM="generic"
ERRORS=0 echo "platform=$PLATFORM" >> "$GITHUB_OUTPUT"
while IFS= read -r -d '' file; do
if ! php -l "$file" 2>&1 | grep -q "No syntax errors"; then - name: Setup PHP
ERRORS=$((ERRORS + 1)) if: steps.platform.outputs.platform == 'joomla' || steps.platform.outputs.platform == 'dolibarr'
fi run: |
done < <(find . -name "*.php" -not -path "./.git/*" -not -path "./vendor/*" -print0) if ! command -v php &> /dev/null; then
echo "PHP lint: ${ERRORS} error(s)" sudo apt-get update -qq
[ "$ERRORS" -eq 0 ] || { echo "::error::PHP syntax errors found"; exit 1; } sudo apt-get install -y -qq php-cli php-mbstring php-xml >/dev/null 2>&1
fi
- name: Validate platform manifest
run: | - name: PHP syntax check
PLATFORM="${{ steps.platform.outputs.platform }}" if: steps.platform.outputs.platform == 'joomla' || steps.platform.outputs.platform == 'dolibarr'
case "$PLATFORM" in run: |
joomla) ERRORS=0
MANIFEST=$(find . -maxdepth 3 -name "*.xml" ! -path "./.git/*" -exec grep -l '<extension' {} \; 2>/dev/null | head -1) while IFS= read -r -d '' file; do
if [ -z "$MANIFEST" ]; then if ! php -l "$file" 2>&1 | grep -q "No syntax errors"; then
echo "::warning::No Joomla manifest found (WaaS site)" ERRORS=$((ERRORS + 1))
exit 0 fi
fi done < <(find . -name "*.php" -not -path "./.git/*" -not -path "./vendor/*" -print0)
echo "Manifest: ${MANIFEST}" echo "PHP lint: ${ERRORS} error(s)"
if command -v php &> /dev/null; then [ "$ERRORS" -eq 0 ] || { echo "::error::PHP syntax errors found"; exit 1; }
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 - name: Validate platform manifest
for ELEMENT in name version description; do run: |
grep -q "<${ELEMENT}>" "$MANIFEST" || { echo "::error::Missing <${ELEMENT}> in manifest"; exit 1; } PLATFORM="${{ steps.platform.outputs.platform }}"
done case "$PLATFORM" in
echo "Joomla manifest valid" joomla)
;; MANIFEST=$(find . -maxdepth 3 -name "*.xml" ! -path "./.git/*" -exec grep -l '<extension' {} \; 2>/dev/null | head -1)
dolibarr) if [ -z "$MANIFEST" ]; then
MOD_FILE=$(find . -maxdepth 4 -name "mod*.class.php" ! -path "./.git/*" -exec grep -l 'extends DolibarrModules' {} \; 2>/dev/null | head -1) echo "::warning::No Joomla manifest found (WaaS site)"
if [ -z "$MOD_FILE" ]; then exit 0
echo "::error::No mod*.class.php found" fi
exit 1 echo "Manifest: ${MANIFEST}"
fi if command -v php &> /dev/null; then
echo "Dolibarr module: ${MOD_FILE}" 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
echo "Generic platform — no manifest validation" grep -q "<${ELEMENT}>" "$MANIFEST" || { echo "::error::Missing <${ELEMENT}> in manifest"; exit 1; }
;; done
esac echo "Joomla manifest valid"
;;
- name: Check update stream format dolibarr)
run: | MOD_FILE=$(find . -maxdepth 4 -name "mod*.class.php" ! -path "./.git/*" -exec grep -l 'extends DolibarrModules' {} \; 2>/dev/null | head -1)
PLATFORM="${{ steps.platform.outputs.platform }}" if [ -z "$MOD_FILE" ]; then
case "$PLATFORM" in echo "::error::No mod*.class.php found"
joomla) exit 1
if [ -f "updates.xml" ]; then fi
if command -v php &> /dev/null; then echo "Dolibarr module: ${MOD_FILE}"
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" echo "Generic platform — no manifest validation"
fi ;;
;; esac
dolibarr)
[ -f "update.txt" ] && echo "update.txt present" || echo "::warning::No update.txt" - name: Check update stream format
;; run: |
esac PLATFORM="${{ steps.platform.outputs.platform }}"
case "$PLATFORM" in
- name: Check changelog has unreleased entry joomla)
run: | if [ -f "updates.xml" ]; then
if [ ! -f "CHANGELOG.md" ]; then if command -v php &> /dev/null; then
echo "::warning::No CHANGELOG.md found" 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; }
exit 0 fi
fi echo "updates.xml valid"
# Check for content under [Unreleased] section fi
if ! grep -q "## \[Unreleased\]" CHANGELOG.md; then ;;
echo "::error::CHANGELOG.md missing [Unreleased] section" dolibarr)
exit 1 [ -f "update.txt" ] && echo "update.txt present" || echo "::warning::No update.txt"
fi ;;
# Check there's at least one entry (Added/Changed/Fixed/Removed) under Unreleased esac
UNRELEASED_CONTENT=$(sed -n '/## \[Unreleased\]/,/## \[/p' CHANGELOG.md | grep -cE '^\s*-\s' || true)
if [ "$UNRELEASED_CONTENT" -eq 0 ]; then - name: Check changelog has unreleased entry
echo "::error::CHANGELOG.md [Unreleased] section has no entries. Add a changelog entry describing your changes." run: |
echo "## Changelog Check: Failed" >> $GITHUB_STEP_SUMMARY if [ ! -f "CHANGELOG.md" ]; then
echo "The \`[Unreleased]\` section in CHANGELOG.md has no entries." >> $GITHUB_STEP_SUMMARY echo "::warning::No CHANGELOG.md found"
echo "Add a line like \`- Description of your change\` under a heading (\`### Added\`, \`### Changed\`, \`### Fixed\`, etc.)" >> $GITHUB_STEP_SUMMARY exit 0
exit 1 fi
fi # Check for content under [Unreleased] section
echo "Changelog: ${UNRELEASED_CONTENT} entry/entries in [Unreleased]" if ! grep -q "## \[Unreleased\]" CHANGELOG.md; then
echo "::error::CHANGELOG.md missing [Unreleased] section"
- name: Verify package source exit 1
run: | fi
SOURCE_DIR="src" # Check there's at least one entry (Added/Changed/Fixed/Removed) under Unreleased
[ ! -d "$SOURCE_DIR" ] && SOURCE_DIR="htdocs" UNRELEASED_CONTENT=$(sed -n '/## \[Unreleased\]/,/## \[/p' CHANGELOG.md | grep -cE '^\s*-\s' || true)
if [ ! -d "$SOURCE_DIR" ]; then if [ "$UNRELEASED_CONTENT" -eq 0 ]; then
echo "::warning::No src/ or htdocs/ directory" echo "::error::CHANGELOG.md [Unreleased] section has no entries. Add a changelog entry describing your changes."
exit 0 echo "## Changelog Check: Failed" >> $GITHUB_STEP_SUMMARY
fi echo "The \`[Unreleased]\` section in CHANGELOG.md has no entries." >> $GITHUB_STEP_SUMMARY
FILE_COUNT=$(find "$SOURCE_DIR" -type f | wc -l) echo "Add a line like \`- Description of your change\` under a heading (\`### Added\`, \`### Changed\`, \`### Fixed\`, etc.)" >> $GITHUB_STEP_SUMMARY
echo "Source: ${FILE_COUNT} files" exit 1
[ "$FILE_COUNT" -gt 0 ] || { echo "::error::Source directory is empty"; exit 1; } fi
echo "Changelog: ${UNRELEASED_CONTENT} entry/entries in [Unreleased]"
# ── Pre-Release RC Build ─────────────────────────────────────────────────
pre-release: - name: Verify package source
name: Build RC Package run: |
runs-on: ubuntu-latest SOURCE_DIR="src"
needs: [branch-policy, validate] [ ! -d "$SOURCE_DIR" ] && SOURCE_DIR="htdocs"
if [ ! -d "$SOURCE_DIR" ]; then
steps: echo "::warning::No src/ or htdocs/ directory"
- name: Trigger RC pre-release exit 0
env: fi
GA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }} FILE_COUNT=$(find "$SOURCE_DIR" -type f | wc -l)
REPO: ${{ github.repository }} echo "Source: ${FILE_COUNT} files"
BRANCH: ${{ github.head_ref }} [ "$FILE_COUNT" -gt 0 ] || { echo "::error::Source directory is empty"; exit 1; }
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
run: | # ── Pre-Release RC Build ─────────────────────────────────────────────────
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\"}}" pre-release:
echo "### Pre-Release" >> $GITHUB_STEP_SUMMARY name: Build RC Package
echo "Triggered RC build on branch \`${BRANCH}\`" >> $GITHUB_STEP_SUMMARY 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."
+1 -1
View File
@@ -10,7 +10,7 @@ on:
env: env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
REGISTRY: git.mokoconsulting.tech REGISTRY: code.mokoconsulting.tech
IMAGE: mokoconsulting/mokogitea IMAGE: mokoconsulting/mokogitea
permissions: permissions:
-233
View File
@@ -1,233 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.Release
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
# PATH: /templates/workflows/universal/pre-release.yml.template
# VERSION: 05.01.00
# BRIEF: Manual pre-release -- builds dev/alpha/beta/rc packages from any branch
name: "Universal: Pre-Release"
on:
pull_request:
types: [closed]
branches:
- dev
workflow_dispatch:
inputs:
stability:
description: 'Pre-release channel'
required: true
type: choice
options:
- development
- alpha
- beta
- release-candidate
permissions:
contents: write
env:
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
GITEA_ORG: ${{ vars.GITEA_ORG || github.repository_owner }}
GITEA_REPO: ${{ vars.GITEA_REPO || github.event.repository.name }}
jobs:
build:
name: "Build Pre-Release (${{ inputs.stability || '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.MOKOGITEA_TOKEN }}
- name: Setup moko-platform tools
env:
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
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-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: |
php ${MOKO_CLI}/manifest_read.php --path . --github-output
- name: Resolve metadata and bump version
id: meta
run: |
STABILITY="${{ inputs.stability || 'development' }}"
case "$STABILITY" in
development) SUFFIX="-dev"; TAG="development" ;;
alpha) SUFFIX="-alpha"; TAG="alpha" ;;
beta) SUFFIX="-beta"; TAG="beta" ;;
release-candidate) SUFFIX="-rc"; TAG="release-candidate" ;;
esac
# 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"
# Strip any existing suffix from version before applying stability
VERSION=$(echo "$VERSION" | sed 's/-\(dev\|alpha\|beta\|rc\)$//')
php ${MOKO_CLI}/version_set_platform.php \
--path . --version "$VERSION" --branch "${{ github.ref_name }}" --stability "$STABILITY" 2>/dev/null || true
# 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
# 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://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
git add -A
git diff --cached --quiet || {
git commit -m "chore(version): pre-release bump to ${VERSION} [skip ci]"
git push origin HEAD 2>&1
}
# Auto-detect element via manifest_element.php
php ${MOKO_CLI}/manifest_element.php \
--path . --version "$VERSION" --stability "$STABILITY" \
--repo "${GITEA_REPO}" --github-output
# 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"
echo "suffix=${SUFFIX}" >> "$GITHUB_OUTPUT"
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
echo "zip_name=${ZIP_NAME}" >> "$GITHUB_OUTPUT"
echo "ext_element=${EXT_ELEMENT}" >> "$GITHUB_OUTPUT"
echo "=== Pre-Release: ${EXT_ELEMENT} ${VERSION}${SUFFIX} ==="
- name: Create release
id: release
run: |
TAG="${{ steps.meta.outputs.tag }}"
VERSION="${{ steps.meta.outputs.version }}"
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
- 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: |
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
if ! git diff --quiet updates.xml 2>/dev/null; then
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
git config --local user.name "gitea-actions[bot]"
git add updates.xml
git commit -m "chore: update ${STABILITY} channel ${VERSION} [skip ci]"
git push origin HEAD 2>&1 || echo "WARNING: push failed"
fi
- name: "Sync updates.xml to all branches"
if: steps.platform.outputs.platform == 'joomla'
run: |
CURRENT_BRANCH="${{ github.ref_name }}"
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
git config --local user.name "gitea-actions[bot]"
for BRANCH in main dev; do
[ "$BRANCH" = "$CURRENT_BRANCH" ] && continue
echo "Syncing updates.xml -> ${BRANCH}"
git fetch origin "${BRANCH}" 2>/dev/null || continue
git checkout "origin/${BRANCH}" -- 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
git commit -m "chore: sync updates.xml from ${CURRENT_BRANCH} [skip ci]"
git push origin HEAD:refs/heads/${BRANCH} 2>&1 || echo "WARNING: push to ${BRANCH} failed"
fi
git checkout "${CURRENT_BRANCH}" 2>/dev/null
done
- name: "Delete lesser pre-release channels (cascade)"
continue-on-error: true
run: |
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
TOKEN="${{ secrets.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 }}"
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
+817
View File
@@ -0,0 +1,817 @@
# ============================================================================
# Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>
#
# This file is part of a Moko Consulting project.
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.Validation
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/moko-platform
# PATH: /templates/workflows/joomla/repo_health.yml.template
# VERSION: 09.23.00
# BRIEF: Enforces repository guardrails by validating release configuration, scripts governance, tooling availability, and core repository health artifacts.
# ============================================================================
name: "Generic: Repo Health"
defaults:
run:
shell: bash
on:
workflow_dispatch:
inputs:
profile:
description: 'Validation profile: all, release, scripts, or repo'
required: true
default: all
type: choice
options:
- all
- release
- scripts
- repo
pull_request:
push:
permissions:
contents: read
env:
# Release policy - Repository Variables Only
RELEASE_REQUIRED_REPO_VARS: RS_FTP_PATH_SUFFIX
RELEASE_OPTIONAL_REPO_VARS: DEV_FTP_SUFFIX
# Scripts governance policy
SCRIPTS_REQUIRED_DIRS:
SCRIPTS_ALLOWED_DIRS: scripts,scripts/fix,scripts/lib,scripts/release,scripts/run,scripts/validate
# Repo health policy
REPO_REQUIRED_ARTIFACTS: README.md,LICENSE,CHANGELOG.md,CONTRIBUTING.md,CODE_OF_CONDUCT.md,.mokogitea/workflows/
REPO_OPTIONAL_FILES: SECURITY.md,GOVERNANCE.md,.editorconfig,.gitattributes,.gitignore,README.md,docs/
REPO_DISALLOWED_DIRS:
REPO_DISALLOWED_FILES: TODO.md,todo.md
# Extended checks toggles
EXTENDED_CHECKS: "true"
# File / directory variables
DOCS_INDEX: docs/docs-index.md
SCRIPT_DIR: scripts
WORKFLOWS_DIR: .mokogitea/workflows
SHELLCHECK_PATTERN: '*.sh'
SPDX_FILE_GLOBS: '*.sh,*.php,*.js,*.ts,*.css,*.xml,*.yml,*.yaml'
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
access_check:
name: Access control
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
outputs:
allowed: ${{ steps.perm.outputs.allowed }}
permission: ${{ steps.perm.outputs.permission }}
steps:
- name: Check actor permission (admin only)
id: perm
env:
TOKEN: ${{ secrets.MOKOGITEA_TOKEN || secrets.MOKOGITEA_TOKEN || github.token }}
REPO: ${{ github.repository }}
ACTOR: ${{ github.actor }}
run: |
set -euo pipefail
ALLOWED=false
PERMISSION=unknown
METHOD=""
# Hardcoded authorized users — always allowed
case "$ACTOR" in
jmiller|gitea-actions[bot])
ALLOWED=true
PERMISSION=admin
METHOD="hardcoded allowlist"
;;
*)
# Detect platform and check permissions via API
API_BASE="${GITHUB_API_URL:-${GITEA_API_URL:-https://api.github.com}}"
RESP=$(curl -sf -H "Authorization: token ${TOKEN}" \
"${API_BASE}/repos/${REPO}/collaborators/${ACTOR}/permission" 2>/dev/null || echo '{}')
PERMISSION=$(echo "$RESP" | grep -oP '"permission"\s*:\s*"\K[^"]+' || echo "unknown")
if [ "$PERMISSION" = "admin" ] || [ "$PERMISSION" = "maintain" ] || [ "$PERMISSION" = "owner" ]; then
ALLOWED=true
fi
METHOD="collaborator API"
;;
esac
echo "permission=${PERMISSION}" >> "$GITHUB_OUTPUT"
echo "allowed=${ALLOWED}" >> "$GITHUB_OUTPUT"
{
echo "## Access Authorization"
echo ""
echo "| Field | Value |"
echo "|-------|-------|"
echo "| **Actor** | \`${ACTOR}\` |"
echo "| **Repository** | \`${REPO}\` |"
echo "| **Permission** | \`${PERMISSION}\` |"
echo "| **Method** | ${METHOD} |"
echo "| **Authorized** | ${ALLOWED} |"
echo ""
if [ "$ALLOWED" = "true" ]; then
echo "${ACTOR} authorized (${METHOD})"
else
echo "${ACTOR} is NOT authorized. Requires admin or maintain role."
fi
} >> "${GITHUB_STEP_SUMMARY}"
- name: Deny execution when not permitted
if: ${{ steps.perm.outputs.allowed != 'true' }}
run: |
set -euo pipefail
printf '%s\n' 'ERROR: Access denied. Admin permission required.' >> "${GITHUB_STEP_SUMMARY}"
exit 1
release_config:
name: Release configuration
needs: access_check
if: ${{ needs.access_check.outputs.allowed == 'true' }}
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
fetch-depth: 0
- name: Guardrails release vars
env:
PROFILE_RAW: ${{ github.event.inputs.profile }}
RS_FTP_PATH_SUFFIX: ${{ vars.RS_FTP_PATH_SUFFIX }}
DEV_FTP_SUFFIX: ${{ vars.DEV_FTP_SUFFIX }}
run: |
set -euo pipefail
profile="${PROFILE_RAW:-all}"
case "${profile}" in
all|release|scripts|repo) ;;
*)
printf '%s\n' "ERROR: Unknown profile: ${profile}" >> "${GITHUB_STEP_SUMMARY}"
exit 1
;;
esac
if [ "${profile}" = 'scripts' ] || [ "${profile}" = 'repo' ]; then
{
printf '%s\n' '### Release configuration (Repository Variables)'
printf '%s\n' "Profile: ${profile}"
printf '%s\n' 'Status: SKIPPED'
printf '%s\n' 'Reason: profile excludes release validation'
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
exit 0
fi
IFS=',' read -r -a required <<< "${RELEASE_REQUIRED_REPO_VARS}"
IFS=',' read -r -a optional <<< "${RELEASE_OPTIONAL_REPO_VARS}"
missing=()
missing_optional=()
for k in "${required[@]}"; do
v="${!k:-}"
[ -z "${v}" ] && missing+=("${k}")
done
for k in "${optional[@]}"; do
v="${!k:-}"
[ -z "${v}" ] && missing_optional+=("${k}")
done
{
printf '%s\n' '### Release configuration (Repository Variables)'
printf '%s\n' "Profile: ${profile}"
printf '%s\n' '| Variable | Status |'
printf '%s\n' '|---|---|'
printf '%s\n' "| RS_FTP_PATH_SUFFIX | ${RS_FTP_PATH_SUFFIX:-NOT SET} |"
printf '%s\n' "| DEV_FTP_SUFFIX | ${DEV_FTP_SUFFIX:-NOT SET} |"
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
if [ "${#missing_optional[@]}" -gt 0 ]; then
{
printf '%s\n' '### Missing optional repository variables'
for m in "${missing_optional[@]}"; do printf '%s\n' "- ${m}"; done
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
fi
if [ "${#missing[@]}" -gt 0 ]; then
{
printf '%s\n' '### Missing required repository variables'
for m in "${missing[@]}"; do printf '%s\n' "- ${m}"; done
printf '%s\n' 'ERROR: Guardrails failed. Missing required repository variables.'
} >> "${GITHUB_STEP_SUMMARY}"
exit 1
fi
{
printf '%s\n' '### Repository variables validation result'
printf '%s\n' 'Status: OK'
printf '%s\n' 'All required repository variables present.'
printf '%s\n' ''
printf '%s\n' '**Note**: Organization secrets (RS_FTP_HOST, RS_FTP_USER, etc.) are validated at deployment time, not in repository health checks.'
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
scripts_governance:
name: Scripts governance
needs: access_check
if: ${{ needs.access_check.outputs.allowed == 'true' }}
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
fetch-depth: 0
- name: Scripts folder checks
env:
PROFILE_RAW: ${{ github.event.inputs.profile }}
run: |
set -euo pipefail
profile="${PROFILE_RAW:-all}"
case "${profile}" in
all|release|scripts|repo) ;;
*)
printf '%s\n' "ERROR: Unknown profile: ${profile}" >> "${GITHUB_STEP_SUMMARY}"
exit 1
;;
esac
if [ "${profile}" = 'release' ] || [ "${profile}" = 'repo' ]; then
{
printf '%s\n' '### Scripts governance'
printf '%s\n' "Profile: ${profile}"
printf '%s\n' 'Status: SKIPPED'
printf '%s\n' 'Reason: profile excludes scripts governance'
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
exit 0
fi
if [ ! -d "${SCRIPT_DIR}" ]; then
{
printf '%s\n' '### Scripts governance'
printf '%s\n' 'Status: OK (advisory)'
printf '%s\n' 'scripts/ directory not present. No scripts governance enforced.'
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
exit 0
fi
if [ -n "${SCRIPTS_REQUIRED_DIRS:-}" ]; then IFS=',' read -r -a required_dirs <<< "${SCRIPTS_REQUIRED_DIRS}"; else required_dirs=(); fi
IFS=',' read -r -a allowed_dirs <<< "${SCRIPTS_ALLOWED_DIRS}"
missing_dirs=()
unapproved_dirs=()
for d in "${required_dirs[@]}"; do
req="${d%/}"
[ ! -d "${req}" ] && missing_dirs+=("${req}/")
done
while IFS= read -r d; do
allowed=false
for a in "${allowed_dirs[@]}"; do
a_norm="${a%/}"
[ "${d%/}" = "${a_norm}" ] && allowed=true
done
[ "${allowed}" = false ] && unapproved_dirs+=("${d%/}/")
done < <(find "${SCRIPT_DIR}" -maxdepth 1 -mindepth 1 -type d 2>/dev/null | sed 's#^\./##')
{
printf '%s\n' '### Scripts governance'
printf '%s\n' "Profile: ${profile}"
printf '%s\n' '| Area | Status | Notes |'
printf '%s\n' '|---|---|---|'
if [ "${#missing_dirs[@]}" -gt 0 ]; then
printf '%s\n' '| Required directories | Warning | Missing required subfolders |'
else
printf '%s\n' '| Required directories | OK | All required subfolders present |'
fi
if [ "${#unapproved_dirs[@]}" -gt 0 ]; then
printf '%s\n' '| Directory policy | Warning | Unapproved directories detected |'
else
printf '%s\n' '| Directory policy | OK | No unapproved directories |'
fi
printf '%s\n' '| Enforcement mode | Advisory | scripts folder is optional |'
printf '\n'
if [ "${#missing_dirs[@]}" -gt 0 ]; then
printf '%s\n' 'Missing required script directories:'
for m in "${missing_dirs[@]}"; do printf '%s\n' "- ${m}"; done
printf '\n'
else
printf '%s\n' 'Missing required script directories: none.'
printf '\n'
fi
if [ "${#unapproved_dirs[@]}" -gt 0 ]; then
printf '%s\n' 'Unapproved script directories detected:'
for m in "${unapproved_dirs[@]}"; do printf '%s\n' "- ${m}"; done
printf '\n'
else
printf '%s\n' 'Unapproved script directories detected: none.'
printf '\n'
fi
printf '%s\n' 'Scripts governance completed in advisory mode.'
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
repo_health:
name: Repository health
needs: access_check
if: ${{ needs.access_check.outputs.allowed == 'true' }}
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
fetch-depth: 0
- name: Repository health checks
env:
PROFILE_RAW: ${{ github.event.inputs.profile }}
run: |
set -euo pipefail
profile="${PROFILE_RAW:-all}"
case "${profile}" in
all|release|scripts|repo) ;;
*)
printf '%s\n' "ERROR: Unknown profile: ${profile}" >> "${GITHUB_STEP_SUMMARY}"
exit 1
;;
esac
if [ "${profile}" = 'release' ] || [ "${profile}" = 'scripts' ]; then
{
printf '%s\n' '### Repository health'
printf '%s\n' "Profile: ${profile}"
printf '%s\n' 'Status: SKIPPED'
printf '%s\n' 'Reason: profile excludes repository health'
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
exit 0
fi
IFS=',' read -r -a required_artifacts <<< "${REPO_REQUIRED_ARTIFACTS}"
IFS=',' read -r -a optional_files <<< "${REPO_OPTIONAL_FILES}"
if [ -n "${REPO_DISALLOWED_DIRS:-}" ]; then IFS=',' read -r -a disallowed_dirs <<< "${REPO_DISALLOWED_DIRS}"; else disallowed_dirs=(); fi
IFS=',' read -r -a disallowed_files <<< "${REPO_DISALLOWED_FILES:-}"
missing_required=()
missing_optional=()
# Source directory: src/ or htdocs/ (either is valid for extension repos)
SOURCE_DIR=""
if [ -d "src" ]; then
SOURCE_DIR="src"
elif [ -d "htdocs" ]; then
SOURCE_DIR="htdocs"
elif [ -d "deploy" ] || [ -d "cli" ] || [ -d "monitoring" ]; then
# Platform/tooling repos don't need src/
SOURCE_DIR=""
else
missing_required+=("src/ or htdocs/ (source directory required)")
fi
for item in "${required_artifacts[@]}"; do
if printf '%s' "${item}" | grep -q '/$'; then
d="${item%/}"
[ ! -d "${d}" ] && missing_required+=("${item}")
else
[ ! -f "${item}" ] && missing_required+=("${item}")
fi
done
for f in "${optional_files[@]}"; do
if printf '%s' "${f}" | grep -q '/$'; then
d="${f%/}"
[ ! -d "${d}" ] && missing_optional+=("${f}")
else
[ ! -f "${f}" ] && missing_optional+=("${f}")
fi
done
for d in "${disallowed_dirs[@]}"; do
d_norm="${d%/}"
[ -d "${d_norm}" ] && missing_required+=("${d_norm}/ (disallowed)")
done
for f in "${disallowed_files[@]}"; do
[ -f "${f}" ] && missing_required+=("${f} (disallowed)")
done
git fetch origin --prune
dev_paths=()
dev_branches=()
while IFS= read -r b; do
name="${b#origin/}"
if [ "${name}" = 'dev' ]; then
dev_branches+=("${name}")
else
dev_paths+=("${name}")
fi
done < <(git branch -r --list 'origin/dev*' | sed 's/^ *//')
if [ "${#dev_paths[@]}" -eq 0 ] && [ "${#dev_branches[@]}" -eq 0 ]; then
missing_required+=("dev or dev/* branch")
fi
content_warnings=()
if [ -f 'CHANGELOG.md' ] && ! grep -Eq '^# Changelog' CHANGELOG.md; then
content_warnings+=("CHANGELOG.md missing '# Changelog' header")
fi
if [ -f 'CHANGELOG.md' ] && grep -Eq '^[# ]*Unreleased' CHANGELOG.md; then
content_warnings+=("CHANGELOG.md contains Unreleased section (review release readiness)")
fi
if [ -f 'LICENSE' ] && ! grep -qiE 'GNU GENERAL PUBLIC LICENSE|GPL' LICENSE; then
content_warnings+=("LICENSE does not look like a GPL text")
fi
if [ -f 'README.md' ] && ! grep -qiE 'moko|Moko' README.md; then
content_warnings+=("README.md missing expected brand keyword")
fi
export PROFILE_RAW="${profile}"
export MISSING_REQUIRED="$(printf '%s\n' "${missing_required[@]:-}")"
export MISSING_OPTIONAL="$(printf '%s\n' "${missing_optional[@]:-}")"
export CONTENT_WARNINGS="$(printf '%s\n' "${content_warnings[@]:-}")"
report_json=$(printf '{"profile":"%s","missing_required":%d,"missing_optional":%d,"content_warnings":%d}' "$profile" "${#missing_required[@]}" "${#missing_optional[@]}" "${#content_warnings[@]}")
{
printf '%s\n' '### Repository health'
printf '%s\n' "Profile: ${profile}"
printf '%s\n' '| Metric | Value |'
printf '%s\n' '|---|---|'
printf '%s\n' "| Missing required | ${#missing_required[@]} |"
printf '%s\n' "| Missing optional | ${#missing_optional[@]} |"
printf '%s\n' "| Content warnings | ${#content_warnings[@]} |"
printf '\n'
printf '%s\n' '### Guardrails report (JSON)'
printf '%s\n' '```json'
printf '%s\n' "${report_json}"
printf '%s\n' '```'
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
if [ "${#missing_required[@]}" -gt 0 ]; then
{
printf '%s\n' '### Missing required repo artifacts'
for m in "${missing_required[@]}"; do printf '%s\n' "- ${m}"; done
printf '%s\n' 'ERROR: Guardrails failed. Missing required repository artifacts.'
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
exit 1
fi
if [ "${#missing_optional[@]}" -gt 0 ]; then
{
printf '%s\n' '### Missing optional repo artifacts'
for m in "${missing_optional[@]}"; do printf '%s\n' "- ${m}"; done
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
fi
if [ "${#content_warnings[@]}" -gt 0 ]; then
{
printf '%s\n' '### Repo content warnings'
for m in "${content_warnings[@]}"; do printf '%s\n' "- ${m}"; done
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
fi
# -- Joomla-specific checks --
joomla_findings=()
MANIFEST="$(find . -maxdepth 2 -name '*.xml' -exec grep -l '<extension' {} \; 2>/dev/null | head -1 || true)"
if [ -z "${MANIFEST}" ]; then
joomla_findings+=("Joomla XML manifest not found (no *.xml with <extension> tag)")
else
if ! grep -qP '<version>' "${MANIFEST}"; then
joomla_findings+=("XML manifest: <version> tag missing")
fi
if ! grep -qP 'type="(component|module|plugin|library|package|template|language)"' "${MANIFEST}"; then
joomla_findings+=("XML manifest: type attribute missing or invalid")
fi
if ! grep -qP '<name>' "${MANIFEST}"; then
joomla_findings+=("XML manifest: <name> tag missing")
fi
if ! grep -qP '<author>' "${MANIFEST}"; then
joomla_findings+=("XML manifest: <author> tag missing")
fi
if ! grep -qP '<namespace' "${MANIFEST}"; then
joomla_findings+=("XML manifest: <namespace> missing (required for Joomla 5+)")
fi
fi
INI_COUNT="$(find . -name '*.ini' -type f 2>/dev/null | wc -l)"
if [ "${INI_COUNT}" -eq 0 ]; then
joomla_findings+=("No .ini language files found")
fi
if [ ! -f 'updates.xml' ]; then
joomla_findings+=("updates.xml missing in root (required for Joomla update server)")
fi
if [ -n "${SOURCE_DIR}" ]; then
INDEX_DIRS=("${SOURCE_DIR}" "${SOURCE_DIR}/admin" "${SOURCE_DIR}/site")
for dir in "${INDEX_DIRS[@]}"; do
if [ -d "${dir}" ] && [ ! -f "${dir}/index.html" ]; then
joomla_findings+=("${dir}/index.html missing (directory listing protection)")
fi
done
fi
if [ "${#joomla_findings[@]}" -gt 0 ]; then
{
printf '%s\n' '### Joomla extension checks'
printf '%s\n' '| Check | Status |'
printf '%s\n' '|---|---|'
for f in "${joomla_findings[@]}"; do
printf '%s\n' "| ${f} | Warning |"
done
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
else
{
printf '%s\n' '### Joomla extension checks'
printf '%s\n' 'All Joomla-specific checks passed.'
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
fi
extended_enabled="${EXTENDED_CHECKS:-true}"
extended_findings=()
if [ "${extended_enabled}" = 'true' ]; then
if [ -f '.github/CODEOWNERS' ] || [ -f 'CODEOWNERS' ] || [ -f 'docs/CODEOWNERS' ]; then
:
else
extended_findings+=("CODEOWNERS not found (.github/CODEOWNERS preferred)")
fi
if ls "${WORKFLOWS_DIR}"/*.yml >/dev/null 2>&1 || ls "${WORKFLOWS_DIR}"/*.yaml >/dev/null 2>&1; then
bad_refs="$(grep -RIn --include='*.yml' --include='*.yaml' -E '^[[:space:]]*uses:[[:space:]]*[^#]+@(main|master)\b' "${WORKFLOWS_DIR}" 2>/dev/null || true)"
if [ -n "${bad_refs}" ]; then
extended_findings+=("Workflows reference actions @main/@master (pin versions): see log excerpt")
{
printf '%s\n' '### Workflow pinning advisory'
printf '%s\n' 'Found uses: entries pinned to main/master:'
printf '%s\n' '```'
printf '%s\n' "${bad_refs}"
printf '%s\n' '```'
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
fi
fi
if [ -f "${DOCS_INDEX}" ]; then
missing_links=""
while IFS= read -r docline; do
for link in $(echo "$docline" | grep -oE '\]\([^)]+\)' | sed 's/\](//' | sed 's/)$//' || true); do
case "$link" in http://*|https://*|"#"*|mailto:*) continue ;; esac
linkpath="${link%%#*}"
linkpath="${linkpath%%\?*}"
[ -z "$linkpath" ] && continue
if [ "${linkpath:0:1}" = "/" ]; then
testpath="${linkpath#/}"
else
testpath="$(dirname "${DOCS_INDEX}")/${linkpath}"
fi
[ ! -e "$testpath" ] && missing_links="${missing_links}${testpath} "
done
done < "${DOCS_INDEX}"
if [ -n "${missing_links}" ]; then
extended_findings+=("docs/docs-index.md contains broken relative links")
{
printf '%s\n' '### Docs index link integrity'
printf '%s\n' 'Broken relative links:'
for bl in ${missing_links}; do
printf '%s\n' "- ${bl}"
done
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
fi
fi
if [ -d "${SCRIPT_DIR}" ]; then
if ! command -v shellcheck >/dev/null 2>&1; then
sudo apt-get update -qq
sudo apt-get install -y shellcheck >/dev/null
fi
sc_out=''
while IFS= read -r shf; do
[ -z "${shf}" ] && continue
out_one="$(shellcheck -S warning -x "${shf}" 2>/dev/null || true)"
if [ -n "${out_one}" ]; then
sc_out="${sc_out}${out_one}\n"
fi
done < <(find "${SCRIPT_DIR}" -type f -name "${SHELLCHECK_PATTERN}" 2>/dev/null | sort)
if [ -n "${sc_out}" ]; then
extended_findings+=("ShellCheck warnings detected (advisory)")
sc_head="$(printf '%s' "${sc_out}" | head -n 200)"
{
printf '%s\n' '### ShellCheck (advisory)'
printf '%s\n' '```'
printf '%s\n' "${sc_head}"
printf '%s\n' '```'
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
fi
fi
spdx_missing=()
IFS=',' read -r -a spdx_globs <<< "${SPDX_FILE_GLOBS}"
spdx_args=()
for g in "${spdx_globs[@]}"; do spdx_args+=("${g}"); done
while IFS= read -r f; do
[ -z "${f}" ] && continue
if ! head -n 40 "${f}" | grep -q 'SPDX-License-Identifier:'; then
spdx_missing+=("${f}")
fi
done < <(git ls-files "${spdx_args[@]}" 2>/dev/null || true)
if [ "${#spdx_missing[@]}" -gt 0 ]; then
extended_findings+=("SPDX header missing in some tracked files (advisory)")
{
printf '%s\n' '### SPDX header advisory'
printf '%s\n' 'Files missing SPDX-License-Identifier (first 40 lines scan):'
for f in "${spdx_missing[@]}"; do printf '%s\n' "- ${f}"; done
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
fi
stale_cutoff_days=180
stale_branches="$(git for-each-ref --format='%(refname:short) %(committerdate:unix)' refs/remotes/origin 2>/dev/null | awk -v now="$(date +%s)" -v days="${stale_cutoff_days}" '{if (now-$2 > days*86400) print $1}' | head -50)"
if [ -n "${stale_branches}" ]; then
extended_findings+=("Stale remote branches detected (advisory)")
{
printf '%s\n' '### Git hygiene advisory'
printf '%s\n' "Branches with last commit older than ${stale_cutoff_days} days (sample up to 50):"
while IFS= read -r b; do [ -n "${b}" ] && printf '%s\n' "- ${b}"; done <<< "${stale_branches}"
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
fi
fi
{
printf '%s\n' '### Guardrails coverage matrix'
printf '%s\n' '| Domain | Status | Notes |'
printf '%s\n' '|---|---|---|'
printf '%s\n' '| Access control | OK | Admin-only execution gate |'
printf '%s\n' '| Release variables | OK | Repository variables validation |'
printf '%s\n' '| Scripts governance | OK | Directory policy and advisory reporting |'
printf '%s\n' '| Repo required artifacts | OK | Required, optional, disallowed enforcement |'
printf '%s\n' '| Repo content heuristics | OK | Brand, license, changelog structure |'
if [ "${extended_enabled}" = 'true' ]; then
if [ "${#extended_findings[@]}" -gt 0 ]; then
printf '%s\n' '| Extended checks | Warning | See extended findings below |'
else
printf '%s\n' '| Extended checks | OK | No findings |'
fi
else
printf '%s\n' '| Extended checks | SKIPPED | EXTENDED_CHECKS disabled |'
fi
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
if [ "${extended_enabled}" = 'true' ] && [ "${#extended_findings[@]}" -gt 0 ]; then
{
printf '%s\n' '### Extended findings (advisory)'
for f in "${extended_findings[@]}"; do printf '%s\n' "- ${f}"; done
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
fi
printf '%s\n' 'Repository health guardrails passed.' >> "${GITHUB_STEP_SUMMARY}"
site-health:
name: Site Health
runs-on: ubuntu-latest
if: github.event_name == 'workflow_dispatch'
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
- name: Uptime check
if: env.URLS != ''
run: |
echo "$URLS" > /tmp/urls.txt
php monitoring/uptime-probe.php --urls /tmp/urls.txt --timeout 15 || echo "::warning::Some sites are down"
rm -f /tmp/urls.txt
env:
URLS: ${{ vars.MONITORED_URLS }}
- name: SSL certificate check
if: env.DOMAINS != ''
run: |
echo "$DOMAINS" > /tmp/domains.txt
php monitoring/ssl-check.php --domains /tmp/domains.txt --warn-days 30 || echo "::warning::SSL certificates expiring soon"
rm -f /tmp/domains.txt
env:
DOMAINS: ${{ vars.MONITORED_DOMAINS }}
- name: Summary
if: always()
run: |
echo "### Site Health" >> $GITHUB_STEP_SUMMARY
echo "Uptime and SSL checks completed." >> $GITHUB_STEP_SUMMARY
# ═══════════════════════════════════════════════════════════════════════
# Issue Reporter — file issues for failed gates
# ═══════════════════════════════════════════════════════════════════════
report-issues:
name: "Report Issues"
runs-on: ubuntu-latest
needs: [access_check, release_config, scripts_governance, repo_health]
if: >-
always() &&
(needs.release_config.result == 'failure' ||
needs.scripts_governance.result == 'failure' ||
needs.repo_health.result == 'failure')
steps:
- name: Checkout
uses: actions/checkout@v4
with:
sparse-checkout: automation/ci-issue-reporter.sh
sparse-checkout-cone-mode: false
- name: "File issues for failed gates"
env:
GITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
run: |
chmod +x automation/ci-issue-reporter.sh
REPORTER="./automation/ci-issue-reporter.sh"
WF="Repo Health"
report_gate() {
local gate="$1" result="$2" details="$3"
if [ "$result" = "failure" ]; then
"$REPORTER" --gate "$gate" --details "$details" --workflow "$WF" --severity error
fi
}
report_gate "Release Configuration" \
"${{ needs.release_config.result }}" \
"Required repository variables are missing (RS_FTP_PATH_SUFFIX). Check repository settings."
report_gate "Scripts Governance" \
"${{ needs.scripts_governance.result }}" \
"Scripts directory policy violations detected. Review required and allowed directories."
report_gate "Repository Health" \
"${{ needs.repo_health.result }}" \
"Repository health checks failed — missing required artifacts, disallowed files, or content warnings. Check the CI run summary."
-312
View File
@@ -1,312 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# 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
#
# Thin wrapper around moko-platform CLI tools.
# Builds packages, updates updates.xml, and optionally deploys via SFTP.
#
# Joomla filters update entries by the user's "Minimum Stability" setting.
name: "Update Server"
on:
push:
branches:
- 'dev'
- 'dev/**'
- 'alpha/**'
- 'beta/**'
- 'rc/**'
paths:
- 'src/**'
- 'htdocs/**'
pull_request:
types: [closed]
branches:
- 'dev'
- 'dev/**'
- 'alpha/**'
- 'beta/**'
- 'rc/**'
paths:
- 'src/**'
- 'htdocs/**'
workflow_dispatch:
inputs:
stability:
description: 'Stability tag'
required: true
default: 'development'
type: choice
options:
- development
- alpha
- beta
- rc
- stable
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
jobs:
update-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@v4
with:
token: ${{ secrets.MOKOGITEA_TOKEN }}
fetch-depth: 0
- name: Setup moko-platform tools
env:
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
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}/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: 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 }}"
# Configure git for bot pushes
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
git config --local user.name "gitea-actions[bot]"
git remote set-url origin "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
# 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
STABILITY="rc"
elif [[ "$BRANCH" == beta/* ]]; then
STABILITY="beta"
elif [[ "$BRANCH" == alpha/* ]]; then
STABILITY="alpha"
else
STABILITY="development"
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"
# Commit version bump if changed
git add -A
git diff --cached --quiet || {
git commit -m "chore(version): auto-bump ${VERSION} [skip ci]" \
--author="gitea-actions[bot] <gitea-actions[bot]@mokoconsulting.tech>"
git push
}
- 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' && steps.platform.outputs.platform == 'joomla'
run: |
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
GITEA_TOKEN="${{ secrets.MOKOGITEA_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
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
if: contains(github.ref, 'dev/') || github.ref == 'refs/heads/dev'
env:
DEV_HOST: ${{ vars.DEV_FTP_HOST }}
DEV_PATH: ${{ vars.DEV_FTP_PATH }}
DEV_SUFFIX: ${{ vars.DEV_FTP_SUFFIX }}
DEV_USER: ${{ vars.DEV_FTP_USERNAME }}
DEV_PORT: ${{ vars.DEV_FTP_PORT }}
DEV_KEY: ${{ secrets.DEV_FTP_KEY }}
DEV_PASS: ${{ secrets.DEV_FTP_PASSWORD }}
run: |
# Permission check: admin or maintain role required
ACTOR="${{ github.actor }}"
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
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
admin|maintain|write) ;;
*)
echo "Deploy denied: ${ACTOR} has '${PERMISSION}' — requires admin, maintain, or write"
exit 0
;;
esac
[ -z "$DEV_HOST" ] || [ -z "$DEV_PATH" ] && { echo "DEV FTP not configured — skipping SFTP"; exit 0; }
SOURCE_DIR="src"
[ ! -d "$SOURCE_DIR" ] && SOURCE_DIR="htdocs"
[ ! -d "$SOURCE_DIR" ] && exit 0
PORT="${DEV_PORT:-22}"
REMOTE="${DEV_PATH%/}"
[ -n "$DEV_SUFFIX" ] && REMOTE="${REMOTE}/${DEV_SUFFIX#/}"
printf '{"host":"%s","port":%s,"username":"%s","remotePath":"%s"' \
"$DEV_HOST" "$PORT" "$DEV_USER" "$REMOTE" > /tmp/sftp-config.json
if [ -n "$DEV_KEY" ]; then
echo "$DEV_KEY" > /tmp/deploy_key && chmod 600 /tmp/deploy_key
printf ',"privateKeyPath":"/tmp/deploy_key"}' >> /tmp/sftp-config.json
else
printf ',"password":"%s"}' "$DEV_PASS" >> /tmp/sftp-config.json
fi
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
- name: Summary
if: always()
run: |
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}\` |" >> $GITHUB_STEP_SUMMARY
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
env: env:
GH_TOKEN: ${{ secrets.GH_MIRROR_TOKEN }} GH_TOKEN: ${{ secrets.GH_MIRROR_TOKEN }}
MOKOGITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} MOKOGITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
MOKOGITEA_URL: https://git.mokoconsulting.tech MOKOGITEA_URL: https://code.mokoconsulting.tech
MOKOGITEA_REPO: MokoConsulting/MokoGitea MOKOGITEA_REPO: MokoConsulting/MokoGitea
UPSTREAM_BRANCH: release/v1.26 UPSTREAM_BRANCH: release/v1.26
DAYS_BACK: ${{ github.event.inputs.days_back || '7' }} DAYS_BACK: ${{ github.event.inputs.days_back || '7' }}
+72
View File
@@ -3,6 +3,78 @@
This changelog goes through the changes that have been made in each release This changelog goes through the changes that have been made in each release
without substantial changes to our git log; to see the highlights of what has without substantial changes to our git log; to see the highlights of what has
been added to each release, please refer to the [blog](https://blog.gitea.com). been added to each release, please refer to the [blog](https://blog.gitea.com).
## [v1.26.1-moko.06.02.00] - 2026-06-02
* FEATURES
* feat(licenses): full commercial license management system
* Package archiving with soft-delete and collapsible archived section
* Search keys by customer, domain, key number, email, or payment ref
* Download gating (none/prerelease/all modes)
* Feed visibility (public/no-download/hidden modes)
* Domain lock grace period (DomainLockHours)
* RepoScope enforcement — packages scoped to specific repos
* Joomla changelog XML endpoint (/changelog.xml)
* WordPress PUC-compatible update feed (/updates/wordpress.json)
* SHA256 checksums from sidecar files in Joomla updates.xml
* Joomla-standard tag values (dev/alpha/beta/rc/stable)
* Double confirmation modals for permanent deletion
* Combolist channel picker (replaces checkboxes)
* Extension metadata in repo settings (per-repo override)
* API: package CRUD, key revoke, key renew, settings GET/PUT
* API: purchase webhook with PaymentRef idempotency
* API: public validation endpoint (no auth)
* Migration v340: all new columns synced
* feat(updates): infourl defaults to release listing page
* feat(updates): downloadkey prefix matches Akeeba pattern (dlid=)
* fix(licenses): expanded delete permissions to org owners + site admins
* fix(licenses): no-download mode shows release notes but hides files
* fix(licenses): releases require login in hidden feed visibility mode
## [v1.26.1-moko.05.15.00] - 2026-05-31
* BREAKING CHANGES
* Deprecated Issue.Ref branch selector UI (#307)
* Removed branch/tag selector from issue sidebar and new issue form
* Removed ref badge from issue lists
* Removed POST /ref web route and UpdateIssueRef handler
* DB column and commit-close logic preserved for backward compatibility
* API create/edit still accept `ref` field (no-op) for backward compat
* FEATURES
* feat(ui): add generic combo-multiselect component (#361)
* Reusable dropdown with search, checkable items, and selected-items display
* Template: `shared/combolist.tmpl` — accepts Items, Name, Title, SelectedValues
* Decoupled from issue sidebar — works in any form context
* feat(updates): extension metadata settings for update feed generation
* feat(licenses): platform enforcement, key deletion, expired key cleanup
* feat(licenses): store keys in plaintext, show full key with copy button
* TECH DEBT
* chore: full namespace migration from git.mokoconsulting.tech to code.mokoconsulting.tech (#336, #337, #344)
* Go module path, all imports, template URLs, workflow configs (2,276 files)
* fix(blame): set HasSourceRenderedToggle for renderable files (#344)
* fix(settings): translate team permission strings via data-locale attributes (#344)
* fix(dropzone): use relative path for non-image attachment markdown links (#344)
* fix(templates): add required validation to issue dropdown fields (#350)
* refactor(ts): remove redundant `handled` field from MarkdownHandleIndentionResult (#350)
* refactor(go): rename HasOrgOrUserVisible to IsOwnerVisibleToDoer (#350)
* refactor(go): replace ValuesRepository with maps.Values (Go 1.21+) (#357)
* refactor(go): remove CanEnableEditor wrapper, use CanContentChange directly (#357)
* fix(ts): parseIssueHref now uses URL pathname and trims appSubUrl (#360)
* fix(actions): enforce MaxJobNumPerRun (256) limit when creating jobs (#360)
* fix(css): use calc(infinity * 1px) for --border-radius-full (#361)
* fix(css): remove legacy .center class from 2015, replace with tw-text-center (#361)
* chore: remove stale TODO from OAuth2 regenerate secret (already implemented) (#332)
* chore: remove stale pull request test stub TODOs (#328)
* chore: remove stale GetProjectsMode TODO
* chore: remove stale mustNotBeArchived/mustEnableEditor FIXME from API
* fix(routes): remove dead legacy /cherry-pick/{sha} route (replaced by /_cherrypick/)
* fix(feed): use full ref name instead of ShortName for file feed revision
* BUGFIXES
* fix(build): use slices.Collect for maps.Values (Go 1.23+ compat)
* fix(licenses): remove duplicate DeleteLicenseKey declaration
* fix(licenses): only show licenses tab when licensing is enabled
* fix(licenses): show feed URLs based on repo update platform setting
* fix(updates): correct dlid prefix and align XML with Joomla standard
## [v1.26.1-moko.05.06.00] - 2026-05-30 ## [v1.26.1-moko.05.06.00] - 2026-05-30
* FEATURES * FEATURES
+161 -161
View File
@@ -1,161 +1,161 @@
# Contributing to Moko Consulting Projects # Contributing to Moko Consulting Projects
Thank you for your interest in contributing. All Moko Consulting repositories follow this universal workflow and version policy. Thank you for your interest in contributing. All Moko Consulting repositories follow this universal workflow and version policy.
## Branching Workflow ## Branching Workflow
``` ```
feature/* ──PR──> dev ──draft PR──> (renamed to rc) ──merge──> main feature/* ──PR──> dev ──draft PR──> (renamed to rc) ──merge──> main
``` ```
### Step by step ### Step by step
1. **Create a feature branch** from `dev`: 1. **Create a feature branch** from `dev`:
```bash ```bash
git checkout dev && git pull git checkout dev && git pull
git checkout -b feature/my-change git checkout -b feature/my-change
``` ```
2. **Work and commit** on your feature branch. Push to origin. 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. 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`. 4. **When ready for release**, open a **draft PR**: `dev` → `main`.
- This automatically renames the source branch to `rc` (release candidate) - This automatically renames the source branch to `rc` (release candidate)
- An RC pre-release is built and uploaded - An RC pre-release is built and uploaded
5. **Alpha and beta branches** are created by manually renaming the branch before the RC stage: 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 `dev` to `alpha` for early testing → alpha pre-release is built
- Rename `alpha` to `beta` for feature-complete testing → beta 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` - 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`. 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: 7. **Merging to main** triggers the stable release pipeline:
- Minor version bump (e.g., `02.09.xx` → `02.10.00`) - Minor version bump (e.g., `02.09.xx` → `02.10.00`)
- Stability suffix stripped (clean version) - Stability suffix stripped (clean version)
- Gitea release created with ZIP/tar.gz packages - Gitea release created with ZIP/tar.gz packages
- `updates.xml` updated (Joomla extensions) - `updates.xml` updated (Joomla extensions)
- `dev` branch recreated from `main` - `dev` branch recreated from `main`
### Branch summary ### Branch summary
| Branch | Purpose | Created by | | Branch | Purpose | Created by |
|--------|---------|-----------| |--------|---------|-----------|
| `feature/*` | New features and fixes | Developer | | `feature/*` | New features and fixes | Developer |
| `dev` | Integration branch | Auto-recreated after release | | `dev` | Integration branch | Auto-recreated after release |
| `alpha` | Alpha pre-release testing | Manual rename from `dev` | | `alpha` | Alpha pre-release testing | Manual rename from `dev` |
| `beta` | Beta pre-release testing | Manual rename from `alpha` | | `beta` | Beta pre-release testing | Manual rename from `alpha` |
| `rc` | Release candidate | Auto-renamed on draft PR to main | | `rc` | Release candidate | Auto-renamed on draft PR to main |
| `main` | Stable releases | Protected, merge only | | `main` | Stable releases | Protected, merge only |
| `version/XX.YY.ZZ` | Archived release snapshots | Auto-created by CI | | `version/XX.YY.ZZ` | Archived release snapshots | Auto-created by CI |
### Protected branches ### Protected branches
| Branch | Direct push | Merge via | | Branch | Direct push | Merge via |
|--------|------------|-----------| |--------|------------|-----------|
| `main` | Blocked (CI bot whitelisted) | PR merge only | | `main` | Blocked (CI bot whitelisted) | PR merge only |
| `dev` | Blocked (CI bot whitelisted) | PR merge from feature/* | | `dev` | Blocked (CI bot whitelisted) | PR merge from feature/* |
| `rc` | Blocked (CI bot whitelisted) | Auto-created on draft PR | | `rc` | Blocked (CI bot whitelisted) | Auto-created on draft PR |
| `alpha` | Blocked (CI bot whitelisted) | Manual rename | | `alpha` | Blocked (CI bot whitelisted) | Manual rename |
| `beta` | Blocked (CI bot whitelisted) | Manual rename | | `beta` | Blocked (CI bot whitelisted) | Manual rename |
| `feature/*` | Open | N/A (source branch) | | `feature/*` | Open | N/A (source branch) |
## Version Policy ## Version Policy
### Format ### Format
All versions use `XX.YY.ZZ` — three two-digit segments, zero-padded: All versions use `XX.YY.ZZ` — three two-digit segments, zero-padded:
- **XX** — Major version (breaking changes) - **XX** — Major version (breaking changes)
- **YY** — Minor version (new features, bumped on release to main) - **YY** — Minor version (new features, bumped on release to main)
- **ZZ** — Patch version (auto-incremented on every push to dev/feature branches) - **ZZ** — Patch version (auto-incremented on every push to dev/feature branches)
Rollover: patch `99` → `00` increments minor; minor `99` → `00` increments major. Rollover: patch `99` → `00` increments minor; minor `99` → `00` increments major.
### Stability suffixes ### Stability suffixes
Each branch appends a suffix to indicate stability: Each branch appends a suffix to indicate stability:
| Branch | Suffix | Example | | Branch | Suffix | Example |
|--------|--------|---------| |--------|--------|---------|
| `main` | (none) | `02.09.00` | | `main` | (none) | `02.09.00` |
| `dev` | `-dev` | `02.09.01-dev` | | `dev` | `-dev` | `02.09.01-dev` |
| `feature/*` | `-dev` | `02.09.01-dev` | | `feature/*` | `-dev` | `02.09.01-dev` |
| `alpha` | `-alpha` | `02.09.01-alpha` | | `alpha` | `-alpha` | `02.09.01-alpha` |
| `beta` | `-beta` | `02.09.01-beta` | | `beta` | `-beta` | `02.09.01-beta` |
| `rc` | `-rc` | `02.09.01-rc` | | `rc` | `-rc` | `02.09.01-rc` |
### Auto version bump ### Auto version bump
On every push to `dev`, `feature/*`, or `patch/*`: On every push to `dev`, `feature/*`, or `patch/*`:
1. Patch version incremented 1. Patch version incremented
2. Stability suffix `-dev` applied 2. Stability suffix `-dev` applied
3. All version-bearing files updated (manifests, CHANGELOG, PHP headers, etc.) 3. All version-bearing files updated (manifests, CHANGELOG, PHP headers, etc.)
4. Commit created with `[skip ci]` to avoid loops 4. Commit created with `[skip ci]` to avoid loops
### Release version flow ### Release version flow
Version bumps happen at specific release events: Version bumps happen at specific release events:
| Event | Bump | Example | | Event | Bump | Example |
|-------|------|---------| |-------|------|---------|
| Feature merged to dev | Patch bump after dev release | `02.09.01-dev` → release → `02.09.02-dev` | | 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` | | 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) | | 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` | | Dev recreated from main | Patch bump | `02.11.00` → `02.11.01-dev` |
### Release stream copies ### Release stream copies
When a higher-stability release is published, copies are created for all lesser streams with the same base version: 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` - **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` - **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). This ensures Joomla sites on ANY stability channel see the update (Joomla only shows versions higher than what's installed).
### Version files ### Version files
The version tools update all files containing version stamps: The version tools update all files containing version stamps:
- `.mokogitea/manifest.xml` (canonical source) - `.mokogitea/manifest.xml` (canonical source)
- Joomla XML manifests (`<version>` tag) - Joomla XML manifests (`<version>` tag)
- `README.md`, `CHANGELOG.md` (`VERSION:` pattern) - `README.md`, `CHANGELOG.md` (`VERSION:` pattern)
- `package.json`, `pyproject.toml` - `package.json`, `pyproject.toml`
- Any text file with a `VERSION: XX.YY.ZZ` label - Any text file with a `VERSION: XX.YY.ZZ` label
Files synced from other repos (with a `# REPO:` header) are not touched. Files synced from other repos (with a `# REPO:` header) are not touched.
## Code Standards ## Code Standards
- **PHP**: PSR-12, tabs for indentation - **PHP**: PSR-12, tabs for indentation
- **Copyright**: all files must include the Moko Consulting copyright header - **Copyright**: all files must include the Moko Consulting copyright header
- **License**: SPDX identifier `GPL-3.0-or-later` (or as specified per repo) - **License**: SPDX identifier `GPL-3.0-or-later` (or as specified per repo)
- **Attribution**: use `Authored-by: Moko Consulting` in commits, not individual names - **Attribution**: use `Authored-by: Moko Consulting` in commits, not individual names
## Commit Messages ## Commit Messages
Use conventional commit format: Use conventional commit format:
``` ```
type(scope): short description type(scope): short description
Optional body with context. Optional body with context.
Authored-by: Moko Consulting Authored-by: Moko Consulting
``` ```
Types: `feat`, `fix`, `chore`, `docs`, `style`, `refactor`, `test`, `ci` Types: `feat`, `fix`, `chore`, `docs`, `style`, `refactor`, `test`, `ci`
Special flags in commit messages: Special flags in commit messages:
- `[skip ci]` — skip all CI workflows - `[skip ci]` — skip all CI workflows
- `[skip bump]` — skip auto version bump only - `[skip bump]` — skip auto version bump only
## Reporting Issues ## Reporting Issues
Use the repository's issue tracker with the appropriate template. Use the repository's issue tracker with the appropriate template.
--- ---
*Moko Consulting <hello@mokoconsulting.tech>* *Moko Consulting <hello@mokoconsulting.tech>*
+6 -3
View File
@@ -21,7 +21,7 @@ RUN apk --no-cache add \
build-base \ build-base \
git git
WORKDIR ${GOPATH}/src/git.mokoconsulting.tech/MokoConsulting/MokoGitea WORKDIR ${GOPATH}/src/code.mokoconsulting.tech/MokoConsulting/MokoGitea
COPY go.mod go.sum ./ COPY go.mod go.sum ./
RUN go mod download RUN go mod download
# Use COPY instead of bind mount as read-only one breaks makefile state tracking # Use COPY instead of bind mount as read-only one breaks makefile state tracking
@@ -43,7 +43,7 @@ RUN chmod 755 /tmp/local/usr/bin/entrypoint \
/tmp/local/etc/s6/gitea/* \ /tmp/local/etc/s6/gitea/* \
/tmp/local/etc/s6/openssh/* \ /tmp/local/etc/s6/openssh/* \
/tmp/local/etc/s6/.s6-svscan/* \ /tmp/local/etc/s6/.s6-svscan/* \
/go/src/git.mokoconsulting.tech/MokoConsulting/MokoGitea/gitea /go/src/code.mokoconsulting.tech/MokoConsulting/MokoGitea/gitea
FROM docker.io/library/alpine:3.23 AS gitea FROM docker.io/library/alpine:3.23 AS gitea
@@ -75,7 +75,10 @@ RUN addgroup \
echo "git:*" | chpasswd -e echo "git:*" | chpasswd -e
COPY --from=build-env /tmp/local / COPY --from=build-env /tmp/local /
COPY --from=build-env /go/src/git.mokoconsulting.tech/MokoConsulting/MokoGitea/gitea /app/gitea/gitea COPY --from=build-env /go/src/code.mokoconsulting.tech/MokoConsulting/MokoGitea/gitea /app/gitea/gitea
# Disable openssh s6 service — we use external SSH (port 2222 via host).
RUN printf '#!/bin/sh\nexec sleep infinity\n' > /etc/s6/openssh/run && chmod 755 /etc/s6/openssh/run
ENV USER=git ENV USER=git
ENV GITEA_CUSTOM=/data/gitea ENV GITEA_CUSTOM=/data/gitea
+6 -6
View File
@@ -11,14 +11,14 @@ Custom Gitea fork with Project Board API
## Pages ## Pages
- [Branding](https://git.mokoconsulting.tech/MokoConsulting/MokoGitea/wiki/Branding) - [Branding](https://code.mokoconsulting.tech/MokoConsulting/MokoGitea/wiki/Branding)
- [Deployment](https://git.mokoconsulting.tech/MokoConsulting/MokoGitea/wiki/Deployment) - [Deployment](https://code.mokoconsulting.tech/MokoConsulting/MokoGitea/wiki/Deployment)
- [Project API](Project API) - [Project API](Project API)
- [roadmap](https://git.mokoconsulting.tech/MokoConsulting/MokoGitea/wiki/roadmap) - [roadmap](https://code.mokoconsulting.tech/MokoConsulting/MokoGitea/wiki/roadmap)
--- ---
**Category:** Infrastructure | **Platform:** [moko-platform wiki](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki) **Category:** Infrastructure | **Platform:** [moko-platform wiki](https://code.mokoconsulting.tech/MokoConsulting/moko-platform/wiki)
--- ---
@@ -28,7 +28,7 @@ Custom Gitea fork with Project Board API
## Documentation ## Documentation
Full documentation is available on the [Wiki](https://git.mokoconsulting.tech/MokoConsulting/MokoGitea/wiki). Full documentation is available on the [Wiki](https://code.mokoconsulting.tech/MokoConsulting/MokoGitea/wiki).
## Contributing ## Contributing
@@ -40,4 +40,4 @@ This project is licensed under the GNU General Public License v3.0 or later -- s
--- ---
*[Moko Consulting](https://mokoconsulting.tech) -- [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/Home)* *[Moko Consulting](https://mokoconsulting.tech) -- [MokoStandards](https://code.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/Home)*
+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
+1 -1
View File
@@ -9,7 +9,7 @@ import (
"fmt" "fmt"
"os" "os"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/assetfs" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/assetfs"
) )
func main() { func main() {
+1 -1
View File
@@ -20,7 +20,7 @@ import (
"strings" "strings"
"unicode/utf8" "unicode/utf8"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/json" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/json"
) )
const ( const (
+1 -1
View File
@@ -15,7 +15,7 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util"
) )
func main() { func main() {
+1 -1
View File
@@ -30,7 +30,7 @@ var primaryLicenseRe = regexp.MustCompile(`^(?i)(LICEN[SC]E|COPYING)$`)
// ignoredNames are LicenseEntry.Name values to exclude from the output. // ignoredNames are LicenseEntry.Name values to exclude from the output.
var ignoredNames = map[string]bool{ var ignoredNames = map[string]bool{
"code.gitea.io/gitea": true, "code.gitea.io/gitea": true,
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/options/license": true, "code.mokoconsulting.tech/MokoConsulting/MokoGitea/options/license": true,
} }
var excludedExt = map[string]bool{ var excludedExt = map[string]bool{
+1 -1
View File
@@ -25,7 +25,7 @@ import (
"sort" "sort"
"strings" "strings"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/build/openapi3gen" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/build/openapi3gen"
"github.com/getkin/kin-openapi/openapi3" "github.com/getkin/kin-openapi/openapi3"
) )
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"regexp" "regexp"
"strings" "strings"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/json" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/json"
"github.com/getkin/kin-openapi/openapi2" "github.com/getkin/kin-openapi/openapi2"
"github.com/getkin/kin-openapi/openapi2conv" "github.com/getkin/kin-openapi/openapi2conv"
+2 -2
View File
@@ -7,8 +7,8 @@ import (
"context" "context"
"fmt" "fmt"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/private" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/private"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+6 -6
View File
@@ -8,12 +8,12 @@ import (
"context" "context"
"fmt" "fmt"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
repo_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo" repo_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/git" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/git"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/gitrepo" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/gitrepo"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log"
repo_module "git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/repository" repo_module "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/repository"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+3 -3
View File
@@ -10,9 +10,9 @@ import (
"os" "os"
"text/tabwriter" "text/tabwriter"
auth_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/auth" auth_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/auth"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
auth_service "git.mokoconsulting.tech/MokoConsulting/MokoGitea/services/auth" auth_service "code.mokoconsulting.tech/MokoConsulting/MokoGitea/services/auth"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+3 -3
View File
@@ -8,9 +8,9 @@ import (
"fmt" "fmt"
"strings" "strings"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/auth" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/auth"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/services/auth/source/ldap" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/services/auth/source/ldap"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+3 -3
View File
@@ -7,9 +7,9 @@ import (
"context" "context"
"testing" "testing"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/auth" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/auth"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/test" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/test"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/services/auth/source/ldap" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/services/auth/source/ldap"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
+3 -3
View File
@@ -9,9 +9,9 @@ import (
"fmt" "fmt"
"net/url" "net/url"
auth_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/auth" auth_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/auth"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/services/auth/source/oauth2" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/services/auth/source/oauth2"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+2 -2
View File
@@ -7,8 +7,8 @@ import (
"context" "context"
"testing" "testing"
auth_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/auth" auth_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/auth"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/services/auth/source/oauth2" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/services/auth/source/oauth2"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
+3 -3
View File
@@ -8,9 +8,9 @@ import (
"errors" "errors"
"strings" "strings"
auth_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/auth" auth_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/auth"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/services/auth/source/smtp" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/services/auth/source/smtp"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+2 -2
View File
@@ -7,8 +7,8 @@ import (
"context" "context"
"testing" "testing"
auth_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/auth" auth_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/auth"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/services/auth/source/smtp" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/services/auth/source/smtp"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
+3 -3
View File
@@ -6,9 +6,9 @@ package cmd
import ( import (
"context" "context"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/graceful" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/graceful"
asymkey_service "git.mokoconsulting.tech/MokoConsulting/MokoGitea/services/asymkey" asymkey_service "code.mokoconsulting.tech/MokoConsulting/MokoGitea/services/asymkey"
repo_service "git.mokoconsulting.tech/MokoConsulting/MokoGitea/services/repository" repo_service "code.mokoconsulting.tech/MokoConsulting/MokoGitea/services/repository"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+5 -5
View File
@@ -8,11 +8,11 @@ import (
"errors" "errors"
"fmt" "fmt"
user_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user" user_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/auth/password" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/auth/password"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/optional" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/optional"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
user_service "git.mokoconsulting.tech/MokoConsulting/MokoGitea/services/user" user_service "code.mokoconsulting.tech/MokoConsulting/MokoGitea/services/user"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+3 -3
View File
@@ -7,9 +7,9 @@ import (
"io" "io"
"testing" "testing"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/unittest" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/unittest"
user_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user" user_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
+6 -6
View File
@@ -9,12 +9,12 @@ import (
"fmt" "fmt"
"strings" "strings"
auth_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/auth" auth_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/auth"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
user_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user" user_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user"
pwd "git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/auth/password" pwd "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/auth/password"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/optional" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/optional"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+4 -4
View File
@@ -8,10 +8,10 @@ import (
"strings" "strings"
"testing" "testing"
auth_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/auth" auth_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/auth"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/unittest" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/unittest"
user_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user" user_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
+4 -4
View File
@@ -9,10 +9,10 @@ import (
"fmt" "fmt"
"strings" "strings"
user_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user" user_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/storage" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/storage"
user_service "git.mokoconsulting.tech/MokoConsulting/MokoGitea/services/user" user_service "code.mokoconsulting.tech/MokoConsulting/MokoGitea/services/user"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+4 -4
View File
@@ -8,10 +8,10 @@ import (
"strings" "strings"
"testing" "testing"
auth_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/auth" auth_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/auth"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/unittest" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/unittest"
user_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user" user_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
+2 -2
View File
@@ -8,8 +8,8 @@ import (
"errors" "errors"
"fmt" "fmt"
auth_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/auth" auth_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/auth"
user_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user" user_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+1 -1
View File
@@ -9,7 +9,7 @@ import (
"os" "os"
"text/tabwriter" "text/tabwriter"
user_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user" user_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+2 -2
View File
@@ -8,8 +8,8 @@ import (
"errors" "errors"
"fmt" "fmt"
user_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user" user_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+3 -3
View File
@@ -6,9 +6,9 @@ package cmd
import ( import (
"testing" "testing"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/unittest" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/unittest"
user_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user" user_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
+5 -5
View File
@@ -15,11 +15,11 @@ import (
"strings" "strings"
"testing" "testing"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/cmd" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/cmd"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/unittest" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/unittest"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/test" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/test"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
+1 -1
View File
@@ -9,7 +9,7 @@ import (
"fmt" "fmt"
"os" "os"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+7 -7
View File
@@ -12,13 +12,13 @@ import (
"strings" "strings"
"text/tabwriter" "text/tabwriter"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/migrations" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/migrations"
migrate_base "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/migrations/base" migrate_base "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/migrations/base"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/container" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/container"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/services/doctor" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/services/doctor"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
"xorm.io/xorm" "xorm.io/xorm"
+3 -3
View File
@@ -7,9 +7,9 @@ import (
"context" "context"
"fmt" "fmt"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+2 -2
View File
@@ -7,8 +7,8 @@ import (
"context" "context"
"testing" "testing"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/services/doctor" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/services/doctor"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
+7 -7
View File
@@ -11,13 +11,13 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/dump" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/dump"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/json" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/json"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/storage" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/storage"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util"
"gitea.com/go-chi/session" "gitea.com/go-chi/session"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
+8 -8
View File
@@ -10,14 +10,14 @@ import (
"os" "os"
"strings" "strings"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/git" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/git"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log"
base "git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/migration" base "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/migration"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/structs" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/structs"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/services/convert" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/services/convert"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/services/migrations" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/services/migrations"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+8 -8
View File
@@ -11,14 +11,14 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/assetfs" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/assetfs"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/glob" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/glob"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/options" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/options"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/public" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/public"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/templates" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/templates"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+1 -1
View File
@@ -9,7 +9,7 @@ import (
"fmt" "fmt"
"os" "os"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/generate" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/generate"
"github.com/mattn/go-isatty" "github.com/mattn/go-isatty"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
+3 -3
View File
@@ -15,9 +15,9 @@ import (
"strings" "strings"
"syscall" "syscall"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+6 -6
View File
@@ -14,12 +14,12 @@ import (
"strings" "strings"
"time" "time"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/git" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/git"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/git/gitcmd" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/git/gitcmd"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/private" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/private"
repo_module "git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/repository" repo_module "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/repository"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+2 -2
View File
@@ -9,8 +9,8 @@ import (
"fmt" "fmt"
"strings" "strings"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/private" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/private"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+2 -2
View File
@@ -7,8 +7,8 @@ import (
"context" "context"
"fmt" "fmt"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/private" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/private"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+2 -2
View File
@@ -10,8 +10,8 @@ import (
"os" "os"
"strings" "strings"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"context" "context"
"testing" "testing"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/unittest" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/unittest"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"os" "os"
"time" "time"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/private" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/private"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+2 -2
View File
@@ -9,8 +9,8 @@ import (
"fmt" "fmt"
"os" "os"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/private" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/private"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+4 -4
View File
@@ -6,10 +6,10 @@ package cmd
import ( import (
"context" "context"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/services/versioned_migration" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/services/versioned_migration"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+11 -11
View File
@@ -10,17 +10,17 @@ import (
"io/fs" "io/fs"
"strings" "strings"
actions_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/actions" actions_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/actions"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
git_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/git" git_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/git"
packages_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/packages" packages_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/packages"
repo_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo" repo_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo"
user_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user" user_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log"
packages_module "git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/packages" packages_module "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/packages"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/storage" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/storage"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/services/versioned_migration" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/services/versioned_migration"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+7 -7
View File
@@ -8,13 +8,13 @@ import (
"strings" "strings"
"testing" "testing"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/packages" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/packages"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/unittest" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/unittest"
user_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user" user_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user"
packages_module "git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/packages" packages_module "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/packages"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/storage" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/storage"
packages_service "git.mokoconsulting.tech/MokoConsulting/MokoGitea/services/packages" packages_service "code.mokoconsulting.tech/MokoConsulting/MokoGitea/services/packages"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
+2 -2
View File
@@ -7,8 +7,8 @@ import (
"context" "context"
"strings" "strings"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/private" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/private"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+15 -15
View File
@@ -15,21 +15,21 @@ import (
"strings" "strings"
"unicode" "unicode"
asymkey_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/asymkey" asymkey_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/asymkey"
git_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/git" git_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/git"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/perm" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/perm"
repo_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo" repo_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/git" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/git"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/git/gitcmd" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/git/gitcmd"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/json" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/json"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/lfstransfer" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/lfstransfer"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/pprof" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/pprof"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/private" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/private"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/process" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/process"
repo_module "git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/repository" repo_module "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/repository"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/services/lfs" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/services/lfs"
"github.com/kballard/go-shellquote" "github.com/kballard/go-shellquote"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
+11 -11
View File
@@ -15,17 +15,17 @@ import (
"strings" "strings"
"time" "time"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/container" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/container"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/graceful" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/graceful"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/gtprof" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/gtprof"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/process" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/process"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/public" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/public"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/templates" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/templates"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/routers" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/routers"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/routers/install" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/routers/install"
"github.com/felixge/fgprof" "github.com/felixge/fgprof"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
+5 -5
View File
@@ -13,11 +13,11 @@ import (
"strconv" "strconv"
"strings" "strings"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/graceful" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/graceful"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/process" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/process"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util"
"github.com/caddyserver/certmagic" "github.com/caddyserver/certmagic"
) )
+3 -3
View File
@@ -9,9 +9,9 @@ import (
"net/http/fcgi" "net/http/fcgi"
"strings" "strings"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/graceful" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/graceful"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
) )
func runHTTP(network, listenAddr, name string, m http.Handler, useProxyProtocol bool) error { func runHTTP(network, listenAddr, name string, m http.Handler, useProxyProtocol bool) error {
+3 -3
View File
@@ -9,9 +9,9 @@ import (
"os" "os"
"strings" "strings"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/graceful" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/graceful"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
"github.com/klauspost/cpuid/v2" "github.com/klauspost/cpuid/v2"
) )
+1 -1
View File
@@ -1,4 +1,4 @@
module git.mokoconsulting.tech/MokoConsulting/MokoGitea module code.mokoconsulting.tech/MokoConsulting/MokoGitea
go 1.26.3 go 1.26.3
+8 -8
View File
@@ -10,16 +10,16 @@ import (
"strings" "strings"
"time" "time"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/cmd" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/cmd"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
// register supported doc types // register supported doc types
_ "git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/markup/asciicast" _ "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/markup/asciicast"
_ "git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/markup/console" _ "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/markup/console"
_ "git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/markup/csv" _ "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/markup/csv"
_ "git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/markup/markdown" _ "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/markup/markdown"
_ "git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/markup/orgmode" _ "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/markup/orgmode"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
+4 -4
View File
@@ -11,10 +11,10 @@ import (
"errors" "errors"
"time" "time"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/optional" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/optional"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/timeutil" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/timeutil"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util"
"xorm.io/builder" "xorm.io/builder"
) )
+5 -5
View File
@@ -6,11 +6,11 @@ package actions
import ( import (
"context" "context"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/perm" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/perm"
repo_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo" repo_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo"
user_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user" user_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/json" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/json"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util"
"xorm.io/xorm/convert" "xorm.io/xorm/convert"
) )
+1 -1
View File
@@ -6,7 +6,7 @@ package actions
import ( import (
"testing" "testing"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/unittest" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/unittest"
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
+11 -11
View File
@@ -11,17 +11,17 @@ import (
"strings" "strings"
"time" "time"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
repo_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo" repo_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo"
user_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user" user_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/git" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/git"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/json" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/json"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
api "git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/structs" api "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/structs"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/timeutil" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/timeutil"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util"
webhook_module "git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/webhook" webhook_module "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/webhook"
"xorm.io/builder" "xorm.io/builder"
) )
+5 -5
View File
@@ -9,11 +9,11 @@ import (
"slices" "slices"
"time" "time"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
user_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user" user_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/timeutil" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/timeutil"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util"
) )
// ActionRunAttempt represents a single execution attempt of an ActionRun. // ActionRunAttempt represents a single execution attempt of an ActionRun.
+3 -3
View File
@@ -6,9 +6,9 @@ package actions
import ( import (
"context" "context"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
user_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user" user_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/container" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/container"
) )
type ActionRunAttemptList []*ActionRunAttempt type ActionRunAttemptList []*ActionRunAttempt
+5 -6
View File
@@ -9,18 +9,17 @@ import (
"slices" "slices"
"time" "time"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
repo_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo" repo_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/actions/jobparser" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/actions/jobparser"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/timeutil" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/timeutil"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util"
"xorm.io/builder" "xorm.io/builder"
) )
// MaxJobNumPerRun is the maximum number of jobs in a single run. // MaxJobNumPerRun is the maximum number of jobs in a single run.
// https://docs.github.com/en/actions/reference/limits#existing-system-limits // https://docs.github.com/en/actions/reference/limits#existing-system-limits
// TODO: check this limit when creating jobs
const MaxJobNumPerRun = 256 const MaxJobNumPerRun = 256
// ActionRunJob represents a job of a run // ActionRunJob represents a job of a run
+5 -5
View File
@@ -6,11 +6,11 @@ package actions
import ( import (
"context" "context"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
repo_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo" repo_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/container" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/container"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/optional" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/optional"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/timeutil" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/timeutil"
"xorm.io/builder" "xorm.io/builder"
) )
+6 -6
View File
@@ -6,12 +6,12 @@ package actions
import ( import (
"context" "context"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
repo_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo" repo_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo"
user_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user" user_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/container" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/container"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/translation" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/translation"
webhook_module "git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/webhook" webhook_module "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/webhook"
"xorm.io/builder" "xorm.io/builder"
) )
+4 -4
View File
@@ -7,10 +7,10 @@ import (
"testing" "testing"
"time" "time"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
repo_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo" repo_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/unittest" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/unittest"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/timeutil" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/timeutil"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
+10 -10
View File
@@ -10,16 +10,16 @@ import (
"strings" "strings"
"time" "time"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
repo_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo" repo_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/shared/types" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/shared/types"
user_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user" user_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/container" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/container"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/optional" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/optional"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/timeutil" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/timeutil"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/translation" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/translation"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util"
runnerv1 "code.gitea.io/actions-proto-go/runner/v1" runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
"xorm.io/builder" "xorm.io/builder"
+4 -4
View File
@@ -6,10 +6,10 @@ package actions
import ( import (
"context" "context"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
repo_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo" repo_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo"
user_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user" user_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/container" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/container"
) )
type RunnerList []*ActionRunner type RunnerList []*ActionRunner
+5 -5
View File
@@ -7,11 +7,11 @@ import (
"context" "context"
"fmt" "fmt"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
repo_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo" repo_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo"
user_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user" user_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/timeutil" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/timeutil"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util"
) )
// ActionRunnerToken represents runner tokens // ActionRunnerToken represents runner tokens
+1 -1
View File
@@ -6,7 +6,7 @@ package actions
import ( import (
"testing" "testing"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/unittest" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/unittest"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
+6 -6
View File
@@ -8,12 +8,12 @@ import (
"fmt" "fmt"
"time" "time"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
repo_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo" repo_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo"
user_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user" user_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/timeutil" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/timeutil"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util"
webhook_module "git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/webhook" webhook_module "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/webhook"
) )
// ActionSchedule represents a schedule of a workflow file // ActionSchedule represents a schedule of a workflow file
+1 -1
View File
@@ -4,7 +4,7 @@
package actions package actions
import ( import (
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
"xorm.io/builder" "xorm.io/builder"
) )
+3 -3
View File
@@ -8,9 +8,9 @@ import (
"strings" "strings"
"time" "time"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
repo_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo" repo_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/timeutil" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/timeutil"
"github.com/robfig/cron/v3" "github.com/robfig/cron/v3"
) )
+3 -3
View File
@@ -6,9 +6,9 @@ package actions
import ( import (
"context" "context"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
repo_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo" repo_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/container" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/container"
"xorm.io/builder" "xorm.io/builder"
) )
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"testing" "testing"
"time" "time"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/test" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/test"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
+1 -1
View File
@@ -6,7 +6,7 @@ package actions
import ( import (
"slices" "slices"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/translation" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/translation"
runnerv1 "code.gitea.io/actions-proto-go/runner/v1" runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
) )
+8 -8
View File
@@ -11,14 +11,14 @@ import (
"strings" "strings"
"time" "time"
auth_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/auth" auth_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/auth"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/unit" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/unit"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/actions/jobparser" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/actions/jobparser"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/timeutil" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/timeutil"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util"
runnerv1 "code.gitea.io/actions-proto-go/runner/v1" runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
lru "github.com/hashicorp/golang-lru/v2" lru "github.com/hashicorp/golang-lru/v2"
+3 -3
View File
@@ -6,9 +6,9 @@ package actions
import ( import (
"context" "context"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/container" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/container"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/timeutil" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/timeutil"
"xorm.io/builder" "xorm.io/builder"
) )
+1 -1
View File
@@ -6,7 +6,7 @@ package actions
import ( import (
"context" "context"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
) )
// ActionTaskOutput represents an output of ActionTask. // ActionTaskOutput represents an output of ActionTask.

Some files were not shown because too many files have changed in this diff Show More