diff --git a/.github/actions/check-go-license-boilerplate/action.yaml b/.github/actions/check-go-license-boilerplate/action.yaml new file mode 100644 index 0000000..8b16f92 --- /dev/null +++ b/.github/actions/check-go-license-boilerplate/action.yaml @@ -0,0 +1,42 @@ +name: Check Go license boilerplate +description: Check license boilerplate used in Go files +inputs: + boilerplate-path: + description: License boilerplate file path + required: true + boilerplate-content: + description: License boilerplate content + default: |- + /* + SPDX-FileCopyrightText: ${YEAR} SAP SE or an SAP affiliate company and ${REPOSITORY} contributors + SPDX-License-Identifier: Apache-2.0 + */ +runs: + using: composite + steps: + - name: Check boilerplate file + shell: bash + env: + INPUT_BOILERPLATE_PATH: ${{ inputs.boilerplate-path }} + INPUT_BOILERPLATE_CONTENT: ${{ inputs.boilerplate-content }} + run: | + this_year=$(date +%Y) + last_year=$((this_year-1)) + repository=$(echo $GITHUB_REPOSITORY | cut -d/ -f2) + + tempdir=$(mktemp -d) + trap 'rm -rf $tempdir' EXIT + + printenv INPUT_BOILERPLATE_CONTENT | YEAR=$this_year REPOSITORY=$repository envsubst > $tempdir/boilerplate-this-year + printenv INPUT_BOILERPLATE_CONTENT | YEAR=$last_year REPOSITORY=$repository envsubst > $tempdir/boilerplate-last-year + + if diff -q $INPUT_BOILERPLATE_PATH $tempdir/boilerplate-this-year >/dev/null; then + exit 0 + fi + if diff -q $INPUT_BOILERPLATE_PATH $tempdir/boilerplate-last-year >/dev/null; then + >&1 echo "Warning: license boilerplate outdated ($last_year); next year, this will result in an error." + exit 0 + fi + + >&1 echo "Error: incorrect license boilerplate." + exit 1 diff --git a/.github/actions/check-go-license-headers/action.yaml b/.github/actions/check-go-license-headers/action.yaml new file mode 100644 index 0000000..6d8db51 --- /dev/null +++ b/.github/actions/check-go-license-headers/action.yaml @@ -0,0 +1,45 @@ +name: Check Go license headers +description: Check license headers of Go files +inputs: + base-path: + description: Base directory + default: . + boilerplate-path: + description: License header file path + required: true +runs: + using: composite + steps: + - name: Check files + shell: ruby {0} + env: + INPUT_BASE_PATH: ${{ inputs.base-path }} + INPUT_BOILERPLATE_PATH: ${{ inputs.boilerplate-path }} + run: | + base_path = ENV["INPUT_BASE_PATH"] + raise "Input parameter base-path must not start with slash" if base_path.start_with?("/") + raise "Input parameter base-path must not be empty" if base_path.empty? + raise "Specified base-path does not exist: #{base_path}" if !Dir.exists?(base_path) + + boilerplate_path = ENV["INPUT_BOILERPLATE_PATH"] + raise "Input parameter boilerplate-path must not start with slash" if boilerplate_path.start_with?("/") + raise "Input parameter boilerplate-path must not be empty" if boilerplate_path.empty? + + boilerplate = File.readlines(boilerplate_path) + errors = 0 + + Dir.glob("**/*.go").each do |p| + file = File.readlines(p) + file.each_with_index do |line,i| + next if line =~ /^\/\/go:build/ + next if line =~ /^\/\/\s*\+build/ + next if line =~ /^\s*$/ + if file[i,boilerplate.size] != boilerplate then + STDERR.puts "#{p}: bad or missing license header" + errors += 1 + end + break + end + end + + exit 1 if errors > 0 \ No newline at end of file diff --git a/.github/actions/get-highest-tag/action.yaml b/.github/actions/get-highest-tag/action.yaml index 20147c4..bc526ad 100644 --- a/.github/actions/get-highest-tag/action.yaml +++ b/.github/actions/get-highest-tag/action.yaml @@ -3,6 +3,7 @@ description: Get highest semver tag in current repository inputs: prefix: description: Tag prefix (only tags with that prefix are considered) + default: '' outputs: tag: description: Highest tag (according to semver ordering) diff --git a/.github/actions/setup-helm-docs/action.yaml b/.github/actions/setup-helm-docs/action.yaml index 1c00296..1d17601 100644 --- a/.github/actions/setup-helm-docs/action.yaml +++ b/.github/actions/setup-helm-docs/action.yaml @@ -3,55 +3,53 @@ description: Setup helm-docs inputs: version: description: Version - required: true default: latest install-directory: description: Target installation directory - required: false default: '$HOME/.helm-docs/bin' outputs: path: description: Path to the installed helm-docs executable value: ${{ steps.install.outputs.path }} runs: - using: "composite" + using: composite steps: - - name: Install helm-docs - id: install - shell: bash - run: | - version=${{ inputs.version}} - install_directory=${{ inputs.install-directory }} - if [ "$version" == latest ]; then - version=$(curl -sSf https://api.github.com/repos/norwoodj/helm-docs/releases/latest | jq -r .tag_name) - fi - version=${version/#v/} - case $(uname -s) in - Linux) - os=Linux - ;; - *) - >&1 echo "Unsupported OS: $(uname -s)" - exit 1 - ;; - esac - case $(uname -m) in - arm64|aarch64) - arch=arm64 - ;; - x86_64|amd64) - arch=x86_64 - ;; - *) - >&1 echo "§Unsupported architecture: $(uname -m)" - exit 1 - ;; - esac - mkdir -p "$install_directory" - temp_directory=$(mktemp -d) - trap 'rm -rf $temp_directory' EXIT - curl -sSfL https://github.com/norwoodj/helm-docs/releases/download/v${version}/helm-docs_${version}_${os}_${arch}.tar.gz | tar xz -C $temp_directory - cp -f $temp_directory/helm-docs $install_directory - chmod a+x "$install_directory/helm-docs" - echo "$install_directory" >> $GITHUB_PATH - echo "path=$install_directory/helm-docs" >> $GITHUB_OUTPUT \ No newline at end of file + - name: Install helm-docs + id: install + shell: bash + run: | + version=${{ inputs.version}} + install_directory=${{ inputs.install-directory }} + if [ "$version" == latest ]; then + version=$(curl -sSf https://api.github.com/repos/norwoodj/helm-docs/releases/latest | jq -r .tag_name) + fi + version=${version/#v/} + case $(uname -s) in + Linux) + os=Linux + ;; + *) + >&1 echo "Unsupported OS: $(uname -s)" + exit 1 + ;; + esac + case $(uname -m) in + arm64|aarch64) + arch=arm64 + ;; + x86_64|amd64) + arch=x86_64 + ;; + *) + >&1 echo "§Unsupported architecture: $(uname -m)" + exit 1 + ;; + esac + mkdir -p "$install_directory" + temp_directory=$(mktemp -d) + trap 'rm -rf $temp_directory' EXIT + curl -sSfL https://github.com/norwoodj/helm-docs/releases/download/v${version}/helm-docs_${version}_${os}_${arch}.tar.gz | tar xz -C $temp_directory + cp -f $temp_directory/helm-docs $install_directory + chmod a+x "$install_directory/helm-docs" + echo "$install_directory" >> $GITHUB_PATH + echo "path=$install_directory/helm-docs" >> $GITHUB_OUTPUT \ No newline at end of file diff --git a/.github/actions/setup-semver/action.yaml b/.github/actions/setup-semver/action.yaml index 129d769..8daae9a 100644 --- a/.github/actions/setup-semver/action.yaml +++ b/.github/actions/setup-semver/action.yaml @@ -3,30 +3,28 @@ description: Setup semver inputs: version: description: Version - required: true default: latest install-directory: description: Target installation directory - required: false default: '$HOME/.semver/bin' outputs: path: description: Path to the installed semver executable value: ${{ steps.install.outputs.path }} runs: - using: "composite" + using: composite steps: - - name: Install semver - id: install - shell: bash - run: | - version=${{ inputs.version}} - install_directory=${{ inputs.install-directory }} - if [ "$version" == latest ]; then - version=master - fi - mkdir -p "$install_directory" - curl -sSf -L -o "$install_directory/semver" https://raw.githubusercontent.com/fsaintjacques/semver-tool/$version/src/semver - chmod a+x "$install_directory/semver" - echo "$install_directory" >> $GITHUB_PATH - echo "path=$install_directory/semver" >> $GITHUB_OUTPUT \ No newline at end of file + - name: Install semver + id: install + shell: bash + run: | + version=${{ inputs.version}} + install_directory=${{ inputs.install-directory }} + if [ "$version" == latest ]; then + version=master + fi + mkdir -p "$install_directory" + curl -sSf -L -o "$install_directory/semver" https://raw.githubusercontent.com/fsaintjacques/semver-tool/$version/src/semver + chmod a+x "$install_directory/semver" + echo "$install_directory" >> $GITHUB_PATH + echo "path=$install_directory/semver" >> $GITHUB_OUTPUT \ No newline at end of file diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000..dbf0fa6 --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,164 @@ +name: Build artifacts + +on: + push: + branches: + - main + + pull_request: + branches: + - main + +concurrency: build-${{ github.ref }} + +env: + REGISTRY: ghcr.io + +defaults: + run: + shell: bash + +jobs: + test: + name: Run tests + runs-on: ubuntu-22.04 + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Setup go + uses: actions/setup-go@v4 + with: + go-version-file: go.mod + + - name: Check that license header boilerplate is correct + uses: ./.github/actions/check-go-license-boilerplate + with: + boilerplate-path: hack/boilerplate.go.txt + + - name: Check that license headers are correct + uses: ./.github/actions/check-go-license-headers + with: + boilerplate-path: hack/boilerplate.go.txt + + - name: Check that generated artifacts are up-to-date + run: | + make generate + echo "Running 'git status' ..." + if [ -z "$(git status --porcelain)" ]; then + echo "Generated artifacts are up-to-date." + else + >&1 echo "Generated artifacts are not up-to-date; probably 'make generate' was not run before committing." + exit 1 + fi + + build-docker_controller: + name: Build Docker image (controller) + runs-on: ubuntu-22.04 + needs: test + permissions: + contents: read + outputs: + image-archive: image_controller.tar + image-repository: ${{ steps.prepare-repository-name.outputs.repository }} + image-tag: ${{ steps.extract-metadata.outputs.version }} + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Prepare repository name + id: prepare-repository-name + run: | + repository=$REGISTRY/${{ github.repository }}/controller + echo "repository=${repository,,}" >> $GITHUB_OUTPUT + + - name: Extract metadata (tags, labels) for Docker + id: extract-metadata + uses: docker/metadata-action@v4 + with: + images: ${{ steps.prepare-repository-name.outputs.repository }} + + - name: Build Docker image + uses: docker/build-push-action@v4 + with: + platforms: linux/amd64,linux/arm64 + context: . + file: build/controller/Dockerfile + cache-from: | + type=gha,scope=sha-${{ github.sha }}/controller + type=gha,scope=${{ github.ref_name }}/controller + type=gha,scope=${{ github.base_ref || 'main' }}/controller + type=gha,scope=main/controller + cache-to: | + type=gha,scope=sha-${{ github.sha }}/controller,mode=max + type=gha,scope=${{ github.ref_name }}/controller,mode=max + outputs: | + type=oci,dest=${{ runner.temp }}/image_controller.tar + tags: ${{ steps.extract-metadata.outputs.tags }} + labels: ${{ steps.extract-metadata.outputs.labels }} + + - name: Upload Docker image archive + uses: actions/upload-artifact@v3 + with: + name: image_controller.tar + path: ${{ runner.temp }}/image_controller.tar + + build-docker_webhook: + name: Build Docker image (webhook) + runs-on: ubuntu-22.04 + needs: test + permissions: + contents: read + outputs: + image-archive: image_webhook.tar + image-repository: ${{ steps.prepare-repository-name.outputs.repository }} + image-tag: ${{ steps.extract-metadata.outputs.version }} + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Prepare repository name + id: prepare-repository-name + run: | + repository=$REGISTRY/${{ github.repository }}/webhook + echo "repository=${repository,,}" >> $GITHUB_OUTPUT + + - name: Extract metadata (tags, labels) for Docker + id: extract-metadata + uses: docker/metadata-action@v4 + with: + images: ${{ steps.prepare-repository-name.outputs.repository }} + + - name: Build Docker image + uses: docker/build-push-action@v4 + with: + platforms: linux/amd64,linux/arm64 + context: . + file: build/webhook/Dockerfile + cache-from: | + type=gha,scope=sha-${{ github.sha }}/webhook + type=gha,scope=${{ github.ref_name }}/webhook + type=gha,scope=${{ github.base_ref || 'main' }}/webhook + type=gha,scope=main/webhook + cache-to: | + type=gha,scope=sha-${{ github.sha }}/webhook,mode=max + type=gha,scope=${{ github.ref_name }}/webhook,mode=max + outputs: | + type=oci,dest=${{ runner.temp }}/image_webhook.tar + tags: ${{ steps.extract-metadata.outputs.tags }} + labels: ${{ steps.extract-metadata.outputs.labels }} + + - name: Upload Docker image archive + uses: actions/upload-artifact@v3 + with: + name: image_webhook.tar + path: ${{ runner.temp }}/image_webhook.tar \ No newline at end of file diff --git a/.github/workflows/determine-bump-level.yaml b/.github/workflows/determine-bump-level.yaml deleted file mode 100644 index 7cb7a8a..0000000 --- a/.github/workflows/determine-bump-level.yaml +++ /dev/null @@ -1,36 +0,0 @@ -name: Determine bump level between two release tags - -on: - push: - tags: [ 'v[0-9].[0-9].[0-9]' ] - -defaults: - run: - shell: bash - -jobs: - determine_bump_level: - name: Determine bump level - runs-on: ubuntu-22.04 - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Determine version bump value - id: version-bump-value - uses: ./.github/actions/determine-bump-level - with: - token: ${{ secrets.WORKFLOW_USER_GH_TOKEN }} - - - name: Create a workflow_dispatch event in clustersecret-operator-helm repo - run: | - curl --request POST \ - --header "Accept: application/vnd.github+json" \ - --header "Authorization: Bearer ${{ secrets.WORKFLOW_USER_GH_TOKEN }}" \ - --url https://api.github.com/repos/sap/clustersecret-operator-helm/actions/workflows/bump-version.yaml/dispatches \ - --data '{ - "ref":"main", - "inputs":{ - "version-bump":"${{ steps.version-bump-value.outputs.bump-level }}" - } - }' diff --git a/.github/workflows/publish-crds.yaml b/.github/workflows/publish-crds.yaml deleted file mode 100644 index 077a535..0000000 --- a/.github/workflows/publish-crds.yaml +++ /dev/null @@ -1,38 +0,0 @@ -name: Publish Custom Resource Definitions - -on: - release: - types: [published] - -env: - REGISTRY: ghcr.io - -defaults: - run: - shell: bash - -jobs: - build: - runs-on: ubuntu-22.04 - permissions: - contents: read - packages: write - - steps: - - name: Setup regctl - run: | - curl -sSf -L -o $RUNNER_TEMP/regctl https://github.com/regclient/regclient/releases/download/v0.4.8/regctl-linux-amd64 - chmod a+x $RUNNER_TEMP/regctl - - - name: Checkout repository - uses: actions/checkout@v3 - - - name: Log in to the registry - run: | - $RUNNER_TEMP/regctl registry login $REGISTRY --user ${{ github.actor }} --pass-stdin <<< ${{ secrets.GITHUB_TOKEN }} - - - name: Build artifact - run: | - cd crds - repository=${{ github.repository }}/crds - tar cvz * | $RUNNER_TEMP/regctl artifact put -m application/gzip $REGISTRY/${repository,,}:${{ github.event.release.tag_name }} \ No newline at end of file diff --git a/.github/workflows/publish-docker.yaml b/.github/workflows/publish-docker.yaml deleted file mode 100644 index c6f8c36..0000000 --- a/.github/workflows/publish-docker.yaml +++ /dev/null @@ -1,121 +0,0 @@ -name: Publish Docker - -on: - release: - types: [published] - - push: - branches: - - main - paths-ignore: - - website/** - - .github/workflows/publish-website.yaml - - README.md - - pull_request: - branches: - - main - paths-ignore: - - website/** - - .github/workflows/publish-website.yaml - - README.md - -env: - REGISTRY: ghcr.io - -defaults: - run: - shell: bash - -jobs: - build-controller: - runs-on: ubuntu-22.04 - permissions: - contents: read - packages: write - env: - IMAGE_NAME: ${{ github.repository }}/controller - - steps: - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - - name: Checkout repository - uses: actions/checkout@v3 - - - name: Log in to the Container registry - uses: docker/login-action@v2 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Extract metadata (tags, labels) for Docker - id: meta - uses: docker/metadata-action@v4 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - - - name: Build Docker image - uses: docker/build-push-action@v4 - with: - platforms: linux/amd64,linux/arm64 - context: . - file: build/controller/Dockerfile - cache-from: | - type=gha,scope=sha-${{ github.sha }}/controller - type=gha,scope=${{ github.ref_name }}/controller - type=gha,scope=${{ github.base_ref || 'main' }}/controller - type=gha,scope=main/controller - cache-to: | - type=gha,scope=sha-${{ github.sha }}/controller,mode=max - type=gha,scope=${{ github.ref_name }}/controller,mode=max - push: ${{ github.event_name == 'release' }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - - build-webhook: - runs-on: ubuntu-22.04 - permissions: - contents: read - packages: write - env: - IMAGE_NAME: ${{ github.repository }}/webhook - - steps: - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - - name: Checkout repository - uses: actions/checkout@v3 - - - name: Log in to the Container registry - uses: docker/login-action@v2 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Extract metadata (tags, labels) for Docker - id: meta - uses: docker/metadata-action@v4 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - - - name: Build Docker image - uses: docker/build-push-action@v4 - with: - platforms: linux/amd64,linux/arm64 - context: . - file: build/webhook/Dockerfile - cache-from: | - type=gha,scope=sha-${{ github.sha }}/webhook - type=gha,scope=${{ github.ref_name }}/webhook - type=gha,scope=${{ github.base_ref || 'main' }}/webhook - type=gha,scope=main/webhook - cache-to: | - type=gha,scope=sha-${{ github.sha }}/webhook,mode=max - type=gha,scope=${{ github.ref_name }}/webhook,mode=max - push: ${{ github.event_name == 'release' }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/publish-website.yaml b/.github/workflows/publish-website.yaml index e27440c..82c4d86 100644 --- a/.github/workflows/publish-website.yaml +++ b/.github/workflows/publish-website.yaml @@ -1,4 +1,4 @@ -name: Publish Website +name: Publish website on: push: @@ -16,7 +16,7 @@ permissions: id-token: write concurrency: - group: "pages" + group: pages cancel-in-progress: false defaults: @@ -58,7 +58,7 @@ jobs: - name: Setup Node uses: actions/setup-node@v3 with: - node-version: '${{ steps.get_node_version.outputs.node_version }}' + node-version: ${{ steps.get_node_version.outputs.node_version }} - name: Update dependencies run: | @@ -81,7 +81,7 @@ jobs: - name: Upload artifact uses: actions/upload-pages-artifact@v1 with: - path: ./website/public + path: website/public deploy: environment: diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml new file mode 100644 index 0000000..26f0e49 --- /dev/null +++ b/.github/workflows/publish.yaml @@ -0,0 +1,256 @@ +name: Publish artifacts + +on: + release: + types: [published] + +concurrency: release-${{ github.event.release.tag_name }} + +env: + REGCTL_VERSION: v0.4.8 + SEMVER_VERSION: 3.4.0 + REGISTRY: ghcr.io + # CHART_REPOSITORY: + # CHART_DIRECTORY: + +defaults: + run: + shell: bash + +jobs: + publish-docker_controller: + name: Publish Docker image (controller) + runs-on: ubuntu-22.04 + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Log in to the Container registry + uses: docker/login-action@v2 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ github.token }} + + - name: Prepare repository name + id: prepare-repository-name + run: | + repository=$REGISTRY/${{ github.repository }}/controller + echo "repository=${repository,,}" >> $GITHUB_OUTPUT + + - name: Extract metadata (tags, labels) for Docker + id: extract-metadata + uses: docker/metadata-action@v4 + with: + images: ${{ steps.prepare-repository-name.outputs.repository }} + + - name: Build and push Docker image + uses: docker/build-push-action@v4 + with: + platforms: linux/amd64,linux/arm64 + context: . + file: build/controller/Dockerfile + cache-from: | + type=gha,scope=sha-${{ github.sha }}/controller + type=gha,scope=${{ github.ref_name }}/controller + type=gha,scope=${{ github.base_ref || 'main' }}/controller + type=gha,scope=main/controller + cache-to: | + type=gha,scope=sha-${{ github.sha }}/controller,mode=max + type=gha,scope=${{ github.ref_name }}/controller,mode=max + push: true + tags: ${{ steps.extract-metadata.outputs.tags }} + labels: ${{ steps.extract-metadata.outputs.labels }} + + publish-docker_webhook: + name: Publish Docker image (webhook) + runs-on: ubuntu-22.04 + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Log in to the Container registry + uses: docker/login-action@v2 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ github.token }} + + - name: Prepare repository name + id: prepare-repository-name + run: | + repository=$REGISTRY/${{ github.repository }}/webhook + echo "repository=${repository,,}" >> $GITHUB_OUTPUT + + - name: Extract metadata (tags, labels) for Docker + id: extract-metadata + uses: docker/metadata-action@v4 + with: + images: ${{ steps.prepare-repository-name.outputs.repository }} + + - name: Build and push Docker image + uses: docker/build-push-action@v4 + with: + platforms: linux/amd64,linux/arm64 + context: . + file: build/webhook/Dockerfile + cache-from: | + type=gha,scope=sha-${{ github.sha }}/webhook + type=gha,scope=${{ github.ref_name }}/webhook + type=gha,scope=${{ github.base_ref || 'main' }}/webhook + type=gha,scope=main/webhook + cache-to: | + type=gha,scope=sha-${{ github.sha }}/webhook,mode=max + type=gha,scope=${{ github.ref_name }}/webhook,mode=max + push: true + tags: ${{ steps.extract-metadata.outputs.tags }} + labels: ${{ steps.extract-metadata.outputs.labels }} + + publish-crds: + name: Publish CRD image + runs-on: ubuntu-22.04 + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Setup regctl + uses: regclient/actions/regctl-installer@main + with: + release: ${{ env.REGCTL_VERSION }} + install-dir: ${{ runner.temp }}/bin + + - name: Log in to the registry + # regctl-login action is currently broken ... + # uses: regclient/actions/regctl-login@main + # with: + # registry: ${{ env.REGISTRY }} + # username: ${{ github.actor }} + # password: ${{ github.token }} + run: | + regctl registry login $REGISTRY --user ${{ github.actor }} --pass-stdin <<< ${{ github.token }} + + - name: Build and push artifact + run: | + cd crds + repository=$REGISTRY/${{ github.repository }}/crds + tar cvz * | regctl artifact put -m application/gzip ${repository,,}:${{ github.event.release.tag_name }} + + update-chart: + name: Update Helm chart + runs-on: ubuntu-22.04 + needs: [publish-docker_controller,publish-docker_webhook,publish-crds] + + steps: + - name: Prepare + id: prepare + run: | + chart_repository=$CHART_REPOSITORY + if [ -z "$chart_repository" ]; then + chart_repository=${{ github.repository }}-helm + fi + echo "chart_repository=$chart_repository" >> $GITHUB_OUTPUT + + chart_directory=$CHART_DIRECTORY + if [ -z "$chart_directory" ]; then + chart_directory=chart + fi + echo "chart_directory=$chart_directory" >> $GITHUB_OUTPUT + + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Checkout chart repository + uses: actions/checkout@v3 + with: + repository: ${{ steps.prepare.outputs.chart_repository }} + path: chart-repository + token: ${{ secrets.WORKFLOW_USER_GH_TOKEN }} + + - name: Setup semver + uses: ./.github/actions/setup-semver + with: + version: ${{ env.SEMVER_VERSION }} + install-directory: ${{ runner.temp }}/bin + + - name: Update chart repository + id: update + run: | + cd chart-repository + chart_directory=${{ steps.prepare.outputs.chart_directory }} + + old_version=$(yq .appVersion $chart_directory/Chart.yaml) + if [ "${old_version:0:1}" != v ] || [ "$(semver validate $old_version)" != valid ]; then + >&1 echo "Found invalid current appVersion ($old_version) in $chart_directory/Chart.yaml)." + exit 1 + fi + + new_version=${{ github.event.release.tag_name }} + if [ "${new_version:0:1}" != v ] || [ "$(semver validate $new_version)" != valid ]; then + >&1 echo "Invalid target appVersion ($new_version)." + exit 1 + fi + + if [ $(semver compare $new_version $old_version) -lt 0 ]; then + echo "Target appVersion ($new_version) is lower than current appVersion ($old_version); skipping update ..." + exit 0 + fi + + version_bump=$(semver diff $new_version $old_version) + echo "Found appVersion bump: $version_bump." + if [ "$version_bump" != major ] && [ "$version_bump" != minor ]; then + version_bump=patch + fi + echo "Performing chart version bump: $version_bump ..." + + echo "Updating custom resource definitions ($chart_directory/crds) ..." + rm -rf $chart_directory/crds + cp -r ../crds $chart_directory + + echo "Updating appVersion in $chart_directory/Chart.yaml (current: $old_version; target: $new_version) ..." + perl -pi -e "s#^appVersion:.*#appVersion: $new_version#g" $chart_directory/Chart.yaml + + if [ -z "$(git status --porcelain)" ]; then + echo "Nothing has changed; skipping commit/push ..." + exit 0 + fi + + git config user.name "${{ vars.WORKFLOW_USER_NAME }}" + git config user.email "${{ vars.WORKFLOW_USER_EMAIL }}" + git add -A + git commit -F- <> $GITHUB_OUTPUT + + - name: Release chart repository + if: steps.update.outputs.version_bump != '' + uses: benc-uk/workflow-dispatch@v1 + with: + repo: ${{ steps.prepare.outputs.chart_repository }} + workflow: release.yaml + ref: main + token: ${{ secrets.WORKFLOW_USER_GH_TOKEN }} + inputs: '{ "version-bump": "${{ steps.update.outputs.version_bump }}" }' diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 9febf5b..f68ceb4 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -1,14 +1,10 @@ -name: Release Docker +name: Trigger release on: workflow_dispatch: inputs: version-bump: description: 'Whether to bump major, minor or patch version' - # For exmaple: - # Bump major version (i.e. current_version=v1.2.3 --> new_version=v2.0.0)' - # Bump minor version (i.e. current_version=v1.2.3 --> new_version=v1.3.0) - # Bump patch version (i.e. current_version=v1.2.3 --> new_version=v1.2.4) required: false default: patch type: choice @@ -17,16 +13,16 @@ on: - minor - patch desired-version: - description: 'Version of docker image to be released' + description: 'Version to be released; if specified, version-bump will be ignored' required: false default: '' - ref: - description: 'The branch, tag, or SHA to release' - required: false - default: 'main' + +concurrency: trigger-release env: - REGISTRY: ghcr.io + TAG_PREFIX: v + INITIAL_TAG: v0.1.0 + SEMVER_VERSION: 3.4.0 defaults: run: @@ -34,49 +30,99 @@ defaults: jobs: release: - name: Create release + name: Trigger release + runs-on: ubuntu-22.04 permissions: contents: write - runs-on: ubuntu-22.04 + + # TODO: ensure that github.ref is not refs/tags/* + # TODO: maybe even ensure that github.ref == refs/heads/main steps: - - name: Checkout + - name: Checkout repository uses: actions/checkout@v3 with: token: ${{ secrets.WORKFLOW_USER_GH_TOKEN }} - - name: Get latest tag - uses: actions-ecosystem/action-get-latest-tag@v1 - if: inputs.desired-version == '' - id: get-latest-tag + - name: Setup semver + uses: ./.github/actions/setup-semver with: - semver_only: true - initial_version: 'v0.0.0' + version: ${{ env.SEMVER_VERSION }} + install-directory: ${{ runner.temp }}/bin - - name: Bump version - uses: actions-ecosystem/action-bump-semver@v1 - if: inputs.desired-version == '' - id: bump-semver + - name: Determine current release + id: get_current_release + uses: ./.github/actions/get-highest-tag with: - current_version: ${{ steps.get-latest-tag.outputs.tag }} - level: ${{ inputs.version-bump }} + prefix: ${{ env.TAG_PREFIX }} - - name: Prepare version - id: prepare-version + - name: Determine target release + id: get_target_release run: | - if "${{ inputs.desired-version != '' }}" - then - echo "version=${{ inputs.desired-version }}" >> $GITHUB_OUTPUT + desired_version=${{ inputs.desired-version }} + current_version=${{ steps.get_current_release.outputs.version }} + version_bump=${{ inputs.version-bump }} + + if [ -z "$desired_version" ]; then + case $version_bump in + major|minor|patch) + # ok + ;; + *) + >&1 echo "Invalid input: version-bump ($version_bump)." + exit 1 + esac + if [ -z "$current_version" ]; then + version=${INITIAL_TAG/#$TAG_PREFIX/} + tag=$INITIAL_TAG + else + version=$(semver bump $version_bump $current_version) + tag=$TAG_PREFIX$version + fi else - echo "version=${{ steps.bump-semver.outputs.new_version }}" >> $GITHUB_OUTPUT - fi - + if [[ $desired_version =~ ^$TAG_PREFIX([0-9].*)$ ]]; then + version=${BASH_REMATCH[1]} + tag=$desired_version + else + >&1 echo "Invalid input: desired-version ($desired_version) should start with $TAG_PREFIX." + exit 1 + fi + if [ "$(semver validate $version)" != valid ]; then + >&1 echo "Invalid input: desired-version ($version) is not a valid semantic version." + exit 1 + fi + if [ "$(semver compare $version $current_version)" -le 0 ]; then + >&1 echo "Invalid input: desired-version ($version) should be higher than current version ($current_version)." + exit 1 + fi + fi + + echo "Target version: $version" + echo "Target tag: $tag" + echo "version=$version" >> $GITHUB_OUTPUT + echo "tag=$tag" >> $GITHUB_OUTPUT + + - name: Determine target commit + id: get_target_commit + run: | + sha=$(git rev-parse HEAD) + echo "Target commit: $sha" + echo "sha=$sha" >> $GITHUB_OUTPUT + + - name: Wait for check suites to complete + uses: sap-contributions/await-check-suites@master + with: + ref: ${{ steps.get_target_commit.outputs.sha }} + intervalSeconds: 10 + timeoutSeconds: 1800 + failStepIfUnsuccessful: true + appSlugFilter: github-actions + - name: Create Release - id: create_release uses: softprops/action-gh-release@v1 with: - tag_name: ${{ steps.prepare-version.outputs.version }} + tag_name: ${{ steps.get_target_release.outputs.tag }} draft: false prerelease: false - target_commitish: ${{ inputs.ref }} + target_commitish: ${{ steps.get_target_commit.outputs.sha }} token: ${{ secrets.WORKFLOW_USER_GH_TOKEN }} - generate_release_notes: true + generate_release_notes: false diff --git a/Makefile b/Makefile index 6c6312f..c6d4169 100644 --- a/Makefile +++ b/Makefile @@ -42,8 +42,8 @@ test-webhook: @go test -v ./internal/admission # generate code -.PHONY: generate-code -generate-code: +.PHONY: generate +generate: @hack/update-codegen.sh --parallel # format code diff --git a/hack/LICENSE_BOILERPLATE.txt b/hack/boilerplate.go.txt similarity index 100% rename from hack/LICENSE_BOILERPLATE.txt rename to hack/boilerplate.go.txt diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index a8db338..1c907ac 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -11,6 +11,7 @@ fi cd $(dirname "${BASH_SOURCE[0]}")/.. +go mod download k8s.io/code-generator CODEGEN_PKG=$(go list -m -f '{{.Dir}}' k8s.io/code-generator) GEN_PKG_PATH=$(go list -m)/pkg OUTPUT_BASE=$(mktemp -d) @@ -26,6 +27,6 @@ trap 'rm -rf "${OUTPUT_BASE}"' EXIT "${GEN_PKG_PATH}"/client "${GEN_PKG_PATH}"/apis \ core.cs.sap.com:v1alpha1 \ --output-base "${OUTPUT_BASE}"/ \ - --go-header-file ./hack/LICENSE_BOILERPLATE.txt + --go-header-file ./hack/boilerplate.go.txt rm -rf "./pkg/client" && cp -Rf "${OUTPUT_BASE}"/"${GEN_PKG_PATH}" .