4b25f5864d
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.
405 lines
16 KiB
YAML
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"
|