- **ADR 0010** (accepted): the build configuration stays expressible as a Forgejo Actions workflow. A new build-definition key needs a workflow counterpart; host-side keys are exempt. - **RFC 0006** (proposed): one workflow for Forgejo and Werkator, and the steps towards it. Step 1 is implemented here. - **`werkator export:forgejo`**, wrapped by **`tools/werkator-to-forgejo`**: converts the committed `.werkator.yml` (never the `.git` layers or `~/.werkator.yml`) into `.forgejo/workflows/werkator-<build>.yml`, one per definition that triggers on its own, follow-ups as jobs with `needs`. Untranslatable constructs become comments and stderr lines; `--strict` refuses. - `AGENTS.md`: the ADR 0010 rule as a hard invariant; column-aligned Markdown tables. - v1.28.0 On Werkator's own `.werkator.yml` the converter names two constructs: `builds.deploy` has no committed trigger (the host adds it), and `werkdock.env` is sandbox environment. PR-doc: `docs/prs/2026-10-03-PR#92-forgejo-actions-compatible-config.md` 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: mhoennig <michael@hoennig.de> Reviewed-on: #92
176 lines
8.4 KiB
Markdown
176 lines
8.4 KiB
Markdown
> **WARNING:** This document describes only the change applied in this PR.
|
|
> It may already be outdated once the next PR is merged.
|
|
> Historic PR-documentation is not maintained along with new PRs — treat it as a snapshot, not as current documentation.
|
|
|
|
## The Problem
|
|
|
|
Werkator's `.werkator.yml` and the Forgejo Actions workflow format describe the same builds in two ways.
|
|
Every new build-definition key could widen that gap, and nothing in the repository said that it should not.
|
|
A project that builds on Forgejo and on Werkator has to keep two CI descriptions in step.
|
|
Nobody could tell how far apart the two formats are for a given repository.
|
|
|
|
## Non-Goals
|
|
|
|
- No full Forgejo Actions compatibility; `uses:`, expressions and matrices stay out.
|
|
- Werkator does not read workflows yet; that is step 5 of RFC 0006.
|
|
- The converter does not guess host policy: it reads the committed file only.
|
|
|
|
## The Scenarios
|
|
|
|
### Feature: `.werkator.yml` converts into Forgejo Actions workflows
|
|
|
|
#### Scenario#92.01: One workflow per definition that triggers on its own
|
|
|
|
So that a trigger, which belongs to a workflow in Forgejo, keeps its build.
|
|
|
|
- **Given** a `.werkator.yml` with a pushed `default` and a `deploy` without a trigger
|
|
- **When** it is converted
|
|
- **Then** each becomes a workflow with checkout, clean, build and the upload of its artifacts
|
|
- **And** each job carries its effective settings, `builds.default` applied
|
|
- **And** the `deploy` workflow has `workflow_dispatch` only, and that is named
|
|
|
|
##### Verified by
|
|
|
|
- [ForgejoWorkflowExporterUnitTest](../../src/test/kotlin/de/hoennig/werkator/forgejo/ForgejoWorkflowExporterUnitTest.kt) — Scenario#92.01
|
|
|
|
#### Scenario#92.02: A branch selector becomes a branches filter
|
|
|
|
So that the same branches build on both systems.
|
|
|
|
- **Given** `trigger.branches` with `*`, an exclusion and a `?`
|
|
- **When** it is converted
|
|
- **Then** `*` becomes `**`, exclusions go last, a filter of exclusions alone starts with `**`, and `?` is escaped and named
|
|
|
|
##### Verified by
|
|
|
|
- [ForgejoWorkflowExporterUnitTest](../../src/test/kotlin/de/hoennig/werkator/forgejo/ForgejoWorkflowExporterUnitTest.kt) — Scenario#92.02
|
|
|
|
#### Scenario#92.03: atTimes becomes a schedule
|
|
|
|
So that a nightly build stays nightly.
|
|
|
|
- **Given** `atTimes` with a daily and an hourly time
|
|
- **When** it is converted
|
|
- **Then** each becomes a cron line
|
|
- **And** a schedule over more than one branch is named, because Forgejo schedules only the default branch
|
|
|
|
##### Verified by
|
|
|
|
- [ForgejoWorkflowExporterUnitTest](../../src/test/kotlin/de/hoennig/werkator/forgejo/ForgejoWorkflowExporterUnitTest.kt) — Scenario#92.03
|
|
|
|
#### Scenario#92.04: A follow-up becomes a job with needs
|
|
|
|
So that a deployment still runs only after a green build.
|
|
|
|
- **Given** a chain of follow-ups, one with literal branches, one with a glob, and one whose predecessor is missing
|
|
- **When** it is converted
|
|
- **Then** the chain becomes jobs of the root's workflow with `needs`
|
|
- **And** literal branches become an `if` on `github.ref_name`; the glob and the missing predecessor are named
|
|
|
|
##### Verified by
|
|
|
|
- [ForgejoWorkflowExporterUnitTest](../../src/test/kotlin/de/hoennig/werkator/forgejo/ForgejoWorkflowExporterUnitTest.kt) — Scenario#92.04
|
|
|
|
#### Scenario#92.05: Image, environment and timeout
|
|
|
|
So that a Docker build runs in the same image.
|
|
|
|
- **Given** a build with `docker.image`, `docker.env` and `timeout: 90s`, and one with a Dockerfile only
|
|
- **When** it is converted
|
|
- **Then** the first gets `container.image`, `env` and `timeout-minutes: 2`
|
|
- **And** the Dockerfile is named, because a workflow needs a prebuilt image
|
|
|
|
##### Verified by
|
|
|
|
- [ForgejoWorkflowExporterUnitTest](../../src/test/kotlin/de/hoennig/werkator/forgejo/ForgejoWorkflowExporterUnitTest.kt) — Scenario#92.05
|
|
|
|
#### Scenario#92.06: Nothing is dropped silently
|
|
|
|
So that the list of untranslated constructs measures the gap ADR 0010 keeps from growing.
|
|
|
|
- **Given** `activeWithin`, `stdoutLog`, `requirePullRequest`, `statusContext`, a multi-line command and `$branch`
|
|
- **When** it is converted
|
|
- **Then** each is listed, and written as a comment above the place it belongs to
|
|
|
|
##### Verified by
|
|
|
|
- [ForgejoWorkflowExporterUnitTest](../../src/test/kotlin/de/hoennig/werkator/forgejo/ForgejoWorkflowExporterUnitTest.kt) — Scenario#92.06
|
|
|
|
#### Scenario#92.07: Only the committed file is read
|
|
|
|
So that no secret and no host policy ends up in a committed workflow.
|
|
|
|
- **Given** a machine config with a token and a build command, and an instance file with defaults
|
|
- **When** `export:forgejo` runs
|
|
- **Then** the workflow holds the committed build command only
|
|
- **And** `--stdout` prints the workflows instead of writing them
|
|
|
|
##### Verified by
|
|
|
|
- [ExportForgejoCommandUnitTest](../../src/test/kotlin/de/hoennig/werkator/commands/ExportForgejoCommandUnitTest.kt) — Scenario#92.07
|
|
|
|
#### Scenario#92.08: --strict refuses
|
|
|
|
So that a CI check can demand a complete conversion.
|
|
|
|
- **Given** a construct without a workflow counterpart
|
|
- **When** `export:forgejo --strict` runs
|
|
- **Then** it writes nothing and exits 1
|
|
- **And** without a committed `.werkator.yml` it exits 2
|
|
|
|
##### Verified by
|
|
|
|
- [ExportForgejoCommandUnitTest](../../src/test/kotlin/de/hoennig/werkator/commands/ExportForgejoCommandUnitTest.kt) — Scenario#92.08
|
|
|
|
#### Scenario#92.09: What the existing repositories showed
|
|
|
|
So that the converter's output for the repositories Werkator builds today says what they need.
|
|
|
|
- **Given** a `builds.default` without a trigger, an image built from a Dockerfile, and a follow-up with an empty `cleanCommand`
|
|
- **When** it is converted
|
|
- **Then** the settings base gets no workflow
|
|
- **And** the Dockerfile is named although the image has a name, and so is the follow-up that builds on its predecessor's worktree
|
|
|
|
##### Verified by
|
|
|
|
- [ForgejoWorkflowExporterUnitTest](../../src/test/kotlin/de/hoennig/werkator/forgejo/ForgejoWorkflowExporterUnitTest.kt) — Scenario#92.09
|
|
|
|
#### Scenario#92.10: The workflows go into the target repository
|
|
|
|
So that the converter can be pointed at any checkout, from anywhere.
|
|
|
|
- **Given** a directory inside a git repository whose root holds the `.werkator.yml`
|
|
- **When** `export:forgejo` runs on it, with `--output-dir .gitea/workflows`
|
|
- **Then** the root's `.werkator.yml` is read, and the workflows are written below the root
|
|
- **And** a directory outside any git repository is a usage error
|
|
|
|
##### Verified by
|
|
|
|
- [ExportForgejoCommandUnitTest](../../src/test/kotlin/de/hoennig/werkator/commands/ExportForgejoCommandUnitTest.kt) — Scenario#92.10
|
|
|
|
## The Solution
|
|
|
|
- [ADR 0010](../adrs/0010-2026-10-03.forgejo-actions-compatible-config.md) records the direction: the build configuration stays expressible as a Forgejo Actions workflow.
|
|
A new build-definition key needs a workflow counterpart; host-side keys are exempt.
|
|
- [RFC 0006](../rfcs/0006-one-workflow-for-forgejo-and-werkator.md) proposes one workflow for both systems and the steps towards it.
|
|
- Step 1 of the RFC is implemented here:
|
|
- `ConfigLoader.loadCommitted` binds the committed `.werkator.yml` alone, `builds.default` applied.
|
|
- `ForgejoWorkflowExporter` (new package `forgejo`) writes one workflow per definition that triggers on its own, with a small YAML writer, so comments can sit where they belong.
|
|
- `ExportForgejoCommand` (`export:forgejo [REPO]`) finds the root of the target repository with `git rev-parse --show-toplevel`, reads the `.werkator.yml` there, writes `.forgejo/workflows/werkator-<build>.yml` into it, prints the untranslated constructs on stderr, and refuses under `--strict`.
|
|
- `tools/werkator-to-forgejo` runs the command from `WERKATOR_BIN`, the `werkator` on `PATH`, or the jar of the checkout.
|
|
- It is a Kotlin command, not a Python script: it binds the file exactly as Werkator does, and its tests run in the existing suite.
|
|
- A trial run over the repositories of mih09 and over hs.hsadmin.ng converted every file; RFC 0006 lists what it found.
|
|
Both forges run Gitea, which reads `.gitea/workflows`, so `--output-dir` matters until the RFC settles the default.
|
|
`werkdock.env` is converted to `env` now, since Werkator has no environment outside a sandbox.
|
|
- `AGENTS.md` carries the rule as a hard invariant and lists ADR 0010 among the decisions in force.
|
|
|
|
## Additional Changes
|
|
|
|
- `AGENTS.md` asks for column-aligned Markdown tables in new documents.
|
|
- `docs/configuration.md`, `docs/llms.md`, the architecture skill and the package list in `AGENTS.md` describe the converter.
|
|
- Version 1.29.0 with its release note.
|
|
|
|
## Follow-up PRs
|
|
|
|
- RFC 0006 step 2: the `GITHUB_*` and `FORGEJO_*` variables in every build.
|