Files
Craftimizer/.gitea/workflows/release.yml
T
JonKazama-Hellion 614e97abf7 Add release pipeline, custom repo manifest, and pre-push linter
First release-ready cycle for Forgeimizer. Bumps the version to 0.1.0,
introduces the Hellion Forge custom repo distribution path, and wires
up the HellionChat-style pre-push lint gate.

Version:
- csproj <Version> 2.9.1.1 → 0.1.0. Forgeimizer adopts its own SemVer
  line starting at 0.1.0; the upstream Craftimizer 2.9.1.1 base is
  documented in the manifest description, CHANGELOG, README, and
  NOTICE for each release.

Release pipeline (.gitea/workflows/):
- build.yml on push/PR/dispatch: downloads Dalamud staging, dotnet
  restore + build of Craftimizer/Craftimizer.csproj. Fails the workflow
  if the plugin no longer compiles against current SDK 15.
- release.yml on v*-tag + dispatch: builds Release, locates the
  packager-produced latest.zip under Craftimizer/bin/x64/Release/,
  extracts the matching ## vX.Y.Z block from CHANGELOG.md via awk,
  appends .gitea/release-footer.md, and attaches everything to the
  Gitea release via gitea.com/actions/release-action.
- release-footer.md: install path with the custom-repo URL, conflict
  notice, attribution to Asriel Camora, MIT licence reference,
  Hellion Forge footer.
- security.yml: references the shared
  JonKazama-Hellion/security-workflows/security-scan.yml@main
  workflow (Semgrep + Trivy) on push/PR + weekly Monday schedule +
  dispatch.

Custom Dalamud repo manifest:
- repo.json at the repo root. AssemblyVersion 0.1.0.0,
  TestingAssemblyVersion 0.1.0.0, all three DownloadLink* pointing
  at releases/download/v0.1.0/latest.zip, embedded Changelog block,
  full description, tag list, icon and image URLs hosted off the
  Hellion Gitea. Subscribers add the raw URL of this file to
  Dalamud's Custom Plugin Repositories list.

Linter tooling:
- dotnet-tools.json with csharpier 1.2.6 as a local tool.
- .markdownlint.json copied from HellionChat (atx headers, dash
  bullets, underscore italics, asterisk strong) with MD060 disabled
  for our long-cell tables.
- renovate.json adapted from HellionChat: weekly schedule, grouped
  minor/patch updates per ecosystem, major updates get their own
  breaking-change PR, weekly lock file refresh, OSV vulnerability
  alerts.

Pre-push lint gate (.githooks/ + scripts/):
- .githooks/pre-push runs scripts/preflight.sh.
- preflight.sh: 4 blocks A (version consistency), B (dotnet build),
  C (dotnet csharpier check Craftimizer/), D (markdownlint via npx).
- verify-version-consistency.sh: csproj <Version> matches
  repo.json AssemblyVersion + TestingAssemblyVersion + a vX.Y.Z
  tag string is present in all three DownloadLink* URLs. Block A
  fails loud with a Fix: hint if anything drifts.
- setup-hooks.sh: sets core.hooksPath to .githooks, chmod +x the
  scripts. Run once after cloning.

CHANGELOG:
- New CHANGELOG.md at the repo root. First entry is v0.1.0 with the
  Hellion-style block (date, summary, bullet list, upstream-base
  attribution, full-history link). The release workflow extracts
  this entry verbatim as the Gitea release body.

Docs:
- README header updated with the new version badge, a release badge,
  and a build badge. New CHANGELOG reference, slash-command table,
  install section with both custom-repo and dev-install paths,
  conflict notice paragraph.

Plugin Version 0.1.0 stays in line with the verify-version-consistency
check; tag v0.1.0 is intentionally NOT pushed in this commit. Once the
user enables Gitea Actions on the repo, push the tag separately to
trigger the first release build.
2026-05-26 20:21:54 +02:00

140 lines
4.9 KiB
YAML

name: Release
# Triggered when a vX.Y.Z tag is pushed. Builds the plugin against the
# current Dalamud staging branch, locates the latest.zip produced by
# DalamudPackager, extracts the matching changelog block from CHANGELOG.md,
# and attaches everything to the Gitea Release.
#
# User-controlled inputs touched by this workflow:
# - the tag name (filtered by on.tags = v*, validated again at runtime
# against ^v\d+\.\d+\.\d+$ before being used in any string)
# All other values are either repo-controlled (paths under
# Craftimizer/bin/x64/Release derived from find) or pinned URLs to goatcorp
# / gitea. Nothing from a webhook event payload (issue/PR titles, commit
# messages, etc.) flows into a run-step.
on:
push:
tags:
- 'v*'
# Manual recovery trigger. Use Gitea's "Run workflow" UI and select the
# tag (e.g. v0.1.0) from the Ref dropdown - not main. The Validate tag
# ref step below hard-fails if a non-tag ref is selected, because
# release-action reads GITHUB_REF directly and rejects anything that
# does not start with refs/tags/.
workflow_dispatch:
permissions:
contents: write
jobs:
release:
name: Build and attach release ZIP
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Validate tag ref
run: |
if [[ "${GITHUB_REF}" != refs/tags/v* ]]; then
echo "::error::Release workflow must run on a v*.X.Y tag ref, got ${GITHUB_REF}"
echo "::error::Push a tag, or pick the tag (not main) in the workflow_dispatch Ref dropdown."
exit 1
fi
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Setup .NET 10
uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5
with:
dotnet-version: 10.0.x
- name: Download Dalamud staging
run: |
hooks="$HOME/.xlcore/dalamud/Hooks/dev"
mkdir -p "$hooks"
curl -fsSL https://goatcorp.github.io/dalamud-distrib/stg/latest.zip -o dalamud.zip
unzip -oq dalamud.zip -d "$hooks"
- name: Build (Release)
run: dotnet build Craftimizer/Craftimizer.csproj --configuration Release
- name: Locate latest.zip
id: locate
run: |
zip="$(find Craftimizer/bin/x64/Release -name latest.zip -print -quit)"
if [ -z "$zip" ]; then
echo "latest.zip not found under Craftimizer/bin/x64/Release" >&2
exit 1
fi
echo "Found: $zip"
echo "path=$zip" >> "$GITHUB_OUTPUT"
# Extract the changelog block for the tagged version from CHANGELOG.md.
# Convention: each release block starts with `## vX.Y.Z` and ends at
# the next `## v` or the `---` trailer at the bottom. Fails the
# workflow if no block exists for the tagged version, which is the
# automated counterpart to the "csproj + repo.json + CHANGELOG kept
# in sync" rule.
- name: Generate release body
env:
TAG_NAME: ${{ github.ref_name }}
run: |
set -euo pipefail
tag="$TAG_NAME"
if [[ ! "$tag" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "::error::Refusing to generate release body for non-semver tag: $tag"
exit 1
fi
version="${tag#v}"
changelog="CHANGELOG.md"
# awk extracts the block starting at "## vX.Y.Z" and stops at the
# next "## v" or the "---" trailer.
block="$(awk -v ver="## v${version}" '
$0 ~ "^"ver" " { take=1; print; next }
take && /^## v[0-9]+\./ { exit }
take && /^---$/ { exit }
take { print }
' "$changelog")"
if [ -z "$block" ]; then
echo "::error::No changelog entry for version $version found in $changelog. Update the changelog before tagging a release."
exit 1
fi
footer=""
if [ -f .gitea/release-footer.md ]; then
footer="$(cat .gitea/release-footer.md)"
fi
{
echo "$block"
echo ""
echo "$footer"
} > release-body.md
echo "Generated release body for $tag:"
echo "----------------------------------------"
cat release-body.md
echo "----------------------------------------"
- name: Expose release body for release-action
id: body
shell: bash
run: |
{
echo 'content<<RELEASE_BODY_EOF'
cat release-body.md
echo 'RELEASE_BODY_EOF'
} >> "$GITHUB_OUTPUT"
- name: Attach to Gitea release
uses: https://gitea.com/actions/release-action@main
with:
files: ${{ steps.locate.outputs.path }}
body: ${{ steps.body.outputs.content }}
api_key: ${{ secrets.GITHUB_TOKEN }}