Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 56 additions & 25 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -710,41 +710,62 @@ jobs:
fail-fast: false
matrix:
include:
- name: quickstart
# test-image-refresh validates the local build → k3d load →
# rollout restart chain, so it must run against a locally built
# image: unset PROJECT_IMAGE (the CI-built image doesn't rebuild
# from source) and force load delivery. Fork-safe: the chain never
# touches a registry.
#
# cleanup-installs.sh between the two: the helm quickstart just
# installed with the *provided* image ref, and install stamps do
# not invalidate on an image-ref change — without the reset the
# refresh suite would keep restarting a deployment that still
# points at the provided tag and never runs the local rebuilds.
# Functional suite, sharded across two runners (was the single `full`
# lane). The two label filters are exact complements within the old
# `!image-refresh` filter — `manager` ∪ `!manager && !image-refresh`
# equals what `full` ran — so no spec is added or dropped, the work is
# just split across two clusters. The membership is a provisional
# first cut; rebalance from the e2e-ginkgo-reports-* per-spec timings
# (docs/design/e2e-ci-runner-sharding-plan.md, "balance from real data").
# Each shard runs config-dir installs (GOCOVERDIR overlay) and collects
# coverage; Codecov unions same-flag `e2e` uploads, so merged coverage
# is the union of both shards — the non-regression ratchet still holds.
- name: full-manager
script: "task test-e2e"
e2e_label_filter: "manager"
e2e_report_name: "full-manager"
needs_artifact: false
coverage: "1"
# Bumped 1 -> 4: the full suite was serialized to avoid the
# cross-target rule-change snapshot coupling, now fixed (per-target
# effective watch plan — docs/design/gittarget-isolation-on-rule-change.md).
e2e_ginkgo_procs: "4"
k3d_agent_count: "0"
- name: full-core
script: "task test-e2e"
e2e_label_filter: "!manager && !image-refresh"
e2e_report_name: "full-core"
needs_artifact: false
coverage: "1"
e2e_ginkgo_procs: "4"
k3d_agent_count: "0"
# Quickstart chain, sharded across two runners (was the single
# `quickstart` lane). quickstart-install runs the two install-mode
# validations on one cluster (cleanup-installs.sh resets the namespace
# between them, since install stamps don't invalidate on an image-ref
# change). image-refresh gets its own runner: it validates the local
# build → k3d load → rollout restart chain, so it must run against a
# locally built image — unset PROJECT_IMAGE and force load delivery.
# Fork-safe: neither leg pushes to a registry. Helm/manifest installs
# don't carry the GOCOVERDIR overlay, so these legs collect no coverage.
- name: quickstart-install
script: >-
export INSTALL_MODE=helm HELM_CHART_SOURCE=./gitops-reverser.tgz
&& task test-e2e-quickstart-helm
&& bash hack/cleanup-installs.sh k3d-gitops-reverser-test-e2e
&& env -u PROJECT_IMAGE IMAGE_DELIVERY_MODE=load task test-image-refresh
&& export INSTALL_MODE=plain-manifests-file
&& task test-e2e-quickstart-manifest
needs_artifact: true
coverage: ""
e2e_ginkgo_procs: "2"
k3d_agent_count: "0"
# Helm/manifest installs don't carry the GOCOVERDIR overlay, so no
# coverage is collected here.
- name: image-refresh
script: >-
export INSTALL_MODE=helm HELM_CHART_SOURCE=./gitops-reverser.tgz
&& env -u PROJECT_IMAGE IMAGE_DELIVERY_MODE=load task test-image-refresh
needs_artifact: true
coverage: ""
- name: full
script: "task test-e2e"
needs_artifact: false
# config-dir install carries the GOCOVERDIR overlay; collect e2e coverage.
coverage: "1"
# Bumped 1 -> 4: the full suite was serialized to avoid the
# cross-target rule-change snapshot coupling, now fixed (per-target
# effective watch plan — docs/design/gittarget-isolation-on-rule-change.md).
# Validated locally at --procs=4; trialing the same in CI.
e2e_ginkgo_procs: "4"
e2e_ginkgo_procs: "2"
k3d_agent_count: "0"
env:
PROJECT_IMAGE: ${{ needs.build.outputs.image }}
Expand Down Expand Up @@ -859,6 +880,14 @@ jobs:
"

- name: Run E2E tests in CI container
# E2E_LABEL_FILTER / E2E_REPORT_NAME are passed through by name (not
# value) so the shell never sees the filter's spaces or `&&` — GitHub
# sets them as process env vars and `docker run -e VAR` forwards them.
# They're only consumed by `task test-e2e` (the functional shards); the
# quickstart legs leave them empty and ignore them.
env:
E2E_LABEL_FILTER: ${{ matrix.e2e_label_filter }}
E2E_REPORT_NAME: ${{ matrix.e2e_report_name }}
run: |
docker run --rm \
--network host \
Expand All @@ -868,6 +897,8 @@ jobs:
-e PROJECT_IMAGE=${{ env.PROJECT_IMAGE }} \
-e IMAGE_DELIVERY_MODE=${{ env.IMAGE_DELIVERY_MODE }} \
-e E2E_GINKGO_PROCS=${{ matrix.e2e_ginkgo_procs }} \
-e E2E_LABEL_FILTER \
-e E2E_REPORT_NAME \
-e K3D_AGENT_COUNT=${{ matrix.k3d_agent_count }} \
-e HOST_PROJECT_PATH=${{ github.workspace }} \
-e KUBECONFIG=${{ env.CI_WORKDIR }}/.stamps/cluster/k3d-gitops-reverser-test-e2e/.kube/config \
Expand Down
40 changes: 40 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,11 @@ jobs:
uses: softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3.0.1
with:
tag_name: ${{ needs.release-please.outputs.tag_name }}
# Keep the release a draft: GitHub's immutable-releases enforcement
# forbids adding assets once a release is published, so every asset
# must land while it is still a draft. The publish-release job flips
# it to published after all assets are attached.
draft: true
append_body: true
files: sbom.spdx.json
body: |
Expand Down Expand Up @@ -260,13 +265,48 @@ jobs:
- name: Install cosign
uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2

- name: Log in to registry for cosign
# `helm registry login` writes helm's own registry config; cosign reads
# ~/.docker/config.json, so it needs its own login or the signature
# upload fails with UNAUTHORIZED.
env:
COSIGN_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COSIGN_USER: ${{ github.actor }}
run: cosign login "${REGISTRY}" --username "${COSIGN_USER}" --password "${COSIGN_TOKEN}"

- name: Sign the Helm chart (cosign keyless)
run: cosign sign --yes "${CHART_REGISTRY}/gitops-reverser@${{ steps.chart.outputs.digest }}"

- name: Upload install.yaml as release asset
uses: softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3.0.1
with:
tag_name: ${{ needs.release-please.outputs.tag_name }}
# Attach to the still-draft release; publish-release publishes it once
# every asset is in place (immutable releases reject post-publish
# uploads).
draft: true
files: dist/install.yaml
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

# Publish the release only after every asset is attached. release-please
# creates the GitHub release as a draft (see release-please-config.json);
# GitHub's immutable-releases enforcement freezes a release the moment it is
# published, so publish-manifest and publish-helm attach their assets to the
# draft and this job flips it to published at the very end. If either publish
# job fails, the release stays an unpublished draft instead of a
# half-populated immutable release.
publish-release:
name: Publish GitHub Release
runs-on: ubuntu-latest
timeout-minutes: 10
needs: [release-please, publish-manifest, publish-helm]
if: needs.release-please.outputs.release_created == 'true'
permissions:
contents: write # publish the draft release (creates the tag)
steps:
- name: Publish the draft release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG_NAME: ${{ needs.release-please.outputs.tag_name }}
run: gh release edit "${TAG_NAME}" --draft=false --repo "${{ github.repository }}"
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
[![CI](https://github.com/ConfigButler/gitops-reverser/actions/workflows/release.yml/badge.svg?branch=main)](https://github.com/ConfigButler/gitops-reverser/actions/workflows/release.yml)
[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/ConfigButler/gitops-reverser/badge)](https://scorecard.dev/viewer/?uri=github.com/ConfigButler/gitops-reverser)
[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/13468/badge)](https://www.bestpractices.dev/projects/13468)
[![Release](https://img.shields.io/github/v/release/ConfigButler/gitops-reverser?sort=semver)](https://github.com/ConfigButler/gitops-reverser/releases)
[![License](https://img.shields.io/github/license/ConfigButler/gitops-reverser)](https://www.apache.org/licenses/LICENSE-2.0)
[![Go](https://img.shields.io/badge/go-1.26-blue?logo=go)](go.mod)
[![Platforms](https://img.shields.io/badge/platforms-amd64%20%7C%20arm64-2ea44f?logo=docker)](#)
[![Go Report Card](https://goreportcard.com/badge/github.com/ConfigButler/gitops-reverser)](https://goreportcard.com/report/github.com/ConfigButler/gitops-reverser)
[![codecov](https://codecov.io/gh/ConfigButler/gitops-reverser/graph/badge.svg)](https://codecov.io/gh/ConfigButler/gitops-reverser)
[![Container](https://img.shields.io/badge/container-ghcr.io%2Fconfigbutler%2Fgitops--reverser-2ea44f?logo=docker)](https://github.com/ConfigButler/gitops-reverser/pkgs/container/gitops-reverser)
[![Open Issues](https://img.shields.io/github/issues/ConfigButler/gitops-reverser)](https://github.com/ConfigButler/gitops-reverser/issues)
Expand Down
Loading