Compare commits

..

3 Commits

Author SHA1 Message Date
argoyle 0ab0aa8bba feat: use file-based release token instead of secret 2026-01-08 20:58:11 +01:00
GitButler 96e4a1eaa2 GitButler Workspace Commit
This is placeholder commit and will be replaced by a merge of your virtual branches.

Due to GitButler managing multiple virtual branches, you cannot switch back and
forth between git branches and virtual branches easily. 

If you switch to another branch, GitButler will need to be reinitialized.
If you commit on this branch, GitButler will throw it away.

For more information about what we're doing here, check out our docs:
https://docs.gitbutler.com/features/branch-management/integration-branch
2026-01-08 20:58:11 +01:00
argoyle f2f0b69479 Merge pull request 'chore: Configure Renovate' (#1) from renovate/configure into main
Reviewed-on: #1
2026-01-08 19:20:36 +00:00
4 changed files with 218 additions and 227 deletions
-12
View File
@@ -1,12 +0,0 @@
{
"permissions": {
"allow": [
"Bash(but --help:*)",
"Bash(but rub --help:*)",
"WebSearch",
"WebFetch(domain:docs.gitea.com)",
"WebFetch(domain:gitea.com)",
"Bash(but status:*)"
]
}
}
+192 -146
View File
@@ -9,19 +9,16 @@ on:
default: false
type: boolean
concurrency:
group: release-${{ github.repository }}
cancel-in-progress: false
env:
GITEA_URL: http://gitea-http.gitea.svc.cluster.local:3000
GITEA_URL: https://git.unbound.se
RELEASE_TOKEN_FILE: /runner-secrets/release-token
GIT_CLIFF_VERSION: "2.12.0"
jobs:
preconditions:
name: Check Preconditions
runs-on: ubuntu-latest
container:
image: amd64/alpine:3.22.2@sha256:b687e78c6e2785808446f45b52f1540a1e58adc07bdcffea354933b18c613d90
steps:
- name: Validate token
run: |
@@ -36,23 +33,22 @@ jobs:
fi
echo "Release token found"
changelog-and-pr:
name: Generate Changelog and Handle PR
changelog:
name: Generate Changelog
runs-on: ubuntu-latest
needs: preconditions
if: github.ref_type == 'branch' && github.ref_name == github.event.repository.default_branch
container:
image: orhunp/git-cliff:2.10.1@sha256:6ba0d1fcb051bd7b154cfb19c4b2b3bfa2c22c475f5285fc30606777b6573119
outputs:
version: ${{ steps.version.outputs.version }}
has_changes: ${{ steps.check.outputs.has_changes }}
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install git-cliff
run: |
curl -sSfL "https://github.com/orhun/git-cliff/releases/download/v${GIT_CLIFF_VERSION}/git-cliff-${GIT_CLIFF_VERSION}-x86_64-unknown-linux-gnu.tar.gz" | tar xz
sudo mv "git-cliff-${GIT_CLIFF_VERSION}/git-cliff" /usr/local/bin/
git-cliff --version
- name: Generate changelog
run: |
git-cliff --bump --unreleased --strip header > CHANGES.md
@@ -76,8 +72,32 @@ jobs:
echo "has_changes=true" >> $GITHUB_OUTPUT
fi
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: changelog-artifacts
path: |
CHANGES.md
CHANGELOG.md
VERSION
handle-pr:
name: Handle Release PR
runs-on: ubuntu-latest
needs: changelog
if: needs.changelog.outputs.has_changes == 'true'
container:
image: amd64/alpine:3.22.2@sha256:b687e78c6e2785808446f45b52f1540a1e58adc07bdcffea354933b18c613d90
steps:
- name: Install dependencies
run: apk add --no-cache git jq curl
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: changelog-artifacts
- name: Create or update release PR
if: steps.check.outputs.has_changes == 'true'
env:
REPOSITORY: ${{ github.repository }}
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
@@ -88,28 +108,27 @@ jobs:
REPO=$(echo "${REPOSITORY}" | cut -d'/' -f2)
API_URL="${GITEA_URL}/api/v1/repos/${OWNER}/${REPO}"
# Fallback to main if DEFAULT_BRANCH is empty
BASE_BRANCH="${DEFAULT_BRANCH:-main}"
echo "Using base branch: ${BASE_BRANCH}"
TITLE="chore(release): prepare for ${VERSION}"
# Read CHANGES.md content and add note (jq --arg will handle JSON escaping)
CHANGES_CONTENT=$(cat CHANGES.md)
PR_NOTE="**Note:** Please use **Squash Merge** when merging this PR."
DESCRIPTION="${CHANGES_CONTENT}"$'\n\n---\n\n'"${PR_NOTE}"
# Read CHANGES.md and escape for JSON
DESCRIPTION=$(cat CHANGES.md | jq -Rs .)
DESCRIPTION="${DESCRIPTION:1:-1}" # Remove surrounding quotes from jq
# Add squash merge reminder
DESCRIPTION="${DESCRIPTION}
---
**Note:** Please use **Squash Merge** when merging this PR."
echo "Checking for existing release PRs..."
PRS=$(curl -sf \
-H "Authorization: token ${TOKEN}" \
"${API_URL}/pulls?state=open" | jq '[.[] | select(.head.ref == "next-release")]')
PR_INDEX=$(echo "${PRS}" | jq -r '.[0].number // empty')
# Delete existing next-release branch to start fresh (auto-closes any open PR)
echo "Checking for existing next-release branch..."
BRANCH_CHECK=$(curl -s --retry 3 --retry-delay 2 --retry-connrefused -w "%{http_code}" -o /dev/null \
BRANCH_EXISTS=$(curl -sf \
-H "Authorization: token ${TOKEN}" \
"${API_URL}/branches/next-release")
if [ "${BRANCH_CHECK}" = "200" ]; then
echo "Deleting existing next-release branch..."
curl -sf --retry 3 --retry-delay 2 --retry-connrefused -X DELETE \
-H "Authorization: token ${TOKEN}" \
"${API_URL}/branches/next-release"
echo "Branch deleted"
fi
"${API_URL}/branches/next-release" 2>/dev/null && echo "true" || echo "false")
# Prepare CHANGELOG.md content
CHANGELOG_CONTENT=$(base64 -w0 < CHANGELOG.md)
@@ -118,54 +137,46 @@ jobs:
VERSION_JSON=$(jq -n --arg v "${VERSION}" '{"version":$v}')
VERSION_CONTENT=$(echo "${VERSION_JSON}" | base64 -w0)
echo "Creating new next-release branch from ${BASE_BRANCH}..."
if [ "${BRANCH_EXISTS}" = "true" ]; then
echo "Updating existing next-release branch..."
# Check if CHANGELOG.md exists on base branch to determine create vs update
CHANGELOG_SHA=$(curl -sf --retry 3 --retry-delay 2 --retry-connrefused \
# Get SHA of existing CHANGELOG.md
CHANGELOG_SHA=$(curl -sf \
-H "Authorization: token ${TOKEN}" \
"${API_URL}/contents/CHANGELOG.md?ref=${BASE_BRANCH}" | jq -r '.sha // empty')
"${API_URL}/contents/CHANGELOG.md?ref=next-release" | jq -r '.sha // empty')
# Update or create CHANGELOG.md
if [ -n "${CHANGELOG_SHA}" ]; then
echo "Updating CHANGELOG.md (exists on ${BASE_BRANCH}) on new branch..."
RESPONSE=$(curl -s --retry 3 --retry-delay 2 --retry-connrefused -w "\n%{http_code}" -X PUT \
curl -sf -X PUT \
-H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
--data "$(jq -n \
--arg content "${CHANGELOG_CONTENT}" \
--arg sha "${CHANGELOG_SHA}" \
--arg message "${TITLE}" \
--arg branch "${BASE_BRANCH}" \
--arg new_branch "next-release" \
'{content: $content, sha: $sha, message: $message, branch: $branch, new_branch: $new_branch}')" \
"${API_URL}/contents/CHANGELOG.md")
--arg branch "next-release" \
'{content: $content, sha: $sha, message: $message, branch: $branch}')" \
"${API_URL}/contents/CHANGELOG.md"
else
echo "Creating CHANGELOG.md on new branch..."
RESPONSE=$(curl -s --retry 3 --retry-delay 2 --retry-connrefused -w "\n%{http_code}" -X POST \
curl -sf -X POST \
-H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
--data "$(jq -n \
--arg content "${CHANGELOG_CONTENT}" \
--arg message "${TITLE}" \
--arg branch "${BASE_BRANCH}" \
--arg new_branch "next-release" \
'{content: $content, message: $message, branch: $branch, new_branch: $new_branch}')" \
"${API_URL}/contents/CHANGELOG.md")
fi
HTTP_CODE=$(echo "${RESPONSE}" | tail -1)
BODY=$(echo "${RESPONSE}" | sed '$d')
if [ "${HTTP_CODE}" -ge 400 ]; then
echo "Error with CHANGELOG.md: ${BODY}"
exit 1
--arg branch "next-release" \
'{content: $content, message: $message, branch: $branch, new_branch: $branch}')" \
"${API_URL}/contents/CHANGELOG.md"
fi
# Check if .version exists on base branch
VERSION_SHA=$(curl -sf --retry 3 --retry-delay 2 --retry-connrefused \
# Get SHA of existing .version
VERSION_SHA=$(curl -sf \
-H "Authorization: token ${TOKEN}" \
"${API_URL}/contents/.version?ref=${BASE_BRANCH}" | jq -r '.sha // empty')
"${API_URL}/contents/.version?ref=next-release" | jq -r '.sha // empty')
# Update or create .version
if [ -n "${VERSION_SHA}" ]; then
echo "Updating .version on next-release branch..."
curl -sf --retry 3 --retry-delay 2 --retry-connrefused -X PUT \
curl -sf -X PUT \
-H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
--data "$(jq -n \
@@ -176,8 +187,31 @@ jobs:
'{content: $content, sha: $sha, message: $message, branch: $branch}')" \
"${API_URL}/contents/.version"
else
echo "Creating .version on next-release branch..."
curl -sf --retry 3 --retry-delay 2 --retry-connrefused -X POST \
curl -sf -X POST \
-H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
--data "$(jq -n \
--arg content "${VERSION_CONTENT}" \
--arg message "${TITLE}" \
--arg branch "next-release" \
'{content: $content, message: $message, branch: $branch}')" \
"${API_URL}/contents/.version"
fi
else
echo "Creating new next-release branch with CHANGELOG.md..."
curl -sf -X POST \
-H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
--data "$(jq -n \
--arg content "${CHANGELOG_CONTENT}" \
--arg message "${TITLE}" \
--arg branch "next-release" \
--arg new_branch "next-release" \
'{content: $content, message: $message, branch: $branch, new_branch: $new_branch}')" \
"${API_URL}/contents/CHANGELOG.md"
echo "Adding .version to next-release branch..."
curl -sf -X POST \
-H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
--data "$(jq -n \
@@ -188,87 +222,98 @@ jobs:
"${API_URL}/contents/.version"
fi
echo "Creating new PR..."
echo "Waiting for next-release branch to be ready..."
for i in $(seq 1 10); do
BRANCH_STATUS=$(curl -s --retry 3 --retry-delay 2 --retry-connrefused \
-w "%{http_code}" -o /dev/null \
if [ -n "${PR_INDEX}" ]; then
echo "Updating existing PR #${PR_INDEX}..."
curl -sf -X PATCH \
-H "Authorization: token ${TOKEN}" \
"${API_URL}/branches/next-release")
if [ "${BRANCH_STATUS}" = "200" ]; then
echo "Branch ready after ${i} attempt(s)"
break
fi
if [ "${i}" = "10" ]; then
echo "Branch next-release not found after 10 attempts, giving up"
exit 1
fi
echo "Branch not ready yet (attempt ${i}/10), waiting..."
sleep 3
done
PR_DATA=$(jq -n \
-H "Content-Type: application/json" \
--data "$(jq -n \
--arg title "${TITLE}" \
--arg body "${DESCRIPTION}" \
'{title: $title, body: $body}')" \
"${API_URL}/pulls/${PR_INDEX}"
else
echo "Creating new PR..."
curl -sf -X POST \
-H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
--data "$(jq -n \
--arg title "${TITLE}" \
--arg body "${DESCRIPTION}" \
--arg head "next-release" \
--arg base "${BASE_BRANCH}" \
'{title: $title, body: $body, head: $head, base: $base}')
for i in $(seq 1 5); do
RESPONSE=$(curl -s --retry 3 --retry-delay 2 --retry-connrefused \
-w "\n%{http_code}" -X POST \
-H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
--data "${PR_DATA}" \
"${API_URL}/pulls")
HTTP_CODE=$(echo "${RESPONSE}" | tail -1)
BODY=$(echo "${RESPONSE}" | sed '$d')
if [ "${HTTP_CODE}" -lt 400 ]; then
echo "PR created successfully"
break
--arg base "${DEFAULT_BRANCH}" \
'{title: $title, body: $body, head: $head, base: $base}')" \
"${API_URL}/pulls"
fi
if [ "${i}" = "5" ]; then
echo "Error creating PR after 5 attempts (HTTP ${HTTP_CODE}): ${BODY}"
exit 1
fi
echo "PR creation attempt ${i}/5 failed (HTTP ${HTTP_CODE}), retrying..."
sleep 3
done
create-release:
name: Create Release
prepare-release:
name: Prepare Release
runs-on: ubuntu-latest
needs: preconditions
if: |
github.ref_type == 'branch' &&
github.ref_name == github.event.repository.default_branch &&
inputs.tag_only != true
(github.ref_type == 'branch' && github.ref_name == github.event.repository.default_branch) ||
github.ref_type == 'tag'
container:
image: orhunp/git-cliff:2.10.1@sha256:6ba0d1fcb051bd7b154cfb19c4b2b3bfa2c22c475f5285fc30606777b6573119
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install git-cliff
run: |
curl -sSfL "https://github.com/orhun/git-cliff/releases/download/v${GIT_CLIFF_VERSION}/git-cliff-${GIT_CLIFF_VERSION}-x86_64-unknown-linux-gnu.tar.gz" | tar xz
sudo mv "git-cliff-${GIT_CLIFF_VERSION}/git-cliff" /usr/local/bin/
git-cliff --version
- name: Generate changelog
run: git-cliff --bump --unreleased --strip header > CHANGES.md
run: |
if [ "${{ github.ref_type }}" = "tag" ]; then
git-cliff --bump --latest --strip header > CHANGES.md
else
git-cliff --bump --unreleased --strip header > CHANGES.md
fi
- name: Get version
id: version
run: |
VERSION=$(git-cliff --bumped-version 2>/dev/null || echo "")
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "${VERSION}" > VERSION
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: release-artifacts
path: |
CHANGES.md
VERSION
create-release:
name: Create Release
runs-on: ubuntu-latest
needs: prepare-release
if: |
github.ref_type == 'branch' &&
github.ref_name == github.event.repository.default_branch &&
inputs.tag_only != true
container:
image: amd64/alpine:3.22.2@sha256:b687e78c6e2785808446f45b52f1540a1e58adc07bdcffea354933b18c613d90
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install dependencies
run: apk add --no-cache git jq curl
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: release-artifacts
- name: Create release
env:
REPOSITORY: ${{ github.repository }}
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
VERSION: ${{ steps.version.outputs.version }}
run: |
TOKEN=$(cat "${RELEASE_TOKEN_FILE}")
if [ ! -r .version ]; then
@@ -276,11 +321,11 @@ jobs:
exit 0
fi
CURRENT_VERSION=$(cat .version 2>/dev/null | jq -r '.version')
VERSION=$(cat .version 2>/dev/null | jq -r '.version')
LATEST=$(git describe --abbrev=0 --tags 2>/dev/null || echo '')
if [ -n "${LATEST}" ] && [ "${CURRENT_VERSION}" = "${LATEST}" ]; then
echo "Version ${CURRENT_VERSION} already exists"
if [ -n "${LATEST}" ] && [ "${VERSION}" = "${LATEST}" ]; then
echo "Version ${VERSION} already exists"
exit 0
fi
@@ -288,15 +333,17 @@ jobs:
REPO=$(echo "${REPOSITORY}" | cut -d'/' -f2)
API_URL="${GITEA_URL}/api/v1/repos/${OWNER}/${REPO}"
MESSAGE=$(cat CHANGES.md)
NAME=$(cat VERSION)
MESSAGE=$(cat CHANGES.md | jq -Rs .)
MESSAGE="${MESSAGE:1:-1}" # Remove surrounding quotes
echo "Creating release ${VERSION}..."
curl -sf --retry 3 --retry-delay 2 --retry-connrefused -X POST \
echo "Creating release ${NAME}..."
curl -sf -X POST \
-H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
--data "$(jq -n \
--arg tag_name "${VERSION}" \
--arg name "${VERSION}" \
--arg tag_name "${NAME}" \
--arg name "${NAME}" \
--arg body "${MESSAGE}" \
--arg target "${DEFAULT_BRANCH}" \
'{tag_name: $tag_name, name: $name, body: $body, target_commitish: $target}')" \
@@ -305,34 +352,31 @@ jobs:
create-tag:
name: Create Tag
runs-on: ubuntu-latest
needs: preconditions
needs: prepare-release
if: |
github.ref_type == 'branch' &&
github.ref_name == github.event.repository.default_branch &&
inputs.tag_only == true
container:
image: amd64/alpine:3.22.2@sha256:b687e78c6e2785808446f45b52f1540a1e58adc07bdcffea354933b18c613d90
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install git-cliff
run: |
curl -sSfL "https://github.com/orhun/git-cliff/releases/download/v${GIT_CLIFF_VERSION}/git-cliff-${GIT_CLIFF_VERSION}-x86_64-unknown-linux-gnu.tar.gz" | tar xz
sudo mv "git-cliff-${GIT_CLIFF_VERSION}/git-cliff" /usr/local/bin/
git-cliff --version
- name: Install dependencies
run: apk add --no-cache git jq curl
- name: Get version
id: version
run: |
VERSION=$(git-cliff --bumped-version 2>/dev/null || echo "")
echo "version=${VERSION}" >> $GITHUB_OUTPUT
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: release-artifacts
- name: Create tag
env:
REPOSITORY: ${{ github.repository }}
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
VERSION: ${{ steps.version.outputs.version }}
run: |
TOKEN=$(cat "${RELEASE_TOKEN_FILE}")
if [ ! -r .version ]; then
@@ -340,11 +384,11 @@ jobs:
exit 0
fi
CURRENT_VERSION=$(cat .version 2>/dev/null | jq -r '.version')
VERSION=$(cat .version 2>/dev/null | jq -r '.version')
LATEST=$(git describe --abbrev=0 --tags 2>/dev/null || echo '')
if [ -n "${LATEST}" ] && [ "${CURRENT_VERSION}" = "${LATEST}" ]; then
echo "Version ${CURRENT_VERSION} already exists"
if [ -n "${LATEST}" ] && [ "${VERSION}" = "${LATEST}" ]; then
echo "Version ${VERSION} already exists"
exit 0
fi
@@ -352,13 +396,15 @@ jobs:
REPO=$(echo "${REPOSITORY}" | cut -d'/' -f2)
API_URL="${GITEA_URL}/api/v1/repos/${OWNER}/${REPO}"
echo "Creating tag ${VERSION}..."
curl -sf --retry 3 --retry-delay 2 --retry-connrefused -X POST \
NAME=$(cat VERSION)
echo "Creating tag ${NAME}..."
curl -sf -X POST \
-H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
--data "$(jq -n \
--arg tag_name "${VERSION}" \
--arg tag_name "${NAME}" \
--arg target "${DEFAULT_BRANCH}" \
--arg message "${VERSION}" \
--arg message "${NAME}" \
'{tag_name: $tag_name, target: $target, message: $message}')" \
"${API_URL}/tags"
-32
View File
@@ -1,32 +0,0 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Repository Overview
This repository contains reusable Gitea Actions workflows for Unbound Software repositories. These workflows are called from other repositories using Gitea's `workflow_call` trigger.
## Architecture
- **Location**: Workflows are stored in `.gitea/workflows/` (not `.github/workflows/`)
- **Platform**: Gitea Actions (compatible with GitHub Actions syntax but runs on Gitea)
- **Runner**: Uses `ubuntu-latest` runner directly (no containers)
- **git-cliff**: Downloaded as binary from GitHub releases, version controlled via `GIT_CLIFF_VERSION` env var
### Release.yml Workflow
The main workflow automates semantic versioning releases using git-cliff for changelog generation:
1. **preconditions**: Validates release token exists at `/runner-secrets/release-token`
2. **changelog**: Generates changelog, determines version bump, checks for changes
3. **handle-pr**: Creates/updates a `next-release` branch and PR with CHANGELOG.md and .version
4. **prepare-release**: Prepares release artifacts when triggered
5. **create-release** or **create-tag**: Creates Gitea release or tag based on `tag_only` input
Version tracking uses a `.version` JSON file containing `{"version":"vX.Y.Z"}`.
## Development Notes
- No build/test commands exist - this is a workflow-only repository
- Workflows use Gitea API directly via curl (not gh CLI)
- Authentication reads from file-based token at `/runner-secrets/release-token`
-11
View File
@@ -2,16 +2,5 @@
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended"
],
"customManagers": [
{
"customType": "regex",
"fileMatch": ["^\\.gitea/workflows/.*\\.ya?ml$"],
"matchStrings": [
"GIT_CLIFF_VERSION:\\s*[\"']?(?<currentValue>[^\"'\\s]+)[\"']?"
],
"depNameTemplate": "orhun/git-cliff",
"datasourceTemplate": "github-releases"
}
]
}