Refactor GitHub Actions workflows (#1023)

* Unify release workflows and add chart/mobile wrappers

* Update chart CI to kube 1.25

* Fetch tagged commit before pushing release branch

* Old `azure/setup-helm`

* Base chart dispatch version on existing chart tags

* `grep` failure with `pipefail` bypasses the user-friendly error message

* `gh-pages` push lacks retry logic

* Auto-incremented chart tag collision

* `grep -Ev` pipeline will crash

* Missed one
This commit is contained in:
Juan José Mata
2026-02-19 21:36:47 +01:00
committed by GitHub
parent 13c2335a6a
commit 69fa440558
8 changed files with 401 additions and 140 deletions

38
.github/workflows/chart-ci.yml vendored Normal file
View File

@@ -0,0 +1,38 @@
name: Chart CI
on:
pull_request:
paths:
- 'charts/**'
- '.github/workflows/chart-ci.yml'
push:
branches:
- main
paths:
- 'charts/**'
- '.github/workflows/chart-ci.yml'
jobs:
helm-checks:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Helm
uses: azure/setup-helm@v4.3.1
- name: Add chart dependencies repositories
run: |
helm repo add cloudnative-pg https://cloudnative-pg.github.io/charts
helm repo add ot-helm https://ot-container-kit.github.io/helm-charts
helm repo update
- name: Build chart dependencies
run: helm dependency build charts/sure
- name: Lint chart
run: helm lint charts/sure
- name: Render templates
run: helm template sure charts/sure --kube-version 1.25.0 >/tmp/sure-chart-rendered.yaml

110
.github/workflows/chart-release.yml vendored Normal file
View File

@@ -0,0 +1,110 @@
name: Chart Release
on:
push:
tags:
- 'chart-v*'
workflow_dispatch:
permissions:
contents: write
jobs:
prepare_release:
runs-on: ubuntu-latest
outputs:
tag_name: ${{ steps.tag.outputs.tag_name }}
chart_version: ${{ steps.tag.outputs.chart_version }}
app_version: ${{ steps.tag.outputs.app_version }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Resolve chart release tag
id: tag
shell: bash
run: |
set -euo pipefail
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
BASE_STABLE_TAG="$(git tag --list 'v*' --sort=-v:refname | { grep -Ev 'alpha|beta|rc' || true; } | head -n 1)"
if [ -z "$BASE_STABLE_TAG" ]; then
echo "::error::No stable app tag found for chart appVersion"
exit 1
fi
LATEST_CHART_TAG="$(git tag --list 'chart-v*' --sort=-v:refname | head -n 1)"
if [ -n "$LATEST_CHART_TAG" ]; then
BASE_CHART_VERSION="${LATEST_CHART_TAG#chart-v}"
else
BASE_CHART_VERSION="$(sed -n 's/^version: //p' charts/sure/Chart.yaml | head -n 1)"
BASE_CHART_VERSION="${BASE_CHART_VERSION:-0.0.0}"
fi
MAJOR="$(echo "$BASE_CHART_VERSION" | cut -d. -f1)"
MINOR="$(echo "$BASE_CHART_VERSION" | cut -d. -f2)"
PATCH="$(echo "$BASE_CHART_VERSION" | cut -d. -f3 | sed 's/[^0-9].*$//')"
PATCH="${PATCH:-0}"
NEXT_PATCH=$((PATCH + 1))
TAG_NAME="chart-v${MAJOR}.${MINOR}.${NEXT_PATCH}"
while git rev-parse "refs/tags/${TAG_NAME}" >/dev/null 2>&1; do
NEXT_PATCH=$((NEXT_PATCH + 1))
TAG_NAME="chart-v${MAJOR}.${MINOR}.${NEXT_PATCH}"
done
CHART_VERSION="${MAJOR}.${MINOR}.${NEXT_PATCH}"
git config user.name "${GITHUB_ACTOR}"
git config user.email "${GITHUB_ACTOR}@users.noreply.github.com"
if ! git tag "$TAG_NAME"; then
echo "::error::Failed to create tag ${TAG_NAME}"
exit 1
fi
if ! git push origin "$TAG_NAME"; then
echo "::error::Failed to push tag ${TAG_NAME} to origin"
exit 1
fi
else
TAG_NAME="${GITHUB_REF_NAME}"
BASE_STABLE_TAG="$(git tag --list 'v*' --sort=-v:refname | grep -Ev 'alpha|beta|rc' | head -n 1 || true)"
fi
CHART_VERSION="${TAG_NAME#chart-v}"
if [ -z "${BASE_STABLE_TAG:-}" ]; then
echo "::warning::No stable app tag found; falling back to CHART_VERSION (${CHART_VERSION}) for appVersion"
fi
APP_VERSION="${BASE_STABLE_TAG:-${CHART_VERSION}}"
echo "tag_name=$TAG_NAME" >> "$GITHUB_OUTPUT"
echo "chart_version=$CHART_VERSION" >> "$GITHUB_OUTPUT"
echo "app_version=$APP_VERSION" >> "$GITHUB_OUTPUT"
publish_chart:
needs: prepare_release
uses: ./.github/workflows/helm-publish.yml
with:
chart_version: ${{ needs.prepare_release.outputs.chart_version }}
app_version: ${{ needs.prepare_release.outputs.app_version }}
update_gh_pages: true
secrets: inherit
release:
needs: [prepare_release, publish_chart]
runs-on: ubuntu-latest
steps:
- name: Download Helm chart artifact
uses: actions/download-artifact@v4
with:
name: helm-chart-package
path: ${{ runner.temp }}/helm-artifacts
- name: Create chart GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.prepare_release.outputs.tag_name }}
name: ${{ needs.prepare_release.outputs.tag_name }}
generate_release_notes: true
files: ${{ runner.temp }}/helm-artifacts/*.tgz

View File

@@ -1,28 +1,6 @@
name: Flutter Mobile Build
on:
push:
branches:
- main
tags:
- 'v*'
paths:
- 'mobile/lib/**'
- 'mobile/android/**'
- 'mobile/ios/**'
- 'mobile/pubspec.yaml'
- 'public/android-chrome-*.png'
- 'public/apple-touch-icon.png'
- '.github/workflows/flutter-build.yml'
pull_request:
paths:
- 'mobile/lib/**'
- 'mobile/android/**'
- 'mobile/ios/**'
- 'mobile/pubspec.yaml'
- 'public/android-chrome-*.png'
- 'public/apple-touch-icon.png'
- '.github/workflows/flutter-build.yml'
workflow_call:
workflow_dispatch:
@@ -189,4 +167,4 @@ jobs:
path: |
mobile/build/ios/iphoneos/Runner.app
mobile/build/ios-build-info.txt
retention-days: 30
retention-days: 30

160
.github/workflows/helm-publish.yml vendored Normal file
View File

@@ -0,0 +1,160 @@
name: Helm Publish
on:
workflow_call:
inputs:
chart_version:
description: Chart semver version (v-prefix allowed)
required: false
type: string
app_version:
description: App version value for Chart.yaml appVersion
required: false
type: string
update_gh_pages:
description: Whether to publish packaged chart to gh-pages index
required: false
type: boolean
default: true
permissions:
contents: write
jobs:
publish:
if: github.repository == 'we-promise/sure'
runs-on: ubuntu-latest
outputs:
chart_version: ${{ steps.version.outputs.chart_version }}
app_version: ${{ steps.version.outputs.app_version }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Helm
uses: azure/setup-helm@v4.3.1
- name: Resolve chart and app versions
id: version
shell: bash
run: |
set -euo pipefail
normalize_version() {
local raw="$1"
echo "${raw#v}"
}
if [ -n "${{ inputs.chart_version }}" ]; then
CHART_VERSION="$(normalize_version "${{ inputs.chart_version }}")"
elif [[ "${GITHUB_REF_TYPE}" == "tag" && "${GITHUB_REF_NAME}" == v* ]]; then
CHART_VERSION="$(normalize_version "${GITHUB_REF_NAME}")"
else
CHART_VERSION="0.0.0-nightly.$(date -u +'%Y%m%d.%H%M%S')"
fi
if [ -n "${{ inputs.app_version }}" ]; then
APP_VERSION="${{ inputs.app_version }}"
elif [[ "${GITHUB_REF_TYPE}" == "tag" && "${GITHUB_REF_NAME}" == v* ]]; then
APP_VERSION="${GITHUB_REF_NAME}"
else
APP_VERSION="${CHART_VERSION}"
fi
echo "chart_version=${CHART_VERSION}" >> "$GITHUB_OUTPUT"
echo "app_version=${APP_VERSION}" >> "$GITHUB_OUTPUT"
- name: Update Chart.yaml version
shell: bash
run: |
set -euo pipefail
sed -i -E "s/^version:.*/version: ${{ steps.version.outputs.chart_version }}/" charts/sure/Chart.yaml
sed -i -E "s/^appVersion:.*/appVersion: \"${{ steps.version.outputs.app_version }}\"/" charts/sure/Chart.yaml
- name: Add Helm repositories
run: |
helm repo add cloudnative-pg https://cloudnative-pg.github.io/charts
helm repo add ot-helm https://ot-container-kit.github.io/helm-charts
helm repo update
- name: Build dependencies
run: helm dependency build charts/sure
- name: Package chart
run: |
mkdir -p .cr-release-packages
helm package charts/sure -d .cr-release-packages
- name: Upload packaged chart artifact
uses: actions/upload-artifact@v4
with:
name: helm-chart-package
path: .cr-release-packages/*.tgz
if-no-files-found: error
retention-days: 7
- name: Checkout gh-pages
if: ${{ inputs.update_gh_pages }}
uses: actions/checkout@v4
with:
ref: gh-pages
path: gh-pages
- name: Update index and push
if: ${{ inputs.update_gh_pages }}
env:
GIT_USER_NAME: ${{ github.actor }}
GIT_USER_EMAIL: ${{ github.actor }}@users.noreply.github.com
run: |
set -euo pipefail
CHART_VERSION="${{ steps.version.outputs.chart_version }}"
MAX_ATTEMPTS=5
cp .cr-release-packages/*.tgz gh-pages/
cd gh-pages
git config user.name "$GIT_USER_NAME"
git config user.email "$GIT_USER_EMAIL"
index_and_commit() {
if [ -f index.yaml ]; then
helm repo index . --url https://we-promise.github.io/sure --merge index.yaml
else
helm repo index . --url https://we-promise.github.io/sure
fi
git add .
if git diff --cached --quiet; then
echo "No Helm chart updates to publish."
return 1
fi
git commit -m "Publish chart ${CHART_VERSION}"
}
index_and_commit || exit 0
for attempt in $(seq 1 "$MAX_ATTEMPTS"); do
echo "Push attempt ${attempt}/${MAX_ATTEMPTS}..."
if git push; then
echo "Chart ${CHART_VERSION} published successfully."
exit 0
fi
if [ "$attempt" -eq "$MAX_ATTEMPTS" ]; then
echo "::error::Failed to push after ${MAX_ATTEMPTS} attempts"
exit 1
fi
backoff=$(( attempt * 2 ))
echo "Push failed; retrying in ${backoff}s after rebase..."
sleep "$backoff"
git fetch origin gh-pages
git rebase origin/gh-pages
git reset HEAD~1 --soft 2>/dev/null || true
index_and_commit || { echo "No changes after rebase."; exit 0; }
done

View File

@@ -1,113 +0,0 @@
name: Release Helm Chart (WIP)
on:
push:
branches:
- main
paths:
- 'charts/**'
tags:
- 'v*'
workflow_dispatch:
jobs:
release:
if: github.repository == 'we-promise/sure'
runs-on: ubuntu-latest
permissions:
contents: write
pages: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Configure Git
env:
GIT_USER_NAME: ${{ github.actor }}
GIT_USER_EMAIL: ${{ github.actor }}@users.noreply.github.com
run: |
git config user.name "$GIT_USER_NAME"
git config user.email "$GIT_USER_EMAIL"
- name: Install Helm
uses: azure/setup-helm@v3
- name: Generate nightly version
id: version
run: |
# Generate version like: 0.0.0-nightly.20251213.173045
if [[ "${GITHUB_REF_TYPE}" == "tag" && "${GITHUB_REF_NAME}" == v* ]]; then
VERSION="${GITHUB_REF_NAME#v}"
else
BASE_VERSION="$(git tag -l 'v*' | sed 's/^v//' | sort -V | tail -n 1)"
if [[ -z "${BASE_VERSION}" ]]; then
BASE_VERSION="0.0.0"
fi
VERSION="${BASE_VERSION}-nightly.$(date -u +'%Y%m%d.%H%M%S')"
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Generated version: $VERSION"
- name: Update Chart.yaml version
run: |
sed -i "s/^version:.*/version: ${{ steps.version.outputs.version }}/" charts/sure/Chart.yaml
sed -i "s/^appVersion:.*/appVersion: \"${{ steps.version.outputs.version }}\"/" charts/sure/Chart.yaml
cat charts/sure/Chart.yaml
- name: Add Helm repositories
run: |
helm repo add cloudnative-pg https://cloudnative-pg.github.io/charts
helm repo add ot-helm https://ot-container-kit.github.io/helm-charts
helm repo update
- name: Build dependencies
run: |
helm dependency build charts/sure
- name: Package chart
run: |
mkdir -p .cr-release-packages
helm package charts/sure -d .cr-release-packages
- name: Checkout gh-pages
uses: actions/checkout@v4
with:
ref: gh-pages
path: gh-pages
- name: Update index and push
env:
GIT_USER_NAME: ${{ github.actor }}
GIT_USER_EMAIL: ${{ github.actor }}@users.noreply.github.com
run: |
# Copy packaged chart
cp .cr-release-packages/*.tgz gh-pages/
# Update index
helm repo index gh-pages --url https://we-promise.github.io/sure --merge gh-pages/index.yaml
# Push to gh-pages
git config --global credential.helper cache
cd gh-pages
git config user.name "$GIT_USER_NAME"
git config user.email "$GIT_USER_EMAIL"
git add .
if git diff --cached --quiet; then
echo "No Helm chart updates to publish."
exit 0
fi
if [[ "${GITHUB_REF_TYPE}" == "tag" && "${GITHUB_REF_NAME}" == v* ]]; then
git commit -m "Release chart for ${{ github.ref_name }}"
else
git commit -m "Release nightly: ${{ steps.version.outputs.version }}"
fi
git push
- name: Upload chart to GitHub Release
if: startsWith(github.ref, 'refs/tags/v')
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.ref_name }}
files: .cr-release-packages/*.tgz

28
.github/workflows/mobile-ci.yml vendored Normal file
View File

@@ -0,0 +1,28 @@
name: Mobile CI
on:
pull_request:
paths:
- 'mobile/**'
- 'public/android-chrome-*.png'
- 'public/apple-touch-icon.png'
- '.github/workflows/flutter-build.yml'
- '.github/workflows/mobile-ci.yml'
push:
branches:
- main
paths:
- 'mobile/**'
- 'public/android-chrome-*.png'
- 'public/apple-touch-icon.png'
- '.github/workflows/flutter-build.yml'
- '.github/workflows/mobile-ci.yml'
concurrency:
group: mobile-ci-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
uses: ./.github/workflows/flutter-build.yml
secrets: inherit

View File

@@ -33,9 +33,14 @@ jobs:
set -euo pipefail
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
BRANCH_NAME="${GITHUB_REF_NAME}"
SAFE_BRANCH_NAME="${BRANCH_NAME//\//-}"
BASE_TAG="${SAFE_BRANCH_NAME}-$(date -u +'%Y%m%d%H%M')"
BASE_STABLE_TAG="$(git tag --list 'v*' --sort=-v:refname | { grep -Ev 'alpha|beta|rc' || true; } | head -n 1)"
if [ -z "$BASE_STABLE_TAG" ]; then
echo "::error::No stable v* tag found to base mobile patch release on"
exit 1
fi
STAMP="$(date -u +'%Y%m%d%H%M')"
BASE_TAG="mobile-${BASE_STABLE_TAG}-p${STAMP}"
TAG_NAME="$BASE_TAG"
TAG_SUFFIX=1

View File

@@ -242,6 +242,17 @@ jobs:
sleep ${delay}
done
helm:
name: Package Helm chart
if: startsWith(github.ref, 'refs/tags/v')
uses: ./.github/workflows/helm-publish.yml
with:
chart_version: ${{ github.ref_name }}
app_version: ${{ github.ref_name }}
update_gh_pages: true
secrets: inherit
mobile:
name: Build Mobile Apps
if: startsWith(github.ref, 'refs/tags/v')
@@ -251,7 +262,7 @@ jobs:
release:
name: Create GitHub Release
if: startsWith(github.ref, 'refs/tags/v')
needs: [merge, mobile]
needs: [merge, mobile, helm]
runs-on: ubuntu-latest
timeout-minutes: 10
@@ -271,6 +282,12 @@ jobs:
name: ios-build-unsigned
path: ${{ runner.temp }}/ios-build
- name: Download Helm chart artifact
uses: actions/download-artifact@v4.3.0
with:
name: helm-chart-package
path: ${{ runner.temp }}/helm-artifacts
- name: Prepare release assets
run: |
mkdir -p ${{ runner.temp }}/release-assets
@@ -307,6 +324,12 @@ jobs:
cp "${{ runner.temp }}/ios-build/ios-build-info.txt" "${{ runner.temp }}/release-assets/"
fi
# Copy Helm chart package(s)
if compgen -G "${{ runner.temp }}/helm-artifacts/*.tgz" > /dev/null; then
cp ${{ runner.temp }}/helm-artifacts/*.tgz "${{ runner.temp }}/release-assets/"
echo "✓ Helm chart package prepared"
fi
echo "Release assets:"
ls -la "${{ runner.temp }}/release-assets/"
@@ -330,6 +353,38 @@ jobs:
> **Note**: These are debug builds intended for testing purposes. For production use, please build from source with proper signing credentials.
create_release_branch:
name: Create or update release branch
if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref_name, 'alpha') && !contains(github.ref_name, 'beta') && !contains(github.ref_name, 'rc')
needs: [release]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Create/update minor release branch
env:
TAG_NAME: ${{ github.ref_name }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
BRANCH_NAME="$(echo "$TAG_NAME" | sed -E 's/^v([0-9]+)\.([0-9]+)\..*/v\1.\2-release-branch/')"
SHA="${GITHUB_SHA}"
echo "Updating ${BRANCH_NAME} -> ${SHA}"
if ! gh api "repos/${GITHUB_REPOSITORY}/git/refs/heads/${BRANCH_NAME}" \
--method PATCH \
--field sha="${SHA}" \
--field force=true 2>/dev/null; then
gh api "repos/${GITHUB_REPOSITORY}/git/refs" \
--method POST \
--field ref="refs/heads/${BRANCH_NAME}" \
--field sha="${SHA}"
fi
bump-pre_release-version:
name: Bump Pre-release Version
if: startsWith(github.ref, 'refs/tags/v') && (contains(github.ref_name, 'alpha') || contains(github.ref_name, 'beta') || contains(github.ref_name, 'rc'))