Skip to content

Instantly share code, notes, and snippets.

@tobias-goertz
Last active July 20, 2021 09:27
Show Gist options
  • Save tobias-goertz/2be3624575e11b99dc29b066c377017e to your computer and use it in GitHub Desktop.
Save tobias-goertz/2be3624575e11b99dc29b066c377017e to your computer and use it in GitHub Desktop.
SetOps GitHub Actions Template

SetOps GitHub Actions Template

Prerequisites

This template is made for a web application with 3 apps (web, job, clock). Each app will be released with the same Image.

Steps to do

  1. Copy template into your existing GH-Actions Workflow

  2. Extend your existing ENVs with the ones in line 4-9 at the beginning of your file and change the values regarding your project

  3. Add the deploy job to the end of your existing jobs

  4. Check your SetOps apps:

    • How many apps does your SetOps deployment have?
    • The template comes with 3 apps: SETOPS_WEB_APP,SETOPS_WORKER_APP & SETOPS_CLOCK_APP
    • Change the name of the apps in the env section of the template
    • if you need more apps, copy lines 97-99 (create release), and 122-124 (activate release) and rename the ENV values. You need to add the name of your app at the env section at the beginning of the file
    • The container Checks (l. 143-168) defaults to HEALTHY in case there is a healthcheck or RUNNING if not
  5. Change the needs section of the deploy job (line 15)

  6. For testing purposes, you might want to change the deployed branch name. Do this in lines 16 & 25.

  7. We use a .git_revision file to make the Revision-SHA available inside a container (see l. 78). Make sure, the file exists in your repo.

Deploy User

Once you configured your template, you need a SetOps user who deploys your application.

  1. Ask in #setops-geniusbar for user creation and name your project repository
  2. The SetOps team will create the SetOps user and share the credentials with Milan (He will add the secrets to the Repo)
  3. The secret values are SETOPS_USER and SETOPS_PASSWORD
  4. The SetOps team will tell you the email of the user, you need to add him via setops --stage <STAGE> user invite invalid@example.com
name: Test-and-Deployment
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: false
env:
SETOPS_WEB_APP: "web"
SETOPS_WORKER_APP: "worker"
SETOPS_CLOCK_APP: "clock"
SETOPS_IMAGE: "IMAGENAME"
SETOPS_STAGE_PREFIX: "ccmycv"
SETOPS_HOST: "zweitag.setops.net"
jobs:
deploy:
name: deploy
runs-on: ubuntu-latest
needs: [test, yarn_eslint, rufo-and-rubocop] # put your other jobs here
if: github.ref == 'refs/heads/production' || github.ref == 'refs/heads/staging'
steps:
# ----- Set env.SETOPS_STAGE from current branch ------
- name: "[Config] Extract branch name"
run: |
echo "BRANCH_NAME=${GITHUB_REF#refs/heads/}" >> $GITHUB_ENV
# Set App env by branch name
- name: "[Config] Set up app env 'staging'"
if: env.BRANCH_NAME == 'staging'
run: |
echo "APP_ENV=staging" >> $GITHUB_ENV
- name: "[Config] Set up app env 'production'"
if: env.BRANCH_NAME == 'production'
run: |
echo "APP_ENV=production" >> $GITHUB_ENV
# Stop here if no app env could be determined
- name: "[Config] Validate app env"
if: env.APP_ENV == ''
run: |
echo "⚠️ Could not determine app env for branch ${{ env.BRANCH_NAME }}"
exit 1
- name: "[Config] Prepare Setops config"
run: |
echo "SETOPS_STAGE=${{ env.SETOPS_STAGE_PREFIX}}-${{ env.APP_ENV }}" >> $GITHUB_ENV
echo "SETOPS_TARGET_IMAGE=${{ env.SETOPS_HOST }}/${{ env.SETOPS_STAGE_PREFIX }}/${{ env.APP_ENV }}:${{ env.SETOPS_WEB_APP }}" >> $GITHUB_ENV
- name: "[Config] Summarize Config"
run: |
echo "Branch name: ${{ env.BRANCH_NAME }}"
echo "App env: ${{ env.APP_ENV }}"
echo "Setops Stage: ${{ env.SETOPS_STAGE }}"
echo "Image: ${{ env.SETOPS_IMAGE }}"
echo "Target Image: ${{ env.SETOPS_TARGET_IMAGE }}"
# ----- Install dependencies -----
- name: "[Setup] Install Setops"
uses: setopsco/setup-setops@v1
with:
setops_url: https://${{ env.SETOPS_HOST }}
setops_username: ${{ secrets.SETOPS_USER }}
setops_password: ${{ secrets.SETOPS_PASSWORD }}
- name: "[Setup] Get Setops login command"
run: |
LOGIN_COMMAND=$(setops registry get-login-command | grep printf)
eval $LOGIN_COMMAND
# ----- Discard old Changeset -----
- name: "[Setup] Discard old Changeset"
run: |
setops --stage ${{ env.SETOPS_STAGE }} discard || true
- name: "[Setup] Install Pack CLI"
uses: buildpacks/github-actions/setup-pack@main
# ----- Build image -----
- name: "[Build] Checkout repository"
uses: actions/checkout@v2
- name: "[Build] Set git revision"
run: |
git rev-parse --short "$GITHUB_SHA" > .git_revision
- name: "[Build] Build image"
run: |
pack build ${{ env.SETOPS_IMAGE }} --builder heroku/buildpacks:20 --env-file=".env.build"
# ----- Push image -----
- name: "[Push] Tag image"
run: |
docker tag ${{ env.SETOPS_IMAGE}}:latest ${{ env.SETOPS_TARGET_IMAGE }}
- name: "[Push] Push image"
run: |
SETOPS_DIGEST=$(docker push ${{ env.SETOPS_TARGET_IMAGE }} | grep -o 'sha256:[a-zA-Z0-9]*')
echo "SETOPS_DIGEST=$SETOPS_DIGEST" >> $GITHUB_ENV
# ----- Create releases -----
- name: "[Release] Create web release"
run: |
SETOPS_RELEASE_ID_WEB=$(setops --stage ${{ env.SETOPS_STAGE }} app release create ${{ env.SETOPS_WEB_APP }} --digest ${{ env.SETOPS_DIGEST }} | grep -o 'ReleaseID.*' | grep -o '[0-9].*')
echo "SETOPS_RELEASE_ID_WEB=$SETOPS_RELEASE_ID_WEB" >> $GITHUB_ENV
- name: "[Release] Create worker release"
run: |
SETOPS_RELEASE_ID_WORKER=$(setops --stage ${{ env.SETOPS_STAGE }} app release create ${{ env.SETOPS_WORKER_APP }} --digest ${{ env.SETOPS_DIGEST }} | grep -o 'ReleaseID.*' | grep -o '[0-9].*')
echo "SETOPS_RELEASE_ID_WORKER=$SETOPS_RELEASE_ID_WORKER" >> $GITHUB_ENV
- name: "[Release] Create clock release"
run: |
SETOPS_RELEASE_ID_CLOCK=$(setops --stage ${{ env.SETOPS_STAGE }} app release create ${{ env.SETOPS_CLOCK_APP }} --digest ${{ env.SETOPS_DIGEST }} | grep -o 'ReleaseID.*' | grep -o '[0-9].*')
echo "SETOPS_RELEASE_ID_CLOCK=$SETOPS_RELEASE_ID_CLOCK" >> $GITHUB_ENV
- name: "[Release] Setops commit"
run: |
setops --stage ${{ env.SETOPS_STAGE }} status
setops --stage ${{ env.SETOPS_STAGE }} --output plain commit
# ----- Run deploy tasks -----
- name: "[Release] Run Deploy Tasks"
run: |
setops --stage ${{ env.SETOPS_STAGE }} run ${{ env.SETOPS_WEB_APP }} --debug --release ${{ env.SETOPS_RELEASE_ID_WEB}} -- './bin/run_deploy_tasks'
# ----- Activate release -----
- name: "[Release] Activate WEB release"
run: |
setops --stage ${{ env.SETOPS_STAGE }} app release set ${{ env.SETOPS_WEB_APP }} ${{ env.SETOPS_RELEASE_ID_WEB }}
- name: "[Release] Activate WORKER release"
run: |
setops --stage ${{ env.SETOPS_STAGE }} app release set ${{ env.SETOPS_WORKER_APP }} ${{ env.SETOPS_RELEASE_ID_WORKER }}
- name: "[Release] Activate CLOCK release"
run: |
setops --stage ${{ env.SETOPS_STAGE }} app release set ${{ env.SETOPS_CLOCK_APP }} ${{ env.SETOPS_RELEASE_ID_CLOCK }}
- name: "[Release] Setops commit"
run: |
setops --stage ${{ env.SETOPS_STAGE }} status
setops --stage ${{ env.SETOPS_STAGE }} --output plain commit
- name: "[Release] Wait for Healthy WEB Container"
timeout-minutes: 2
run: |
until setops --stage ${{ env.SETOPS_STAGE }} app ps ${{ env.SETOPS_WEB_APP }} |grep -w -E "${{ env.SETOPS_RELEASE_ID_WEB }}.*HEALTHY"
do
echo "Container not up & healthy, retry in 5 seconds"
sleep 5
done
- name: "[Release] Wait for Healthy WORKER Container"
timeout-minutes: 2
run: |
until setops --stage ${{ env.SETOPS_STAGE }} app ps ${{ env.SETOPS_WORKER_APP }} |grep -w -E "${{ env.SETOPS_RELEASE_ID_WORKER }}.*RUNNING"
do
echo "Container not up & healthy, retry in 5 seconds"
sleep 5
done
- name: "[Release] Wait for Healthy CLOCK Container"
timeout-minutes: 2
run: |
until setops --stage ${{ env.SETOPS_STAGE }} app ps ${{ env.SETOPS_CLOCK_APP }} |grep -w -E "${{ env.SETOPS_RELEASE_ID_CLOCK }}.*RUNNING"
do
echo "Container not up & healthy, retry in 5 seconds"
sleep 5
done
- name: "Summarize Deployment"
run: |
echo "✅ Action succeeded!"
echo "-------------------------"
echo "Setops Web App: ${{ env.SETOPS_WEB_APP }}"
echo "Setops Worker App: ${{ env.SETOPS_WORKER_APP }}"
echo "Setops Clock App: ${{ env.SETOPS_CLOCK_APP }}"
echo "Setops Stage: ${{ env.SETOPS_STAGE }}"
echo "Image Digest: ${{ env.SETOPS_DIGEST }}"
echo "Release ID Web: ${{ env.SETOPS_RELEASE_ID_WEB }}"
echo "Release ID Worker: ${{ env.SETOPS_RELEASE_ID_WORKER }}"
echo "Release ID Clock: ${{ env.SETOPS_RELEASE_ID_CLOCK }}"
#!/usr/bin/env bash
# Somewhat inspired by https://github.com/gunpowderlabs/buildpack-ruby-rake-deploy-tasks/blob/master/bin/compile
set -e # fail fast
set -o pipefail # don't ignore exit codes when piping output
echo ""
echo "+-----------------------------+"
echo "| |"
echo "| Running deploy tasks ... |"
echo "| |"
echo "+-----------------------------+"
if [ -z "$DEPLOY_TASKS" ]; then
echo "DEPLOY_TASKS has not been set or is empty."
echo "If set, it should include a list of commands split by ';'"
echo "e.g. DEPLOY_TASKS=rails db:migrate;echo \"HI\""
else
while IFS=';' read -ra TASKS; do
for task in "${TASKS[@]}"; do
echo "==> $task"
echo ""
$task || {
echo "==> \"$task\" failed - exiting"
exit 1
}
echo "==> \"$task\" succeeded"
echo ""
done
done <<< "$DEPLOY_TASKS"
echo ""
echo "+-----------------------------+"
echo "| |"
echo "| Deploy tasks succeeded |"
echo "| |"
echo "+-----------------------------+"
fi
@tobias-goertz
Copy link
Author

Ah yes you're right 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment