- Shell 100%
| references | ||
| scripts | ||
| templates | ||
| action.yml | ||
| README.md | ||
actions-magento-package
Composite action to validate and publish Magento 2 Composer modules (magento2-module)
to the Forgejo Package Registry.
Consolidates learnings from Cocobolo (mature inline pipelines) and Kalicr
(kalicr-core legacy, kalicr-zunify first adopter) into one reusable action for
both orgs (registry_org: kalicr | cocobolo).
Why this exists
Before: each package repo duplicated ~300 lines of package.yml (six parallel
validate jobs + release-readiness + release). After: consumers keep ~100 lines of
YAML with package metadata only; all logic lives here.
Same operational model as actions-magento-deploy: pin by commit SHA, never float on a branch.
Job graph
┌─────────────┐
PR/push develop │ validate │ php/xml/contract/strict/security/archive
feature/* └──────┬──────┘
│
PR → production ▼
┌──────────────────┐
│ release-readiness │ semver bump, no duplicate tags
└────────┬─────────┘
│
push production ▼
┌─────────────┐
│ release │ tag + Forgejo release + registry ZIP
└─────────────┘
release needs [validate, release-readiness] — a failing validate cannot publish.
Modes
INPUT_MODE |
When |
|---|---|
validate |
Every non-tag push and PR |
release-readiness |
PR to production, or production push/dispatch |
release |
production push or workflow_dispatch |
Validate gates
Single job, same coverage as Cocobolo's six parallel jobs:
php -lon all.php- XML validation (
xmllintor PHP SimpleXML fallback) composer validate --no-check-lock --no-check-publish- Module contract: name, type, PSR-4,
registration.php,module.xml composer.jsonversion↔module.xmlsetup_versiondeclare(strict_types=1)on every PHP file- Dangerous functions scan with
\bexec\((nocurl_execfalse positives) - Required files:
README.md,CHANGELOG.md,registration.php,composer.json,etc/module.xml - Blocks committed
.env,auth.json,credentials.json - Archive smoke test (ZIP build +
unzip -t)
Release behavior
On push to production:
- Create tag
v{version}via Forgejo API - Create Forgejo release
- Build ZIP (excludes
.git,.forgejo,.actions) - Publish to
https://git.kalicr.com/api/packages/{registry_org}/composer
Version from composer.json, or workflow_dispatch input override.
| Event | Tag/release | Registry 409 |
|---|---|---|
push → production |
Created; 409 = fail | 409 = fail |
workflow_dispatch |
Skipped | 409 = warning (idempotent retry) |
Consumer workflow (Forgejo)
kalicr/actions-magento-package must stay public. Forgejo cannot reliably consume
private reusable action repos across repositories; private action repos fail during checkout
with remote: User permission denied / HTTP 403.
Working pattern (proven on kalicr-zunify):
- Checkout package repo
- Checkout
kalicr/actions-magento-package→.actions/magento-package(ref: PACKAGE_ACTION_REF) - Run
bash "${FORGEJO_ACTION_PATH}/scripts/run-package.sh"with explicit per-stepINPUT_*env vars
Keep FORGEJO_ACTION_PATH and package metadata on the execution step itself. This Forgejo/act
runner does not reliably expose workflow-level env values to run commands; relying on global
env can produce bash: /scripts/run-package.sh: No such file or directory.
Copy templates/package.workflow.yml and replace PACKAGE_*
placeholders. See references/MIGRATION.md for full migration steps.
Inputs
Metadata (all modes)
| Input | Example |
|---|---|
INPUT_PACKAGE_NAME |
kalicr/zunify |
INPUT_MAGENTO_MODULE |
Kalicr_Zunify |
INPUT_PSR4_NAMESPACE |
Kalicr\Zunify\ |
INPUT_REGISTRY_ORG |
kalicr or cocobolo |
INPUT_ARCHIVE_BASENAME |
kalicr-zunify |
INPUT_FORGEJO_OWNER |
kalicr |
INPUT_FORGEJO_REPO |
kalicr-zunify |
Release only
| Input | Source |
|---|---|
INPUT_PACKAGE_USERNAME |
secret FORGEJO_PACKAGE_USERNAME |
INPUT_PACKAGE_TOKEN |
secret FORGEJO_PACKAGE_TOKEN |
INPUT_GITHUB_SHA |
${{ github.sha }} |
INPUT_GITHUB_REF_NAME |
${{ github.ref_name }} |
INPUT_GITHUB_EVENT_NAME |
${{ github.event_name }} |
INPUT_WORKFLOW_VERSION |
optional workflow_dispatch input |
Structure
action.yml
scripts/
run-package.sh # mode dispatcher
validate.sh
release-readiness.sh
release.sh
lib.sh
templates/
package.workflow.yml
references/
MIGRATION.md
Bootstrap (first-time org setup)
Forgejo org repos cannot be created via git push --set-upstream. Create empty repo in UI:
- https://git.kalicr.com/org/kalicr/repos/new →
actions-magento-package, default branchproduction - Push local
productionbranch - Pin
PACKAGE_ACTION_REFin each consumer to the resulting commit SHA
Operational rules
- Keep this action repository public so Forgejo consumers can checkout it across repos
- Pin action by commit SHA in
PACKAGE_ACTION_REF, not branch name - Keep critical
FORGEJO_ACTION_PATH/INPUT_*values on each execution step, not only workflow-levelenv - Bump
composer.json+module.xmlbefore PRdevelop→production - Publish secrets live at org level (
FORGEJO_PACKAGE_*); consumerauth.jsontokens are for install only - Do not cut release tags manually except disaster recovery
Release flow (summary)
feature/* → PR develop → PR production → push production
→ validate + release-readiness + release
→ tag v{X.Y.Z} + Forgejo Packages
Install in Magento projects:
composer require kalicr/zunify:1.0.2
# or
composer require cocobolo/module-visual-search:0.2.0
Consumers (migration status)
| Package | Org | Status |
|---|---|---|
kalicr-zunify |
kalicr | Adopted (reference) |
cocobolo-visual-search |
cocobolo | Inline → migrate |
cocobolo-visual-search-ui |
cocobolo | Inline → migrate |
cocobolo-core |
cocobolo | Inline → migrate (+ release-readiness) |
kalicr-core |
kalicr | Legacy tag publish → migrate |