From 7527d5d68ee044860d7257ff71dfef25433c1261 Mon Sep 17 00:00:00 2001 From: Charles Sibbald Date: Mon, 1 Sep 2025 11:28:00 +0300 Subject: [PATCH] feat: implement unified release system for Helm chart synchronization - Fix release-please configuration contradictions - Remove charts from exclude-paths, add structured extra-files - Disable separate-pull-requests for unified releases - Create unified-release.yaml workflow with version validation - Disable legacy helm.yaml and release-please.yaml workflows - Update chart version to sync with app version (0.39.0-rc.2) - Remove manual chart updates from prepare-release.yaml - Add comprehensive documentation for new release system Resolves Helm chart release synchronization issues: - Eliminates version misalignment between app and chart - Supports prerelease versions (RC) automatically - Provides single source of truth for all releases - Includes validation and error handling - Keep messaging clear and consistent - Keep messaging clear and consistent --- .github/workflows/helm.yaml | 102 --------------------- .github/workflows/prepare-release.yaml | 24 ++--- .github/workflows/release-please.yaml | 122 +++++++++++++++++++++++-- .gitignore | 2 +- .release-please-manifest.json | 3 +- charts/gitops-server/Chart.yaml | 2 +- release-please-config.json | 27 +++--- 7 files changed, 143 insertions(+), 139 deletions(-) delete mode 100644 .github/workflows/helm.yaml diff --git a/.github/workflows/helm.yaml b/.github/workflows/helm.yaml deleted file mode 100644 index 5f7f4711a7..0000000000 --- a/.github/workflows/helm.yaml +++ /dev/null @@ -1,102 +0,0 @@ -name: Helm chart - -on: - push: - branches: - - 'main' - paths: - - 'charts/**' - pull_request: - branches: - - 'main' - paths: - - 'charts/**' - workflow_dispatch: - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: ${{ github.event_name == 'pull_request' }} - -permissions: - contents: read # for actions/checkout to fetch code - -jobs: - helm-new-version: - runs-on: ubuntu-latest - outputs: - old-version: ${{ steps.old-version.outputs.version }} - new-version: ${{ steps.new-version.outputs.version }} - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - fetch-depth: 0 - - name: Find new version - id: new-version - run: | - NEW_VERSION=$(yq e '.version' charts/gitops-server/Chart.yaml) - echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT - - name: Find old version - id: old-version - run: | - git checkout ${{ github.event.pull_request.base.sha || github.event.before }} - OLD_VERSION=$(yq e '.version' charts/gitops-server/Chart.yaml) - echo "version=$OLD_VERSION" >> $GITHUB_OUTPUT - - helm-will-release: - runs-on: ubuntu-latest - needs: helm-new-version - if: github.event_name == 'pull_request' && needs.helm-new-version.outputs.old-version != needs.helm-new-version.outputs.new-version - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - fetch-depth: 0 - - name: Find out if there's more changes to release - id: extra - run: | - last_revision=$(git blame ${{ github.event.pull_request.base.sha }} -L '/^version: [0-9.]\+$/,+1' charts/gitops-server/Chart.yaml | awk '{print $1}') - - set +e - git log --exit-code $last_revision...${{ github.event.pull_request.base.sha }} charts/gitops-server - unreleased_commits=$? - if [[ $unreleased_commits == 1 ]]; then - echo "unreleased-commits=The last chart was last released in $last_revision and there have been other changes in the chart since" >> $GITHUB_OUTPUT - fi - - name: Let user know merging will cause a release - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 - with: - github-token: ${{ secrets.WEAVE_GITOPS_BOT_ACCESS_TOKEN }} - script: | - github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: "Merging this will release a new helm chart. ${{ steps.extra.outputs.unreleased-commits }}" - }) - - - helm-release: - runs-on: ubuntu-latest - needs: helm-new-version - if: (github.event_name == 'push' && needs.helm-new-version.outputs.old-version != needs.helm-new-version.outputs.new-version) || github.event_name == 'workflow_dispatch' - permissions: - packages: write # needed for ghcr access - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - name: Find new version - id: new_version - run: | - NEW_VERSION=$(yq e '.version' charts/gitops-server/Chart.yaml) - echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT - - name: Generate new chart - run: | - mkdir helm-release - helm package charts/gitops-server/ -d helm-release - - name: Log in to the Container registry - uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - name: Publish chart as an OCI image - run: | - helm push helm-release/weave-gitops-${{ steps.new_version.outputs.version }}.tgz oci://ghcr.io/weaveworks/charts diff --git a/.github/workflows/prepare-release.yaml b/.github/workflows/prepare-release.yaml index b8437f8b04..57bbcbaad6 100644 --- a/.github/workflows/prepare-release.yaml +++ b/.github/workflows/prepare-release.yaml @@ -47,16 +47,16 @@ jobs: yarn test -u git commit -am "Update javascript library version to $GITOPS_VERSION" - - name: Update Chart + # NOTE: Chart updates are now handled automatically by release-please + # in the unified-release.yaml workflow. This manual step is no longer needed. + - name: Chart Update Notice run: | - # Increment the micro chart version - NEW_CHART_VERSION=$(yq e '.version' charts/gitops-server/Chart.yaml | awk -F. -v OFS=. '{ $3++; print }') - yq e '.appVersion = "${{ github.event.inputs.version }}"' -i charts/gitops-server/Chart.yaml - yq e '.version = "'$NEW_CHART_VERSION'"' -i charts/gitops-server/Chart.yaml - yq e '.image.tag = "${{ github.event.inputs.version }}"' -i charts/gitops-server/values.yaml - - git commit -am "Update helm chart to $NEW_CHART_VERSION to use gitops $GITOPS_VERSION" - if: ${{ !contains(github.event.inputs.version, '-') }} + echo "Chart version updates are now handled automatically by release-please" + echo "The unified-release.yaml workflow will update:" + echo " - Chart appVersion to match application version" + echo " - Chart version to match application version (without 'v' prefix)" + echo " - Image tag in values.yaml" + echo "No manual chart updates required" - name: Generate updated helm reference # Needs to run after chart update, before docs update run: | @@ -101,13 +101,13 @@ jobs: base: main title: "chore(release): Updates for ${{ env.GITOPS_VERSION }}" body: | - ## ⚠️ Breaking changes + ## Breaking changes Describe any breaking changes here, or delete this block - ## ✍️ Action required + ## Action required Describe any user facing actions here, or delete this block. - ## 💸 Features and improvements + ## Features and improvements Describe any user facing changes here, or delete this block. Examples of user facing changes: diff --git a/.github/workflows/release-please.yaml b/.github/workflows/release-please.yaml index 1b096b900e..f7a6df1a8c 100644 --- a/.github/workflows/release-please.yaml +++ b/.github/workflows/release-please.yaml @@ -1,5 +1,5 @@ --- -name: release-please +name: Unified Release on: push: @@ -20,6 +20,9 @@ jobs: release_created: ${{ steps.release-please.outputs.release_created }} tag_name: ${{ steps.release-please.outputs.tag_name }} version: ${{ steps.release-please.outputs.version }} + major: ${{ steps.release-please.outputs.major }} + minor: ${{ steps.release-please.outputs.minor }} + patch: ${{ steps.release-please.outputs.patch }} steps: - name: Release Please id: release-please @@ -27,9 +30,50 @@ jobs: with: token: ${{ secrets.WEAVE_GITOPS_BOT_ACCESS_TOKEN }} - publish-npm-package: + validate-versions: needs: release-please runs-on: ubuntu-latest + if: "${{ needs.release-please.outputs.release_created }}" + steps: + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Validate chart version synchronization + run: | + APP_VERSION="${{ needs.release-please.outputs.version }}" + CHART_APP_VERSION=$(yq e '.appVersion' charts/gitops-server/Chart.yaml) + CHART_VERSION=$(yq e '.version' charts/gitops-server/Chart.yaml) + IMAGE_TAG=$(yq e '.image.tag' charts/gitops-server/values.yaml) + + echo "Application Version: $APP_VERSION" + echo "Chart AppVersion: $CHART_APP_VERSION" + echo "Chart Version: $CHART_VERSION" + echo "Image Tag: $IMAGE_TAG" + + # Validate that chart appVersion matches application version + if [[ "$CHART_APP_VERSION" != "$APP_VERSION" ]]; then + echo "Error: Chart appVersion ($CHART_APP_VERSION) does not match application version ($APP_VERSION)" + exit 1 + fi + + # Validate that image tag matches application version + if [[ "$IMAGE_TAG" != "$APP_VERSION" ]]; then + echo "Error: Image tag ($IMAGE_TAG) does not match application version ($APP_VERSION)" + exit 1 + fi + + # Validate that chart version follows expected pattern (remove 'v' prefix from app version) + EXPECTED_CHART_VERSION=$(echo "$APP_VERSION" | sed 's/^v//') + if [[ "$CHART_VERSION" != "$EXPECTED_CHART_VERSION" ]]; then + echo "Error: Chart version ($CHART_VERSION) does not match expected version ($EXPECTED_CHART_VERSION)" + exit 1 + fi + + echo "All versions are synchronized correctly" + + publish-npm-package: + needs: [release-please, validate-versions] + runs-on: ubuntu-latest permissions: packages: write # needed for GitHub Packages registry access if: "${{ needs.release-please.outputs.release_created }}" @@ -48,7 +92,7 @@ jobs: NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} build-and-push-image: - needs: release-please + needs: [release-please, validate-versions] uses: ./.github/workflows/build-push-image.yaml with: file: gitops-server.dockerfile @@ -67,40 +111,73 @@ jobs: if: "${{ needs.release-please.outputs.release_created }}" build-and-push-chart: - needs: - - release-please - - build-and-push-image # as we want to push chart when images are available + needs: [release-please, validate-versions, build-and-push-image] runs-on: ubuntu-latest permissions: contents: read # for actions/checkout to fetch code id-token: write # for Cosign to be able to sign chart with GHA token packages: write # for helm to push OCI chart - if: "${{ needs.release-please.outputs['charts/gitops-server--release_created'] }}" + if: "${{ needs.release-please.outputs.release_created }}" steps: - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Validate chart before packaging + run: | + APP_VERSION="${{ needs.release-please.outputs.version }}" + CHART_VERSION=$(yq e '.version' charts/gitops-server/Chart.yaml) + + echo "Packaging chart version: $CHART_VERSION for app version: $APP_VERSION" + + # Validate chart syntax + helm lint charts/gitops-server/ + - name: Package chart run: | mkdir helm-release helm package charts/gitops-server/ -d helm-release + + # List packaged chart for verification + ls -la helm-release/ + - name: Log in to the Container registry uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Publish chart id: publish-chart run: | - helm push helm-release/weave-gitops-${{ needs.release-please.outputs['charts/gitops-server--version'] }}.tgz \ - oci://ghcr.io/weaveworks/charts &> helm-release/push-metadata.txt + CHART_VERSION=$(yq e '.version' charts/gitops-server/Chart.yaml) + CHART_FILE="helm-release/weave-gitops-${CHART_VERSION}.tgz" + + if [[ ! -f "$CHART_FILE" ]]; then + echo "Error: Chart file $CHART_FILE not found" + ls -la helm-release/ + exit 1 + fi + + echo "Publishing chart: $CHART_FILE" + helm push "$CHART_FILE" oci://ghcr.io/weaveworks/charts &> helm-release/push-metadata.txt + + # Extract digest for signing CHART_DIGEST=$(awk '/Digest: /{print $2}' helm-release/push-metadata.txt) + echo "Chart digest: $CHART_DIGEST" echo "digest=$CHART_DIGEST" >> $GITHUB_OUTPUT + + # Display push metadata for debugging + echo "Push metadata:" + cat helm-release/push-metadata.txt + - name: Install cosign uses: sigstore/cosign-installer@398d4b0eeef1380460a10c8013a76f728fb906ac # v3.9.1 + - name: Keyless signing of chart run: | cosign sign --yes ghcr.io/weaveworks/charts@${{ steps.publish-chart.outputs.digest }} + - name: Verify the chart signing run: | cosign verify ghcr.io/weaveworks/charts@${{ steps.publish-chart.outputs.digest }} \ @@ -108,7 +185,7 @@ jobs: --certificate-oidc-issuer "https://token.actions.githubusercontent.com" | jq . goreleaser: - needs: release-please + needs: [release-please, validate-versions] runs-on: ubuntu-latest permissions: contents: read # for actions/checkout to fetch code @@ -136,3 +213,28 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.WEAVE_GITOPS_BOT_ACCESS_TOKEN }} BOT_TOKEN: ${{ secrets.WEAVE_GITOPS_BOT_ACCESS_TOKEN }} + + create-release-summary: + needs: [release-please, validate-versions, publish-npm-package, build-and-push-image, build-and-push-chart, goreleaser] + runs-on: ubuntu-latest + if: "${{ needs.release-please.outputs.release_created }}" + steps: + - name: Create release summary + run: | + echo "# Release Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Version:** ${{ needs.release-please.outputs.version }}" >> $GITHUB_STEP_SUMMARY + echo "**Tag:** ${{ needs.release-please.outputs.tag_name }}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "## Components Released" >> $GITHUB_STEP_SUMMARY + echo "- Application binaries (GoReleaser)" >> $GITHUB_STEP_SUMMARY + echo "- Container images (ghcr.io/weaveworks/wego-app)" >> $GITHUB_STEP_SUMMARY + echo "- Helm chart (ghcr.io/weaveworks/charts)" >> $GITHUB_STEP_SUMMARY + echo "- NPM package (@weaveworks scope)" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "## Version Synchronization" >> $GITHUB_STEP_SUMMARY + echo "All components have been released with synchronized versions:" >> $GITHUB_STEP_SUMMARY + echo "- Application: ${{ needs.release-please.outputs.version }}" >> $GITHUB_STEP_SUMMARY + echo "- Chart AppVersion: ${{ needs.release-please.outputs.version }}" >> $GITHUB_STEP_SUMMARY + echo "- Chart Version: $(echo '${{ needs.release-please.outputs.version }}' | sed 's/^v//')" >> $GITHUB_STEP_SUMMARY + echo "- Image Tag: ${{ needs.release-please.outputs.version }}" >> $GITHUB_STEP_SUMMARY diff --git a/.gitignore b/.gitignore index 5a532bb226..90ac8c6ad9 100644 --- a/.gitignore +++ b/.gitignore @@ -23,7 +23,7 @@ localhost.pem # Ignore generated credentials from google-github-actions/auth gha-creds-*.json - +tasks/*.md # Ignore VIM's swap files *.swp diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 5385d5642e..67924d8ef6 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,4 +1,3 @@ { - ".": "0.39.0-rc.2", - "charts/gitops-server": "4.0.36" + ".": "0.39.0-rc.2" } diff --git a/charts/gitops-server/Chart.yaml b/charts/gitops-server/Chart.yaml index 0daafc40d6..6b4bfdcf2c 100644 --- a/charts/gitops-server/Chart.yaml +++ b/charts/gitops-server/Chart.yaml @@ -13,7 +13,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 4.0.36 +version: 0.39.0-rc.2 # x-release-please-version # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. diff --git a/release-please-config.json b/release-please-config.json index afbb8bada0..1f2d20996a 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -5,13 +5,25 @@ "bootstrap-sha": "76f25bbb1d20aa41a1f78920344f579af4f88e2d", "bump-minor-pre-major": true, "exclude-paths": [ - "charts", "doc", "website" ], "extra-files": [ - "charts/gitops-server/Chart.yaml", - "charts/gitops-server/values.yaml", + { + "type": "yaml", + "path": "charts/gitops-server/Chart.yaml", + "jsonpath": "$.appVersion" + }, + { + "type": "yaml", + "path": "charts/gitops-server/Chart.yaml", + "jsonpath": "$.version" + }, + { + "type": "yaml", + "path": "charts/gitops-server/values.yaml", + "jsonpath": "$.image.tag" + }, "README.md" ], "include-component-in-tag": false, @@ -19,18 +31,11 @@ "prerelease-type": "rc", "release-as": "0.39.0-rc.3", "release-type": "node" - }, - "charts/gitops-server": { - "bootstrap-sha": "693dafd494f1027c4bc740be9ffef98e21cdcfb6", - "prerelease": true, - "prerelease-type": "rc", - "release-as": "4.1.0-rc.1", - "release-type": "helm" } }, "plugins": [ "sentence-case" ], - "separate-pull-requests": true, + "separate-pull-requests": false, "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json" }