Repository navigation
Epic: build reusable release automation with LibreSign as first consumer #70
Description
Goal
Deliver a production-grade, reusable release automation system using LibreSign as the first consumer.
The normal maintainer journey must require human action only at two review gates:
- review and merge the generated release preparation PR;
- review and publish the generated GitHub Release draft.
Everything else must be deterministic, testable and reproducible.
LibreSign/libresign#8447 is a disposable proof of concept. It is not a merge target and is not a production dependency. It may be consulted only to extract behavior, tests and lessons.
Prototype status
LibreSign/libresign#8447 and github-workflows#77 are prototype/reference work only.
They may be used to extract useful behavior, fixtures and lessons, but:
- neither is a production source of truth;
- neither is a merge prerequisite for the final implementation;
- conflicting prototype behavior is superseded by this epic and its child contracts;
- release-specific Python prototype behavior is retired only when the corresponding PHP implementation reaches tested parity.
Repository boundaries
LibreCodeCoop/release-tool
Owns the reusable PHP release engine:
- CLI / PHAR;
- domain policies and contracts;
- Git/GitHub/filesystem/process adapters;
- consumer configuration schema;
- release-engine tests and PHAR distribution.
LibreCodeCoop/github-workflows
Owns reusable GitHub orchestration around the PHAR:
- composite actions/reusable workflows;
- workflow catalog/distribution;
- authentication/permission wiring;
- orchestration tests;
- no duplicated release business logic.
LibreSign/libresign
Owns consumer-specific integration only:
- release configuration;
- stable-branch/version mapping;
- release-file mapping;
- per-major changelog source files;
- Makefile/package behavior;
- thin workflow/catalog integration.
LibreSign/documentation
Owns the public human documentation for:
- automated release journey;
- equivalent manual procedure;
- recovery/troubleshooting;
- release-tool and consumer configuration guidance.
It does not own a copy of the changelog or release-history dataset. Canonical release history remains in LibreSign/libresign/docs/changelogs/changelog-<major>.md.
Maintainer journey
Actions → Prepare release
↓
read-only ReleasePlan
↓
generated reviewable release PR(s)
↓
maintainer review + authorized merge
↓
post-merge revalidation
↓
milestone transition
↓
GitHub Release draft
↓
maintainer review
↓
Publish release
↓
existing build/sign/App Store publisher
↓
verification
A workstation is not required for the normal path.
The same engine is available through a local CLI for dry-run, diagnostics, manual execution and recovery.
Prepare release inputs
The maintainer-facing workflow exposes:
- branch — required;
- commit/ref override — optional planning base; default is selected branch HEAD. It is not the final release SHA when release metadata still needs to be committed;
- version override — optional; default is automatic calculation;
- release channel — alpha / beta / rc / final;
- ignore open backport — explicit boolean override;
- create follow-up milestone — explicit boolean/choice where applicable.
Any supplied ref must resolve to an immutable SHA that is an ancestor of/equal to the selected branch HEAD. Release preparation may create a new commit on top of that base; the final GitHub Release is pinned to the merged release-preparation commit, not blindly to the input ref.
Version policy
For an existing release line:
- at least one included merged PR whose PR title is Conventional Commit
feat→ next minor; - otherwise any releasable activity → next patch.
Releasable patch activity includes fixes, translations, dependency updates, documentation, tests, refactors, CI and maintenance.
Internal commits inside a PR never promote the release type.
Direct commits not represented by PRs may count as releasable activity, especially translation synchronization, but do not promote to minor.
A deliberately backported feature still promotes that stable line to the next minor.
Major releases are part of opening a new LibreSign/Nextcloud release line and are not inferred from Conventional Commits.
Prerelease behavior is defined in #80.
Backport blocker
A backport request/comment without an actual PR does not block.
Only an actual open backport PR for the selected stable line blocks by default.
The maintainer can explicitly override this blocker.
Detection must use selected base branch plus backport metadata/patterns; a repository-wide backport-request label query is insufficient.
Project metadata semantics
Keep release/planning dimensions separate:
- GitHub Project Status represents workflow/planning state;
- Milestone represents the target release train/version;
- merged PR Conventional Commit title is the SemVer classification source;
- labels provide auxiliary context such as bug/enhancement, feature area, platform, dependencies, security and backport metadata.
Do not use Project Status or contextual labels as the primary SemVer source.
Changelog policy
LibreSign uses one changelog source file per app major under:
docs/changelogs/changelog-<major>.md
The files follow Keep a Changelog semantics and are maintained in English only. There is no per-language changelog workflow.
The selected stable branch is authoritative for the release being prepared. main keeps the aggregate release-history archive for all supported majors and receives the exact released changelog entry after stable preparation.
Release activity is collected once and used independently by:
- version policy;
- changelog policy.
Rules:
- PR titles are the primary Conventional Commit source;
- translation activity may come from direct commits;
- dependency-bot PRs are collapsed into one dependency entry;
- already-published changes are not duplicated;
- labels/context may help categorization but cannot override SemVer.
Detailed changelog strategy is #79. LibreSign integration/package behavior is #81.
Release files
For a selected LibreSign stable release, the production release PR changes only:
docs/changelogs/changelog-<major>.md;appinfo/info.xml;package.json;package-lock.json.
If synchronization of the aggregate release-history archive on main requires a separate PR, that PR changes only the corresponding per-major changelog file and reuses the already-reviewed stable release entry.
No release of an older stable may change main's app/package version to the older version.
Milestones
Normal stable releases use the stable-specific release milestone.
The automation can:
- identify the current milestone;
- rename it to the release version;
- create a follow-up milestone when requested;
- move remaining open items;
- close the released milestone.
EOL/lifecycle data may be shown as context, but support status is not inferred automatically because LibreSign may intentionally support lines beyond community lifecycle.
Prerelease milestone behavior is compatible with #80.
Draft and publication
After an authorized merge:
- revalidate the final merged state;
- apply/finalize milestone transition;
- create/update one GitHub Release draft pinned to the validated SHA;
- include curated release notes, closed milestone link and full compare link.
The maintainer explicitly clicks Publish release.
The existing publication workflow remains responsible for packaging, signing, uploading the asset and publishing to the Nextcloud App Store.
A pre-publication correction stays on the same planned version unless the maintainer intentionally starts a different release.
Multi-stable releases
Each stable release is manually initiated.
When several stables are released in one maintenance cycle:
- prepare as needed;
- publish oldest stable first;
- verify successful publication/App Store visibility;
- publish the next stable.
Do not automatically select all maintained stable branches in the first production version.
Architecture
The reusable architecture is defined in #78.
Rules:
- workflow YAML orchestrates; it does not own release policy;
- the production engine is the PHP CLI/PHAR defined by Bootstrap the production-grade PHP CLI, PHAR and quality platform #82;
- domain logic has no GitHub Actions dependency;
- the same PHP engine powers GitHub Actions and local CLI;
- consumer-specific paths and conventions are configuration/adapters;
- do not create a monolithic
ReleaseManager; - do not implement production release logic in refactor(release): automate release preparation and drafts LibreSign/libresign#8447.
Implementation order / dependencies
The following order is normative for autonomous implementation. Each step must leave a stable artifact/contract used by the next step.
Phase 1 — architecture and executable foundation
- Define the reusable release engine architecture and stage contracts #78 — architecture, repository boundaries and stage contracts.
- Bootstrap the production-grade PHP CLI, PHAR and quality platform #82 — bootstrap
LibreCodeCoop/release-tool, PHP CLI/PHAR, QA platform and release of the tool itself. - Define business-driven test architecture and conventions for release-tool #90 — business-driven test architecture, directory conventions, data providers and acceptance-test strategy.
- Provide a reusable action for pinned release-tool PHAR execution #87 — reusable Action that installs/verifies a pinned PHAR for GitHub workflows.
- Define and validate the consumer configuration contract for the release tool #83 — versioned
.nextcloud-release.ymlschema, parser and typed consumer configuration.
Artifacts available after Phase 1:
release-tool.phar
setup-release-tool reusable Action
test/fixture conventions
ConsumerConfig schema v1
Phase 2 — reusable domain policies
- Define security-release-safe domain and serialization contracts #84 — security-release-safe domain/serialization contract.
- Support alpha, beta, RC and final release channels #80 — Version / ReleaseChannel / prerelease state model.
- Support per-major Keep a Changelog storage as a reusable changelog strategy #79 — ChangelogPolicy / per-major renderer and migration support.
These extend the same PHP foundation and test conventions. They may proceed in parallel only after their declared dependencies are complete.
Phase 3 — planning and preparation
- Plan and validate a selected release with the reusable engine #71 — planner/discovery; produces immutable
ReleasePlan v1. - Prepare deterministic reviewable release PRs from a ReleasePlan #72 — preparation; consumes
ReleasePlan v1and producesReleasePreparation v1.
Phase 4 — first real consumer integration and post-merge finalization
- Integrate the reusable release tooling and per-major changelog packaging in LibreSign #81 — add the LibreSign consumer config, per-major changelog layout and package/Makefile integration.
- Finalize the merged stable release and synchronize aggregate changelog history #73 — after the generated stable PR is merged, revalidate it and produce
PreparedRelease v1; synchronize the exact released changelog entry to the aggregate history onmain. - Plan and apply reusable release milestone transitions #74 — consume
PreparedRelease v1, apply milestone transition and produceMilestoneTransition v1.
Phase 5 — draft, publication and verification
- Prepare the GitHub Release draft from finalized release artifacts #75 — consume finalized artifacts and create
ReleaseDraft v1; stop at the human Publish gate. - Validate built release artifacts with the PHP release tool #89 — reusable PHP validation of built release archives; produces
ArtifactValidation v1. - Verify the published release, artifact and App Store handoff #88 — after the human publishes, consume the released identity + artifact validation and produce
PublicationVerification v1.
Phase 6 — end-to-end orchestration
- Provide the maintainer-facing Prepare Release workflow and end-to-end orchestration #76 — compose the already-proven stages into the maintainer-facing Prepare Release workflow. This issue must not invent new release policy.
Phase 7 — release documentation and single-source history
- Keep LibreSign release history canonical in the app repository #86 — enforce LibreSign/libresign as the single canonical changelog/release-history source and ensure no documentation synchronization duplicates that content.
- Document the complete LibreSign release lifecycle and manual path LibreSign/documentation#97 — document automated/manual process, recovery, security mode, configuration and the canonical changelog location using the implemented contracts.
Phase 8 — production scenario validation
- Validate source CLI + PHAR + GitHub Actions parity.
- Validate a normal final release.
- Validate a prerelease sequence.
- Validate a translation-only/maintenance-only release.
- Validate an open-backport blocker and explicit override.
- Validate a security-mode release without sensitive-data leakage.
- Validate failure/recovery paths, including stale state and failed publication.
- Only after these scenarios are proven should the reusable system be generalized to additional consumer apps.
Artifact chain
The implementation should evolve by consuming the output of the previous stage rather than rediscovering state:
ConsumerConfig v1
+
domain policies
↓
ReleasePlan v1
↓
ReleasePreparation v1
↓
human merge
↓
PreparedRelease v1
↓
MilestoneTransition v1
↓
ReleaseDraft v1
↓
human Publish
↓
ArtifactValidation v1
+
publisher/App Store checks
↓
PublicationVerification v1
An issue must not recreate a value already finalized by an upstream artifact. It may revalidate that value against current external state.
Required cross-issue contract
Every implementation issue must:
- reference Epic: build reusable release automation with LibreSign as first consumer #70;
- state explicit dependencies;
- avoid duplicating policy owned by another issue;
- include unit/integration acceptance criteria;
- update documentation when user-visible/maintainer-visible behavior changes;
- avoid using chat history as an implementation source.
If two issues conflict, the later explicit architectural decision in #70/#78 takes precedence and the conflicting child issue must be corrected before implementation continues.
Issue closure rule
A child implementation issue is complete only when both are true:
- every listed Acceptance Criterion is demonstrably satisfied;
- every listed Definition of Done item is complete.
Closing evidence should be visible in the implementation PR/checks/artifacts, not only asserted in a comment.
For implementation issues, evidence normally includes as applicable:
- merged or ready-for-review production code in the correct repository;
- committed versioned schema/artifact contracts promised by the issue;
- required Unit/Integration/Acceptance tests following Define business-driven test architecture and conventions for release-tool #90;
- relevant CI/quality checks green;
- source CLI and PHAR parity where the issue exposes CLI behavior;
- no unresolved TODO/placeholders for behavior required by the issue;
- superseded prototype/Python behavior retired only after parity is proven;
- dependent issue can consume the produced artifact/contract without another architectural decision;
- user/maintainer-visible documentation updated in the proper documentation location when behavior changed.
An issue must not be closed merely because a prototype exists, a happy-path test passes, or coverage increased.
Source of truth
Production source of truth is:
- implemented/tested engine contracts in
LibreCodeCoop/release-tool; - reusable orchestration contracts in
LibreCodeCoop/github-workflows; - consumer configuration/integration in
LibreSign/libresign; - published process documentation in
LibreSign/documentation; changelog/release history remains canonical inLibreSign/libresign.
Chat history and LibreSign/libresign#8447 are not sources of truth.
Definition of done
A maintainer can:
- start a release from GitHub Actions without a local checkout;
- select branch and optional overrides;
- inspect a deterministic plan;
- receive a narrowly scoped, reviewable release PR;
- merge through an authorized maintainer path;
- receive a correct GitHub Release draft automatically;
- review and publish the draft;
- reuse the existing build/sign/App Store publisher;
- verify the published version;
- reproduce the planning/manual procedure locally through the CLI;
- follow the public LibreSign documentation without needing implementation-specific tribal knowledge.
Activity
[-]Automate the LibreSign release train with composable workflows[/-][+]Epic: automate the LibreSign release lifecycle[/+][-]Epic: automate the LibreSign release lifecycle[/-][+]Epic: build reusable release automation with LibreSign as first consumer[/+]vitormattos commentedon Sep 21, 2026
Epic completion evidence:
Prepare releaseworkflow with the two intended human gates only: merge the generated release PR, then publish the generated GitHub Release draft..nextcloud-release.yml, per-major canonical changelogs and the existing package/sign/App Store publisher.The normal release path no longer requires a maintainer workstation; local CLI remains available for equivalent planning, diagnostics and recovery.