Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .github/workflows/pr-title.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: PR Title

on:
pull_request:
types: [opened, edited, synchronize, reopened]

permissions:
pull-requests: read

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: amannn/action-semantic-pull-request@0723387faaf9b38adef4775cd42cfd5155ed6017 # v5.5.3
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
70 changes: 60 additions & 10 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,29 @@ name: Release
on:
push:
tags: ["v*"]
# Manual trigger: builds <version> and creates the v<version> tag + draft release.
# Manual trigger: builds <version> and creates a draft v<version> release.
workflow_dispatch:
inputs:
version:
description: "Version to release, e.g. 0.1.0"
required: true
# Called by version.yml on merge to main with a computed version.
workflow_call:
inputs:
version:
description: "Version to release, e.g. 0.1.0"
required: true
type: string
notes:
description: "Release body / notes (Markdown)"
required: false
type: string
default: ""
publish:
description: "Flip the draft to a published release"
required: false
type: boolean
default: false

permissions:
contents: write
Expand All @@ -26,15 +43,21 @@ jobs:
steps:
- id: v
shell: bash
env:
IN_VERSION: ${{ inputs.version }}
REF_NAME: ${{ github.ref_name }}
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
raw="${{ github.event.inputs.version }}"
set -euo pipefail
if [ -n "$IN_VERSION" ]; then
raw="$IN_VERSION"
else
raw="${GITHUB_REF_NAME}"
raw="$REF_NAME"
fi
version="${raw#v}"
echo "version=$version" >> "$GITHUB_OUTPUT"
echo "tag=v$version" >> "$GITHUB_OUTPUT"
{
echo "version=$version"
echo "tag=v$version"
} >> "$GITHUB_OUTPUT"
echo "Releasing version $version (tag v$version)"

create-release:
Expand All @@ -44,23 +67,30 @@ jobs:
GH_TOKEN: ${{ github.token }}
TAG: ${{ needs.setup.outputs.tag }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false
- name: Ensure draft release exists
shell: bash
env:
IN_NOTES: ${{ inputs.notes }}
run: |
notes="See the assets below to download and install.
set -euo pipefail
default_notes="See the assets below to download and install.

Installers are unsigned until code-signing credentials are configured:
macOS Gatekeeper and Windows SmartScreen may warn on first launch."
notes="${IN_NOTES:-$default_notes}"
if gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
echo "Release $TAG already exists; reusing it."
else
printf '%s\n' "$notes" > "$RUNNER_TEMP/notes.md"
gh release create "$TAG" \
--repo "$GITHUB_REPOSITORY" \
--draft \
--target "$GITHUB_SHA" \
--title "HyperDeck Adapter $TAG" \
--notes "$notes"
--notes-file "$RUNNER_TEMP/notes.md"
fi

macos:
Expand All @@ -72,6 +102,8 @@ jobs:
VERSION: ${{ needs.setup.outputs.version }}
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-go@v5
with:
go-version: "1.26"
Expand Down Expand Up @@ -135,6 +167,8 @@ jobs:
VERSION: ${{ needs.setup.outputs.version }}
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-go@v5
with:
go-version: "1.26"
Expand Down Expand Up @@ -184,6 +218,8 @@ jobs:
VERSION: ${{ needs.setup.outputs.version }}
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-go@v5
with:
go-version: "1.26"
Expand Down Expand Up @@ -224,5 +260,19 @@ jobs:
mkdir -p dist
gh release download "$TAG" --repo "$GITHUB_REPOSITORY" --dir dist --pattern '*'
rm -f dist/checksums.txt
( cd dist && sha256sum * > ../checksums.txt )
( cd dist && sha256sum -- * > ../checksums.txt )
gh release upload "$TAG" checksums.txt --repo "$GITHUB_REPOSITORY" --clobber

publish:
needs: [setup, checksums]
if: ${{ inputs.publish }}
runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ needs.setup.outputs.tag }}
steps:
- name: Publish the release
shell: bash
run: |
set -euo pipefail
gh release edit "$TAG" --repo "$GITHUB_REPOSITORY" --draft=false
70 changes: 70 additions & 0 deletions .github/workflows/version.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: Auto Release

on:
push:
branches: [main]

permissions:
contents: read

concurrency:
group: auto-release
cancel-in-progress: false

jobs:
compute:
runs-on: ubuntu-latest
outputs:
new_tag: ${{ steps.out.outputs.new_tag }}
new_version: ${{ steps.out.outputs.new_version }}
changelog: ${{ steps.tag.outputs.changelog }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
fetch-depth: 0
persist-credentials: false
- id: tag
uses: mathieudutour/github-tag-action@d28fa2ccfbd16e871a4bdf35e11b3ad1bd56c0c1 # v6.2
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
dry_run: true
# default_bump: false is load-bearing: it makes a merge with no
# feat/fix/breaking commit produce an empty new_tag, which is what
# skips the release. Do not remove it or docs-only merges will release.
default_bump: false
release_branches: main
fetch_all_tags: true
- id: out
shell: bash
env:
PREV_VERSION: ${{ steps.tag.outputs.previous_version }}
NEW_VERSION: ${{ steps.tag.outputs.new_version }}
NEW_TAG: ${{ steps.tag.outputs.new_tag }}
run: |
set -euo pipefail
if [ -z "$NEW_TAG" ]; then
echo "No releasable commits since the last tag; skipping release."
{
echo "new_tag="
echo "new_version="
} >> "$GITHUB_OUTPUT"
exit 0
fi
version="$(bash build/ci/clamp_version.sh "$PREV_VERSION" "$NEW_VERSION")"
{
echo "new_version=$version"
echo "new_tag=v$version"
} >> "$GITHUB_OUTPUT"
echo "Release $version (previous $PREV_VERSION; action proposed $NEW_VERSION)"

release:
needs: compute
if: needs.compute.outputs.new_tag != ''
permissions:
contents: write
uses: ./.github/workflows/release.yml
with:
version: ${{ needs.compute.outputs.new_version }}
notes: ${{ needs.compute.outputs.changelog }}
publish: true
secrets: inherit
26 changes: 26 additions & 0 deletions build/ci/clamp_version.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env bash
# Clamp a computed semantic version to the 0.x range.
#
# github-tag-action sends 0.x + a breaking change to 1.0.0; we stay in 0.x
# until 1.0.0 is shipped deliberately. When the previous version is 0.x and the
# computed version is not, replace it with a minor bump of the previous version
# (0.<minor>.<patch> -> 0.<minor+1>.0). Otherwise pass the computed version
# through unchanged.
#
# Usage: clamp_version.sh <previous_version> <computed_version>
# Inputs must be bare semver (no leading "v"); the caller strips any prefix.
set -euo pipefail

prev="${1:?previous_version required}"
computed="${2:?computed_version required}"

prev_major="${prev%%.*}"
computed_major="${computed%%.*}"

if [ "$prev_major" = "0" ] && [ "$computed_major" != "0" ]; then
rest="${prev#*.}" # <minor>.<patch>
prev_minor="${rest%%.*}" # <minor>
printf '0.%s.0\n' "$((prev_minor + 1))"
else
printf '%s\n' "$computed"
fi
27 changes: 27 additions & 0 deletions build/ci/clamp_version_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env bash
set -euo pipefail
here="$(cd "$(dirname "$0")" && pwd)"
clamp="$here/clamp_version.sh"

fail=0
check() {
local desc="$1" prev="$2" computed="$3" want="$4" got
got="$(bash "$clamp" "$prev" "$computed")"
if [ "$got" = "$want" ]; then
printf 'ok - %s\n' "$desc"
else
printf 'FAIL - %s: clamp(%s, %s) = %s, want %s\n' "$desc" "$prev" "$computed" "$got" "$want"
fail=1
fi
}

check "breaking change stays in 0.x" 0.1.0 1.0.0 0.2.0
check "feat minor within 0.x passes through" 0.1.0 0.2.0 0.2.0
check "fix patch within 0.x passes through" 0.1.0 0.1.1 0.1.1
check "breaking at higher 0.x minor" 0.9.0 1.0.0 0.10.0
check "breaking ignores prev patch digit" 0.9.3 1.0.0 0.10.0
check "minor zero bumps to 0.1.0" 0.0.4 1.0.0 0.1.0
check "already 1.x passes through" 1.2.0 2.0.0 2.0.0
check "1.x minor passes through" 1.2.0 1.3.0 1.3.0

exit "$fail"
Loading
Loading