Skip to content

Commit

Permalink
Add release workflow
Browse files Browse the repository at this point in the history
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
  • Loading branch information
stefanprodan committed May 29, 2024
1 parent 4136e0a commit 162a5dd
Show file tree
Hide file tree
Showing 8 changed files with 167 additions and 64 deletions.
3 changes: 0 additions & 3 deletions .dockerignore

This file was deleted.

119 changes: 119 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
name: release
on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
tag:
description: 'image tag prefix'
default: 'rc'
required: true

permissions:
contents: read

env:
CONTROLLER: ${{ github.event.repository.name }}

jobs:
release:
outputs:
image_url: ${{ steps.slsa.outputs.image_url }}
image_digest: ${{ steps.slsa.outputs.image_digest }}
runs-on: ubuntu-latest
permissions:
contents: write # for creating the GitHub release.
id-token: write # for creating OIDC tokens for signing.
packages: write # for pushing and signing container images.
steps:
- name: Checkout
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- name: Setup Kustomize
uses: fluxcd/pkg/actions/kustomize@main
- name: Prepare
id: prep
run: |
VERSION="${{ github.event.inputs.tag }}-${GITHUB_SHA::8}"
if [[ $GITHUB_REF == refs/tags/* ]]; then
VERSION=${GITHUB_REF/refs\/tags\//}
fi
echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT
echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT
- name: Setup QEMU
uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # v3.0.0
- name: Setup Docker Buildx
id: buildx
uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb # v3.3.0
- name: Login to GitHub Container Registry
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Generate images meta
id: meta
uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.1
with:
images: |
ghcr.io/controlplaneio-fluxcd/${{ env.CONTROLLER }}
tags: |
type=raw,value=${{ steps.prep.outputs.VERSION }}
- name: Publish images
id: build-push
uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 # v5.3.0
with:
sbom: true
provenance: true
push: true
builder: ${{ steps.buildx.outputs.name }}
context: .
file: ./Dockerfile
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
- uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 # v3.5.0
- name: Sign images
env:
COSIGN_EXPERIMENTAL: 1
run: |
cosign sign --yes ghcr.io/controlplaneio-fluxcd/${{ env.CONTROLLER }}@${{ steps.build-push.outputs.digest }}
- name: Create release
if: startsWith(github.ref, 'refs/tags/v')
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release create ${{ github.ref_name }} --generate-notes --verify-tag
- name: Upload release artifacts
if: startsWith(github.ref, 'refs/tags/v')
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
mkdir -p config/release
kustomize build ./config/default > ./config/release/install.yaml
gh release upload ${{ github.ref_name }} ./config/release/install.yaml
- name: Generate SLSA metadata
id: slsa
run: |
image_url=fluxcd/${{ env.CONTROLLER }}:${{ steps.prep.outputs.version }}
echo "image_url=$image_url" >> $GITHUB_OUTPUT
image_digest=${{ steps.build-push.outputs.digest }}
echo "image_digest=$image_digest" >> $GITHUB_OUTPUT
ghcr-provenance:
needs: [release]
permissions:
actions: read # for detecting the Github Actions environment.
id-token: write # for creating OIDC tokens for signing.
packages: write # for uploading attestations.
if: startsWith(github.ref, 'refs/tags/v')
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.0.0
with:
image: ghcr.io/${{ needs.release.outputs.image_url }}
digest: ${{ needs.release.outputs.image_digest }}
registry-username: ${{ github.actor }}
secrets:
registry-password: ${{ secrets.GITHUB_TOKEN }}
28 changes: 13 additions & 15 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,34 +1,32 @@
# Build the manager binary
FROM golang:1.22 AS builder
# Build the operator binary using the Docker's Debian image.
FROM --platform=${BUILDPLATFORM} golang:1.22 AS builder
ARG TARGETOS
ARG TARGETARCH

WORKDIR /workspace
# Copy the Go Modules manifests

# Copy the Go Modules manifests.
COPY go.mod go.mod
COPY go.sum go.sum
# cache deps before building and copying source so that we don't need to re-download as much
# and so that source changes don't invalidate our downloaded layer

# Cache the Go Modules
RUN go mod download

# Copy the go source
# Copy the Go sources.
COPY cmd/main.go cmd/main.go
COPY api/ api/
COPY internal/ internal/

# Build
# the GOARCH has not a default value to allow the binary be built according to the host where the command
# was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO
# the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore,
# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform.
# Build the operator binary.
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o flux-operator cmd/main.go

# Use distroless as minimal base image to package the manager binary
# Refer to https://github.com/GoogleContainerTools/distroless for more details
# Run the operator binary using Google's Distroless image.
FROM gcr.io/distroless/static:nonroot
WORKDIR /

# Copy the binary and manifests data.
COPY --from=builder /workspace/flux-operator .
COPY data/ /data/
USER 65532:65532

# Run the operator as a non-root user.
USER 65532:65532
ENTRYPOINT ["/flux-operator"]
43 changes: 17 additions & 26 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
# Makefile for building, testing, and deploying the Flux Operator.

# Image URL to use all building/pushing image targets
IMG ?= flux-operator:latest
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
IMG ?= ghcr.io/controlplaneio-fluxcd/flux-operator:latest

# ENVTEST_K8S_VERSION refers to the version of kubebuilder
# assets to be downloaded by envtest binary.
ENVTEST_K8S_VERSION = 1.30.0

# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
# Get the currently used golang install path
# (in GOPATH/bin, unless GOBIN is set).
ifeq (,$(shell go env GOBIN))
GOBIN=$(shell go env GOPATH)/bin
else
GOBIN=$(shell go env GOBIN)
endif

# CONTAINER_TOOL defines the container tool to be used for building images.
# Be aware that the target commands are only tested with Docker which is
# scaffolded by default. However, you might want to replace it to use other
# tools. (i.e. podman)
CONTAINER_TOOL ?= docker

# Setting SHELL to bash allows bash commands to be executed by recipes.
Expand All @@ -24,23 +26,6 @@ SHELL = /usr/bin/env bash -o pipefail
.PHONY: all
all: build

##@ General

# The help target prints out all targets with their descriptions organized
# beneath their categories. The categories are represented by '##@' and the
# target descriptions by '##'. The awk command is responsible for reading the
# entire set of makefiles included in this invocation, looking for lines of the
# file as xyz: ## something, and then pretty-format the target and help. Then,
# if there's a line with ##@ something, that gets pretty-printed as a category.
# More info on the usage of ANSI control characters for terminal formatting:
# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters
# More info on the awk command:
# http://linuxcommand.org/lc3_adv_awk.php

.PHONY: help
help: ## Display this help.
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)

##@ Development

.PHONY: manifests
Expand Down Expand Up @@ -73,11 +58,11 @@ test-e2e:
go test ./test/e2e/ -v -ginkgo.v

.PHONY: lint
lint: golangci-lint ## Run golangci-lint linter
lint: golangci-lint ## Run golangci-lint linter.
$(GOLANGCI_LINT) run

.PHONY: lint-fix
lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes
lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes.
$(GOLANGCI_LINT) run --fix

##@ Build
Expand Down Expand Up @@ -107,7 +92,7 @@ docker-push: ## Push docker image with the manager.

PLATFORMS ?= linux/arm64,linux/amd64
.PHONY: docker-buildx
docker-buildx: ## Build and push docker image for the manager for cross-platform support
docker-buildx: ## Build and push docker image for the manager for cross-platform support.
# copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile
sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross
- $(CONTAINER_TOOL) buildx create --name flux-operator-builder
Expand Down Expand Up @@ -199,3 +184,9 @@ GOBIN=$(LOCALBIN) go install $${package} ;\
mv "$$(echo "$(1)" | sed "s/-$(3)$$//")" $(1) ;\
}
endef

##@ General

.PHONY: help
help: ## Display this help.
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
2 changes: 2 additions & 0 deletions internal/controller/fluxinstance_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ func (r *FluxInstanceReconciler) reconcile(ctx context.Context,
return requeueAfter(obj), nil
}

// build reads the distribution manifests from the storage path,
// matches the version and builds the final resources.
func (r *FluxInstanceReconciler) build(ctx context.Context,
obj *fluxcdv1.FluxInstance) (*builder.Result, error) {
log := ctrl.LoggerFrom(ctx)
Expand Down
16 changes: 7 additions & 9 deletions test/e2e/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import (

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"github.com/controlplaneio-fluxcd/flux-operator/test/utils"
)

const (
Expand All @@ -26,16 +24,16 @@ var _ = BeforeSuite(func() {

By("building the flux-operator image")
cmd := exec.Command("make", "docker-build", fmt.Sprintf("IMG=%s", image))
_, err = utils.Run(cmd)
_, err = Run(cmd)
ExpectWithOffset(1, err).NotTo(HaveOccurred())

By("loading the flux-operator image on Kind")
err = utils.LoadImageToKindClusterWithName(image)
err = LoadImageToKindClusterWithName(image)
ExpectWithOffset(1, err).NotTo(HaveOccurred())

By("deploying flux-operator")
cmd = exec.Command("make", "deploy", fmt.Sprintf("IMG=%s", image))
_, err = utils.Run(cmd)
_, err = Run(cmd)
ExpectWithOffset(1, err).NotTo(HaveOccurred())

By("validating that the flux-operator pod is running as expected")
Expand All @@ -51,9 +49,9 @@ var _ = BeforeSuite(func() {
"-n", namespace,
)

podOutput, err := utils.Run(cmd)
podOutput, err := Run(cmd)
ExpectWithOffset(2, err).NotTo(HaveOccurred())
podNames := utils.GetNonEmptyLines(string(podOutput))
podNames := GetNonEmptyLines(string(podOutput))
if len(podNames) != 1 {
return fmt.Errorf("expect 1 flux-operator pods running, but got %d", len(podNames))
}
Expand All @@ -65,7 +63,7 @@ var _ = BeforeSuite(func() {
"pods", controllerPodName, "-o", "jsonpath={.status.phase}",
"-n", namespace,
)
status, err := utils.Run(cmd)
status, err := Run(cmd)
ExpectWithOffset(2, err).NotTo(HaveOccurred())
if string(status) != "Running" {
return fmt.Errorf("flux-operator pod in %s status", status)
Expand All @@ -79,6 +77,6 @@ var _ = BeforeSuite(func() {
var _ = AfterSuite(func() {
By("uninstalling flux-operator")
cmd := exec.Command("make", "undeploy")
_, err := utils.Run(cmd)
_, err := Run(cmd)
Expect(err).NotTo(HaveOccurred())
})
18 changes: 8 additions & 10 deletions test/e2e/instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import (

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"github.com/controlplaneio-fluxcd/flux-operator/test/utils"
)

var _ = Describe("FluxInstance", Ordered, func() {
Expand All @@ -21,13 +19,13 @@ var _ = Describe("FluxInstance", Ordered, func() {
cmd := exec.Command("kubectl", "apply",
"-k", "config/samples", "-n", namespace,
)
_, err := utils.Run(cmd)
_, err := Run(cmd)
ExpectWithOffset(2, err).NotTo(HaveOccurred())

cmd = exec.Command("kubectl", "wait", "FluxInstance/flux", "-n", namespace,
"--for=condition=Ready", "--timeout=5m",
)
_, err = utils.Run(cmd)
_, err = Run(cmd)
ExpectWithOffset(2, err).NotTo(HaveOccurred())
return nil
}
Expand All @@ -42,19 +40,19 @@ var _ = Describe("FluxInstance", Ordered, func() {
cmd := exec.Command("kubectl", "-n", namespace, "patch", "FluxInstance/flux",
"--type=json", `-p=[{"op": "replace", "path": "/spec/cluster/multitenant", "value":true}]`,
)
_, err := utils.Run(cmd)
_, err := Run(cmd)
ExpectWithOffset(2, err).NotTo(HaveOccurred())

cmd = exec.Command("kubectl", "wait", "FluxInstance/flux", "-n", namespace,
"--for=condition=Ready", "--timeout=5m",
)
_, err = utils.Run(cmd)
_, err = Run(cmd)
ExpectWithOffset(2, err).NotTo(HaveOccurred())

cmd = exec.Command("kubectl", "get", "deploy/kustomize-controller",
"-n", namespace, "-o=yaml",
)
output, err := utils.Run(cmd)
output, err := Run(cmd)
ExpectWithOffset(2, err).NotTo(HaveOccurred())
ExpectWithOffset(2, output).To(ContainSubstring("no-cross-namespace-refs=true"))

Expand All @@ -69,16 +67,16 @@ var _ = Describe("FluxInstance", Ordered, func() {
By("delete FluxInstance")
cmd := exec.Command("kubectl", "delete", "-k", "config/samples",
"--timeout=30s", "-n", namespace)
_, err := utils.Run(cmd)
_, err := Run(cmd)
Expect(err).NotTo(HaveOccurred())
By("source-controller deleted")
cmd = exec.Command("kubectl", "get", "deploy/source-controller", "-n", namespace)
_, err = utils.Run(cmd)
_, err = Run(cmd)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("not found"))
By("namespace exists")
cmd = exec.Command("kubectl", "get", "ns", namespace)
_, err = utils.Run(cmd)
_, err = Run(cmd)
Expect(err).NotTo(HaveOccurred())
})
})
Expand Down
Loading

0 comments on commit 162a5dd

Please sign in to comment.