diff --git a/.github/release-please-config.json b/.github/release-please-config.json new file mode 100644 index 0000000000..28281accc0 --- /dev/null +++ b/.github/release-please-config.json @@ -0,0 +1,46 @@ +{ + "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "packages": { + "weave-gitops": { + "release-type": "go", + "changelog-path": "CHANGELOG.md", + "version-file": "go.mod", + "extra-files": [ + "package.json", + "charts/gitops-server/Chart.yaml", + "charts/gitops-server/values.yaml" + ], + "bump-minor-pre-major": true, + "include-v-in-tag": true, + "extra-changelog-sections": [ + { + "type": "feat", + "section": "## ๐Ÿš€ Enhancements" + }, + { + "type": "fix", + "section": "## ๐Ÿ› Bug Fixes" + }, + { + "type": "docs", + "section": "## ๐Ÿ“– Documentation" + }, + { + "type": "refactor", + "section": "## ๐Ÿ”ง Refactoring" + }, + { + "type": "test", + "section": "## ๐Ÿงช Testing" + }, + { + "type": "chore", + "section": "## ๐Ÿ› ๏ธ Maintenance", + "hidden": true + } + ], + "pr-header": "chore", + "package-name": "weave-gitops" + } + } +} diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index ace32c6537..da5e47dbde 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -1,3 +1,5 @@ +name: PR CI + on: push: branches: @@ -12,12 +14,12 @@ concurrency: cancel-in-progress: ${{ github.event_name == 'pull_request' }} permissions: - contents: read # for actions/checkout to fetch code + contents: read -name: PR CI Workflow jobs: - ci-js: - name: CI Test JS + # Test JavaScript/UI + test-js: + name: Test JavaScript runs-on: ubuntu-latest steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 @@ -27,11 +29,8 @@ jobs: node-version-file: package.json cache: yarn - run: make node_modules - - name: Check that package.json & package-lock.json were updated in commit - run: | - echo "Using node.js "$(node --version) - echo "Using Yarn "$(yarn --version) - git diff --no-ext-diff --exit-code + - name: Verify package files + run: git diff --no-ext-diff --exit-code - run: make ui-audit - run: make ui - run: make ui-lint @@ -39,8 +38,9 @@ jobs: - run: make ui-test - run: make ui-lib - ci-go: - name: CI Test Go + # Test Go code + test-go: + name: Test Go runs-on: ubuntu-latest steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 @@ -52,8 +52,9 @@ jobs: uses: fluxcd/flux2/action@4a15fa6a023259353ef750acf1c98fe88407d4d0 # v2.7.2 - run: make unit-tests - ci-static: - name: CI Check Static Checks + # Static analysis and code quality + lint: + name: Lint and format check runs-on: ubuntu-latest steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 @@ -64,118 +65,32 @@ jobs: - run: make check-format - run: make lint - run: go mod tidy - - name: Check that go mod tidy has been run + - name: Verify go mod tidy run: git diff --no-ext-diff --exit-code - run: make proto - - name: Check that make proto has been run + - name: Verify proto generation run: git diff --no-ext-diff --exit-code - run: make fakes - - name: Check that make fakes has been run + - name: Verify fakes generation run: git diff --no-ext-diff --exit-code - build-push-image: - name: CI Build Image + # Build Docker images (but don't push on PRs) + build-images: + name: Build Docker Images uses: ./.github/workflows/build-push-image.yaml with: file: ${{ matrix.docker-image }}.dockerfile image: ghcr.io/${{ github.repository }}/${{ matrix.docker-image }} - push: ${{ github.event_name != 'pull_request' && github.repository == 'weaveworks/weave-gitops' }} + push: ${{ github.event_name != 'pull_request' }} tags: | type=ref,event=branch type=ref,event=pr permissions: - contents: read # for actions/checkout to fetch code - id-token: write # for Cosign to be able to sign images with GHA token - packages: write # for docker/build-push-action to push images + contents: read + id-token: write + packages: write strategy: matrix: docker-image: - gitops - - gitops-server - - ci-upload-binary: - name: Upload Binary - Disabled - runs-on: ${{ matrix.os }} - needs: [ci-go, ci-static, ci-js] - strategy: - matrix: - os: [ubuntu-latest, macOS-latest] - if: ${{ github.event_name != 'pull_request' && github.repository == 'weaveworks/weave-gitops' }} - steps: - - name: Checkout code - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - name: Setup Go - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 - with: - go-version-file: go.mod - - name: Clean - run: make clean - - id: gitsha - run: | - gitsha=$(git rev-parse --short ${{ github.sha }}) - echo "sha=$gitsha" >> $GITHUB_OUTPUT - - name: build - run: | - make gitops - - name: Upload binary - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: gitops-${{ matrix.os }}-${{ steps.gitsha.outputs.sha }} - path: bin/gitops - overwrite: true - - ci-publish-js-lib: - name: Publish js library - runs-on: ubuntu-latest - if: "${{ github.repository_owner == 'weaveworks' && github.ref_name == 'main'}}" - needs: [ci-js] - permissions: - packages: write - outputs: - js-version: ${{ steps.package-version.outputs.js-version }} - steps: - - name: Checkout - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - with: - # avoid the merge commit that on.pull_request creates - # fallback to github.sha if not present (e.g. on.push(main)) - # https://github.com/actions/checkout#checkout-pull-request-head-commit-instead-of-merge-commit - # We want the correct sha so we can tag the npm package correctly - ref: ${{ github.event.pull_request.head.sha || github.sha }} - fetch-depth: 0 - - name: Setup Node.js - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 - with: - node-version-file: package.json - registry-url: "https://npm.pkg.github.com" - scope: "@weaveworks" - - run: yarn - - run: make ui-lib - - name: Update package version - id: package-version - run: | - GITOPS_VERSION=$(git describe) - echo "js-version=$GITOPS_VERSION" >> $GITHUB_OUTPUT - jq '.version = "'$GITOPS_VERSION'" | .name = "@weaveworks/weave-gitops-main"' < dist/package.json > dist/package-new.json - mv dist/package-new.json dist/package.json - cp .npmrc dist - - run: cd dist && npm publish - env: - NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - # release step updates 'release' status check for non releases branches. See ../../doc/incidents/issues-3907 for full context. - release: - if: ${{ github.event_name == 'pull_request' && !startsWith(github.event.pull_request.head.ref, 'releases/') && !github.event.pull_request.head.repo.fork }} - runs-on: ubuntu-latest - steps: - - name: Release - run: | - curl --fail --request POST \ - --url https://api.github.com/repos/${{ github.repository }}/statuses/${{ github.event.pull_request.head.sha }} \ - --header 'authorization: Bearer ${{ secrets.WEAVE_GITOPS_BOT_ACCESS_TOKEN }}' \ - --header 'content-type: application/json' \ - --data '{ - "state":"success", - "description":"release not required", - "context":"release" - }' + - gitops-server \ No newline at end of file diff --git a/.github/workflows/release-please.yaml b/.github/workflows/release-please.yaml index cf651108bc..73426ea0a3 100644 --- a/.github/workflows/release-please.yaml +++ b/.github/workflows/release-please.yaml @@ -1,5 +1,4 @@ ---- -name: release-please +name: Release Please on: push: @@ -7,234 +6,147 @@ on: - main permissions: - contents: read + contents: write + pull-requests: write jobs: + # This job creates or updates the release PR based on conventional commits release-please: runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write - if: "${{ github.repository_owner == 'weaveworks' && github.ref_name == 'main' }}" + if: ${{ github.repository_owner == 'weaveworks' }} outputs: - 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 }} + release_created: ${{ steps.release-please.outputs.release_created }} + release_pr: ${{ steps.release-please.outputs.release_pr }} steps: + - name: Checkout + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - name: Release Please id: release-please uses: googleapis/release-please-action@c2a5a2bd6a758a0937f1ddb1e8950609867ed15c # v4.3.0 with: token: ${{ secrets.WEAVE_GITOPS_BOT_ACCESS_TOKEN }} + config-file: .github/release-please-config.json - validate-versions: + # This job publishes the release after the release PR is merged + publish-release: needs: release-please runs-on: ubuntu-latest - if: "${{ needs.release-please.outputs.release_created }}" - steps: - - name: Checkout - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - - 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 + if: ${{ needs.release-please.outputs.release_created == 'true' }} permissions: - packages: write # needed for GitHub Packages registry access - if: "${{ needs.release-please.outputs.release_created }}" + contents: write + id-token: write + packages: write steps: + - name: Extract version info + id: version + run: | + VERSION="${{ needs.release-please.outputs.version }}" + echo "version=${VERSION#v}" >> $GITHUB_OUTPUT + echo "tag=v${VERSION#v}" >> $GITHUB_OUTPUT + echo "Publishing release: v${VERSION#v}" + - name: Checkout uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + fetch-depth: 0 + + - name: Setup Go + uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 + with: + go-version-file: go.mod + - name: Setup Node.js uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 with: node-version-file: package.json registry-url: "https://npm.pkg.github.com" scope: "@weaveworks" - - run: yarn - - run: make ui-lib && cd dist && npm publish + + # Run GoReleaser to create binaries and GitHub Release + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0 + with: + version: latest + args: release --clean --skip=validate env: - NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - build-and-push-image: - needs: [release-please, validate-versions] - uses: ./.github/workflows/build-push-image.yaml - with: - file: gitops-server.dockerfile - flavor: | - latest=true - image: ghcr.io/weaveworks/wego-app - platforms: linux/amd64,linux/arm64 - push: true - tags: | - type=raw,value=${{ needs.release-please.outputs.tag_name }} - type=semver,pattern={{version}},value=${{ needs.release-please.outputs.version }} - permissions: - contents: read # for actions/checkout to fetch code - id-token: write # for Cosign to be able to sign images with GHA token - packages: write # for docker/build-push-action to push images - if: "${{ needs.release-please.outputs.release_created }}" - - build-and-push-chart: - 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.release_created }}" - steps: - - name: Checkout - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + GITHUB_TOKEN: ${{ secrets.WEAVE_GITOPS_BOT_ACCESS_TOKEN }} + FLUX_VERSION: $(make echo-flux-version) + + # Build and push Docker images + - name: Build and push Docker image + uses: docker/build-push-action@0adf9959216b96bec444f325f1e493d4aa344497 # v6.14.0 + with: + context: . + file: gitops-server.dockerfile + platforms: linux/amd64,linux/arm64 + push: true + tags: | + ghcr.io/weaveworks/wego-app:${{ steps.version.outputs.tag }} + ghcr.io/weaveworks/wego-app:latest + build-args: | + FLUX_VERSION=$(make echo-flux-version) + labels: | + org.opencontainers.image.version=${{ steps.version.outputs.tag }} + org.opencontainers.image.revision=${{ github.sha }} + cache-from: type=gha + cache-to: type=gha,mode=max - - name: Validate chart before packaging + # Sign Docker image + - name: Install cosign + uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0 + + - name: Sign Docker image 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 + cosign sign --yes ghcr.io/weaveworks/wego-app:${{ steps.version.outputs.tag }} + + # Publish NPM package + - name: Publish NPM package run: | - mkdir helm-release + yarn + make ui-lib + jq '.version = "'${{ steps.version.outputs.version }}'"' < dist/package.json > dist/package.tmp && mv dist/package.tmp dist/package.json + cp .npmrc dist + cd dist && npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + # Build and publish Helm chart + - name: Package Helm chart + run: | + mkdir -p 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 + + - name: Login to GHCR uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - - name: Publish chart - id: publish-chart + + - name: Push Helm chart run: | 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@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0 - - - name: Keyless signing of chart - run: | - cosign sign --yes ghcr.io/weaveworks/charts@${{ steps.publish-chart.outputs.digest }} - - - name: Verify the chart signing + helm push helm-release/weave-gitops-${CHART_VERSION}.tgz oci://ghcr.io/weaveworks/charts + + - name: Sign Helm chart run: | - cosign verify ghcr.io/weaveworks/charts@${{ steps.publish-chart.outputs.digest }} \ - --certificate-identity "https://github.com/${{ github.workflow_ref }}" \ - --certificate-oidc-issuer "https://token.actions.githubusercontent.com" | jq . - - goreleaser: - needs: [release-please, validate-versions] - runs-on: ubuntu-latest - permissions: - contents: read # for actions/checkout to fetch code - id-token: write # for Cosign to be able to sign release artifacts with GHA token - if: "${{ needs.release-please.outputs.release_created }}" - steps: - - name: Checkout - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - with: - fetch-depth: 0 - - name: Setup Go - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 - with: - go-version-file: go.mod - - name: Include brew publishing - run: cat .goreleaser.brew.yml >> .goreleaser.yml - if: ${{ !contains(needs.release-please.outputs.version, '-') }} - - name: Install cosign - uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0 - - name: Run GoReleaser - uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0 - with: - version: latest - args: release --clean - 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: + CHART_VERSION=$(yq e '.version' charts/gitops-server/Chart.yaml) + helm push helm-release/weave-gitops-${CHART_VERSION}.tgz oci://ghcr.io/weaveworks/charts 2>&1 | tee chart-digest.txt + DIGEST=$(grep Digest chart-digest.txt | awk '{print $2}') + cosign sign --yes ghcr.io/weaveworks/charts@${DIGEST} + + # Note: Website versioning is handled by Release Please config + # The docs workflow will automatically build and deploy when main is updated + - 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 + echo "**Version:** ${{ steps.version.outputs.tag }}" >> $GITHUB_STEP_SUMMARY + echo "**Components Released:**" >> $GITHUB_STEP_SUMMARY + echo "- Binaries (GoReleaser)" >> $GITHUB_STEP_SUMMARY + echo "- Docker images" >> $GITHUB_STEP_SUMMARY + echo "- Helm chart" >> $GITHUB_STEP_SUMMARY + echo "- NPM package" >> $GITHUB_STEP_SUMMARY