From a4ebdd73f15d27bcfcec8aa8a8066d812022627f Mon Sep 17 00:00:00 2001 From: Kirill Plis Date: Tue, 27 Jan 2026 08:22:53 +0100 Subject: [PATCH 1/3] cicd optimization --- .github/workflows/build-image.yaml | 5 - .github/workflows/commit-and-push.yaml | 0 .github/workflows/deploy-to-eks.yaml | 192 +++++++++++++++++++++++++ .github/workflows/kubernetes.yaml | 2 +- 4 files changed, 193 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/commit-and-push.yaml create mode 100644 .github/workflows/deploy-to-eks.yaml diff --git a/.github/workflows/build-image.yaml b/.github/workflows/build-image.yaml index 2edb895..a15a166 100644 --- a/.github/workflows/build-image.yaml +++ b/.github/workflows/build-image.yaml @@ -17,11 +17,6 @@ on: description: If provided, sets targets for as many image builds as targets specified default: "" type: string - preScript: - required: false - description: If provided, runs a script after repo checkout and before the docker image is built. Useful in case that you need to build a package outside of the docker image (and load the artifacts via copy). - default: "" - type: string enableContainerScan: required: false description: Apply the container scan diff --git a/.github/workflows/commit-and-push.yaml b/.github/workflows/commit-and-push.yaml new file mode 100644 index 0000000..e69de29 diff --git a/.github/workflows/deploy-to-eks.yaml b/.github/workflows/deploy-to-eks.yaml new file mode 100644 index 0000000..dcf0f36 --- /dev/null +++ b/.github/workflows/deploy-to-eks.yaml @@ -0,0 +1,192 @@ +name: Kubernetes +on: + workflow_call: + inputs: + artifactName: + required: false + description: Downloads a previously uploaded artifact (has to be in the same workflow). Both artifactPath and artifactName have to be passed. + default: "" + type: string + artifactPath: + required: false + description: Downloads a previously uploaded artifact (has to be in the same workflow). Both artifactPath and artifactName have to be passed. + default: "" + type: string + createGitHubDeployment: + required: false + default: false + type: boolean + enableContainerScan: + required: false + default: true + type: boolean + enableSlackNotification: + required: false + default: false + type: boolean + env: + required: true + type: string + imageTargets: + required: false + description: Sets targets for as many image builds as targets specified in Containerfile + default: "" + type: string + preScript: + required: false + description: Runs a script after repo checkout and before the docker image is built. Useful in case that you need to build a package outside of the docker image (and load the artifacts via copy). + default: "" + type: string + ref: + required: true + type: string + runner: + required: false + default: ubicloud-standard-2 # TODO: or ubuntu-latest? + type: string + sentryOrg: + required: false + type: string + sentryProject: + required: false + type: string + tagPath: + required: false + type: string + secrets: + # slackBotToken: + # required: false + # description: The Slack bot token to write messages in the desired channels (required if slack channel ids are provided) + AWS_ROLE_TO_ASSUME: + required: true + description: AWS OIDC role for GitHub to assume + repoAccessToken: + required: true + description: The Github token to perform operations cross-repo (not github.token!) + +jobs: + init: + runs-on: ${{ inputs.runner }} + outputs: + version: ${{ steps.vars.outputs.version }} + steps: + - name: Load deployment variables + id: vars + run: | + REF="${{ inputs.ref }}" + SHA="${{ github.sha }}" + if [[ "${{ inputs.env }}" == 'prod' ]] + then + # shellcheck disable=SC2086 + echo "version=${REF##*/}" >> $GITHUB_OUTPUT + else + # shellcheck disable=SC2086 + echo "version=${SHA:0:7}" >> $GITHUB_OUTPUT + + build: + needs: init + runs-on: ${{ inputs.runner }} + permissions: + contents: read + id-token: write + uses: parcelLab/ci/.github/workflows/build-image.yaml@v9.0.0 + with: + artifactName: ${{ inputs.artifactName }} + artifactPath: ${{ inputs.artifactPath }} + imageTargets: ${{ inputs.imageTargets }} + enableContainerScan: ${{ inputs.enableContainerScan }} + runner: ${{ inputs.runner }} + version: ${{ needs.initialize.outputs.version }} + secrets: inherit + + commit: + needs: build + environment: ${{ github.event.deployment.payload.env }} + concurrency: commit-${{ inputs.deploymentRepoURL }}-${{ github.sha }} + runs-on: ${{ inputs.runner }} + steps: + - name: Checkout current git repository + uses: actions/checkout@v6 + - name: Deploy ${{ github.sha }} to ${{ github.event.deployment.environment }} values + uses: mikefarah/yq@v4.30.8 + with: + cmd: yq '(.${{ inputs.tagPath }} = "${{ needs.initialize.outputs.version }}")' -i remote/${{ inputs.deploymentRepoPath }}/values.yaml + - name: Commit and push new tag + run: | + set -euxo pipefail + git config user.email "dev.bot@parcellab.com" + git config user.name "parcellab-dev-bot" + git add .chart/${{ inputs.env }}/values.yaml + if git diff --cached --quiet; then + echo "No changes to commit" + exit 0 + fi + git commit -m "chore(deploy): set ${{ inputs.env }} image tag to ${{ needs.kubernetes.outputs.version }}" + + if [ "${{ inputs.env }}" = "staging" ]; then + echo "Commit new tag to staging" + NEW_SHA=$(git rev-parse HEAD) + git tag -fa staging -m "staging deploy ${VERSION} (${NEW_SHA}) via ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" "${NEW_SHA}" + git push origin -f refs/tags/staging + else + echo "Commit new tag to ${{ inputs.env }}" + git push origin HEAD:main + fi + + post-deploy: + needs: [commit] + runs-on: ${{ inputs.runner }} + steps: + - if: inputs.enableSlackNotification + name: Send out Slack notification + continue-on-error: true + uses: darioblanco/slack-deployment@main + env: + SLACK_BOT_TOKEN: ${{ secrets.slackBotToken }} + with: + channel_id: ${{ needs.initialize.outputs.channel-id }} + deployment_description: ${{ github.event.deployment.payload.description == null && 'No description' || github.event.deployment.payload.description }} + deployment_name: ${{ github.event.deployment.payload.name == null && 'unknown' || github.event.deployment.payload.name }} + environment: ${{ github.event.deployment.payload.env == null && 'unknown' || github.event.deployment.payload.env }} + owner: ${{ github.event.deployment.payload.author == null && github.actor || github.event.deployment.payload.author }} + package: ${{ github.event.deployment.payload.name == null && 'unknown' || github.event.deployment.payload.name }} + ref: ${{ github.event.deployment.ref == null && 'unknown' || github.event.deployment.ref }} + repo: ${{ github.repository }} + sha: ${{ github.sha }} + status_url: ${{ github.event.deployment.payload.statusUrl == null && 'https://github.com' || github.event.deployment.payload.statusUrl }} + url: ${{ github.event.deployment.payload.url == null && 'https://github.com' || github.event.deployment.payload.url }} + version: ${{ needs.initialize.outputs.version }} + - if: inputs.sentryOrg != '' && inputs.sentryProject != '' + name: Create Sentry release + uses: getsentry/action-release@v1 + env: + SENTRY_AUTH_TOKEN: ${{ secrets.sentryAuthToken }} + SENTRY_ORG: ${{ inputs.sentryOrg }} + SENTRY_PROJECT: ${{ inputs.sentryProject }} + SENTRY_URL: ${{ inputs.sentryUrl }} + with: + environment: ${{ inputs.sentryEnvironment != '' && inputs.sentryEnvironment || github.event.deployment.payload.env }} + set_commits: skip + version: ${{ needs.initialize.outputs.version }} + continue-on-error: true + - if: inputs.createGitHubDeployment + name: Create GitHub Deployment + uses: chrnorm/deployment-action@v2 + with: + token: ${{ secrets.REPO_ACCESS_TOKEN }} + ref: ${{ github.event.inputs.ref }} + environment: ${{ github.event.inputs.env }} + description: ${{ github.event.inputs.description != '' && github.event.inputs.description || format('Manual deployment {0}', github.sha) }} + auto-merge: false + payload: | + {"env":${{ toJSON(github.event.inputs.env) }},"name":"product-api","author":${{ toJSON(github.event.inputs.author) }},"description":${{ toJSON(github.event.inputs.description) }},"kubernetes":{"versionKey":"monolith.image.tag"}} + - if: inputs.createGitHubDeployment + name: Set GitHub Deployment status to successfull + uses: chrnorm/deployment-status@v2 + with: + deployment-id: ${{ github.event.deployment.id }} + environment-url: ${{ github.event.deployment.payload.url }} + environment: ${{ github.event.deployment.payload.env }} + state: "success" + token: ${{ github.token }} + \ No newline at end of file diff --git a/.github/workflows/kubernetes.yaml b/.github/workflows/kubernetes.yaml index 761c0e4..c8ce5eb 100644 --- a/.github/workflows/kubernetes.yaml +++ b/.github/workflows/kubernetes.yaml @@ -204,7 +204,7 @@ jobs: repository: ${{ inputs.deploymentRepoURL }} directory: remote github_token: ${{ secrets.repoAccessToken }} - branch: main + branch: ${{ input.ref }} - if: success() name: Successful ${{ github.event.deployment.payload.name }} deployment uses: chrnorm/deployment-status@v2 From b9f99ca2559078a6199f42942f1f19b6e7f228d4 Mon Sep 17 00:00:00 2001 From: Kirill Plis Date: Fri, 13 Feb 2026 09:54:25 +0100 Subject: [PATCH 2/3] save changes --- ...-eks.yaml => build-and-deploy-to-eks.yaml} | 29 +++++++------------ 1 file changed, 10 insertions(+), 19 deletions(-) rename .github/workflows/{deploy-to-eks.yaml => build-and-deploy-to-eks.yaml} (88%) diff --git a/.github/workflows/deploy-to-eks.yaml b/.github/workflows/build-and-deploy-to-eks.yaml similarity index 88% rename from .github/workflows/deploy-to-eks.yaml rename to .github/workflows/build-and-deploy-to-eks.yaml index dcf0f36..a0634f8 100644 --- a/.github/workflows/deploy-to-eks.yaml +++ b/.github/workflows/build-and-deploy-to-eks.yaml @@ -20,10 +20,6 @@ on: required: false default: true type: boolean - enableSlackNotification: - required: false - default: false - type: boolean env: required: true type: string @@ -32,17 +28,12 @@ on: description: Sets targets for as many image builds as targets specified in Containerfile default: "" type: string - preScript: - required: false - description: Runs a script after repo checkout and before the docker image is built. Useful in case that you need to build a package outside of the docker image (and load the artifacts via copy). - default: "" - type: string ref: required: true type: string runner: required: false - default: ubicloud-standard-2 # TODO: or ubuntu-latest? + default: ubuntu-latest type: string sentryOrg: required: false @@ -50,19 +41,19 @@ on: sentryProject: required: false type: string + slackChannelId: + required: false + type: string tagPath: required: false type: string secrets: - # slackBotToken: - # required: false - # description: The Slack bot token to write messages in the desired channels (required if slack channel ids are provided) + slackBotToken: + required: false + description: The Slack bot token to write messages in the desired channels (required if slack channel ids are provided) AWS_ROLE_TO_ASSUME: required: true description: AWS OIDC role for GitHub to assume - repoAccessToken: - required: true - description: The Github token to perform operations cross-repo (not github.token!) jobs: init: @@ -137,15 +128,15 @@ jobs: needs: [commit] runs-on: ${{ inputs.runner }} steps: - - if: inputs.enableSlackNotification + - if: inputs.slackChannelId name: Send out Slack notification continue-on-error: true uses: darioblanco/slack-deployment@main env: SLACK_BOT_TOKEN: ${{ secrets.slackBotToken }} with: - channel_id: ${{ needs.initialize.outputs.channel-id }} - deployment_description: ${{ github.event.deployment.payload.description == null && 'No description' || github.event.deployment.payload.description }} + channel_id: ${{ inputs.slackChannelId }} + deployment_description: "No description" deployment_name: ${{ github.event.deployment.payload.name == null && 'unknown' || github.event.deployment.payload.name }} environment: ${{ github.event.deployment.payload.env == null && 'unknown' || github.event.deployment.payload.env }} owner: ${{ github.event.deployment.payload.author == null && github.actor || github.event.deployment.payload.author }} From 9db008a13c09904929e81292634af3e45070ed2f Mon Sep 17 00:00:00 2001 From: Kirill Plis Date: Mon, 16 Feb 2026 12:12:53 +0100 Subject: [PATCH 3/3] fix references --- .../workflows/build-and-deploy-to-eks.yaml | 73 ++++++++++++------- 1 file changed, 48 insertions(+), 25 deletions(-) diff --git a/.github/workflows/build-and-deploy-to-eks.yaml b/.github/workflows/build-and-deploy-to-eks.yaml index a0634f8..d6761d5 100644 --- a/.github/workflows/build-and-deploy-to-eks.yaml +++ b/.github/workflows/build-and-deploy-to-eks.yaml @@ -12,6 +12,17 @@ on: description: Downloads a previously uploaded artifact (has to be in the same workflow). Both artifactPath and artifactName have to be passed. default: "" type: string + description: + required: false + type: string + deploymentRepoPath: + required: false + description: Path to the values.yaml file in the deployment repository (e.g. .chart/staging) + type: string + deploymentRepoURL: + required: false + description: URL of the deployment repository + type: string createGitHubDeployment: required: false default: false @@ -41,6 +52,12 @@ on: sentryProject: required: false type: string + sentryEnvironment: + required: false + type: string + sentryUrl: + required: false + type: string slackChannelId: required: false type: string @@ -51,6 +68,10 @@ on: slackBotToken: required: false description: The Slack bot token to write messages in the desired channels (required if slack channel ids are provided) + sentryAuthToken: + required: false + REPO_ACCESS_TOKEN: + required: false AWS_ROLE_TO_ASSUME: required: true description: AWS OIDC role for GitHub to assume @@ -87,36 +108,37 @@ jobs: imageTargets: ${{ inputs.imageTargets }} enableContainerScan: ${{ inputs.enableContainerScan }} runner: ${{ inputs.runner }} - version: ${{ needs.initialize.outputs.version }} + version: ${{ needs.init.outputs.version }} secrets: inherit commit: needs: build - environment: ${{ github.event.deployment.payload.env }} + environment: ${{ inputs.env }} concurrency: commit-${{ inputs.deploymentRepoURL }}-${{ github.sha }} runs-on: ${{ inputs.runner }} steps: - name: Checkout current git repository uses: actions/checkout@v6 - - name: Deploy ${{ github.sha }} to ${{ github.event.deployment.environment }} values + - name: Deploy ${{ github.sha }} to ${{ inputs.env }} values uses: mikefarah/yq@v4.30.8 with: - cmd: yq '(.${{ inputs.tagPath }} = "${{ needs.initialize.outputs.version }}")' -i remote/${{ inputs.deploymentRepoPath }}/values.yaml + cmd: yq '(.${{ inputs.tagPath }} = "${{ needs.init.outputs.version }}")' -i ${{ inputs.deploymentRepoPath }}/values.yaml - name: Commit and push new tag run: | set -euxo pipefail git config user.email "dev.bot@parcellab.com" git config user.name "parcellab-dev-bot" - git add .chart/${{ inputs.env }}/values.yaml + git add ${{ inputs.deploymentRepoPath }}/values.yaml if git diff --cached --quiet; then echo "No changes to commit" exit 0 fi - git commit -m "chore(deploy): set ${{ inputs.env }} image tag to ${{ needs.kubernetes.outputs.version }}" + git commit -m "chore(deploy): set ${{ inputs.env }} image tag to ${{ needs.init.outputs.version }}" if [ "${{ inputs.env }}" = "staging" ]; then echo "Commit new tag to staging" NEW_SHA=$(git rev-parse HEAD) + VERSION="${{ needs.init.outputs.version }}" git tag -fa staging -m "staging deploy ${VERSION} (${NEW_SHA}) via ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" "${NEW_SHA}" git push origin -f refs/tags/staging else @@ -125,7 +147,7 @@ jobs: fi post-deploy: - needs: [commit] + needs: [init, commit] runs-on: ${{ inputs.runner }} steps: - if: inputs.slackChannelId @@ -137,16 +159,16 @@ jobs: with: channel_id: ${{ inputs.slackChannelId }} deployment_description: "No description" - deployment_name: ${{ github.event.deployment.payload.name == null && 'unknown' || github.event.deployment.payload.name }} - environment: ${{ github.event.deployment.payload.env == null && 'unknown' || github.event.deployment.payload.env }} - owner: ${{ github.event.deployment.payload.author == null && github.actor || github.event.deployment.payload.author }} - package: ${{ github.event.deployment.payload.name == null && 'unknown' || github.event.deployment.payload.name }} - ref: ${{ github.event.deployment.ref == null && 'unknown' || github.event.deployment.ref }} + deployment_name: ${{ inputs.artifactName != '' && inputs.artifactName || 'unknown' }} + environment: ${{ inputs.env }} + owner: ${{ github.actor }} + package: ${{ inputs.artifactName != '' && inputs.artifactName || 'unknown' }} + ref: ${{ inputs.ref }} repo: ${{ github.repository }} sha: ${{ github.sha }} - status_url: ${{ github.event.deployment.payload.statusUrl == null && 'https://github.com' || github.event.deployment.payload.statusUrl }} - url: ${{ github.event.deployment.payload.url == null && 'https://github.com' || github.event.deployment.payload.url }} - version: ${{ needs.initialize.outputs.version }} + status_url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + version: ${{ needs.init.outputs.version }} - if: inputs.sentryOrg != '' && inputs.sentryProject != '' name: Create Sentry release uses: getsentry/action-release@v1 @@ -156,28 +178,29 @@ jobs: SENTRY_PROJECT: ${{ inputs.sentryProject }} SENTRY_URL: ${{ inputs.sentryUrl }} with: - environment: ${{ inputs.sentryEnvironment != '' && inputs.sentryEnvironment || github.event.deployment.payload.env }} + environment: ${{ inputs.sentryEnvironment != '' && inputs.sentryEnvironment || inputs.env }} set_commits: skip - version: ${{ needs.initialize.outputs.version }} + version: ${{ needs.init.outputs.version }} continue-on-error: true - if: inputs.createGitHubDeployment name: Create GitHub Deployment uses: chrnorm/deployment-action@v2 + id: deployment with: token: ${{ secrets.REPO_ACCESS_TOKEN }} - ref: ${{ github.event.inputs.ref }} - environment: ${{ github.event.inputs.env }} - description: ${{ github.event.inputs.description != '' && github.event.inputs.description || format('Manual deployment {0}', github.sha) }} + ref: ${{ inputs.ref }} + environment: ${{ inputs.env }} + description: ${{ inputs.description != '' && inputs.description || format('Manual deployment {0}', github.sha) }} auto-merge: false payload: | - {"env":${{ toJSON(github.event.inputs.env) }},"name":"product-api","author":${{ toJSON(github.event.inputs.author) }},"description":${{ toJSON(github.event.inputs.description) }},"kubernetes":{"versionKey":"monolith.image.tag"}} + {"env":${{ toJSON(inputs.env) }},"name":"product-api","author":${{ toJSON(github.actor) }},"description":${{ toJSON(inputs.description) }},"kubernetes":{"versionKey":"monolith.image.tag"}} - if: inputs.createGitHubDeployment - name: Set GitHub Deployment status to successfull + name: Set GitHub Deployment status to successful uses: chrnorm/deployment-status@v2 with: - deployment-id: ${{ github.event.deployment.id }} - environment-url: ${{ github.event.deployment.payload.url }} - environment: ${{ github.event.deployment.payload.env }} + deployment-id: ${{ steps.deployment.outputs.deployment_id }} + environment-url: ${{ steps.deployment.outputs.environment_url }} + environment: ${{ inputs.env }} state: "success" token: ${{ github.token }} \ No newline at end of file