Skip to content

Build branch and deploy to env #1

Build branch and deploy to env

Build branch and deploy to env #1

name: Build branch and deploy to env
on:
workflow_dispatch:
inputs:
branch:
description: "Git ref (branch or tag) to build and deploy"
required: true
environment:
description: "Target environment"
type: choice
required: true
default: staging
options:
- staging
- sandbox
- production
permissions:
id-token: write
contents: read
env:
AWS_REGION: us-east-1
ECR_REPOSITORY: registry
EKS_CLUSTER: ce-registry-eks
jobs:
build-and-deploy:
if: ${{ github.repository_owner == 'CredentialEngine' }}
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ inputs.branch }}
fetch-depth: 0
submodules: recursive
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT }}:role/github-oidc-widget
aws-region: ${{ env.AWS_REGION }}
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Compute image tags
id: tags
run: |
REF_TAG=$(echo "${{ inputs.branch }}" | sed 's#refs/heads/##' | tr '[:upper:]' '[:lower:]' | sed -E 's#[^a-z0-9._-]+#-#g')
DATE_TAG=$(date -u +%Y.%m.%d).$(printf "%04d" $(( GITHUB_RUN_NUMBER % 10000 )) )
echo "ref_tag=$REF_TAG" >> "$GITHUB_OUTPUT"
echo "date_tag=$DATE_TAG" >> "$GITHUB_OUTPUT"
- name: Build and push image
uses: docker/build-push-action@v5
with:
context: .
file: Dockerfile
platforms: linux/amd64
push: true
tags: |
${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ steps.tags.outputs.ref_tag }}
${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ steps.tags.outputs.date_tag }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Install kubectl
uses: azure/setup-kubectl@v4
with:
version: v1.29.6
- name: Update kubeconfig
run: |
aws eks update-kubeconfig --name "${{ env.EKS_CLUSTER }}" --region "${{ env.AWS_REGION }}"
- name: Deploy to selected environment (set images)
env:
IMAGE: ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ steps.tags.outputs.ref_tag }}
run: |
ENV="${{ inputs.environment }}"
case "$ENV" in
staging) NS="credreg-staging" ; ENV_DIR="k8s-manifests-staging" ;;
sandbox) NS="credreg-sandbox" ; ENV_DIR="k8s-manifests-sandbox" ;;
production) NS="credreg-prod" ; ENV_DIR="k8s-manifests-prod" ;;
*) echo "Unknown environment: $ENV" >&2; exit 1 ;;
esac
echo "Updating deployments in $NS to image $IMAGE"
kubectl -n "$NS" set image deploy/main-app main-app="$IMAGE"
kubectl -n "$NS" set image deploy/worker-app worker="$IMAGE"
kubectl -n "$NS" rollout status deploy/main-app --timeout=10m
kubectl -n "$NS" rollout status deploy/worker-app --timeout=10m
echo "Applying ConfigMap for $ENV"
pushd terraform/environments/eks > /dev/null
kubectl -n "$NS" apply -f "$ENV_DIR/app-configmap.yaml"
popd > /dev/null
echo "Restarting deployments to pick up config changes"
kubectl -n "$NS" rollout restart deploy/worker-app
kubectl -n "$NS" rollout restart deploy/main-app
kubectl -n "$NS" rollout status deploy/worker-app --timeout=10m
kubectl -n "$NS" rollout status deploy/main-app --timeout=10m
- name: Run DB migrations
env:
IMAGE: ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ steps.tags.outputs.ref_tag }}
run: |
set -euo pipefail
ENV="${{ inputs.environment }}"
case "$ENV" in
staging)
NS="credreg-staging"
MANIFEST="terraform/environments/eks/k8s-manifests-staging/db-migrate-job.yaml"
;;
sandbox)
NS="credreg-sandbox"
MANIFEST="terraform/environments/eks/k8s-manifests-sandbox/db-migrate-job.yaml"
;;
production)
NS="credreg-prod"
MANIFEST="terraform/environments/eks/k8s-manifests-prod/db-migrate-job.yaml"
;;
*)
echo "Unknown environment: $ENV" >&2
exit 1
;;
esac
if [ ! -f "$MANIFEST" ]; then
echo "Migration manifest $MANIFEST not found; skipping"
exit 0
fi
IMAGE_VALUE="${IMAGE:-}"
if [ -z "$IMAGE_VALUE" ]; then
echo "IMAGE env not set; reading current image from deploy/main-app"
IMAGE_VALUE=$(kubectl -n "$NS" get deploy/main-app -o jsonpath='{.spec.template.spec.containers[?(@.name=="main-app")].image}')
fi
if [ -z "$IMAGE_VALUE" ]; then
echo "Unable to determine image for migrations" >&2
exit 1
fi
echo "Launching DB migration job in $NS with image $IMAGE_VALUE"
JOB_NAME=$(
sed -e "s#namespace: .*#namespace: $NS#" \
-e "s#image: .*#image: $IMAGE_VALUE#" "$MANIFEST" |
kubectl -n "$NS" create -f - -o name | sed 's|job.batch/||'
)
kubectl -n "$NS" wait --for=condition=complete "job/$JOB_NAME" --timeout=10m
kubectl -n "$NS" logs -f "job/$JOB_NAME" --all-containers=true
- name: Notify Slack (deploy)
if: always()
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
REPO: ${{ github.repository }}
RUN_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
ENVIRONMENT: ${{ inputs.environment }}
BRANCH: ${{ inputs.branch }}
IMAGE: ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ steps.tags.outputs.ref_tag }}
run: |
if [ -z "${SLACK_WEBHOOK_URL}" ]; then
echo "SLACK_WEBHOOK_URL not set; skipping notification";
exit 0;
fi
STATUS="${{ job.status }}"; EMOJI=✅; [ "$STATUS" = "failure" ] && EMOJI=❌
MSG="$EMOJI Deploy ${STATUS} for ${REPO} (env: ${ENVIRONMENT}, branch: ${BRANCH}). Image: ${IMAGE}. ${RUN_URL}"
payload=$(jq -nc --arg text "$MSG" '{text:$text}')
curl -sS -X POST -H 'Content-type: application/json' --data "$payload" "$SLACK_WEBHOOK_URL" || true