diff --git a/.github/workflows/README.md b/.github/workflows/README.md new file mode 100644 index 0000000..66ff8f9 --- /dev/null +++ b/.github/workflows/README.md @@ -0,0 +1,22 @@ +# Github Actions +This monorepo consists of 3 artifacts that are versioned, built, and released separately. +- minimal-app +- operator +- operator/webhook + +## PR builds +When a PR is opened or updated, it will determine if any files changed in each of the sub-project directories. +If a file has changed it will trigger a build for that sub-project which runs a number of checks. + +## Releasing +Release builds are triggered when code is merged to the main branch. +It will also listen to each subdirectory and run the respective release job for each sub-project if any changes were found. + +To perform a new release, simply update the version for a given subproject. +The version can be found either in a version.txt file or pom.xml file at the root of each subproject. +New releases of the same version will never overwrite old releases. +If the intent is to overwrite an old github release or docker image package, then the old artifact and its associated git tags should be deleted first. +If a previous attempt at release failed, it can be re-ran by going to the github actions tab, choose the job that failed, click re-run on the top right, and either run all jobs or failed jobs. + +## Caching +There is currently no caching for builds, but it could be added at a later date. diff --git a/.github/workflows/minimal-app.yml b/.github/workflows/minimal-app.yml new file mode 100644 index 0000000..b26b348 --- /dev/null +++ b/.github/workflows/minimal-app.yml @@ -0,0 +1,94 @@ +name: minimal-app-workflow + +on: + workflow_dispatch: + pull_request: + paths: + - minimal-app/** + - .github/workflows/minimal-app.yml + push: + branches: + - main + paths: + - operator/** + - "!operator/webhook/**" + - .github/workflows/operator.yml + +env: + WORKING_DIR: ./minimal-app + JAVA_VERSION: 17 + GIT_TAG_PREFIX: minimal-app_v + +jobs: + build: + name: build image + if: github.ref != 'refs/heads/main' + runs-on: ubuntu-latest + defaults: + run: + shell: bash + working-directory: ${{ env.WORKING_DIR }} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-java@v3 + with: + java-version: "${{ env.JAVA_VERSION }}" + distribution: "temurin" + - run: mvn --batch-mode --update-snapshots verify + name: build image + + release: + if: github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + defaults: + run: + shell: bash + working-directory: ${{ env.WORKING_DIR }} + permissions: + contents: write # create git tags + packages: write # push docker images + steps: + - uses: actions/checkout@v4 + - run: | + VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) + REGISTRY=$(mvn help:evaluate -Dexpression=docker.registry -q -DforceStdout) + IMAGE_NAME=$(mvn help:evaluate -Dexpression=image-name -q -DforceStdout) + echo "VERSION=$VERSION" >> "$GITHUB_OUTPUT" + echo "REGISTRY=$REGISTRY" >> "$GITHUB_OUTPUT" + echo "TAG_NAME=${{ env.GIT_TAG_PREFIX }}$VERSION" >> "$GITHUB_OUTPUT" + echo "IMAGE_NAME=$REGISTRY/$IMAGE_NAME:$VERSION" >> "$GITHUB_OUTPUT" + cat $GITHUB_OUTPUT + id: naming-selector + name: generate names for artifacts + + - run: | + ! docker manifest inspect ${{ steps.naming-selector.outputs.IMAGE_NAME }} + name: confirm image is not already pushed + + - run: | + git fetch --tags + ! git rev-parse -q --verify "refs/tags/${{ steps.naming-selector.outputs.TAG_NAME }}" + name: confirm git tag does not exist + + - uses: actions/setup-java@v3 + with: + java-version: "${{ env.JAVA_VERSION }}" + distribution: "temurin" + - run: mvn --batch-mode --update-snapshots verify + name: build image + + - uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 + with: + registry: ${{ steps.naming-selector.outputs.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - run: docker push ${{ steps.naming-selector.outputs.IMAGE_NAME }} + + - uses: mathieudutour/github-tag-action@v6.1 + id: tag_version + with: + custom_tag: ${{ steps.naming-selector.outputs.TAG_NAME }} + github_token: ${{ secrets.GITHUB_TOKEN }} + # avoid v prefix before tag + tag_prefix: "" diff --git a/.github/workflows/operator.yml b/.github/workflows/operator.yml new file mode 100644 index 0000000..8c0d1b5 --- /dev/null +++ b/.github/workflows/operator.yml @@ -0,0 +1,74 @@ +name: operator-workflow +on: + workflow_dispatch: + pull_request: + paths: + - operator/** + - "!operator/webhook/**" + - .github/workflows/operator.yml + push: + branches: + - main + paths: + - operator/** + - "!operator/webhook/**" + - .github/workflows/operator.yml + +env: + WORKING_DIR: ./operator + GIT_TAG_PREFIX: operator_v + +jobs: + build: + if: github.ref != 'refs/heads/main' + runs-on: ubuntu-latest + defaults: + run: + shell: bash + working-directory: ${{ env.WORKING_DIR }} + steps: + - uses: actions/checkout@v4 + - run: make prep-release + name: generate release files + + release: + if: github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + defaults: + run: + shell: bash + working-directory: ${{ env.WORKING_DIR }} + steps: + - uses: actions/checkout@v4 + + - run: | + VERSION=$(cat version.txt) + echo "VERSION=$VERSION" >> "$GITHUB_OUTPUT" + echo "TAG_NAME=${{ env.GIT_TAG_PREFIX }}$VERSION" >> "$GITHUB_OUTPUT" + cat $GITHUB_OUTPUT + id: naming-selector + name: generate names for artifacts + + - run: | + git fetch --tags + ! git rev-parse -q --verify "refs/tags/${{ steps.naming-selector.outputs.TAG_NAME }}" + name: confirm git tag does not exist + + - run: make prep-release + name: generate release files + + - uses: mathieudutour/github-tag-action@v6.1 + id: tag_version + with: + custom_tag: ${{ steps.naming-selector.outputs.TAG_NAME }} + github_token: ${{ secrets.GITHUB_TOKEN }} + # avoid v prefix before tag + tag_prefix: "" + + - uses: ncipollo/release-action@v1 + with: + tag: ${{ steps.tag_version.outputs.new_tag }} + name: Release ${{ steps.tag_version.outputs.new_tag }} + body: ${{ steps.tag_version.outputs.changelog }} + artifactErrorsFailBuild: true + artifacts: ${{ env.WORKING_DIR }}/output/* diff --git a/.github/workflows/webhook.yml b/.github/workflows/webhook.yml new file mode 100644 index 0000000..80e8820 --- /dev/null +++ b/.github/workflows/webhook.yml @@ -0,0 +1,105 @@ +name: webhook-workflow +on: + workflow_dispatch: + pull_request: + paths: + - operator/webhook/** + - .github/workflows/webhook.yml + push: + branches: + - main + paths: + - operator/** + - "!operator/webhook/**" + - .github/workflows/operator.yml + +env: + WORKING_DIR: ./operator/webhook + GIT_TAG_PREFIX: webhook_v + +jobs: + test: + name: unit test + runs-on: ubuntu-latest + defaults: + run: + shell: bash + working-directory: ${{ env.WORKING_DIR }} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + - run: python3 -m pip install -r requirements.txt + - run: python3 -m pip install -r requirements-dev.txt + - run: make test + + build: + name: build image + needs: test + if: github.ref != 'refs/heads/main' + runs-on: ubuntu-latest + defaults: + run: + shell: bash + working-directory: ${{ env.WORKING_DIR }} + steps: + - uses: actions/checkout@v4 + - uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 + with: + context: ${{ env.WORKING_DIR }} + push: false + + release: + needs: test + if: github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + defaults: + run: + shell: bash + working-directory: ${{ env.WORKING_DIR }} + permissions: + contents: write # create git tags + packages: write # push docker images + steps: + - uses: actions/checkout@v4 + - run: | + VERSION=$(make get-version) + REGISTRY=$(make get-registry) + IMAGE_NAME=$(make get-image-name) + echo "VERSION=$VERSION" >> "$GITHUB_OUTPUT" + echo "REGISTRY=$REGISTRY" >> "$GITHUB_OUTPUT" + echo "TAG_NAME=${{ env.GIT_TAG_PREFIX }}$VERSION" >> "$GITHUB_OUTPUT" + echo "FULL_IMAGE_NAME=$REGISTRY/$IMAGE_NAME:$VERSION" >> "$GITHUB_OUTPUT" + cat $GITHUB_OUTPUT + id: naming-selector + name: generate names for artifacts + + - run: | + ! docker manifest inspect ${{ steps.naming-selector.outputs.FULL_IMAGE_NAME }} + name: confirm image is not already pushed + + - run: | + git fetch --tags + ! git rev-parse -q --verify "refs/tags/${{ steps.naming-selector.outputs.TAG_NAME }}" + name: confirm git tag does not exist + + - uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 + with: + registry: ${{ steps.naming-selector.outputs.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 + with: + context: ${{ env.WORKING_DIR }} + push: true + tags: ${{ steps.naming-selector.outputs.FULL_IMAGE_NAME }} + + - uses: mathieudutour/github-tag-action@v6.1 + id: tag_version + with: + custom_tag: ${{ steps.naming-selector.outputs.TAG_NAME }} + github_token: ${{ secrets.GITHUB_TOKEN }} + # avoid v prefix before tag + tag_prefix: "" diff --git a/.gitignore b/.gitignore index 582ceec..107625d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ target/ !**/src/main/**/target/ !**/src/test/**/target/ .env +operator/output ### IntelliJ IDEA ### .idea/modules.xml diff --git a/README.md b/README.md index c81be4e..22b2e4c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # Kubernetes Enterprise Integration Patterns (Keip) +[![operator](https://github.com/OctoConsulting/keip/actions/workflows/operator.yml/badge.svg?branch=main)](https://github.com/OctoConsulting/keip/actions/workflows/operator.yml) +[![webhook](https://github.com/OctoConsulting/keip/actions/workflows/webhook.yml/badge.svg?branch=main)](https://github.com/OctoConsulting/keip/actions/workflows/webhook.yml) +[![minimal-app](https://github.com/OctoConsulting/keip/actions/workflows/minimal-app.yml/badge.svg?branch=main)](https://github.com/OctoConsulting/keip/actions/workflows/minimal-app.yml) + The goal of Keip is to provide a simple method for deploying Spring Integration routes using Kuberenetes semantics. Once installed on a Kubernetes cluster, creating SI routes is done by defining the route in XML and diff --git a/minimal-app/pom.xml b/minimal-app/pom.xml index 94d4d72..da3bb29 100644 --- a/minimal-app/pom.xml +++ b/minimal-app/pom.xml @@ -15,6 +15,7 @@ ghcr.io/octoconsulting + keip/${project.artifactId} https://github.com/octoconsulting/keip @@ -115,7 +116,7 @@ - ${docker.registry}/keip/${project.artifactId} + ${docker.registry}/${image-name} ${project.version} diff --git a/operator/Makefile b/operator/Makefile index b4419d9..a12f94b 100644 --- a/operator/Makefile +++ b/operator/Makefile @@ -1,5 +1,3 @@ -# VERSION = 0.1.0 - KEIP_INTEGRATION_IMAGE ?= ghcr.io/octoconsulting/keip-default-image:0.0.2 KUBECTL := kubectl @@ -13,6 +11,14 @@ all: metacontroller/deploy controller/deploy .PHONY: clean clean: controller/undeploy metacontroller/undeploy +prep-release: + rm -rf output + mkdir output + kustomize build ./controller > ./output/controller.yaml + kustomize build ./crd > ./output/crd.yaml + cp ./metacontroller/kustomization.yaml ./output/metacontroller.yaml + ls -al ./output + metacontroller/deploy: $(KUBECTL) apply -k metacontroller diff --git a/operator/crd/v1alpha1/crd.yaml b/operator/crd/crd.yaml similarity index 100% rename from operator/crd/v1alpha1/crd.yaml rename to operator/crd/crd.yaml diff --git a/operator/crd/v1alpha1/kustomization.yaml b/operator/crd/kustomization.yaml similarity index 100% rename from operator/crd/v1alpha1/kustomization.yaml rename to operator/crd/kustomization.yaml diff --git a/operator/version.txt b/operator/version.txt new file mode 100644 index 0000000..6c6aa7c --- /dev/null +++ b/operator/version.txt @@ -0,0 +1 @@ +0.1.0 \ No newline at end of file diff --git a/operator/webhook/Makefile b/operator/webhook/Makefile index ac38465..22ba2d2 100644 --- a/operator/webhook/Makefile +++ b/operator/webhook/Makefile @@ -9,6 +9,18 @@ PYTHON := python3 TEST_COVERAGE_DIR := .test_coverage TEST_COVERAGE_FILE := $(TEST_COVERAGE_DIR)/.coverage +.PHONY: get-version +get-version: + @echo $(VERSION) + +.PHONY: get-registry +get-registry: + @echo $(IMG_REGISTRY) + +.PHONY: get-image-name +get-image-name: + @echo $(IMG_NAME) + .PHONY: start-dev start-dev-server: $(PYTHON) -m uvicorn --port 7080 --reload --app-dir .. webhook.app:app diff --git a/operator/webhook/requirements-dev.txt b/operator/webhook/requirements-dev.txt index d97c158..d51a3a0 100644 --- a/operator/webhook/requirements-dev.txt +++ b/operator/webhook/requirements-dev.txt @@ -1,4 +1,4 @@ -mypy -pytest -httpx -coverage \ No newline at end of file +mypy==1.8.0 +pytest==8.0.0 +httpx==0.26.0 +coverage==7.4.1