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:
|
branches:
|
||||||
- master
|
- master
|
||||||
- dev
|
- 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:
|
schedule:
|
||||||
- cron: '0 19 * * 0'
|
- cron: '0 19 * * 0'
|
||||||
|
|
||||||
@@ -53,12 +63,44 @@ jobs:
|
|||||||
|
|
||||||
- name: Determine version
|
- name: Determine version
|
||||||
id: version
|
id: version
|
||||||
|
env:
|
||||||
|
DISPATCH_RELEASE_TAG: ${{ inputs.release_tag }}
|
||||||
|
OVERWRITE_EXISTING_RELEASE: ${{ inputs.overwrite_existing_release }}
|
||||||
run: |
|
run: |
|
||||||
if [[ "${{ github.ref }}" == refs/tags/* ]]; then
|
if [[ "${{ github.ref }}" == refs/tags/* ]]; then
|
||||||
VERSION="${GITHUB_REF#refs/tags/}"
|
VERSION="${GITHUB_REF#refs/tags/}"
|
||||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||||
echo "is_release=true" >> $GITHUB_OUTPUT
|
echo "is_release=true" >> $GITHUB_OUTPUT
|
||||||
echo "Detected version from tag: $VERSION"
|
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
|
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 "")
|
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
|
||||||
if [ -n "$LATEST_TAG" ]; then
|
if [ -n "$LATEST_TAG" ]; then
|
||||||
@@ -505,7 +547,7 @@ jobs:
|
|||||||
name: "🚀 Release Artifacts"
|
name: "🚀 Release Artifacts"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [prepare, build-linux, build-windows-amd64, merge-manifest]
|
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:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
steps:
|
steps:
|
||||||
@@ -515,32 +557,42 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Prepare Release Notes Context
|
- name: Prepare Release Notes Context
|
||||||
|
env:
|
||||||
|
RELEASE_VERSION: ${{ needs.prepare.outputs.version }}
|
||||||
|
OVERWRITE_EXISTING_RELEASE: ${{ inputs.overwrite_existing_release }}
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
git fetch --tags --force origin
|
git fetch --tags --force origin
|
||||||
|
|
||||||
CURRENT_TAG="${GITHUB_REF_NAME}"
|
CURRENT_TAG="$RELEASE_VERSION"
|
||||||
CURRENT_COMMIT="$(git rev-list -n 1 "$CURRENT_TAG")"
|
if [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ] && [ "${OVERWRITE_EXISTING_RELEASE}" = "true" ]; then
|
||||||
PREVIOUS_TAG="$(git describe --tags --abbrev=0 --match 'v[0-9]*.[0-9]*.[0-9]*' "${CURRENT_COMMIT}^" 2>/dev/null || true)"
|
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"
|
EMPTY_TREE="4b825dc642cb6eb9a060e54bf8d69288fbee4904"
|
||||||
|
|
||||||
if [ -n "$PREVIOUS_TAG" ]; then
|
if [ -n "$PREVIOUS_TAG" ]; then
|
||||||
RANGE_LABEL="$PREVIOUS_TAG..$CURRENT_TAG"
|
RANGE_LABEL="$PREVIOUS_TAG..$CURRENT_COMMIT"
|
||||||
git log --pretty=format:'- %h %s' "$PREVIOUS_TAG..$CURRENT_TAG" > commits.md
|
git log --pretty=format:'- %h %s' "$PREVIOUS_TAG..$CURRENT_COMMIT" > commits.md
|
||||||
git diff --name-only "$PREVIOUS_TAG" "$CURRENT_TAG" > changed-files.md
|
git diff --name-only "$PREVIOUS_TAG" "$CURRENT_COMMIT" > changed-files.md
|
||||||
git diff --stat "$PREVIOUS_TAG" "$CURRENT_TAG" > diffstat.md
|
git diff --stat "$PREVIOUS_TAG" "$CURRENT_COMMIT" > diffstat.md
|
||||||
else
|
else
|
||||||
RANGE_LABEL="$CURRENT_TAG"
|
RANGE_LABEL="$CURRENT_COMMIT"
|
||||||
git log --pretty=format:'- %h %s' "$CURRENT_TAG" > commits.md
|
git log --pretty=format:'- %h %s' "$CURRENT_COMMIT" > commits.md
|
||||||
git diff --name-only "$EMPTY_TREE" "$CURRENT_TAG^{tree}" > changed-files.md
|
git diff --name-only "$EMPTY_TREE" "$CURRENT_COMMIT^{tree}" > changed-files.md
|
||||||
git diff --stat "$EMPTY_TREE" "$CURRENT_TAG^{tree}" > diffstat.md
|
git diff --stat "$EMPTY_TREE" "$CURRENT_COMMIT^{tree}" > diffstat.md
|
||||||
fi
|
fi
|
||||||
|
|
||||||
{
|
{
|
||||||
echo "# Release Context"
|
echo "# Release Context"
|
||||||
echo
|
echo
|
||||||
echo "Current tag: $CURRENT_TAG"
|
echo "Current tag: $CURRENT_TAG"
|
||||||
|
echo "Current commit: $CURRENT_COMMIT"
|
||||||
echo "Previous tag: ${PREVIOUS_TAG:-none}"
|
echo "Previous tag: ${PREVIOUS_TAG:-none}"
|
||||||
echo "Range: $RANGE_LABEL"
|
echo "Range: $RANGE_LABEL"
|
||||||
echo
|
echo
|
||||||
@@ -687,6 +739,14 @@ jobs:
|
|||||||
- `SHA256SUMS`
|
- `SHA256SUMS`
|
||||||
EOF
|
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
|
- name: Download all artifacts
|
||||||
uses: actions/download-artifact@v8
|
uses: actions/download-artifact@v8
|
||||||
with:
|
with:
|
||||||
@@ -707,9 +767,11 @@ jobs:
|
|||||||
- name: Create Release
|
- name: Create Release
|
||||||
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3
|
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3
|
||||||
with:
|
with:
|
||||||
|
tag_name: ${{ needs.prepare.outputs.version }}
|
||||||
files: |
|
files: |
|
||||||
artifacts/linux-*/*.tar.gz
|
artifacts/linux-*/*.tar.gz
|
||||||
artifacts/openwrt-*/*.apk
|
artifacts/openwrt-*/*.apk
|
||||||
artifacts/windows-*/*.zip
|
artifacts/windows-*/*.zip
|
||||||
SHA256SUMS
|
SHA256SUMS
|
||||||
body_path: release-notes.md
|
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:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
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:
|
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
|
required: false
|
||||||
type: string
|
type: string
|
||||||
create_release_tag:
|
confirm_overwrite:
|
||||||
description: "Create and push a new release tag after syncing."
|
description: "Type OVERWRITE to confirm rebuilding an existing release."
|
||||||
required: false
|
required: false
|
||||||
default: true
|
type: string
|
||||||
type: boolean
|
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: sync-dev-to-master
|
group: sync-dev-to-master
|
||||||
@@ -84,10 +92,13 @@ jobs:
|
|||||||
git push origin master
|
git push origin master
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Create and Push Release Tag
|
- name: Resolve Release Tag
|
||||||
if: ${{ inputs.create_release_tag != false }}
|
id: release_tag
|
||||||
|
if: ${{ inputs.release_mode != 'sync_only' }}
|
||||||
env:
|
env:
|
||||||
REQUESTED_VERSION: ${{ github.event.inputs.version }}
|
RELEASE_MODE: ${{ inputs.release_mode }}
|
||||||
|
REQUESTED_VERSION: ${{ inputs.version }}
|
||||||
|
CONFIRM_OVERWRITE: ${{ inputs.confirm_overwrite }}
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
@@ -97,6 +108,11 @@ jobs:
|
|||||||
REQUESTED_VERSION="${REQUESTED_VERSION#"${REQUESTED_VERSION%%[![:space:]]*}"}"
|
REQUESTED_VERSION="${REQUESTED_VERSION#"${REQUESTED_VERSION%%[![:space:]]*}"}"
|
||||||
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
|
if [ -n "$REQUESTED_VERSION" ]; then
|
||||||
TAG_NAME="$REQUESTED_VERSION"
|
TAG_NAME="$REQUESTED_VERSION"
|
||||||
if [[ "$TAG_NAME" != v* ]]; then
|
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)"
|
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
|
if [ -z "$LATEST_TAG" ]; then
|
||||||
TAG_NAME="v0.1.0"
|
if [ "$RELEASE_MODE" = "new" ]; then
|
||||||
echo "No existing vX.Y.Z tag found. Starting at $TAG_NAME"
|
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
|
else
|
||||||
VERSION="${LATEST_TAG#v}"
|
if [ "$RELEASE_MODE" = "new" ]; then
|
||||||
IFS='.' read -r MAJOR MINOR PATCH <<< "$VERSION"
|
VERSION="${LATEST_TAG#v}"
|
||||||
TAG_NAME="v${MAJOR}.${MINOR}.$((PATCH + 1))"
|
IFS='.' read -r MAJOR MINOR PATCH <<< "$VERSION"
|
||||||
echo "Auto bumped release tag from $LATEST_TAG to $TAG_NAME"
|
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
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -122,21 +148,62 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if git rev-parse -q --verify "refs/tags/$TAG_NAME" >/dev/null; then
|
if [ "$RELEASE_MODE" = "new" ]; then
|
||||||
echo "::error::Tag '$TAG_NAME' already exists locally."
|
if git rev-parse -q --verify "refs/tags/$TAG_NAME" >/dev/null; then
|
||||||
exit 1
|
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
|
fi
|
||||||
|
|
||||||
if git ls-remote --exit-code --tags origin "refs/tags/$TAG_NAME" >/dev/null 2>&1; then
|
echo "tag_name=$TAG_NAME" >> "$GITHUB_OUTPUT"
|
||||||
echo "::error::Tag '$TAG_NAME' already exists on origin."
|
|
||||||
exit 1
|
- name: Create and Push Release Tag
|
||||||
fi
|
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 tag -a "$TAG_NAME" -m "Release $TAG_NAME"
|
||||||
git push origin "$TAG_NAME"
|
git push origin "$TAG_NAME"
|
||||||
|
|
||||||
- name: Skip Release Tag
|
- name: Dispatch Overwrite Release Build
|
||||||
if: ${{ inputs.create_release_tag == false }}
|
if: ${{ inputs.release_mode == 'overwrite' }}
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.PAT_TOKEN }}
|
||||||
|
TAG_NAME: ${{ steps.release_tag.outputs.tag_name }}
|
||||||
run: |
|
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