diff --git a/.gitea/workflows/build-main.yml b/.gitea/workflows/build-main.yml index 00d904a..898a6bf 100644 --- a/.gitea/workflows/build-main.yml +++ b/.gitea/workflows/build-main.yml @@ -1,14 +1,73 @@ name: Build package +# One workflow for checks, build and release, because the publish step has to +# depend on the checks and `needs:` only works between jobs of one workflow. on: push: branches: - main tags: - 'v*' + pull_request: jobs: + php-lint: + runs-on: gitea-runner-server03 + strategy: + matrix: + php-version: ['8.2', '8.3', '8.4'] + steps: + - uses: actions/checkout@v7 + + - uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + coverage: none + + - name: Syntax check + run: | + find lib tests appinfo -name '*.php' -print0 | xargs -0 -n1 -- php -l + + xml-lint: + runs-on: gitea-runner-server03 + steps: + - uses: actions/checkout@v7 + + - name: Install xmllint + run: | + apt-get update + apt-get install -y --no-install-recommends libxml2-utils + + - name: Download appstore schema + run: wget -q https://raw.githubusercontent.com/nextcloud/appstore/master/nextcloudappstore/api/v1/release/info.xsd -O info.xsd + + - name: Validate appinfo/info.xml + run: xmllint --schema info.xsd appinfo/info.xml --noout + + unit-tests: + runs-on: gitea-runner-server03 + steps: + - uses: actions/checkout@v7 + + - uses: shivammathur/setup-php@v2 + with: + php-version: '8.3' + extensions: sqlite, pdo_sqlite + coverage: none + + - name: Install dependencies + run: composer install --no-progress --prefer-dist + + - name: Run unit tests + run: composer run test:unit + + # Building and publishing stay in one job on purpose: handing the tarball to a + # separate publish job would mean actions/upload-artifact (unusable here, see + # CLAUDE.md) or actions/cache, and neither is worth a second Gitea backend API + # in the critical path. On a pull request this job stops after `make appstore` + # and just acts as a build check. package: + needs: [php-lint, xml-lint, unit-tests] runs-on: gitea-runner-server03 # contents: write maps to Code: write (deleting the latest-main tag) plus # Releases: write (creating releases and uploading the asset) - everything @@ -32,6 +91,7 @@ jobs: run: make appstore - name: Publish release + if: gitea.event_name == 'push' env: GITEA_API: ${{ gitea.server_url }}/api/v1 REPO: ${{ gitea.repository }} diff --git a/.gitea/workflows/lint-info-xml.yml b/.gitea/workflows/lint-info-xml.yml deleted file mode 100644 index 3847f55..0000000 --- a/.gitea/workflows/lint-info-xml.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Lint info.xml - -on: - push: - branches: [main] - pull_request: - -jobs: - xml-lint: - runs-on: gitea-runner-server03 - steps: - - uses: actions/checkout@v7 - - - name: Install xmllint - run: | - apt-get update - apt-get install -y --no-install-recommends libxml2-utils - - - name: Download appstore schema - run: wget -q https://raw.githubusercontent.com/nextcloud/appstore/master/nextcloudappstore/api/v1/release/info.xsd -O info.xsd - - - name: Validate appinfo/info.xml - run: xmllint --schema info.xsd appinfo/info.xml --noout diff --git a/.gitea/workflows/lint-php.yml b/.gitea/workflows/lint-php.yml deleted file mode 100644 index 263960c..0000000 --- a/.gitea/workflows/lint-php.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Lint PHP - -on: - push: - branches: [main] - pull_request: - -jobs: - php-lint: - runs-on: gitea-runner-server03 - strategy: - matrix: - php-version: ['8.2', '8.3', '8.4'] - steps: - - uses: actions/checkout@v7 - - - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php-version }} - coverage: none - - - name: Syntax check - run: | - find lib tests appinfo -name '*.php' -print0 | xargs -0 -n1 -- php -l diff --git a/.gitea/workflows/phpunit.yml b/.gitea/workflows/phpunit.yml deleted file mode 100644 index e2cae71..0000000 --- a/.gitea/workflows/phpunit.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: PHPUnit - -on: - push: - branches: [main] - pull_request: - -jobs: - unit-tests: - runs-on: gitea-runner-server03 - steps: - - uses: actions/checkout@v7 - - - uses: shivammathur/setup-php@v2 - with: - php-version: '8.3' - extensions: sqlite, pdo_sqlite - coverage: none - - - name: Install dependencies - run: composer install --no-progress --prefer-dist - - - name: Run unit tests - run: composer run test:unit diff --git a/CLAUDE.md b/CLAUDE.md index 4f9b4e9..cc55af6 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -46,23 +46,31 @@ There is no meaningful way to test the Deck integration itself outside a real Ne ### Release process 1. Bump `` in `appinfo/info.xml` and `version` in `package.json` (keep them in sync). -2. Commit, push to `main`, confirm the lint/phpunit pipelines are green. -3. `git tag vX.Y.Z && git push origin vX.Y.Z` — this triggers the tag branch of `.gitea/workflows/build-main.yml`, which builds the frontend, runs `make appstore`, and attaches `workflow_deck_automation.tar.gz` as the asset on a normal (non-pre-) release for that tag. +2. Commit, push to `main`, confirm the run of `.gitea/workflows/build-main.yml` is green. +3. `git tag vX.Y.Z && git push origin vX.Y.Z` — this triggers the tag branch of the same workflow, which re-runs the checks, builds the frontend, runs `make appstore`, and attaches `workflow_deck_automation.tar.gz` as the asset on a normal (non-pre-) release for that tag. **If the tagged build fails and no artifact was ever produced**, fix the issue on `main` and *move* the existing tag to the fixed commit instead of bumping to a new version number (`git tag -d vX.Y.Z && git tag -a vX.Y.Z -m "..." && git push origin :refs/tags/vX.Y.Z && git push origin vX.Y.Z`) — this is how `v0.1.0` was handled through several build fixes before it first built successfully. The job deletes any pre-existing *release* for the tag before creating the new one, so a moved tag republishes cleanly instead of failing on a duplicate asset name. Once a version has actually produced a published artifact, don't move its tag anymore; bump normally instead. **No `actions/upload-artifact` anywhere — and don't reintroduce it.** This self-hosted Gitea instance identifies as GHES to the official `actions/*` JS actions, which refuse to run `@actions/artifact` v2.0.0+ (used internally by `upload-artifact@v4` and later) against GHES: `GHESNotSupportedError`, which pinned us to `@v3` for a while. Publishing through the Gitea release REST API with `curl` sidesteps that version-specific backend API entirely, so the build workflow uses that instead. `actions/checkout` and `actions/setup-node` were never affected — only the artifact upload/download actions are, because they're the ones talking to a versioned backend rather than just running local commands — and can stay on their latest majors. -### One workflow, two triggers +### One workflow for everything -`.gitea/workflows/build-main.yml` handles both cases; there is deliberately no separate release workflow, because the build steps were identical and only the publishing target differed. It runs on pushes to `main` **and** on `v*` tags, and the final step branches on `gitea.ref`: +`.gitea/workflows/build-main.yml` is the *only* workflow: it carries the checks (`php-lint` across 8.2/8.3/8.4, `xml-lint`, `unit-tests`) and the `package` job that builds and publishes. They used to be four separate workflow files, which meant they all triggered independently on the same push and a `latest-main` release was published even when PHPUnit was red. `needs:` only works between jobs of the same workflow (and Gitea's `workflow_run` can depend on one workflow at a time), so gating the release on the checks required merging them into this file. Don't split them back out. + +Consequences of that shape, all intentional: + +- **`package` builds *and* publishes in one job.** Handing the tarball to a separate publish job would need `actions/upload-artifact` (unusable here, see above) or `actions/cache` — a second Gitea backend API in the critical path for no gain. +- **The workflow also runs on `pull_request`**, where the `Publish release` step is skipped via `if: gitea.event_name == 'push'` and the job degrades into a frontend-build check. That matters: `npm run build` used to run only on `main`, so no PR ever exercised it. +- **Tags now get linted and tested too.** Previously the check workflows triggered only on `main` pushes and PRs, so a `v*` tag published completely unverified. + +It runs on pushes to `main` **and** on `v*` tags, and the publish step branches on `gitea.ref`: - **`main`** → rolling pre-release tagged `latest-main`; both the release *and* the tag are deleted and recreated each run, so the download URL for `workflow_deck_automation.tar.gz` always serves the newest `main` build. - **`v*`** → normal release on the tag that was just pushed. Only a stale release is deleted here — **never the tag**, since deleting it would destroy the ref that triggered the run. That's what the `RECREATE_TAG` flag guards. The `latest-main` half exists so a build can be grabbed and copied onto the server (`nextcloud.gnilebein.de`) without cutting a version tag first — it produced `v0.1.0`-shaped raw-repo confusion once already when the app directory was populated by copying the git working tree instead of a built package; this gives a one-click alternative to that mistake. -Note that `make appstore` is pure `mkdir`/`tar`/`rm` — no `composer`, no `php`. The workflow therefore needs Node only; a `setup-php` step here would be dead weight (the deleted release workflow had one). +Note that `make appstore` is pure `mkdir`/`tar`/`rm` — no `composer`, no `php`. The `package` job therefore needs Node only; a `setup-php` step *there* would be dead weight (the deleted release workflow had one). PHP is set up in the check jobs, which is a different job and a different container. **No manually created token is needed.** The publish step authenticates with `secrets.GITEA_TOKEN`, the token Gitea injects into every Actions job automatically (Gitea 1.27.1 here). The job declares `permissions: contents: write`, which Gitea maps to *Code: write* (needed to delete the `latest-main` tag) plus *Releases: write* (creating the release and uploading the asset).