diff --git a/.github/workflows/publish-helm.yml b/.github/workflows/publish-helm.yml deleted file mode 100644 index 41aea69a..00000000 --- a/.github/workflows/publish-helm.yml +++ /dev/null @@ -1,26 +0,0 @@ ---- -name: Re-publish helm chart -on: - workflow_dispatch: - inputs: - tag: - description: 'Release tag' - required: true - type: string -jobs: - promote: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Release Helm chart - run: | - ansible-playbook ansible/helm-release.yml -v \ - -e operator_image=quay.io/${{ github.repository }} \ - -e chart_owner=${{ github.repository_owner }} \ - -e tag=${{ inputs.tag }} \ - -e gh_token=${{ secrets.GITHUB_TOKEN }} \ - -e gh_user=${{ github.actor }} \ - -e repo_type=https diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..8220eace --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,51 @@ +name: Release Chart + +on: + push: + branches: + - main + +jobs: + release: + permissions: + contents: write + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Configure Git + run: | + git config user.name "$GITHUB_ACTOR" + git config user.email "$GITHUB_ACTOR@users.noreply.github.com" + + - name: Generate Chart + run: | + make helm-chart-generate + + - name: Check for changes to generated helm chart + id: check_changes + run: | + git status --porcelain charts/ | grep -q "." && echo "changes=true" >> $GITHUB_OUTPUT || echo "changes=false" >> $GITHUB_OUTPUT + + # If we generated a new helm chart, we need to commit it + # We need to do this step because our helm chart is not the source of truth, it's generated from starter + # Note that failing to do this doesn't break this release, but it can break future ones and make the release state confusing + - name: Commit generated chart + id: update_source + run: | + git pull + git add charts/ + git commit -m "Generated chart for release" + git push + if: steps.check_changes.outputs.changes == 'true' + + # Chart releaser will internally only run if there is a diff in charts, + # but we explicitly check to keep the chart releaser and our generates charts/ dir in sync + - name: Run chart-releaser + uses: helm/chart-releaser-action@v1.6.0 + env: + CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + if: steps.check_changes.outputs.changes == 'true' diff --git a/.gitignore b/.gitignore index a438e40a..430ab4ef 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ gh-pages/ /bundle /bundle_tmp* /bundle.Dockerfile -/charts + /.cr-release-packages .vscode/ __pycache__ @@ -17,4 +17,3 @@ site/ Dockerfile requirements.yml watches.yaml -Makefile.awx-operator diff --git a/.helm/starter/Chart.yaml b/.helm/starter/Chart.yaml index 929291e8..9a97af88 100644 --- a/.helm/starter/Chart.yaml +++ b/.helm/starter/Chart.yaml @@ -4,6 +4,6 @@ description: The community-supported AWX Operator Helm Chart name: awx-operator type: application # the current version of this helm chart -version: 0.1.0 +version: 3.0.0 # The version of the awx-operator to install appVersion: 2.19.1 diff --git a/Makefile b/Makefile index 094df378..17be0c20 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,12 @@ -# Include the Makefile from the ansible/awx-operator repository. -# This Makefile is created with the clone-awx-operator.py script. -include Makefile.awx-operator +# VERSION defines the project version for the bundle. +# Update this value when you upgrade the version of your project. +# To re-generate a bundle for another specific version without changing the standard setup, you can: +# - use the VERSION as arg of the bundle target (e.g make bundle VERSION=0.0.2) +# - use environment variables to overwrite this value (e.g export VERSION=0.0.2) +VERSION ?= $(shell git describe --tags) +PREV_VERSION ?= $(shell git describe --abbrev=0 --tags $(shell git rev-list --tags --skip=1 --max-count=1)) + +CONTAINER_CMD ?= docker # GNU vs BSD in-place sed ifeq ($(shell sed --version 2>/dev/null | grep -q GNU && echo gnu),gnu) @@ -9,15 +15,143 @@ else SED_I := sed -i '' endif +# CHANNELS define the bundle channels used in the bundle. +# Add a new line here if you would like to change its default config. (E.g CHANNELS = "candidate,fast,stable") +# To re-generate a bundle for other specific channels without changing the standard setup, you can: +# - use the CHANNELS as arg of the bundle target (e.g make bundle CHANNELS=candidate,fast,stable) +# - use environment variables to overwrite this value (e.g export CHANNELS="candidate,fast,stable") +ifneq ($(origin CHANNELS), undefined) +BUNDLE_CHANNELS := --channels=$(CHANNELS) +endif + +# DEFAULT_CHANNEL defines the default channel used in the bundle. +# Add a new line here if you would like to change its default config. (E.g DEFAULT_CHANNEL = "stable") +# To re-generate a bundle for any other default channel without changing the default setup, you can: +# - use the DEFAULT_CHANNEL as arg of the bundle target (e.g make bundle DEFAULT_CHANNEL=stable) +# - use environment variables to overwrite this value (e.g export DEFAULT_CHANNEL="stable") +ifneq ($(origin DEFAULT_CHANNEL), undefined) +BUNDLE_DEFAULT_CHANNEL := --default-channel=$(DEFAULT_CHANNEL) +endif +BUNDLE_METADATA_OPTS ?= $(BUNDLE_CHANNELS) $(BUNDLE_DEFAULT_CHANNEL) + +# IMAGE_TAG_BASE defines the docker.io namespace and part of the image name for remote images. +# This variable is used to construct full image tags for bundle and catalog images. +# +# For example, running 'make bundle-build bundle-push catalog-build catalog-push' will build and push both +# ansible.com/awx-operator-bundle:$VERSION and ansible.com/awx-operator-catalog:$VERSION. +IMAGE_TAG_BASE ?= quay.io/ansible/awx-operator + +# BUNDLE_IMG defines the image:tag used for the bundle. +# You can use it as an arg. (E.g make bundle-build BUNDLE_IMG=/:) +BUNDLE_IMG ?= $(IMAGE_TAG_BASE)-bundle:v$(VERSION) + +# BUNDLE_GEN_FLAGS are the flags passed to the operator-sdk generate bundle command +BUNDLE_GEN_FLAGS ?= -q --overwrite --version $(VERSION) $(BUNDLE_METADATA_OPTS) + +# USE_IMAGE_DIGESTS defines if images are resolved via tags or digests +# You can enable this value if you would like to use SHA Based Digests +# To enable set flag to true +USE_IMAGE_DIGESTS ?= false +ifeq ($(USE_IMAGE_DIGESTS), true) + BUNDLE_GEN_FLAGS += --use-image-digests +endif + +# Image URL to use all building/pushing image targets +IMG ?= $(IMAGE_TAG_BASE):$(VERSION) +NAMESPACE ?= awx + # Helm variables CHART_NAME ?= awx-operator +CHART_DESCRIPTION ?= A Helm chart for the AWX Operator CHART_OWNER ?= $(GH_REPO_OWNER) CHART_REPO ?= awx-operator CHART_BRANCH ?= gh-pages CHART_DIR ?= gh-pages CHART_INDEX ?= index.yaml -# use python3 if python isn't in the path -PYTHON ?= $(shell which python >/dev/null 2>&1 && echo python || echo python3) + +.PHONY: all +all: docker-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 commands 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\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: print-% +print-%: ## Print any variable from the Makefile. Use as `make print-VARIABLE` + @echo $($*) + +##@ Build + +.PHONY: run +run: ansible-operator ## Run against the configured Kubernetes cluster in ~/.kube/config + ANSIBLE_ROLES_PATH="$(ANSIBLE_ROLES_PATH):$(shell pwd)/roles" $(ANSIBLE_OPERATOR) run + +.PHONY: docker-build +docker-build: ## Build docker image with the manager. + ${CONTAINER_CMD} build $(BUILD_ARGS) -t ${IMG} . + +.PHONY: docker-push +docker-push: ## Push docker image with the manager. + ${CONTAINER_CMD} push ${IMG} + +# PLATFORMS defines the target platforms for the manager image be build to provide support to multiple +# architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to: +# - able to use docker buildx . More info: https://docs.docker.com/build/buildx/ +# - have enable BuildKit, More info: https://docs.docker.com/develop/develop-images/build_enhancements/ +# - be able to push the image for your registry (i.e. if you do not inform a valid value via IMG=> than the export will fail) +# To properly provided solutions that supports more than one platform you should use this option. +PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le +.PHONY: docker-buildx +docker-buildx: ## Build and push docker image for the manager for cross-platform support + - docker buildx create --name project-v3-builder + docker buildx use project-v3-builder + - docker buildx build --push $(BUILD_ARGS) --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile . + - docker buildx rm project-v3-builder + + +##@ Deployment + +.PHONY: install +install: kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config. + $(KUSTOMIZE) build config/crd | kubectl apply -f - + +.PHONY: uninstall +uninstall: kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. + $(KUSTOMIZE) build config/crd | kubectl delete -f - + +.PHONY: gen-resources +gen-resources: kustomize ## Generate resources for controller and print to stdout + @cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} + @cd config/default && $(KUSTOMIZE) edit set namespace ${NAMESPACE} + @$(KUSTOMIZE) build config/default + +.PHONY: deploy +deploy: kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config. + @cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} + @cd config/default && $(KUSTOMIZE) edit set namespace ${NAMESPACE} + @$(KUSTOMIZE) build config/default | kubectl apply -f - + +.PHONY: undeploy +undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config. + @cd config/default && $(KUSTOMIZE) edit set namespace ${NAMESPACE} + $(KUSTOMIZE) build config/default | kubectl delete -f - + +OS := $(shell uname -s | tr '[:upper:]' '[:lower:]') +ARCHA := $(shell uname -m | sed -e 's/x86_64/amd64/' -e 's/aarch64/arm64/') +ARCHX := $(shell uname -m | sed -e 's/amd64/x86_64/' -e 's/aarch64/arm64/') .PHONY: kustomize KUSTOMIZE = $(shell pwd)/bin/kustomize @@ -35,6 +169,93 @@ KUSTOMIZE = $(shell which kustomize) endif endif +.PHONY: operator-sdk +OPERATOR_SDK = $(shell pwd)/bin/operator-sdk +operator-sdk: ## Download operator-sdk locally if necessary, preferring the $(pwd)/bin path over global if both exist. +ifeq (,$(wildcard $(OPERATOR_SDK))) +ifeq (,$(shell which operator-sdk 2>/dev/null)) + @{ \ + set -e ;\ + mkdir -p $(dir $(OPERATOR_SDK)) ;\ + curl -sSLo $(OPERATOR_SDK) https://github.com/operator-framework/operator-sdk/releases/download/v1.33.0/operator-sdk_$(OS)_$(ARCHA) ;\ + chmod +x $(OPERATOR_SDK) ;\ + } +else +OPERATOR_SDK = $(shell which operator-sdk) +endif +endif + +.PHONY: ansible-operator +ANSIBLE_OPERATOR = $(shell pwd)/bin/ansible-operator +ansible-operator: ## Download ansible-operator locally if necessary, preferring the $(pwd)/bin path over global if both exist. +ifeq (,$(wildcard $(ANSIBLE_OPERATOR))) +ifeq (,$(shell which ansible-operator 2>/dev/null)) + @{ \ + set -e ;\ + mkdir -p $(dir $(ANSIBLE_OPERATOR)) ;\ + curl -sSLo $(ANSIBLE_OPERATOR) https://github.com/operator-framework/ansible-operator-plugins/releases/download/v1.34.0/ansible-operator_$(OS)_$(ARCHA) ;\ + chmod +x $(ANSIBLE_OPERATOR) ;\ + } +else +ANSIBLE_OPERATOR = $(shell which ansible-operator) +endif +endif + +.PHONY: bundle +bundle: kustomize operator-sdk ## Generate bundle manifests and metadata, then validate generated files. + $(OPERATOR_SDK) generate kustomize manifests -q + cd config/manager && $(KUSTOMIZE) edit set image controller=$(IMG) + $(KUSTOMIZE) build config/manifests | $(OPERATOR_SDK) generate bundle -q --overwrite --version $(VERSION) $(BUNDLE_METADATA_OPTS) + $(OPERATOR_SDK) bundle validate ./bundle + +.PHONY: bundle-build +bundle-build: ## Build the bundle image. + ${CONTAINER_CMD} build -f bundle.Dockerfile -t $(BUNDLE_IMG) . + +.PHONY: bundle-push +bundle-push: ## Push the bundle image. + $(MAKE) docker-push IMG=$(BUNDLE_IMG) + +.PHONY: opm +OPM = ./bin/opm +opm: ## Download opm locally if necessary. +ifeq (,$(wildcard $(OPM))) +ifeq (,$(shell which opm 2>/dev/null)) + @{ \ + set -e ;\ + mkdir -p $(dir $(OPM)) ;\ + curl -sSLo $(OPM) https://github.com/operator-framework/operator-registry/releases/download/v1.26.0/$(OS)-$(ARCHA)-opm ;\ + chmod +x $(OPM) ;\ + } +else +OPM = $(shell which opm) +endif +endif + +# A comma-separated list of bundle images (e.g. make catalog-build BUNDLE_IMGS=example.com/operator-bundle:v0.1.0,example.com/operator-bundle:v0.2.0). +# These images MUST exist in a registry and be pull-able. +BUNDLE_IMGS ?= $(BUNDLE_IMG) + +# The image tag given to the resulting catalog image (e.g. make catalog-build CATALOG_IMG=example.com/operator-catalog:v0.2.0). +CATALOG_IMG ?= $(IMAGE_TAG_BASE)-catalog:v$(VERSION) + +# Set CATALOG_BASE_IMG to an existing catalog image tag to add $BUNDLE_IMGS to that image. +ifneq ($(origin CATALOG_BASE_IMG), undefined) +FROM_INDEX_OPT := --from-index $(CATALOG_BASE_IMG) +endif + +# Build a catalog image by adding bundle images to an empty catalog using the operator package manager tool, 'opm'. +# This recipe invokes 'opm' in 'semver' bundle add mode. For more information on add modes, see: +# https://github.com/operator-framework/community-operators/blob/7f1438c/docs/packaging-operator.md#updating-your-existing-operator +.PHONY: catalog-build +catalog-build: opm ## Build a catalog image. + $(OPM) index add --container-tool ${CONTAINER_CMD} --mode semver --tag $(CATALOG_IMG) --bundles $(BUNDLE_IMGS) $(FROM_INDEX_OPT) + +# Push the catalog image. +.PHONY: catalog-push +catalog-push: ## Push a catalog image. + $(MAKE) docker-push IMG=$(CATALOG_IMG) + .PHONY: kubectl-slice KUBECTL_SLICE = $(shell pwd)/bin/kubectl-slice kubectl-slice: ## Download kubectl-slice locally if necessary. @@ -51,27 +272,6 @@ KUBECTL_SLICE = $(shell which kubectl-slice) endif endif -.PHONY: yq -YQ = $(shell pwd)/bin/yq -yq: ## Download yq locally if necessary. -ifeq (,$(wildcard $(YQ))) -ifeq (,$(shell which yq 2>/dev/null)) - @{ \ - set -e ;\ - mkdir -p $(dir $(HELM)) ;\ - curl -sSLo - https://github.com/mikefarah/yq/releases/download/v4.20.2/yq_$(OS)_$(ARCHA).tar.gz | \ - tar xzf - -C bin/ ;\ - mv bin/yq_$(OS)_$(ARCHA) bin/yq ;\ - } -else -YQ = $(shell which yq) -endif -endif - -.PHONY: chart-version -chart-version: yq -CHART_VERSION = $(shell cat .helm/starter/Chart.yaml | $(YQ) '.version') - .PHONY: helm HELM = $(shell pwd)/bin/helm helm: ## Download helm locally if necessary. @@ -90,6 +290,23 @@ HELM = $(shell which helm) endif endif +.PHONY: yq +YQ = $(shell pwd)/bin/yq +yq: ## Download yq locally if necessary. +ifeq (,$(wildcard $(YQ))) +ifeq (,$(shell which yq 2>/dev/null)) + @{ \ + set -e ;\ + mkdir -p $(dir $(HELM)) ;\ + curl -sSLo - https://github.com/mikefarah/yq/releases/download/v4.20.2/yq_$(OS)_$(ARCHA).tar.gz | \ + tar xzf - -C bin/ ;\ + mv bin/yq_$(OS)_$(ARCHA) bin/yq ;\ + } +else +YQ = $(shell which yq) +endif +endif + PHONY: cr CR = $(shell pwd)/bin/cr cr: ## Download cr locally if necessary. @@ -114,10 +331,6 @@ helm-chart: helm-chart-generate .PHONY: helm-chart-generate helm-chart-generate: kustomize helm kubectl-slice yq charts - - @echo "== Clone the AWX Operator repository ==" - $(PYTHON) clone-awx-operator.py - @echo "== KUSTOMIZE: Set image and chart label ==" cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} cd config/manager && $(KUSTOMIZE) edit set label helm.sh/chart:$(CHART_NAME) @@ -125,11 +338,13 @@ helm-chart-generate: kustomize helm kubectl-slice yq charts @echo "== Gather Helm Chart Metadata ==" # remove the existing chart if it exists - # edit and copy the Chart.yaml ourselves since helm doesn't do it: https://github.com/helm/helm/issues/9551#issuecomment-811217822 rm -rf charts/$(CHART_NAME) + # create new chart metadata in Chart.yaml cd charts && \ - $(HELM) create $(CHART_NAME) --starter $(shell pwd)/.helm/starter ;\ - $(YQ) '.name = "$(CHART_NAME)"' $(shell pwd)/.helm/starter/Chart.yaml > $(CHART_NAME)/Chart.yaml;\ + $(HELM) create awx-operator --starter $(shell pwd)/.helm/starter ;\ + $(YQ) -i '.version = "$(VERSION)"' $(CHART_NAME)/Chart.yaml ;\ + $(YQ) -i '.appVersion = "$(VERSION)" | .appVersion style="double"' $(CHART_NAME)/Chart.yaml ;\ + $(YQ) -i '.description = "$(CHART_DESCRIPTION)"' $(CHART_NAME)/Chart.yaml ;\ @echo "Generated chart metadata:" @cat charts/$(CHART_NAME)/Chart.yaml @@ -151,24 +366,14 @@ helm-chart-generate: kustomize helm kubectl-slice yq charts for file in charts/$(CHART_NAME)/raw-files/*rolebinding*; do\ $(YQ) -i '.subjects[0].namespace = "{{ .Release.Namespace }}"' $${file};\ done - # Correct .metadata.name for cluster scoped resources cluster_scoped_files="charts/$(CHART_NAME)/raw-files/clusterrolebinding-awx-operator-proxy-rolebinding.yaml charts/$(CHART_NAME)/raw-files/clusterrole-awx-operator-metrics-reader.yaml charts/$(CHART_NAME)/raw-files/clusterrole-awx-operator-proxy-role.yaml";\ for file in $${cluster_scoped_files}; do\ $(YQ) -i '.metadata.name += "-{{ .Release.Name }}"' $${file};\ done + # Correct the reference for the clusterrolebinding $(YQ) -i '.roleRef.name += "-{{ .Release.Name }}"' 'charts/$(CHART_NAME)/raw-files/clusterrolebinding-awx-operator-proxy-rolebinding.yaml' - - # Feed controller deployment file into template to allow for override from values - for file in charts/$(CHART_NAME)/raw-files/deployment-*-controller-manager.yaml; do\ - cat $${file} >> charts/$(CHART_NAME)/templates/operator-controller/_operator-controller.tpl;\ - echo "\n---" >> charts/$(CHART_NAME)/templates/operator-controller/_operator-controller.tpl;\ - rm -f $${file} ;\ - done - echo '{{- end -}}' >> charts/$(CHART_NAME)/templates/operator-controller/_operator-controller.tpl - - # move all custom resource definitions to crds folder mkdir charts/$(CHART_NAME)/crds mv charts/$(CHART_NAME)/raw-files/customresourcedefinition*.yaml charts/$(CHART_NAME)/crds/. @@ -180,54 +385,6 @@ helm-chart-generate: kustomize helm kubectl-slice yq charts rm -rf charts/$(CHART_NAME)/raw-files # create and populate NOTES.txt - @echo "AWX Operator installed with Helm Chart version {{ .Chart.Version }}" > charts/$(CHART_NAME)/templates/NOTES.txt - - @echo "Helm chart successfully configured for $(CHART_NAME)" - - -.PHONY: helm-package -helm-package: helm-chart chart-version - @echo "== Package Current Chart Version ==" - mkdir -p .cr-release-packages - # package the chart and put it in .cr-release-packages dir - $(HELM) package ./charts/$(CHART_NAME) -d .cr-release-packages/$(CHART_VERSION) - -# List all tags oldest to newest. -TAGS := $(shell git ls-remote --tags --sort=version:refname --refs -q | cut -d/ -f3) - -# The actual release happens in ansible/helm-release.yml, which calls this targer -# until https://github.com/helm/chart-releaser/issues/122 happens, chart-releaser is not ideal for a chart -# that is contained within a larger repo, where a tag may not require a new chart version -.PHONY: helm-index -helm-index: - # when running in CI the gh-pages branch is checked out by the ansible playbook - # TODO: test if gh-pages directory exists and if not exist - - @echo "== GENERATE INDEX FILE ==" - # This step to workaround issues with old releases being dropped. - # Until https://github.com/helm/chart-releaser/issues/133 happens - @echo "== CHART FETCH previous releases ==" - # Download all old releases - mkdir -p .cr-release-packages - - for tag in $(TAGS); do\ - dl_url="https://github.com/$(CHART_OWNER)/$(CHART_REPO)/releases/download/$${tag}/$(CHART_REPO)-$${tag}.tgz";\ - echo "Downloading $${tag} from $${dl_url}";\ - curl -RLOs -z "$(CHART_REPO)-$${tag}.tgz" --fail $${dl_url};\ - result=$$?;\ - if [ $${result} -eq 0 ]; then\ - echo "Downloaded $${dl_url}";\ - mkdir -p .cr-release-packages/$${tag};\ - mv ./$(CHART_REPO)-$${tag}.tgz .cr-release-packages/$${tag};\ - else\ - echo "Skipping release $${tag}; No helm chart present";\ - rm -rf "$(CHART_REPO)-$${tag}.tgz";\ - fi;\ - done;\ - - # generate the index file in the root of the gh-pages branch - # --merge will leave any values in index.yaml that don't get generated by this command, but - # it is likely that all values are overridden - $(HELM) repo index .cr-release-packages --url https://github.com/$(CHART_OWNER)/$(CHART_REPO)/releases/download/ --merge $(CHART_DIR)/index.yaml - - mv .cr-release-packages/index.yaml $(CHART_DIR)/index.yaml + @echo "AWX Operator installed with Helm Chart version $(VERSION)" > charts/$(CHART_NAME)/templates/NOTES.txt + + @echo "Helm chart successfully configured for $(CHART_NAME) $(shell $(HELM) show chart .helm/starter | grep version)" diff --git a/README.md b/README.md index 3cc4b274..ed759b3d 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,20 @@ Use `--force-conflicts` flag to resolve the conflict. kubectl apply --server-side --force-conflicts -k github.com/ansible/awx-operator/config/crd?ref= ``` +## Releases +Releases occur using the [chart-releaser](https://github.com/helm/chart-releaser-action) action, which creates chart artifacts as github releases and updates a helm repo index held in the `gh-pages` branch. + +> The original releases from awx-operator were pre-seeded into the `index.yaml` + +Chart-releaser is designed to use the `charts` directory as the source of truth for the current state of the chart. If there are changes to it, the action will generate a release. Unlike many other helm charts, this one is generated on the fly by pulling in the awx-operator source code. As a result, the release workflow will also commit the state of the generated chart to the charts directory. + +### The `charts/` directory is a reflection of the release state, not a source of truth to edit for new features +Keep in mind that any changes to how the helm chart works should be done to the starter template. + +### Versioning +The current CI setup will skip releases for commits that don't make any changes to the generated chart. The use-case for this is documentation or other file updates that don't impact the helm chart. But *any* release that affects helm chart generation *must* increment the `version` field in `.helm/starter/Chart.yaml`, which is our source of truth for versioning in this repo. + + ## Custom Resource Configuration The goal of adding helm configurations is to abstract out and simplify the creation of multi-resource configs. The `AWX.spec` field maps directly to the spec configs of the `AWX` resource that the operator provides, which are detailed in the [main README](https://github.com/ansible/awx-operator/blob/devel/README.md). Other sub-config can be added with the goal of simplifying more involved setups that require additional resources to be specified. diff --git a/ansible/helm-release.yml b/ansible/helm-release.yml deleted file mode 100644 index aeb788d6..00000000 --- a/ansible/helm-release.yml +++ /dev/null @@ -1,122 +0,0 @@ ---- -- hosts: localhost - vars: - chart_repo: awx-operator - environment: - CHART_OWNER: "{{ chart_owner }}" - tasks: - - name: Look up release - uri: - url: "https://api.github.com/repos/{{ chart_owner }}/{{ chart_repo }}/releases/tags/{{ tag }}" - register: release - ignore_errors: yes - - - fail: - msg: | - Release must exist before running this playbook - when: release is not success - - - name: Set helm filename and commit message - set_fact: - asset_already_attached: False - helm_file_name: "awx-operator-{{ tag }}.tgz" - commit_message: "Updated index.yaml for release {{ release.json.tag_name }}" - - - name: See if file is already attached - set_fact: - asset_already_attached: True - loop: "{{ release.json.get('assets', []) }}" - loop_control: - label: "{{ item.name }}" - when: item.name == helm_file_name - - - when: not asset_already_attached - block: - - name: Build and package helm chart - command: | - make helm-package - environment: - VERSION: "{{ tag }}" - IMAGE_TAG_BASE: "{{ operator_image }}" - args: - chdir: "{{ playbook_dir }}/../" - - # Move to chart releaser after https://github.com/helm/chart-releaser/issues/122 exists - - name: Upload helm chart - uri: - url: "https://uploads.github.com/repos/{{ chart_owner }}/{{ chart_repo }}/releases/{{ release.json.id }}/assets?name={{ helm_file_name }}" - src: "{{ playbook_dir }}/../.cr-release-packages/{{ tag }}/awx-operator-{{ tag }}.tgz" - headers: - Authorization: "token {{ gh_token }}" - Content-Type: "application/octet-stream" - status_code: - - 200 - - 201 - register: asset_upload - changed_when: asset_upload.json.state == "uploaded" - - - name: Ensure gh-pages exists - file: - state: directory - path: "{{ playbook_dir }}/../gh-pages" - - - name: Check if we have published the release - command: - cmd: "git log --grep='{{ commit_message }}'" - chdir: "{{ playbook_dir }}/../gh-pages" - register: commits_for_release - - - when: commits_for_release.stdout == '' - block: - - name: Make a temp dir - tempfile: - state: directory - register: temp_dir - - - name: Clone the gh-pages branch from {{ chart_owner }} - git: - repo: "{{ ((repo_type | default('http')) == 'ssh') | ternary(ssh_repo, http_repo) }}" - dest: "{{ temp_dir.path }}" - single_branch: yes - version: gh-pages - vars: - http_repo: "https://github.com/{{ chart_owner }}/{{ chart_repo }}" - ssh_repo: "git@github.com:{{ chart_owner }}/{{ chart_repo }}.git" - - - name: Publish helm index - ansible.builtin.command: - cmd: make helm-index - environment: - CHART_OWNER: "{{ chart_owner }}" - CR_TOKEN: "{{ gh_token }}" - CHART_DIR: "{{ temp_dir.path }}" - args: - chdir: "{{ playbook_dir }}/.." - - - name: Set url base swap in gitconfig - command: - cmd: "git config --local url.https://{{ gh_user }}:{{ gh_token }}@github.com/.insteadOf https://github.com/" - args: - chdir: "{{ temp_dir.path }}/" - no_log: true - - - name: Stage and Push commit to gh-pages branch - command: - cmd: "{{ item }}" - loop: - - git add index.yaml - - git commit -m "{{ commit_message }}" - - git push - args: - chdir: "{{ temp_dir.path }}/" - environment: - GIT_AUTHOR_NAME: "{{ gh_user }}" - GIT_AUTHOR_EMAIL: "{{ gh_user }}@users.noreply.github.com" - GIT_COMMITTER_NAME: "{{ gh_user }}" - GIT_COMMITTER_EMAIL: "{{ gh_user }}@users.noreply.github.com" - - always: - - name: Remove temp dir - file: - path: "{{ temp_dir.path }}" - state: absent diff --git a/charts/.gitkeep b/charts/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/clone-awx-operator.py b/clone-awx-operator.py index fcfcb3aa..7bb41651 100755 --- a/clone-awx-operator.py +++ b/clone-awx-operator.py @@ -110,10 +110,7 @@ def main(args: Args) -> None: for keep_file in keep_files: src = pathlib.Path(temp_dir, keep_file) - if keep_file == "Makefile": - dst = pathlib.Path.cwd() / "Makefile.awx-operator" - else: - dst = pathlib.Path.cwd() / keep_file + dst = pathlib.Path.cwd() / keep_file print(f"Updating {keep_file!r} ...", file=sys.stderr, flush=True)