Files
shared-workflows/.gitea/workflows/Release.yml
T
argoyle 4b25f5864d feat(release): enhance release workflow with improvements
Adds fallback to main branch if DEFAULT_BRANCH is empty and updates 
the way CHANGELOG.md and .version files are handled in the release 
process. Refactors checks for existing branches and includes 
detailed logging for transparency. This improves the robustness of 
the release workflow and ensures relevant files are created or 
updated correctly.
2026-01-09 07:38:33 +01:00

405 lines
16 KiB
YAML

name: Unbound Release
on:
workflow_call:
inputs:
tag_only:
description: 'Set to true to only create tags without full releases'
required: false
default: false
type: boolean
env:
GITEA_URL: http://gitea-http.gitea.svc.cluster.local:3000
RELEASE_TOKEN_FILE: /runner-secrets/release-token
GIT_CLIFF_VERSION: "2.11.0"
jobs:
preconditions:
name: Check Preconditions
runs-on: ubuntu-latest
steps:
- name: Validate token
run: |
if [ ! -r "${RELEASE_TOKEN_FILE}" ]; then
echo "Release token file not found at ${RELEASE_TOKEN_FILE}"
echo "This workflow requires the runner to have RELEASE_TOKEN configured."
exit 1
fi
if [ ! -s "${RELEASE_TOKEN_FILE}" ]; then
echo "Release token file is empty"
exit 1
fi
echo "Release token found"
changelog-and-pr:
name: Generate Changelog and Handle PR
runs-on: ubuntu-latest
needs: preconditions
if: github.ref_type == 'branch' && github.ref_name == github.event.repository.default_branch
steps:
- name: Checkout
uses: actions/checkout@v6
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
git-cliff --bump | sed "s/[[:space:]]\+$//" > CHANGELOG.md
- name: Get bumped version
id: version
run: |
VERSION=$(git-cliff --bumped-version 2>/dev/null || echo "")
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "${VERSION}" > VERSION
- name: Check for changes
id: check
run: |
LATEST=$(cat .version 2>/dev/null | jq -r '.version' 2>/dev/null || git describe --abbrev=0 --tags 2>/dev/null || echo '')
VERSION=$(cat VERSION)
if [ -n "${LATEST}" ] && [ "${VERSION}" = "${LATEST}" ]; then
echo "has_changes=false" >> $GITHUB_OUTPUT
else
echo "has_changes=true" >> $GITHUB_OUTPUT
fi
- name: Create or update release PR
if: steps.check.outputs.has_changes == 'true'
env:
REPOSITORY: ${{ github.repository }}
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
run: |
TOKEN=$(cat "${RELEASE_TOKEN_FILE}")
VERSION=$(cat VERSION)
OWNER=$(echo "${REPOSITORY}" | cut -d'/' -f1)
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}"
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')
echo "Checking for existing next-release branch..."
BRANCH_CHECK=$(curl -s -w "%{http_code}" -o /dev/null \
-H "Authorization: token ${TOKEN}" \
"${API_URL}/branches/next-release")
echo "Branch check HTTP status: ${BRANCH_CHECK}"
if [ "${BRANCH_CHECK}" = "200" ]; then
BRANCH_EXISTS="true"
else
BRANCH_EXISTS="false"
fi
echo "Branch exists: ${BRANCH_EXISTS}"
# Prepare CHANGELOG.md content
CHANGELOG_CONTENT=$(base64 -w0 < CHANGELOG.md)
# Prepare .version content
VERSION_JSON=$(jq -n --arg v "${VERSION}" '{"version":$v}')
VERSION_CONTENT=$(echo "${VERSION_JSON}" | base64 -w0)
if [ "${BRANCH_EXISTS}" = "true" ]; then
echo "Updating existing next-release branch..."
# Get SHA of existing CHANGELOG.md
CHANGELOG_SHA=$(curl -sf \
-H "Authorization: token ${TOKEN}" \
"${API_URL}/contents/CHANGELOG.md?ref=next-release" | jq -r '.sha // empty')
# Update or create CHANGELOG.md
if [ -n "${CHANGELOG_SHA}" ]; then
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 "next-release" \
'{content: $content, sha: $sha, message: $message, branch: $branch}')" \
"${API_URL}/contents/CHANGELOG.md"
else
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" \
'{content: $content, message: $message, branch: $branch, new_branch: $branch}')" \
"${API_URL}/contents/CHANGELOG.md"
fi
# Get SHA of existing .version
VERSION_SHA=$(curl -sf \
-H "Authorization: token ${TOKEN}" \
"${API_URL}/contents/.version?ref=next-release" | jq -r '.sha // empty')
# Update or create .version
if [ -n "${VERSION_SHA}" ]; then
curl -sf -X PUT \
-H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
--data "$(jq -n \
--arg content "${VERSION_CONTENT}" \
--arg sha "${VERSION_SHA}" \
--arg message "${TITLE}" \
--arg branch "next-release" \
'{content: $content, sha: $sha, message: $message, branch: $branch}')" \
"${API_URL}/contents/.version"
else
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 from ${BASE_BRANCH}..."
# Check if CHANGELOG.md exists on base branch to determine create vs update
CHANGELOG_SHA=$(curl -sf \
-H "Authorization: token ${TOKEN}" \
"${API_URL}/contents/CHANGELOG.md?ref=${BASE_BRANCH}" | jq -r '.sha // empty')
if [ -n "${CHANGELOG_SHA}" ]; then
echo "Updating CHANGELOG.md (exists on ${BASE_BRANCH}) on new branch..."
RESPONSE=$(curl -s -w "\n%{http_code}" -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")
else
echo "Creating CHANGELOG.md on new branch..."
RESPONSE=$(curl -s -w "\n%{http_code}" -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
fi
# Check if .version exists on base branch
VERSION_SHA=$(curl -sf \
-H "Authorization: token ${TOKEN}" \
"${API_URL}/contents/.version?ref=${BASE_BRANCH}" | jq -r '.sha // empty')
if [ -n "${VERSION_SHA}" ]; then
echo "Updating .version on next-release branch..."
curl -sf -X PUT \
-H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
--data "$(jq -n \
--arg content "${VERSION_CONTENT}" \
--arg sha "${VERSION_SHA}" \
--arg message "${TITLE}" \
--arg branch "next-release" \
'{content: $content, sha: $sha, message: $message, branch: $branch}')" \
"${API_URL}/contents/.version"
else
echo "Creating .version on next-release branch..."
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
fi
if [ -n "${PR_INDEX}" ]; then
echo "Updating existing PR #${PR_INDEX}..."
curl -sf -X PATCH \
-H "Authorization: token ${TOKEN}" \
-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 "${DEFAULT_BRANCH}" \
'{title: $title, body: $body, head: $head, base: $base}')" \
"${API_URL}/pulls"
fi
create-release:
name: Create Release
runs-on: ubuntu-latest
needs: preconditions
if: |
github.ref_type == 'branch' &&
github.ref_name == github.event.repository.default_branch &&
inputs.tag_only != true
steps:
- name: Checkout
uses: actions/checkout@v6
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
- name: Get version
id: version
run: |
VERSION=$(git-cliff --bumped-version 2>/dev/null || echo "")
echo "version=${VERSION}" >> $GITHUB_OUTPUT
- 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
echo "Version file not found"
exit 0
fi
CURRENT_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"
exit 0
fi
OWNER=$(echo "${REPOSITORY}" | cut -d'/' -f1)
REPO=$(echo "${REPOSITORY}" | cut -d'/' -f2)
API_URL="${GITEA_URL}/api/v1/repos/${OWNER}/${REPO}"
MESSAGE=$(cat CHANGES.md)
echo "Creating release ${VERSION}..."
curl -sf -X POST \
-H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
--data "$(jq -n \
--arg tag_name "${VERSION}" \
--arg name "${VERSION}" \
--arg body "${MESSAGE}" \
--arg target "${DEFAULT_BRANCH}" \
'{tag_name: $tag_name, name: $name, body: $body, target_commitish: $target}')" \
"${API_URL}/releases"
create-tag:
name: Create Tag
runs-on: ubuntu-latest
needs: preconditions
if: |
github.ref_type == 'branch' &&
github.ref_name == github.event.repository.default_branch &&
inputs.tag_only == true
steps:
- name: Checkout
uses: actions/checkout@v6
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: Get version
id: version
run: |
VERSION=$(git-cliff --bumped-version 2>/dev/null || echo "")
echo "version=${VERSION}" >> $GITHUB_OUTPUT
- 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
echo "Version file not found"
exit 0
fi
CURRENT_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"
exit 0
fi
OWNER=$(echo "${REPOSITORY}" | cut -d'/' -f1)
REPO=$(echo "${REPOSITORY}" | cut -d'/' -f2)
API_URL="${GITEA_URL}/api/v1/repos/${OWNER}/${REPO}"
echo "Creating tag ${VERSION}..."
curl -sf -X POST \
-H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
--data "$(jq -n \
--arg tag_name "${VERSION}" \
--arg target "${DEFAULT_BRANCH}" \
--arg message "${VERSION}" \
'{tag_name: $tag_name, target: $target, message: $message}')" \
"${API_URL}/tags"