Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 170 additions & 0 deletions .github/workflows/build-push-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
on:
workflow_call:
inputs:
service-name:
description: "Name of the service to build. Used as the default image name and src dir unless 'image-name' or 'src-path' are used."
type: string
required: true
stage-name:
description: "The backend environment we are building for (API calls are pointed to). This should be one of (development, staging, production)."
type: string
required: true
deploy-namespace:
description: "The Kubernetes namespace to deploy the service to."
type: string
required: false
docker-build-args:
description: "Extra args passed to 'docker build'."
type: string
required: false
docker-image-ref:
description: "The version number or sha used in creating image tag."
type: string
required: false
default: "${{ github.sha }}"
dockerfiles:
description: "JSON list of dockerfiles to build, e.g. ['Dockerfile1', 'Dockerfile2']"
type: string
required: false
default: "['Dockerfile']"
docker-bake-target:
description: "The target to build with docker bake."
type: string
required: false
docker-bake-platforms:
description: "The platforms to build with docker bake."
type: string
required: false
migration-job-file:
description: "The file path to the migration k8s job YAML."
type: string
required: false
default: "deployment/migration-job.yaml"



jobs:
# Looks for PR labels like "deploy-to-<env>" so we can deploy to those envs
get-deploy-labels:
name: Get Deploy Envs
runs-on: mdb-dev
concurrency:
group: ${{ github.workflow_ref }} # workflow_ref contains the workflow name and branch ref
cancel-in-progress: true # Cancel any in-progress runs on this branch - this one is newer
outputs:
deploy-envs: ${{ steps.get-labels.outputs.deploy-envs }}
steps:
- id: get-labels
uses: mindsdb/github-actions/get-deploy-labels@main


# Build docker image(s) based on Dockerfile(s) and push to ECR
build:
runs-on: mdb-dev
needs: [get-deploy-labels]
if: ${{ !inputs.docker-bake && needs.get-deploy-labels.outputs.deploy-envs != '[]' }}
strategy:
matrix:
dockerfile: ${{fromJson(inputs.dockerfiles)}}
concurrency:
group: ${{ github.workflow_ref }} # workflow_ref contains the workflow name and branch ref
cancel-in-progress: true # Cancel any in-progress runs on this branch - this one is newer
env:
AWS_REGION: us-east-1
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.docker-image-ref }}
# Build via docker-bake if a bakefile is specified
- if: ${{ contains(matrix.dockerfile, '.hcl') }}
uses: mindsdb/github-actions/docker-bake@main
with:
git-sha: ${{ inputs.docker-image-ref }}
target: ${{ inputs.docker-bake-target }}
platforms: ${{ inputs.docker-bake-platforms }}
push-cache: false
# Otherwise build via regular docker
- if: ${{ !contains(matrix.dockerfile, '.hcl') }}
uses: mindsdb/github-actions/build-push-ecr@main
with:
module-name: ${{ inputs.service-name }}
build-for-environment: ${{ inputs.stage-name }}
image-ref: ${{ inputs.docker-image-ref }}
extra-build-args: "-f ${{ matrix.dockerfile }}"


migrate:
runs-on: mdb-dev
needs: [get-deploy-labels, build]
strategy:
matrix:
deploy-env: ${{fromJson(needs.get-deploy-labels.outputs.deploy-envs)}}
concurrency:
group: deploy-${{ matrix.deploy-env }} # All deployments for this env are grouped together
cancel-in-progress: false # Don't cancel in-progress deployments, it breaks helm
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.docker-image-ref }}
- name: Migrate
run: |
export NAMESPACE=${{inputs.deploy-namespace || matrix.deploy-env}}
export IMAGE_TAG=${{ inputs.stage-name }}-${{ inputs.docker-image-ref }}
export JOB_NAME=$(grep -E '^ *name:' ${{ inputs.migration-job-file }} | head -1 | awk '{print $2}')

kubectl -n $NAMESPACE delete job --ignore-not-found $JOB_NAME
envsubst '${IMAGE_TAG} ${NAMESPACE}' < ${{ inputs.migration-job-file }} | kubectl apply -f -
Comment on lines +111 to +116

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correctness: envsubst '${IMAGE_TAG} ${NAMESPACE}' < ${{ inputs.migration-job-file }} will not substitute variables in the YAML unless the YAML contains ${IMAGE_TAG} and ${NAMESPACE} placeholders; if the YAML uses a different variable format or hardcoded values, the migration job will use incorrect image or namespace.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In .github/workflows/build-push-deploy.yml, lines 111-116, the workflow uses `envsubst '${IMAGE_TAG} ${NAMESPACE}' < ${{ inputs.migration-job-file }}` to substitute variables in the migration job YAML. This only works if the YAML contains exactly `${IMAGE_TAG}` and `${NAMESPACE}` placeholders. If the YAML uses different variable names or hardcoded values, the migration job will not use the correct image or namespace, leading to failed or incorrect migrations. Change the line to use `envsubst < ${{ inputs.migration-job-file }}` so all environment variables are substituted, ensuring the correct values are injected.
📝 Committable Code Suggestion

‼️ Ensure you review the code suggestion before committing it to the branch. Make sure it replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
export NAMESPACE=${{inputs.deploy-namespace || matrix.deploy-env}}
export IMAGE_TAG=${{ inputs.stage-name }}-${{ inputs.docker-image-ref }}
export JOB_NAME=$(grep -E '^ *name:' ${{ inputs.migration-job-file }} | head -1 | awk '{print $2}')
kubectl -n $NAMESPACE delete job --ignore-not-found $JOB_NAME
envsubst '${IMAGE_TAG} ${NAMESPACE}' < ${{ inputs.migration-job-file }} | kubectl apply -f -
export NAMESPACE=${{inputs.deploy-namespace || matrix.deploy-env}}
export IMAGE_TAG=${{ inputs.stage-name }}-${{ inputs.docker-image-ref }}
export JOB_NAME=$(grep -E '^ *name:' ${{ inputs.migration-job-file }} | head -1 | awk '{print $2}')
kubectl -n $NAMESPACE delete job --ignore-not-found $JOB_NAME
envsubst < ${{ inputs.migration-job-file }} | kubectl apply -f -


kubectl -n "$NAMESPACE" wait --for=condition=complete --timeout=1m "job/$JOB_NAME"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

performance: kubectl -n "$NAMESPACE" wait --for=condition=complete --timeout=1m "job/$JOB_NAME" uses a fixed 1-minute timeout, which can cause unnecessary resource contention or failed deployments for large/slow migrations, impacting reliability and user experience.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In .github/workflows/build-push-deploy.yml, line 118, the migration job wait step uses a hardcoded 1-minute timeout, which can cause failures for long-running migrations and resource contention. Refactor this to use a configurable timeout (e.g., an input like `migration-wait-timeout` with a sensible default such as 5m), so that deployments can scale for larger jobs.
📝 Committable Code Suggestion

‼️ Ensure you review the code suggestion before committing it to the branch. Make sure it replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
kubectl -n "$NAMESPACE" wait --for=condition=complete --timeout=1m "job/$JOB_NAME"
kubectl -n "$NAMESPACE" wait --for=condition=complete --timeout=${{ inputs.migration-wait-timeout || '5m' }} "job/$JOB_NAME"


# Deploy the built image to the specified environments
# Deploys to all environments at once
deploy:
runs-on: mdb-dev
needs: [ get-deploy-labels, build, migrate ]
strategy:
matrix:
deploy-env: ${{fromJson(needs.get-deploy-labels.outputs.deploy-envs)}}
concurrency:
group: deploy-${{ matrix.deploy-env }} # All deployments for this env are grouped together
cancel-in-progress: false # Don't cancel in-progress deployments, it breaks helm
environment:
# Assuming that ENV_URL is set in a github environment in the repo
# If not the link in the slack message will be borked, thats all
name: ${{ matrix.deploy-env }}
url: ${{ vars.ENV_URL }}
steps:
- uses: actions/checkout@v4
- uses: mindsdb/github-actions/setup-env@main
- name: Notify of deployment starting
# This same message will be updated later with the deployment status
id: slack
uses: mindsdb/github-actions/slack-deploy-msg@main
with:
channel-id: ${{ secrets.SLACK_DEPLOYMENTS_CHANNEL_ID }}
status: "started"
color: "#0099CC"
env-name: ${{ matrix.deploy-env }}
env-url: ${{ vars.ENV_URL }}
slack-token: ${{ secrets.GH_ACTIONS_SLACK_BOT_TOKEN }}
- uses: DevOps-Nirvana/aws-helm-multi-deploy-nodocker@v4
# Do the actual deployment
with:
environment-slug: ${{matrix.deploy-env}}
k8s-namespace: ${{inputs.deploy-namespace || matrix.deploy-env}}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correctness: k8s-namespace assignment uses ${{inputs.deploy-namespace || matrix.deploy-env}}, but GitHub Actions expressions do not support || for defaulting, causing the value to be set to the literal string or empty if deploy-namespace is not provided, resulting in deployments to the wrong namespace or failure.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In .github/workflows/build-push-deploy.yml, line 123, the expression for `k8s-namespace` uses `${{inputs.deploy-namespace || matrix.deploy-env}}`, but GitHub Actions expressions do not support `||` for defaulting. Update this line to use a supported conditional expression so that if `inputs.deploy-namespace` is set (not empty), it is used; otherwise, fall back to `matrix.deploy-env`. Replace the line with: `k8s-namespace: ${{ inputs.deploy-namespace != '' && inputs.deploy-namespace || matrix.deploy-env }}`.
📝 Committable Code Suggestion

‼️ Ensure you review the code suggestion before committing it to the branch. Make sure it replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
k8s-namespace: ${{inputs.deploy-namespace || matrix.deploy-env}}
k8s-namespace: ${{ inputs.deploy-namespace != '' && inputs.deploy-namespace || matrix.deploy-env }}

image-tag: ${{ inputs.stage-name }}-${{ github.sha }}
timeout: 600s
# We need to wait till deployment is finished here, since the calling workflow might test the deployment env once this job is done
wait: "true"
- name: Notify of deployment finish
# Update the slack message from before with the deployment status
uses: mindsdb/github-actions/slack-deploy-msg@main
if: always()
with:
channel-id: ${{ secrets.SLACK_DEPLOYMENTS_CHANNEL_ID }}
status: "${{ job.status == 'success' && 'finished' || 'failed' }}"
color: "${{ job.status == 'success' && '#00C851' || '#FF4444' }}"
env-name: ${{ matrix.deploy-env }}
env-url: ${{ vars.ENV_URL }}
slack-token: ${{ secrets.GH_ACTIONS_SLACK_BOT_TOKEN }}
update-message-id: ${{ steps.slack.outputs.ts }}