From 76278b395d5d66d6043af470d2a0c0530d19f928 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 6 Oct 2026 14:26:36 +0000 Subject: [PATCH] One-button plugin releases and create-ervisio-plugin - reusable workflow plugin-release.yml: bump, changelog, tag, build, validate, release, notify the registry - template release.yml calls it (workflow_dispatch patch/minor/major) - create-ervisio-plugin: a new plugin project in one command - template CI validates against Ervisio main Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01YBUx1d4niJfMeuwPGpikuu --- .github/workflows/plugin-release.yml | 160 +++++++++++++++++++++++++ CHANGELOG.md | 5 + README.md | 14 ++- docs/publishing.md | 39 ++++-- package.json | 7 +- scripts/create.mjs | 121 +++++++++++++++++++ template/.github/workflows/ci.yml | 2 +- template/.github/workflows/release.yml | 90 ++++---------- 8 files changed, 352 insertions(+), 86 deletions(-) create mode 100644 .github/workflows/plugin-release.yml create mode 100755 scripts/create.mjs diff --git a/.github/workflows/plugin-release.yml b/.github/workflows/plugin-release.yml new file mode 100644 index 0000000..59ab72e --- /dev/null +++ b/.github/workflows/plugin-release.yml @@ -0,0 +1,160 @@ +# Reusable release workflow for Ervisio plugins. A plugin's release.yml calls +# it (see template/.github/workflows/release.yml); everything happens here, so +# fixing the release process means changing this one file. +# +# Run by hand (Actions > Release > Run workflow, choose patch/minor/major): +# 1. bumps the version in plugin/manifest.json and package.json(-lock), +# 2. adds a "## X.Y.Z" section to CHANGELOG.md (the notes you typed, or the +# commit subjects since the last release), +# 3. commits "Release X.Y.Z", tags vX.Y.Z and pushes both, +# 4. builds, packs, validates the manifest with Ervisio's own validator, +# 5. creates the GitHub release with the tarball and its sha256, +# 6. tells the registry (Ervisio/plugins) to pick it up now, when the +# REGISTRY_TOKEN secret exists (organization secret; without it the +# registry still finds the release within six hours). +# Run on a pushed vX.Y.Z tag: steps 4-6 only (the old way still works). +name: Plugin release + +on: + workflow_call: + inputs: + bump: + description: 'patch, minor or major; empty when called for a pushed tag' + type: string + default: '' + notes: + description: 'Release notes; empty = the commit subjects since the last release' + type: string + default: '' + ervisio-ref: + description: 'Ervisio release whose manifest validator is used' + type: string + default: 'main' + secrets: + REGISTRY_TOKEN: + required: false + +jobs: + release: + runs-on: ubuntu-24.04 + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: actions/setup-node@v4 + with: + node-version: 24 + + - name: Bump the version and write the changelog + if: inputs.bump != '' + env: + BUMP: ${{ inputs.bump }} + NOTES: ${{ inputs.notes }} + run: | + case "$BUMP" in patch|minor|major) ;; *) echo "::error::bump must be patch, minor or major"; exit 1;; esac + if [ "$GITHUB_REF_TYPE" != branch ]; then echo "::error::run it on a branch (normally main)"; exit 1; fi + old="$(node -p "require('./plugin/manifest.json').version")" + new="$(node -e ' + const [a,b,c] = process.argv[1].split("-")[0].split(".").map(Number); + const k = process.argv[2]; + console.log(k === "major" ? `${a+1}.0.0` : k === "minor" ? `${a}.${b+1}.0` : `${a}.${b}.${c+1}`); + ' "$old" "$BUMP")" + if git rev-parse -q --verify "refs/tags/v$new" >/dev/null; then echo "::error::tag v$new exists already"; exit 1; fi + echo "Releasing $old -> $new" + # manifest.json: only the version line changes, the rest keeps its formatting. + node -e ' + const fs = require("fs"); const p = "plugin/manifest.json"; + const s = fs.readFileSync(p, "utf8"); + const out = s.replace(/("version"\s*:\s*")[^"]*(")/, `$1${process.argv[1]}$2`); + if (out === s) { console.error("no version in manifest.json"); process.exit(1); } + JSON.parse(out); fs.writeFileSync(p, out); + ' "$new" + npm version "$new" --no-git-tag-version --allow-same-version >/dev/null + # Notes: what was typed, or the commit subjects since the last tag. + body="$RUNNER_TEMP/section.md" + if [ -n "$NOTES" ]; then + printf '%s\n' "$NOTES" > "$body" + else + last="$(git describe --tags --abbrev=0 --match 'v[0-9]*' 2>/dev/null || true)" + git log --no-merges --format='- %s' ${last:+"$last"..}HEAD | grep -v '^- Release [0-9]' > "$body" || true + [ -s "$body" ] || echo "- Maintenance release." > "$body" + fi + node -e ' + const fs = require("fs"); const [ver, bodyFile] = process.argv.slice(1); + const date = new Date().toISOString().slice(0, 10); + const section = `## ${ver} - ${date}\n\n${fs.readFileSync(bodyFile, "utf8").trim()}\n`; + let s = fs.existsSync("CHANGELOG.md") ? fs.readFileSync("CHANGELOG.md", "utf8") : "# Changelog\n"; + const i = s.search(/^## /m); + s = i < 0 ? s.trimEnd() + "\n\n" + section : s.slice(0, i) + section + "\n" + s.slice(i); + fs.writeFileSync("CHANGELOG.md", s); + ' "$new" "$body" + git -c user.name="github-actions[bot]" -c user.email="41898282+github-actions[bot]@users.noreply.github.com" \ + commit -q -am "Release $new" + git tag -a "v$new" -m "$new" + git push origin "HEAD:$GITHUB_REF_NAME" "v$new" + echo "TAG=v$new" >> "$GITHUB_ENV" + + - name: Tag of this release + if: inputs.bump == '' + run: | + if [ "$GITHUB_REF_TYPE" != tag ]; then echo "::error::choose patch, minor or major"; exit 1; fi + echo "TAG=$GITHUB_REF_NAME" >> "$GITHUB_ENV" + + - name: Install + run: if [ -f package-lock.json ]; then npm ci; else npm install; fi + - name: Build + run: npm run build + - name: Pack (checks tag = manifest version = package.json version) + run: npm run pack + + - uses: actions/checkout@v4 + with: + repository: Ervisio/ervisio + ref: ${{ inputs.ervisio-ref }} + path: .ervisio-core + - uses: actions/setup-go@v5 + with: + go-version-file: .ervisio-core/server/go.mod + cache: false + - name: Validate the manifest (Ervisio's own checks, throwaway key) + run: | + (cd .ervisio-core/server && CGO_ENABLED=0 go build -o "$RUNNER_TEMP/plugin-sign" ./internal/modules/plugins/cmd/plugin-sign) + id="$(node -p "require('./plugin/manifest.json').id")" + version="$(node -p "require('./plugin/manifest.json').version")" + echo "ID=$id" >> "$GITHUB_ENV"; echo "VERSION=$version" >> "$GITHUB_ENV" + (cd dist && sha256sum -c "$id-$version.tar.gz.sha256") + V="$RUNNER_TEMP/validate"; mkdir -p "$V" + tar -xzf "dist/$id-$version.tar.gz" -C "$V" + test "$(ls "$V")" = "$id" + if [ -n "$(find "$V" ! -type f ! -type d)" ]; then echo "links or special files in the tarball"; exit 1; fi + pub="$("$RUNNER_TEMP/plugin-sign" -genkey "$RUNNER_TEMP/throwaway.key" | sed -n 's/^public key: //p')" + "$RUNNER_TEMP/plugin-sign" -key "$RUNNER_TEMP/throwaway.key" "$V/$id" + "$RUNNER_TEMP/plugin-sign" -verify -pub "$pub" "$V/$id" + rm -f "$RUNNER_TEMP/throwaway.key" + - name: Release notes (CHANGELOG.md section of this version) + run: | + notes="$RUNNER_TEMP/notes.md" + awk -v v="$VERSION" ' + /^## / { if (p) exit; h=$0; sub(/^## +\[?v?/, "", h); gsub(/\]/, " ", h); split(h, a, /[ \t(]+/); if (a[1] == v) { p=1; next } } + p { print }' CHANGELOG.md > "$notes" + if ! grep -q '[^[:space:]]' "$notes"; then echo "::error::CHANGELOG.md has no section for $VERSION"; exit 1; fi + cat "$notes" + - name: Publish the release + env: + GH_TOKEN: ${{ github.token }} + run: | + gh release create "$TAG" --verify-tag --title "$ID $VERSION" --notes-file "$RUNNER_TEMP/notes.md" \ + "dist/$ID-$VERSION.tar.gz" "dist/$ID-$VERSION.tar.gz.sha256" + - name: Tell the registry + env: + REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }} + run: | + if [ -z "$REGISTRY_TOKEN" ]; then + echo "::notice::REGISTRY_TOKEN is not set: the registry picks this release up within six hours (or run its Sync workflow)." + exit 0 + fi + GH_TOKEN="$REGISTRY_TOKEN" gh api repos/Ervisio/plugins/dispatches \ + -f event_type=plugin-release -f "client_payload[id]=$ID" -f "client_payload[repo]=$GITHUB_REPOSITORY" + echo "Registry notified: $ID $VERSION" diff --git a/CHANGELOG.md b/CHANGELOG.md index e7d390a..4e79850 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,11 @@ Windows support (Ervisio 0.6). Plugins written for 0.2 run unchanged on Linux; t under one name; Windows named pipes as `socket`. - `sdk.platform`: the server's system. - docs/sdk.md: "Windows" section. +- One-button releases: the reusable workflow `.github/workflows/plugin-release.yml` bumps the version, writes the + changelog, tags, releases and tells the registry. The template's `release.yml` calls it (Actions › Release › Run + workflow). Existing plugins: replace `.github/workflows/release.yml` with the template's. +- `create-ervisio-plugin `: a new plugin project from the template in one command (`--platforms`, `--github`). +- The template's CI validates against Ervisio `main`, so `platforms` and other new manifest fields are accepted. ## 0.2.0 diff --git a/README.md b/README.md index 0031b20..9b6b480 100644 --- a/README.md +++ b/README.md @@ -19,14 +19,20 @@ frame and reaches the machine only through what the manifest declares: commands, ## Getting started +One command makes a new plugin project (template, id, names, platforms, git, the Release button): + ```sh -npx degit Ervisio/plugin-sdk/template my-plugin # or copy the template/ folder -cd my-plugin +npm exec --yes --package=github:Ervisio/plugin-sdk -- create-ervisio-plugin my-tool --name "My tool" --platforms linux,windows +cd plugin-my-tool npm install -npm run build # dist/hello/index.js + manifest.json +npm run build # dist/my-tool/index.js + manifest.json ``` -Then turn on developer mode in Ervisio and load `dist/hello` from Plugins › Developer. +Add `--github Ervisio` to also create and push the GitHub repository (needs the `gh` CLI). Then turn on developer mode +in Ervisio and load `dist/my-tool` from Plugins › Developer. + +Releasing is one button: **Actions › Release › Run workflow** (patch / minor / major). See +[docs/publishing.md](docs/publishing.md). The package is not on npm yet; the template depends on it through git: diff --git a/docs/publishing.md b/docs/publishing.md index d410f0f..cf4cf61 100644 --- a/docs/publishing.md +++ b/docs/publishing.md @@ -24,11 +24,21 @@ release tarball. Both use `ervisio-plugin-pack`, installed with this package. ## Releasing -1. Set the new version in `plugin/manifest.json` and `package.json`, and add a `## X.Y.Z` section to `CHANGELOG.md`. - Say plainly what changed, and say it when the release asks for new permissions (capabilities) and why. -2. Commit, then tag and push: `git tag -a vX.Y.Z -m "X.Y.Z" && git push origin vX.Y.Z`. -3. The release workflow checks that the tag equals the manifest and package versions, builds, validates the manifest - with Ervisio's own validator, and creates the GitHub release. +On GitHub: **Actions › Release › Run workflow**, choose `patch`, `minor` or `major`, optionally type the release notes, +and run it. That is all. The workflow (the reusable one in this repository, `.github/workflows/plugin-release.yml`): + +1. bumps the version in `plugin/manifest.json` and `package.json`, +2. adds a `## X.Y.Z` section to `CHANGELOG.md`: the notes you typed, or the commit subjects since the last release + (write commit subjects as you want them read: "Add the Logs tab", "Fix the stop button"), +3. commits `Release X.Y.Z`, tags `vX.Y.Z` and pushes both, +4. builds, validates the manifest with Ervisio's own validator and creates the GitHub release, +5. tells the registry, which publishes it (see below). + +When a release asks for new permissions, say so in the notes and why. Pushing a `vX.Y.Z` tag yourself still works: +the workflow then does steps 4 and 5. + +If `main` is protected so that GitHub Actions cannot push to it, allow `github-actions[bot]` to bypass the rule, or +release by pushing the tag yourself. ### Release assets (the contract with the registry) @@ -48,13 +58,18 @@ Open a pull request on [Ervisio/plugins](https://github.com/Ervisio/plugins) tha `registry.json`, following its [CONTRIBUTING.md](https://github.com/Ervisio/plugins/blob/main/CONTRIBUTING.md). After that: -* The registry checks the latest release of every listed repository every few hours. A new version becomes a pull - request in the registry that shows the manifest, the release notes and the permission changes against the previous - version ("new permissions: ..."). A maintainer can also run the registry's "Sync" workflow by hand for a faster - pickup. -* Only registry maintainers merge. On merge, the registry signs the plugin with the Ervisio team key (`manifest.sig` - over the manifest, which lists the sha256 of every file), attaches the signed tarball to a release of the registry, - and publishes the new signed catalog. +* The release workflow tells the registry right away when the organization secret `REGISTRY_TOKEN` exists (a + fine-grained token allowed to run workflows on Ervisio/plugins: "Contents: read and write" there). Without it the + registry checks every listed repository every six hours. +* **Plugins of the Ervisio team** (`"trust": "team"` in `registry.json`): a new version that asks for **no new + permissions** is signed and published at once, with no pull request; it is in the marketplace a few minutes after + you press Release. A version with new or wider permissions, and the first version of a plugin, become a pull + request that shows the manifest, the notes and the permission changes; a maintainer merges it, then it is + published. +* **Community plugins**: every new version is a pull request, reviewed by a maintainer. +* On publish the registry signs the plugin with the Ervisio team key (`manifest.sig` over the manifest, which lists the + sha256 of every file), attaches the signed tarball to a release of the registry, and publishes the new signed + catalog. * Every plugin in the catalog is signed and shows as verified. Ervisio installs only signed plugins by default, and the consent dialog shows the user exactly the permissions your manifest asks for. diff --git a/package.json b/package.json index 1e1ffbf..9535a9a 100644 --- a/package.json +++ b/package.json @@ -59,10 +59,13 @@ "scripts/pack.mjs", "docs", "README.md", - "LICENSE" + "LICENSE", + "scripts/create.mjs", + "template" ], "bin": { - "ervisio-plugin-pack": "scripts/pack.mjs" + "ervisio-plugin-pack": "scripts/pack.mjs", + "create-ervisio-plugin": "scripts/create.mjs" }, "peerDependencies": { "@types/react": "^18.3.0", diff --git a/scripts/create.mjs b/scripts/create.mjs new file mode 100755 index 0000000..1360354 --- /dev/null +++ b/scripts/create.mjs @@ -0,0 +1,121 @@ +#!/usr/bin/env node +// create-ervisio-plugin: a new plugin project from the template, ready to +// build, with the one-button Release workflow. +// +// npm exec --yes --package=github:Ervisio/plugin-sdk -- create-ervisio-plugin [options] +// +// --name "Display name" default: the id, capitalised +// --description "..." one line for the marketplace +// --author "..." default: git config user.name +// --platforms linux,windows where it works (default: linux) +// --dir default: plugin- +// --github also create /plugin- on GitHub and push (needs the gh CLI, logged in) +// +// It copies template/, fills in the id, names and platforms, runs git init +// with a first commit, and prints the next steps. +import { execFileSync } from 'node:child_process'; +import { cpSync, existsSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { dirname, join, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const args = process.argv.slice(2); +const opt = (name, def) => { + const i = args.indexOf(`--${name}`); + return i >= 0 && args[i + 1] !== undefined ? args[i + 1] : def; +}; +const fail = (msg) => { + console.error(`create-ervisio-plugin: ${msg}`); + process.exit(1); +}; +const sh = (cmd, a, o = {}) => execFileSync(cmd, a, { stdio: ['ignore', 'pipe', 'pipe'], encoding: 'utf8', ...o }).trim(); +const tryOut = (cmd, a) => { + try { + return sh(cmd, a); + } catch { + return ''; + } +}; + +const id = args.find((a, i) => !a.startsWith('--') && !(i > 0 && args[i - 1].startsWith('--'))); +if (!id) fail('usage: create-ervisio-plugin [--name "Name"] [--platforms linux,windows] [--github ]'); +if (!/^[a-z][a-z0-9-]{1,39}$/.test(id)) fail(`id "${id}" must be 2-40 lowercase letters, digits or dashes, starting with a letter`); +const name = opt('name', id.split('-').map((w) => w[0].toUpperCase() + w.slice(1)).join(' ')); +const description = opt('description', `${name} for Ervisio.`); +const author = opt('author', tryOut('git', ['config', 'user.name']) || 'Your name'); +const platforms = opt('platforms', 'linux').split(',').map((s) => s.trim()).filter(Boolean); +for (const p of platforms) if (p !== 'linux' && p !== 'windows') fail(`platform "${p}" is not linux or windows`); +const dir = resolve(opt('dir', `plugin-${id}`)); +const owner = opt('github', ''); +if (existsSync(dir)) fail(`${dir} exists already`); + +const template = join(dirname(fileURLToPath(import.meta.url)), '..', 'template'); +if (!existsSync(join(template, 'plugin', 'manifest.json'))) fail(`template not found at ${template}`); +cpSync(template, dir, { recursive: true, filter: (src) => !/[\\/](node_modules|dist)([\\/]|$)/.test(src) }); +rmSync(join(dir, 'package-lock.json'), { force: true }); + +const edit = (rel, fn) => { + const p = join(dir, rel); + writeFileSync(p, fn(readFileSync(p, 'utf8'))); +}; +edit('plugin/manifest.json', (s) => { + const m = JSON.parse(s); + m.id = id; + m.name = name; + m.description = description; + m.author = author; + m.version = '0.1.0'; + m.contributes.pages = [{ ...(m.contributes.pages?.[0] ?? { icon: 'plugins' }), id, title: name }]; + if (platforms.length !== 1 || platforms[0] !== 'linux') { + m.platforms = platforms; + m.minCore = '0.6.1'; + } + if (platforms.includes('windows') && !platforms.includes('linux')) { + m.capabilities.commands = [ + { argv: ['powershell.exe', '-NoProfile', '-NonInteractive', '-Command', '(Get-Date) - (Get-CimInstance Win32_OperatingSystem).LastBootUpTime | Select-Object -ExpandProperty TotalHours'], description: 'Hours since the last boot', name: 'uptime' }, + ]; + } else if (platforms.includes('windows')) { + m.minCore = '0.6.2'; + m.capabilities.commands = [ + { ...m.capabilities.commands[0], platforms: ['linux'] }, + { argv: ['powershell.exe', '-NoProfile', '-NonInteractive', '-Command', '(Get-Date) - (Get-CimInstance Win32_OperatingSystem).LastBootUpTime | Select-Object -ExpandProperty TotalHours'], description: 'Hours since the last boot', name: 'uptime', platforms: ['windows'] }, + ]; + } + return JSON.stringify(m, null, 2) + '\n'; +}); +edit('package.json', (s) => { + const p = JSON.parse(s); + p.name = `ervisio-plugin-${id}`; + p.version = '0.1.0'; + return JSON.stringify(p, null, 2) + '\n'; +}); +edit('vite.config.ts', (s) => s.replaceAll('hello', id)); +edit('src/index.ts', (s) => s.replace("registerPage('hello'", `registerPage('${id}'`).replace("title: 'Hello'", `title: ${JSON.stringify(name)}`)); +edit('README.md', (s) => s.replace('# Hello, an Ervisio plugin', `# ${name}, an Ervisio plugin`).replaceAll('dist/hello', `dist/${id}`).replaceAll('hello-', `${id}-`)); +writeFileSync(join(dir, 'CHANGELOG.md'), `# Changelog\n\n## 0.1.0\n\n- First version.\n`); + +sh('git', ['init', '-q', '-b', 'main'], { cwd: dir }); +sh('git', ['add', '-A'], { cwd: dir }); +const ident = tryOut('git', ['config', 'user.email']) ? [] : ['-c', 'user.name=Ervisio plugin', '-c', 'user.email=plugin@localhost']; +sh('git', [...ident, 'commit', '-q', '-m', `${name}: first version`], { cwd: dir }); +console.log(`Created ${dir}`); + +if (owner) { + const repo = `${owner}/plugin-${id}`; + try { + execFileSync('gh', ['repo', 'create', repo, '--public', '--source', dir, '--push', '--description', description], { stdio: 'inherit' }); + console.log(`Pushed to https://github.com/${repo}`); + } catch { + fail(`could not create ${repo} with gh (is it installed and logged in?). The project is ready in ${dir}.`); + } +} + +console.log(` +Next: + cd ${dir} + npm install + npm run build # dist/${id}/: load it from Ervisio > Plugins > Developer +${owner ? '' : ` gh repo create /plugin-${id} --public --source . --push\n`} +Release: on GitHub, Actions > Release > Run workflow (patch / minor / major). +Marketplace: the first time, add the plugin to registry.json in Ervisio/plugins + {"id": "${id}", "repo": "${owner || ''}/plugin-${id}", "trust": "team", "category": "..."} +after that every release is picked up by itself.`); diff --git a/template/.github/workflows/ci.yml b/template/.github/workflows/ci.yml index 1a70a99..bf5923d 100644 --- a/template/.github/workflows/ci.yml +++ b/template/.github/workflows/ci.yml @@ -12,7 +12,7 @@ permissions: env: # The Ervisio release whose manifest validator is used. - ERVISIO_REF: v0.3.0 + ERVISIO_REF: main jobs: build: diff --git a/template/.github/workflows/release.yml b/template/.github/workflows/release.yml index 4d94f57..b05fbda 100644 --- a/template/.github/workflows/release.yml +++ b/template/.github/workflows/release.yml @@ -1,77 +1,33 @@ -# Publishes a release when a version tag is pushed: -# -# git tag -a v1.2.0 -m "1.2.0" && git push origin v1.2.0 -# -# The tag must equal the version in plugin/manifest.json and package.json. -# Assets: -.tar.gz (one top folder /, unsigned manifest) and -# -.tar.gz.sha256. The Ervisio plugin registry (Ervisio/plugins) -# picks the release up, reviews it, signs it with the Ervisio team key and -# lists it in the marketplace. No secrets are needed here. +# Release: Actions > Release > Run workflow, choose patch, minor or major +# (and optionally type the release notes). The version, CHANGELOG.md, the tag +# and the GitHub release are done for you, then the Ervisio registry is told; +# a version that asks for no new permissions is in the marketplace minutes +# later. Pushing a vX.Y.Z tag yourself still works. +# The steps live in Ervisio/plugin-sdk (.github/workflows/plugin-release.yml). name: Release on: + workflow_dispatch: + inputs: + bump: + description: 'Which part of the version goes up' + type: choice + options: [patch, minor, major] + default: patch + notes: + description: 'Release notes (empty: the commit subjects since the last release)' + type: string + required: false push: tags: ['v*.*.*'] permissions: - contents: read - -env: - ERVISIO_REF: v0.3.0 + contents: write jobs: release: - runs-on: ubuntu-24.04 - permissions: - contents: write - env: - TAG: ${{ github.ref_name }} - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 24 - - name: Install - run: if [ -f package-lock.json ]; then npm ci; else npm install; fi - - name: Build - run: npm run build - - name: Pack (checks tag = manifest version = package.json version) - run: npm run pack - - uses: actions/checkout@v4 - with: - repository: Ervisio/ervisio - ref: ${{ env.ERVISIO_REF }} - path: .ervisio-core - - uses: actions/setup-go@v5 - with: - go-version-file: .ervisio-core/server/go.mod - cache: false - - name: Validate the manifest (Ervisio's own checks, throwaway key) - run: | - (cd .ervisio-core/server && CGO_ENABLED=0 go build -o "$RUNNER_TEMP/plugin-sign" ./internal/modules/plugins/cmd/plugin-sign) - id="$(node -p "require('./plugin/manifest.json').id")" - version="$(node -p "require('./plugin/manifest.json').version")" - echo "ID=$id" >> "$GITHUB_ENV"; echo "VERSION=$version" >> "$GITHUB_ENV" - (cd dist && sha256sum -c "$id-$version.tar.gz.sha256") - V="$RUNNER_TEMP/validate"; mkdir -p "$V" - tar -xzf "dist/$id-$version.tar.gz" -C "$V" - test "$(ls "$V")" = "$id" - if [ -n "$(find "$V" ! -type f ! -type d)" ]; then echo "links or special files in the tarball"; exit 1; fi - pub="$("$RUNNER_TEMP/plugin-sign" -genkey "$RUNNER_TEMP/throwaway.key" | sed -n 's/^public key: //p')" - "$RUNNER_TEMP/plugin-sign" -key "$RUNNER_TEMP/throwaway.key" "$V/$id" - "$RUNNER_TEMP/plugin-sign" -verify -pub "$pub" "$V/$id" - rm -f "$RUNNER_TEMP/throwaway.key" - - name: Release notes (CHANGELOG.md section of this version) - run: | - notes="$RUNNER_TEMP/notes.md" - awk -v v="$VERSION" ' - /^## / { if (p) exit; h=$0; sub(/^## +\[?v?/, "", h); gsub(/\]/, " ", h); split(h, a, /[ \t(]+/); if (a[1] == v) { p=1; next } } - p { print }' CHANGELOG.md > "$notes" - if ! grep -q '[^[:space:]]' "$notes"; then echo "::error::CHANGELOG.md has no section for $VERSION"; exit 1; fi - cat "$notes" - - name: Publish - env: - GH_TOKEN: ${{ github.token }} - run: | - gh release create "$TAG" --verify-tag --title "$ID $VERSION" --notes-file "$RUNNER_TEMP/notes.md" \ - "dist/$ID-$VERSION.tar.gz" "dist/$ID-$VERSION.tar.gz.sha256" + uses: Ervisio/plugin-sdk/.github/workflows/plugin-release.yml@main + with: + bump: ${{ github.event_name == 'workflow_dispatch' && inputs.bump || '' }} + notes: ${{ inputs.notes }} + secrets: inherit