Add release workflow publishing builds to Gitea
Publish plugin / publish (push) Failing after 4s

Build, verify and publish dist/<id>.plugin to the Releases tab on every
push to main. Nothing is plugin-specific: the id and version are read
from plugin.json, so the workflow keeps working once this template is
renamed into a real plugin.

The version in plugin.json decides what happens: a new version creates
tag v<version> and a new release, while an unchanged version rebuilds the
existing release and replaces its attachment. The tag is never moved, so
it keeps pointing at the commit that first introduced that version, but
the release notes are refreshed to name the commit the build came from.

The upload is gated on verify_bundle.py, so a bundle that fails offline
verification is never published. dist/ stays gitignored and the artifact
is always built by CI rather than committed.
This commit is contained in:
lyuksovannyy committed 2026-09-13 00:04:32 +02:00
1 parent ae63f8b9a3
commit cfa6dd9e1e
3 files changed
+313

No files matched your search

+85
View File
@@ -0,0 +1,85 @@
name: Publish plugin
# Builds dist/<id>.plugin and publishes it to the Releases tab.
#
# The version in plugin.json is the single source of truth:
# new version -> a new v<version> tag and release are created
# same version -> the existing release is rebuilt, replacing its attachment
#
# So a normal push to main always produces a downloadable build, and bumping
# the version in plugin.json is what cuts a new release. Pushing a v* tag by
# hand still works and uses that tag verbatim.
#
# dist/ is gitignored, so the artifact is always built here rather than
# committed. The build uses --release because --dev embeds absolute paths from
# whichever machine produced it.
on:
push:
branches:
- main
tags:
- "v*"
workflow_dispatch:
permissions:
contents: write
jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Check out sources
uses: actions/checkout@v4
- name: Validate plugin metadata and sources
run: python3 tools/bundle.py --check
- name: Build release bundle
id: build
run: |
set -eu
python3 tools/bundle.py --release
plugin_id=$(python3 -c "import json; print(json.load(open('plugin.json'))['id'])")
version=$(python3 -c "import json; print(json.load(open('plugin.json'))['version'])")
artifact="dist/${plugin_id}.plugin"
test -s "$artifact"
echo "artifact=${artifact}" >> "$GITHUB_OUTPUT"
echo "asset_name=${plugin_id}.plugin" >> "$GITHUB_OUTPUT"
echo "version=${version}" >> "$GITHUB_OUTPUT"
echo "built ${artifact} ($(wc -c < "$artifact") bytes)"
- name: Verify the built bundle
# Executes the bundle against faked SDK modules and asserts the
# plugin's observable behaviour. A build that fails this is not
# publishable, so this gates the upload.
run: python3 tools/verify_bundle.py "${{ steps.build.outputs.artifact }}"
- name: Resolve release tag
id: tag
run: |
set -eu
if [ "${GITHUB_REF_TYPE:-}" = "tag" ]; then
# Hand-pushed tag: honour it exactly as written.
tag="${GITHUB_REF_NAME}"
else
# Branch push or manual run: the version in plugin.json decides
# whether this is a new release or a rebuild of the current one.
tag="v${{ steps.build.outputs.version }}"
fi
echo "tag=${tag}" >> "$GITHUB_OUTPUT"
echo "publishing as ${tag}"
- name: Publish release and upload plugin
env:
# Org-level secret holding a user token with write:repository scope.
# Not using a `||` fallback to GITEA_TOKEN: Gitea's expression engine
# supports only always(), so the operator would not evaluate.
GITEA_TOKEN: ${{ secrets.API_TOKEN }}
run: |
python3 tools/release.py \
--api "${{ github.server_url }}/api/v1/repos/${{ github.repository }}" \
--tag "${{ steps.tag.outputs.tag }}" \
--artifact "${{ steps.build.outputs.artifact }}" \
--asset-name "${{ steps.build.outputs.asset_name }}" \
--commitish "${{ github.sha }}"