Skip to content

Commit

Permalink
Helm chart release automation
Browse files Browse the repository at this point in the history
push helm chart as oci image to ghcr on release (tag)

Signed-off-by: adrianc <[email protected]>
  • Loading branch information
adrianchiris committed Sep 2, 2024
1 parent e6ad1e1 commit 3a347b4
Show file tree
Hide file tree
Showing 4 changed files with 236 additions and 123 deletions.
28 changes: 28 additions & 0 deletions .github/workflows/chart-push-release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: "Push helm chart on release"

env:
IMAGE_NAME: ghcr.io/${{ github.repository }}

on:
push:
tags:
- v*
jobs:
package-and-push-helm-chart:
runs-on: ubuntu-22.04
steps:
- name: Check out the repo
uses: actions/checkout@v4

- name: update chart
env:
GITHUB_TAG: ${{ github.ref_name }}
GITHUB_REPO_OWNER: ${{ github.repository_owner }}
run: make chart-prepare-release

- name: push chart
env:
GITHUB_TAG: ${{ github.ref_name }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_REPO_OWNER: ${{ github.repository_owner }}
run: make chart-push-release
261 changes: 138 additions & 123 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,135 @@ COVER_MODE = atomic
COVER_PROFILE = cover.out
LCOV_PATH = lcov.info

.PHONY: all
all: build
## Location to install dependencies to
LOCALBIN ?= $(shell pwd)/bin
$(LOCALBIN):
mkdir -p $(LOCALBIN)

## Location for build binaries
BUILDDIR ?= $(shell pwd)/build
$(BUILDDIR):
mkdir -p $(BUILDDIR)

##@ Binary Dependencies download
MOCKERY ?= $(LOCALBIN)/mockery
MOCKERY_VERSION ?= v2.44.2
.PHONY: mockery
mockery: $(MOCKERY) ## Download mockery locally if necessary.
$(MOCKERY): | $(LOCALBIN)
GOBIN=$(LOCALBIN) go install github.com/vektra/mockery/v2@$(MOCKERY_VERSION)

.PHONY: kustomize
KUSTOMIZE ?= $(LOCALBIN)/kustomize
KUSTOMIZE_VERSION ?= v5.4.2
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. If wrong version is installed, it will be removed before downloading.
$(KUSTOMIZE): $(LOCALBIN)
@if test -x $(LOCALBIN)/kustomize && ! $(LOCALBIN)/kustomize version | grep -q $(KUSTOMIZE_VERSION); then \
echo "$(LOCALBIN)/kustomize version is not expected $(KUSTOMIZE_VERSION). Removing it before installing."; \
rm -rf $(LOCALBIN)/kustomize; \
fi
test -s $(LOCALBIN)/kustomize || GOBIN=$(LOCALBIN) go install sigs.k8s.io/kustomize/kustomize/v5@$(KUSTOMIZE_VERSION)

.PHONY: controller-gen
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen
CONTROLLER_TOOLS_VERSION ?= v0.15.0
controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary. If wrong version is installed, it will be overwritten.
$(CONTROLLER_GEN): $(LOCALBIN)
test -s $(LOCALBIN)/controller-gen && $(LOCALBIN)/controller-gen --version | grep -q $(CONTROLLER_TOOLS_VERSION) || \
GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_TOOLS_VERSION)

.PHONY: envtest
ENVTEST ?= $(LOCALBIN)/setup-envtest
ENVTEST_VERSION ?= latest
envtest: $(ENVTEST) ## Download envtest-setup locally if necessary.
$(ENVTEST): $(LOCALBIN)
test -s $(LOCALBIN)/setup-envtest || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@$(ENVTEST_VERSION)

.PHONY: operator-sdk
OPERATOR_SDK ?= $(LOCALBIN)/operator-sdk
operator-sdk: ## Download operator-sdk locally if necessary.
ifeq (,$(wildcard $(OPERATOR_SDK)))
ifeq (, $(shell which operator-sdk 2>/dev/null))
@{ \
set -e ;\
mkdir -p $(dir $(OPERATOR_SDK)) ;\
OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH) && \
curl -sSLo $(OPERATOR_SDK) https://github.com/operator-framework/operator-sdk/releases/download/$(OPERATOR_SDK_VERSION)/operator-sdk_$${OS}_$${ARCH} ;\
chmod +x $(OPERATOR_SDK) ;\
}
else
OPERATOR_SDK = $(shell which operator-sdk)
endif
endif

.PHONY: opm
OPM = $(LOCALBIN)/opm
opm: ## Download opm locally if necessary.
ifeq (,$(wildcard $(OPM)))
ifeq (,$(shell which opm 2>/dev/null))
@{ \
set -e ;\
mkdir -p $(dir $(OPM)) ;\
OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH) && \
curl -sSLo $(OPM) https://github.com/operator-framework/operator-registry/releases/download/v1.23.0/$${OS}-$${ARCH}-opm ;\
chmod +x $(OPM) ;\
}
else
OPM = $(shell which opm)
endif
endif

SKAFFOLD_VER := v2.12.0
SKAFFOLD := $(abspath $(LOCALBIN)/skaffold-$(SKAFFOLD_VER))
.PHONY: skaffold
skaffold: $(SKAFFOLD) ## Download skaffold locally if necessary.
$(SKAFFOLD): | $(LOCALBIN)
@{ \
set -e;\
OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH) && \
curl -fsSL https://storage.googleapis.com/skaffold/releases/$(SKAFFOLD_VER)/skaffold-$${OS}-$${ARCH} -o $(SKAFFOLD); \
chmod +x $(SKAFFOLD);\
}

# minikube is used to set-up a local kubernetes cluster for dev work.
MINIKUBE_VER := v1.33.1
MINIKUBE := $(abspath $(LOCALBIN)/minikube-$(MINIKUBE_VER))
.PHONY: minikube
minikube: $(MINIKUBE) ## Download minikube locally if necessary.
$(MINIKUBE): | $(LOCALBIN)
@{ \
set -e;\
OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH) && \
curl -fsSL https://storage.googleapis.com/minikube/releases/$(MINIKUBE_VER)/minikube-$${OS}-$${ARCH} -o $(MINIKUBE); \
chmod +x $(MINIKUBE);\
}

HELM := $(abspath $(LOCALBIN)/helm)
.PHONY: helm
helm: $(HELM) ## Download helm (last release) locally if necessary.
$(HELM): | $(LOCALBIN)
@{ \
curl -fsSL -o $(LOCALBIN)/get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 && \
chmod 700 $(LOCALBIN)/get_helm.sh && \
HELM_INSTALL_DIR=$(LOCALBIN) USE_SUDO=false $(LOCALBIN)/get_helm.sh && \
rm -f $(LOCALBIN)/get_helm.sh; \
}

YQ := $(abspath $(LOCALBIN)/yq)
YQ_VERSION=v4.44.1
.PHONY: yq
yq: $(YQ) ## Download yq locally if necessary.
$(YQ): | $(LOCALBIN)
@curl -fsSL -o $(YQ) https://github.com/mikefarah/yq/releases/download/$(YQ_VERSION)/yq_linux_amd64 && chmod +x $(YQ)

GOLANGCI_LINT = $(LOCALBIN)/golangci-lint
GOLANGCI_LINT_VERSION ?= v1.59.1
.PHONY: golangci-lint ## Download golangci-lint locally if necessary.
golangci-lint:
@[ -f $(GOLANGCI_LINT) ] || { \
set -e ;\
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(shell dirname $(GOLANGCI_LINT)) $(GOLANGCI_LINT_VERSION) ;\
}

##@ General

Expand All @@ -111,6 +238,9 @@ all: build
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)

.PHONY: all
all: build

.PHONY: clean
clean: ## clean files
rm -rf $(LOCALBIN)
Expand Down Expand Up @@ -138,15 +268,6 @@ unit-test: envtest ## Run unit tests.
.PHONY: test-e2e # Run the e2e tests against a Kind k8s instance that is spun up.
test-e2e:
go test ./test/e2e/ -v -ginkgo.v

GOLANGCI_LINT = $(LOCALBIN)/golangci-lint
GOLANGCI_LINT_VERSION ?= v1.59.1
golangci-lint:
@[ -f $(GOLANGCI_LINT) ] || { \
set -e ;\
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(shell dirname $(GOLANGCI_LINT)) $(GOLANGCI_LINT_VERSION) ;\
}


.PHONY: lint
lint: golangci-lint ## Run golangci-lint linter & yamllint
Expand Down Expand Up @@ -225,16 +346,6 @@ undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/confi

##@ Build Dependencies

## Location to install dependencies to
LOCALBIN ?= $(shell pwd)/bin
$(LOCALBIN):
mkdir -p $(LOCALBIN)

## Location for build binaries
BUILDDIR ?= $(shell pwd)/build
$(BUILDDIR):
mkdir -p $(BUILDDIR)

.PHONY: bundle
bundle: manifests kustomize operator-sdk ## Generate bundle manifests and metadata, then validate generated files.
$(OPERATOR_SDK) generate kustomize manifests -q
Expand Down Expand Up @@ -274,110 +385,14 @@ catalog-build: opm ## Build a catalog image.
catalog-push: ## Push a catalog image.
$(MAKE) docker-push IMG=$(CATALOG_IMG)

##@ Binary Dependencies download

MOCKERY ?= $(LOCALBIN)/mockery
MOCKERY_VERSION ?= v2.44.2
.PHONY: mockery
mockery: $(MOCKERY) ## Download mockery locally if necessary.
$(MOCKERY): | $(LOCALBIN)
GOBIN=$(LOCALBIN) go install github.com/vektra/mockery/v2@$(MOCKERY_VERSION)

.PHONY: kustomize
KUSTOMIZE ?= $(LOCALBIN)/kustomize
KUSTOMIZE_VERSION ?= v5.4.2
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. If wrong version is installed, it will be removed before downloading.
$(KUSTOMIZE): $(LOCALBIN)
@if test -x $(LOCALBIN)/kustomize && ! $(LOCALBIN)/kustomize version | grep -q $(KUSTOMIZE_VERSION); then \
echo "$(LOCALBIN)/kustomize version is not expected $(KUSTOMIZE_VERSION). Removing it before installing."; \
rm -rf $(LOCALBIN)/kustomize; \
fi
test -s $(LOCALBIN)/kustomize || GOBIN=$(LOCALBIN) go install sigs.k8s.io/kustomize/kustomize/v5@$(KUSTOMIZE_VERSION)

.PHONY: controller-gen
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen
CONTROLLER_TOOLS_VERSION ?= v0.15.0
controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary. If wrong version is installed, it will be overwritten.
$(CONTROLLER_GEN): $(LOCALBIN)
test -s $(LOCALBIN)/controller-gen && $(LOCALBIN)/controller-gen --version | grep -q $(CONTROLLER_TOOLS_VERSION) || \
GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_TOOLS_VERSION)
.PHONY: chart-prepare-release
chart-prepare-release: | $(YQ) ## prepare helm chart for release
@GITHUB_TAG=$(GITHUB_TAG) GITHUB_REPO_OWNER=$(GITHUB_REPO_OWNER) hack/release/chart-update.sh

.PHONY: envtest
ENVTEST ?= $(LOCALBIN)/setup-envtest
ENVTEST_VERSION ?= latest
envtest: $(ENVTEST) ## Download envtest-setup locally if necessary.
$(ENVTEST): $(LOCALBIN)
test -s $(LOCALBIN)/setup-envtest || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@$(ENVTEST_VERSION)

.PHONY: operator-sdk
OPERATOR_SDK ?= $(LOCALBIN)/operator-sdk
operator-sdk: ## Download operator-sdk locally if necessary.
ifeq (,$(wildcard $(OPERATOR_SDK)))
ifeq (, $(shell which operator-sdk 2>/dev/null))
@{ \
set -e ;\
mkdir -p $(dir $(OPERATOR_SDK)) ;\
OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH) && \
curl -sSLo $(OPERATOR_SDK) https://github.com/operator-framework/operator-sdk/releases/download/$(OPERATOR_SDK_VERSION)/operator-sdk_$${OS}_$${ARCH} ;\
chmod +x $(OPERATOR_SDK) ;\
}
else
OPERATOR_SDK = $(shell which operator-sdk)
endif
endif

.PHONY: opm
OPM = $(LOCALBIN)/opm
opm: ## Download opm locally if necessary.
ifeq (,$(wildcard $(OPM)))
ifeq (,$(shell which opm 2>/dev/null))
@{ \
set -e ;\
mkdir -p $(dir $(OPM)) ;\
OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH) && \
curl -sSLo $(OPM) https://github.com/operator-framework/operator-registry/releases/download/v1.23.0/$${OS}-$${ARCH}-opm ;\
chmod +x $(OPM) ;\
}
else
OPM = $(shell which opm)
endif
endif

SKAFFOLD_VER := v2.12.0
SKAFFOLD := $(abspath $(LOCALBIN)/skaffold-$(SKAFFOLD_VER))
.PHONY: skaffold
skaffold: $(SKAFFOLD) ## Download skaffold locally if necessary.
$(SKAFFOLD): | $(LOCALBIN)
@{ \
set -e;\
OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH) && \
curl -fsSL https://storage.googleapis.com/skaffold/releases/$(SKAFFOLD_VER)/skaffold-$${OS}-$${ARCH} -o $(SKAFFOLD); \
chmod +x $(SKAFFOLD);\
}

# minikube is used to set-up a local kubernetes cluster for dev work.
MINIKUBE_VER := v1.33.1
MINIKUBE := $(abspath $(LOCALBIN)/minikube-$(MINIKUBE_VER))
.PHONY: minikube
minikube: $(MINIKUBE) ## Download minikube locally if necessary.
$(MINIKUBE): | $(LOCALBIN)
@{ \
set -e;\
OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH) && \
curl -fsSL https://storage.googleapis.com/minikube/releases/$(MINIKUBE_VER)/minikube-$${OS}-$${ARCH} -o $(MINIKUBE); \
chmod +x $(MINIKUBE);\
}

HELM := $(abspath $(LOCALBIN)/helm)
.PHONY: helm
helm: $(HELM) ## Download helm (last release) locally if necessary.
$(HELM): | $(LOCALBIN)
@{ \
curl -fsSL -o $(LOCALBIN)/get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 && \
chmod 700 $(LOCALBIN)/get_helm.sh && \
HELM_INSTALL_DIR=$(LOCALBIN) USE_SUDO=false $(LOCALBIN)/get_helm.sh && \
rm -f $(LOCALBIN)/get_helm.sh; \
}
.PHONY: chart-push-release
chart-push-release: | $(HELM) ## push release helm chart
@GITHUB_TAG=$(GITHUB_TAG) GITHUB_TOKEN=$(GITHUB_TOKEN) GITHUB_REPO_OWNER=$(GITHUB_REPO_OWNER) hack/release/chart-push.sh

##@ Dev

Expand Down
34 changes: 34 additions & 0 deletions hack/release/chart-push.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#!/bin/bash
set -ex

# github repo owner: e.g mellanox
GITHUB_REPO_OWNER=${GITHUB_REPO_OWNER:-}
# github api token with package:write permissions
GITHUB_TOKEN=${GITHUB_TOKEN:-}
# github tag e.g v1.2.3
GITHUB_TAG=${GITHUB_TAG:-}

BASE=${PWD}
HELM_CMD="${BASE}/bin/helm"
HELM_CHART=${BASE}/deployment/maintenance-operator-chart
HELM_CHART_VERSION=${GITHUB_TAG#"v"}
HELM_CHART_TARBALL="maintenance-operator-chart-${HELM_CHART_VERSION}.tgz"

if [ -z "$GITHUB_REPO_OWNER" ]; then
echo "ERROR: GITHUB_REPO_OWNER must be provided as env var"
exit 1
fi

if [ -z "$GITHUB_TOKEN" ]; then
echo "ERROR: GITHUB_TOKEN must be provided as env var"
exit 1
fi

if [ -z "$GITHUB_TAG" ]; then
echo "ERROR: GITHUB_TAG must be provided as env var"
exit 1
fi

$HELM_CMD package ${HELM_CHART}
$HELM_CMD registry login ghcr.io -u ${GITHUB_REPO_OWNER} -p ${GITHUB_TOKEN}
$HELM_CMD push ${HELM_CHART_TARBALL} oci://ghcr.io/${GITHUB_REPO_OWNER}
36 changes: 36 additions & 0 deletions hack/release/chart-update.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/bin/bash
set -ex

# github tag e.g v1.2.3
GITHUB_TAG=${GITHUB_TAG:-}
# github repo owner e.g mellanox
GITHUB_REPO_OWNER=${GITHUB_REPO_OWNER:-}

BASE=${PWD}
YQ_CMD="${BASE}/bin/yq"
HELM_VALUES=${BASE}/deployment/maintenance-operator-chart/values.yaml
HELM_CHART=${BASE}/deployment/maintenance-operator-chart/Chart.yaml


if [ -z "$GITHUB_TAG" ]; then
echo "ERROR: GITHUB_TAG must be provided as env var"
exit 1
fi

if [ -z "$GITHUB_REPO_OWNER" ]; then
echo "ERROR: GITHUB_REPO_OWNER must be provided as env var"
exit 1
fi

# tag provided via env var
OPERATOR_TAG=${GITHUB_TAG}

# patch values.yaml in-place

# maintenance-operator image:
OPERATOR_REPO=${GITHUB_REPO_OWNER} # this is used to allow to release maintenance-operator from forks
$YQ_CMD -i ".operator.image.repository = \"ghcr.io/${OPERATOR_REPO}/maintenance-operator\"" ${HELM_VALUES}

# patch Chart.yaml in-place
$YQ_CMD -i ".version = \"${OPERATOR_TAG#"v"}\"" ${HELM_CHART}
$YQ_CMD -i ".appVersion = \"${OPERATOR_TAG}\"" ${HELM_CHART}

0 comments on commit 3a347b4

Please sign in to comment.