ci(release): add overwrite release rebuild mode
This commit is contained in:
88
.github/workflows/build-dockerhub.yml
vendored
88
.github/workflows/build-dockerhub.yml
vendored
@@ -16,7 +16,17 @@ on:
|
||||
branches:
|
||||
- master
|
||||
- dev
|
||||
workflow_dispatch: {}
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release_tag:
|
||||
description: "Existing release tag to rebuild, e.g. v1.2.3"
|
||||
required: false
|
||||
type: string
|
||||
overwrite_existing_release:
|
||||
description: "Overwrite assets/body of an existing GitHub Release"
|
||||
required: false
|
||||
default: false
|
||||
type: boolean
|
||||
schedule:
|
||||
- cron: '0 19 * * 0'
|
||||
|
||||
@@ -53,12 +63,44 @@ jobs:
|
||||
|
||||
- name: Determine version
|
||||
id: version
|
||||
env:
|
||||
DISPATCH_RELEASE_TAG: ${{ inputs.release_tag }}
|
||||
OVERWRITE_EXISTING_RELEASE: ${{ inputs.overwrite_existing_release }}
|
||||
run: |
|
||||
if [[ "${{ github.ref }}" == refs/tags/* ]]; then
|
||||
VERSION="${GITHUB_REF#refs/tags/}"
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "is_release=true" >> $GITHUB_OUTPUT
|
||||
echo "Detected version from tag: $VERSION"
|
||||
elif [[ "${{ github.event_name }}" == "workflow_dispatch" && "$OVERWRITE_EXISTING_RELEASE" == "true" ]]; then
|
||||
git fetch --tags --force origin
|
||||
|
||||
VERSION="${DISPATCH_RELEASE_TAG:-}"
|
||||
VERSION="${VERSION#"${VERSION%%[![:space:]]*}"}"
|
||||
VERSION="${VERSION%"${VERSION##*[![:space:]]}"}"
|
||||
|
||||
if [[ "$VERSION" != v* ]]; then
|
||||
VERSION="v$VERSION"
|
||||
fi
|
||||
|
||||
if [[ ! "$VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "::error::Invalid release tag '$VERSION'. Use vX.Y.Z, for example v1.2.3."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! git ls-remote --exit-code --tags origin "refs/tags/$VERSION" >/dev/null 2>&1; then
|
||||
echo "::error::Tag '$VERSION' does not exist on origin."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TAG_COMMIT="$(git rev-list -n 1 "$VERSION")"
|
||||
MASTER_COMMIT="$(git rev-parse HEAD)"
|
||||
echo "Overwrite release tag: $VERSION"
|
||||
echo "Tag commit: $TAG_COMMIT"
|
||||
echo "Master commit used for rebuilt assets: $MASTER_COMMIT"
|
||||
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "is_release=true" >> $GITHUB_OUTPUT
|
||||
elif [[ "${{ github.ref }}" == refs/heads/master ]] && ([[ "${{ github.event_name }}" == "workflow_dispatch" ]] || [[ "${{ github.event_name }}" == "schedule" ]]); then
|
||||
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
|
||||
if [ -n "$LATEST_TAG" ]; then
|
||||
@@ -505,7 +547,7 @@ jobs:
|
||||
name: "🚀 Release Artifacts"
|
||||
runs-on: ubuntu-latest
|
||||
needs: [prepare, build-linux, build-windows-amd64, merge-manifest]
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
if: startsWith(github.ref, 'refs/tags/') || (github.event_name == 'workflow_dispatch' && inputs.overwrite_existing_release == true)
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
@@ -515,32 +557,42 @@ jobs:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Prepare Release Notes Context
|
||||
env:
|
||||
RELEASE_VERSION: ${{ needs.prepare.outputs.version }}
|
||||
OVERWRITE_EXISTING_RELEASE: ${{ inputs.overwrite_existing_release }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
git fetch --tags --force origin
|
||||
|
||||
CURRENT_TAG="${GITHUB_REF_NAME}"
|
||||
CURRENT_COMMIT="$(git rev-list -n 1 "$CURRENT_TAG")"
|
||||
PREVIOUS_TAG="$(git describe --tags --abbrev=0 --match 'v[0-9]*.[0-9]*.[0-9]*' "${CURRENT_COMMIT}^" 2>/dev/null || true)"
|
||||
CURRENT_TAG="$RELEASE_VERSION"
|
||||
if [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ] && [ "${OVERWRITE_EXISTING_RELEASE}" = "true" ]; then
|
||||
CURRENT_COMMIT="$(git rev-parse HEAD)"
|
||||
TAG_COMMIT="$(git rev-list -n 1 "$CURRENT_TAG")"
|
||||
PREVIOUS_TAG="$(git describe --tags --abbrev=0 --match 'v[0-9]*.[0-9]*.[0-9]*' "${TAG_COMMIT}^" 2>/dev/null || true)"
|
||||
else
|
||||
CURRENT_COMMIT="$(git rev-list -n 1 "$CURRENT_TAG")"
|
||||
PREVIOUS_TAG="$(git describe --tags --abbrev=0 --match 'v[0-9]*.[0-9]*.[0-9]*' "${CURRENT_COMMIT}^" 2>/dev/null || true)"
|
||||
fi
|
||||
EMPTY_TREE="4b825dc642cb6eb9a060e54bf8d69288fbee4904"
|
||||
|
||||
if [ -n "$PREVIOUS_TAG" ]; then
|
||||
RANGE_LABEL="$PREVIOUS_TAG..$CURRENT_TAG"
|
||||
git log --pretty=format:'- %h %s' "$PREVIOUS_TAG..$CURRENT_TAG" > commits.md
|
||||
git diff --name-only "$PREVIOUS_TAG" "$CURRENT_TAG" > changed-files.md
|
||||
git diff --stat "$PREVIOUS_TAG" "$CURRENT_TAG" > diffstat.md
|
||||
RANGE_LABEL="$PREVIOUS_TAG..$CURRENT_COMMIT"
|
||||
git log --pretty=format:'- %h %s' "$PREVIOUS_TAG..$CURRENT_COMMIT" > commits.md
|
||||
git diff --name-only "$PREVIOUS_TAG" "$CURRENT_COMMIT" > changed-files.md
|
||||
git diff --stat "$PREVIOUS_TAG" "$CURRENT_COMMIT" > diffstat.md
|
||||
else
|
||||
RANGE_LABEL="$CURRENT_TAG"
|
||||
git log --pretty=format:'- %h %s' "$CURRENT_TAG" > commits.md
|
||||
git diff --name-only "$EMPTY_TREE" "$CURRENT_TAG^{tree}" > changed-files.md
|
||||
git diff --stat "$EMPTY_TREE" "$CURRENT_TAG^{tree}" > diffstat.md
|
||||
RANGE_LABEL="$CURRENT_COMMIT"
|
||||
git log --pretty=format:'- %h %s' "$CURRENT_COMMIT" > commits.md
|
||||
git diff --name-only "$EMPTY_TREE" "$CURRENT_COMMIT^{tree}" > changed-files.md
|
||||
git diff --stat "$EMPTY_TREE" "$CURRENT_COMMIT^{tree}" > diffstat.md
|
||||
fi
|
||||
|
||||
{
|
||||
echo "# Release Context"
|
||||
echo
|
||||
echo "Current tag: $CURRENT_TAG"
|
||||
echo "Current commit: $CURRENT_COMMIT"
|
||||
echo "Previous tag: ${PREVIOUS_TAG:-none}"
|
||||
echo "Range: $RANGE_LABEL"
|
||||
echo
|
||||
@@ -687,6 +739,14 @@ jobs:
|
||||
- `SHA256SUMS`
|
||||
EOF
|
||||
|
||||
if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ "${{ inputs.overwrite_existing_release }}" = "true" ]; then
|
||||
{
|
||||
echo
|
||||
echo "<!-- rebuilt-from: $(git rev-parse HEAD) -->"
|
||||
echo "<!-- rebuilt-at: $(date -u +%Y-%m-%dT%H:%M:%SZ) -->"
|
||||
} >> release-notes.md
|
||||
fi
|
||||
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
@@ -707,9 +767,11 @@ jobs:
|
||||
- name: Create Release
|
||||
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3
|
||||
with:
|
||||
tag_name: ${{ needs.prepare.outputs.version }}
|
||||
files: |
|
||||
artifacts/linux-*/*.tar.gz
|
||||
artifacts/openwrt-*/*.apk
|
||||
artifacts/windows-*/*.zip
|
||||
SHA256SUMS
|
||||
body_path: release-notes.md
|
||||
overwrite_files: true
|
||||
|
||||
115
.github/workflows/sync-dev-to-master.yml
vendored
115
.github/workflows/sync-dev-to-master.yml
vendored
@@ -3,15 +3,23 @@ name: Sync Dev to Master
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release_mode:
|
||||
description: "Release mode: new creates a tag, overwrite rebuilds an existing release, sync_only only syncs branches."
|
||||
required: true
|
||||
default: "new"
|
||||
type: choice
|
||||
options:
|
||||
- new
|
||||
- overwrite
|
||||
- sync_only
|
||||
version:
|
||||
description: "Release tag, e.g. v1.2.3. Leave empty to auto bump patch. Used only when create_release_tag is true."
|
||||
description: "Release tag, e.g. v1.2.3. Empty auto bumps for new or uses latest existing tag for overwrite."
|
||||
required: false
|
||||
type: string
|
||||
create_release_tag:
|
||||
description: "Create and push a new release tag after syncing."
|
||||
confirm_overwrite:
|
||||
description: "Type OVERWRITE to confirm rebuilding an existing release."
|
||||
required: false
|
||||
default: true
|
||||
type: boolean
|
||||
type: string
|
||||
|
||||
concurrency:
|
||||
group: sync-dev-to-master
|
||||
@@ -84,10 +92,13 @@ jobs:
|
||||
git push origin master
|
||||
fi
|
||||
|
||||
- name: Create and Push Release Tag
|
||||
if: ${{ inputs.create_release_tag != false }}
|
||||
- name: Resolve Release Tag
|
||||
id: release_tag
|
||||
if: ${{ inputs.release_mode != 'sync_only' }}
|
||||
env:
|
||||
REQUESTED_VERSION: ${{ github.event.inputs.version }}
|
||||
RELEASE_MODE: ${{ inputs.release_mode }}
|
||||
REQUESTED_VERSION: ${{ inputs.version }}
|
||||
CONFIRM_OVERWRITE: ${{ inputs.confirm_overwrite }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
@@ -97,6 +108,11 @@ jobs:
|
||||
REQUESTED_VERSION="${REQUESTED_VERSION#"${REQUESTED_VERSION%%[![:space:]]*}"}"
|
||||
REQUESTED_VERSION="${REQUESTED_VERSION%"${REQUESTED_VERSION##*[![:space:]]}"}"
|
||||
|
||||
if [ "$RELEASE_MODE" = "overwrite" ] && [ "${CONFIRM_OVERWRITE:-}" != "OVERWRITE" ]; then
|
||||
echo "::error::confirm_overwrite must be exactly 'OVERWRITE' when release_mode=overwrite."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -n "$REQUESTED_VERSION" ]; then
|
||||
TAG_NAME="$REQUESTED_VERSION"
|
||||
if [[ "$TAG_NAME" != v* ]]; then
|
||||
@@ -107,13 +123,23 @@ jobs:
|
||||
LATEST_TAG="$(git tag --list 'v*.*.*' --sort=-v:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -n 1 || true)"
|
||||
|
||||
if [ -z "$LATEST_TAG" ]; then
|
||||
TAG_NAME="v0.1.0"
|
||||
echo "No existing vX.Y.Z tag found. Starting at $TAG_NAME"
|
||||
if [ "$RELEASE_MODE" = "new" ]; then
|
||||
TAG_NAME="v0.1.0"
|
||||
echo "No existing vX.Y.Z tag found. Starting at $TAG_NAME"
|
||||
else
|
||||
echo "::error::No existing vX.Y.Z tag found to overwrite."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
VERSION="${LATEST_TAG#v}"
|
||||
IFS='.' read -r MAJOR MINOR PATCH <<< "$VERSION"
|
||||
TAG_NAME="v${MAJOR}.${MINOR}.$((PATCH + 1))"
|
||||
echo "Auto bumped release tag from $LATEST_TAG to $TAG_NAME"
|
||||
if [ "$RELEASE_MODE" = "new" ]; then
|
||||
VERSION="${LATEST_TAG#v}"
|
||||
IFS='.' read -r MAJOR MINOR PATCH <<< "$VERSION"
|
||||
TAG_NAME="v${MAJOR}.${MINOR}.$((PATCH + 1))"
|
||||
echo "Auto bumped release tag from $LATEST_TAG to $TAG_NAME"
|
||||
else
|
||||
TAG_NAME="$LATEST_TAG"
|
||||
echo "No release tag requested. Using latest existing release tag: $TAG_NAME"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -122,21 +148,62 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if git rev-parse -q --verify "refs/tags/$TAG_NAME" >/dev/null; then
|
||||
echo "::error::Tag '$TAG_NAME' already exists locally."
|
||||
exit 1
|
||||
if [ "$RELEASE_MODE" = "new" ]; then
|
||||
if git rev-parse -q --verify "refs/tags/$TAG_NAME" >/dev/null; then
|
||||
echo "::error::Tag '$TAG_NAME' already exists locally."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if git ls-remote --exit-code --tags origin "refs/tags/$TAG_NAME" >/dev/null 2>&1; then
|
||||
echo "::error::Tag '$TAG_NAME' already exists on origin."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
if ! git rev-parse -q --verify "refs/tags/$TAG_NAME" >/dev/null; then
|
||||
echo "::error::Tag '$TAG_NAME' does not exist locally."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! git ls-remote --exit-code --tags origin "refs/tags/$TAG_NAME" >/dev/null 2>&1; then
|
||||
echo "::error::Tag '$TAG_NAME' does not exist on origin."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TAG_COMMIT="$(git rev-list -n 1 "$TAG_NAME")"
|
||||
MASTER_COMMIT="$(git rev-parse HEAD)"
|
||||
echo "Overwrite release tag: $TAG_NAME"
|
||||
echo "Tag commit: $TAG_COMMIT"
|
||||
echo "Master commit used for rebuilt assets: $MASTER_COMMIT"
|
||||
fi
|
||||
|
||||
if git ls-remote --exit-code --tags origin "refs/tags/$TAG_NAME" >/dev/null 2>&1; then
|
||||
echo "::error::Tag '$TAG_NAME' already exists on origin."
|
||||
exit 1
|
||||
fi
|
||||
echo "tag_name=$TAG_NAME" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Create and Push Release Tag
|
||||
if: ${{ inputs.release_mode == 'new' }}
|
||||
env:
|
||||
TAG_NAME: ${{ steps.release_tag.outputs.tag_name }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
git tag -a "$TAG_NAME" -m "Release $TAG_NAME"
|
||||
git push origin "$TAG_NAME"
|
||||
|
||||
- name: Skip Release Tag
|
||||
if: ${{ inputs.create_release_tag == false }}
|
||||
- name: Dispatch Overwrite Release Build
|
||||
if: ${{ inputs.release_mode == 'overwrite' }}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.PAT_TOKEN }}
|
||||
TAG_NAME: ${{ steps.release_tag.outputs.tag_name }}
|
||||
run: |
|
||||
echo "create_release_tag=false; synced dev to master without creating a release tag."
|
||||
set -euo pipefail
|
||||
|
||||
gh workflow run build-dockerhub.yml \
|
||||
--ref master \
|
||||
-f release_tag="$TAG_NAME" \
|
||||
-f overwrite_existing_release=true
|
||||
|
||||
echo "Dispatched release rebuild for $TAG_NAME from master."
|
||||
|
||||
- name: Skip Release
|
||||
if: ${{ inputs.release_mode == 'sync_only' }}
|
||||
run: |
|
||||
echo "release_mode=sync_only; synced dev to master without creating or rebuilding a release."
|
||||
|
||||
Reference in New Issue
Block a user