Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into qt/refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
qtomlinson committed Jun 5, 2024
2 parents 15b78d4 + 7a47b07 commit 0d53133
Show file tree
Hide file tree
Showing 6 changed files with 6,392 additions and 0 deletions.
134 changes: 134 additions & 0 deletions .github/workflows/app-build-and-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# This workflow will build a docker image, push it to ghcr.io, and deploy it to an Azure WebApp.
# v1.1.0 - This tag coordinates the other reusable parts of this workflow.
# * app-build-docker-image.yml
# * app-deploy-to-azure.yml
# * app-is-deployable.yml
name: Build and Deploy to prod service app

on:
workflow_call:
secrets:
AZURE_CREDENTIALS:
description: 'Service principal that has access to the Azure apps (dev and prod) - Defined in org action secrets'
required: true
AZURE_WEBAPP_PUBLISH_PROFILE:
description: 'Publish profile for the Azure WebApp being deployed - Defined in repo action secrets'
required: true
AZURE_SECONDARY_WEBAPP_PUBLISH_PROFILE:
description: 'Publish profile for a secondary Azure WebApp if being deployed - Defined in repo action secrets'
required: false
DEPLOY_TOKEN:
description: 'Token that is used to determine if the deployment is allowed - Defined in org action secrets'
required: true
PRODUCTION_DEPLOYERS:
description: 'Name of the team that defines who can deploy to production - Defined in org action secrets'
required: true

inputs:
deploy-env:
description: 'environment to deploy (i.e. dev | prod)'
required: true
type: string
application-type:
description: 'application type (i.e. api | worker | ui) - used as a label on the Docker image'
required: true
type: string
azure-app-base-name:
description: 'Azure application name of webapp to deploy (i.e. clearlydefined-api | cdcrawler | clearlydefined)'
required: true
type: string
azure-app-name-postfix:
description: 'postfix to apply to the base name for the primary deploy site (e.g. -prod, -dev)'
required: true
type: string
secondary-azure-app-name-postfix:
description: 'postfix to apply to the base name for a secondary deploy site (e.g. -prod-europe, do not specify if no secondary site)'
type: string
default: ''

jobs:
determine-trigger:
name: Determine if this was triggered by a release or workflow_dispatch
runs-on: ubuntu-latest
outputs:
is-release: ${{ env.IS_RELEASE }}
steps:
- name: Check if this was triggered by a release
id: release
run: |
echo "IS_RELEASE"=${{ github.event_name == 'release' }} >> $GITHUB_ENV
get-version:
name: Get version from package-lock.json
runs-on: ubuntu-latest
needs: determine-trigger
outputs:
version: ${{ env.VERSION }}
steps:
- uses: actions/[email protected]
- name: Get version from package-lock.json
id: get_version
shell: bash
run: |
version='v'$(jq -r '.version' package-lock.json) # e.g. v1.2.0
if [[ ${{ inputs.deploy-env }} == 'prod' ]]; then
if [[ ${{ needs.determine-trigger.outputs.is-release }} == 'true' ]]; then
# validate the version when triggered by a release
if [[ $version != ${{ github.event.release.tag_name }} ]]; then
echo "Version in package-lock.json ($version) does not match the release tag (${{ github.event.release.tag_name }})"
exit 1
fi
fi
elif [[ ${{ inputs.deploy-env }} == 'dev' ]]; then
short_sha=$(echo "${{ github.sha }}" | cut -c 1-10)
version=$version'-dev-'$short_sha # e.g. v1.2.0-dev:1234567890
else
echo "Invalid deploy-env: ${{ inputs.deploy-env }}. Must be 'dev' or 'prod'"
exit 1
fi
echo "VERSION=$version" >> $GITHUB_ENV
echo "BuildAndDeploy: get-version -> outputs -> version: $version"
build-and-publish-image:
name: Build and publish Docker image
needs: get-version
uses: clearlydefined/operations/.github/workflows/[email protected]
secrets:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
PRODUCTION_DEPLOYERS: ${{ secrets.PRODUCTION_DEPLOYERS }}
with:
deploy-env: ${{ inputs.deploy-env }}
application-type: ${{ inputs.application-type }}
image-tag: ${{ needs.get-version.outputs.version }}

deploy-primary-app-to-azure:
name: Deploy to primary Azure app
needs: [get-version, build-and-publish-image]
uses: clearlydefined/operations/.github/workflows/[email protected]
secrets:
AZURE_WEBAPP_PUBLISH_PROFILE: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}
AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }}
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
PRODUCTION_DEPLOYERS: ${{ secrets.PRODUCTION_DEPLOYERS }}
with:
deploy-env: ${{ inputs.deploy-env }}
azure-webapp-name: ${{ inputs.azure-app-base-name }}${{ inputs.azure-app-name-postfix }}
application-version: ${{ needs.get-version.outputs.version }}
image-name-with-tag: ${{ needs.build-and-publish-image.outputs.docker-image-name-with-tag }}

deploy-secondary-app-to-azure:
name: Deploy to secondary Azure app
if: ${{ inputs.secondary-azure-app-name-postfix != '' }}
needs: [get-version, build-and-publish-image]
uses: clearlydefined/operations/.github/workflows/[email protected]
secrets:
AZURE_WEBAPP_PUBLISH_PROFILE: ${{ secrets.AZURE_SECONDARY_WEBAPP_PUBLISH_PROFILE }}
AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }}
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
PRODUCTION_DEPLOYERS: ${{ secrets.PRODUCTION_DEPLOYERS }}
with:
deploy-env: ${{ inputs.deploy-env }}
azure-webapp-name: ${{ inputs.azure-app-base-name }}${{ inputs.secondary-azure-app-name-postfix }}
application-version: ${{ needs.get-version.outputs.version }}
image-name-with-tag: ${{ needs.build-and-publish-image.outputs.docker-image-name-with-tag }}
86 changes: 86 additions & 0 deletions .github/workflows/app-build-docker-image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# This workflow will build a docker image, push it to ghcr.io. It returns the docker image name and tag.
name: Build docker image for Azure app

on:
workflow_call:
secrets:
DEPLOY_TOKEN:
description: 'Token that is used to determine if the deployment is allowed - Defined in org action secrets'
required: true
PRODUCTION_DEPLOYERS:
description: 'Name of the team that defines who can deploy to production - Defined in org action secrets'
required: true

inputs:
deploy-env:
description: 'environment to deploy (i.e. dev | prod) - used as a label for the Docker image'
required: true
type: string
application-type:
description: 'application type (i.e. api | worker | ui) - used as a label for the Docker image'
required: true
type: string
image-tag:
description: 'the tag to use for the image (e.g. prod: v1.2.0, dev: v1.2.0+dev:1D3F567890)'
required: true
type: string

outputs:
docker-image-name-with-tag:
value: ${{ jobs.determine-image-name.outputs.docker-image-name-with-tag }}

jobs:
check-deployable:
uses: clearlydefined/operations/.github/workflows/[email protected]
with:
deploy-env: ${{ inputs.deploy-env }}
secrets:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
PRODUCTION_DEPLOYERS: ${{ secrets.PRODUCTION_DEPLOYERS }}

determine-image-name:
name: Determine Image Name
runs-on: ubuntu-latest
outputs:
docker-image-name-with-tag: ${{ env.DOCKER_IMAGE_NAME_WITH_TAG }}
steps:
- name: Determine Docker Image Name
id: determine_image_name
run: |
image_base_name=ghcr.io/${{ github.repository }} # e.g. ghcr.io/clearlydefined/service
if [[ ${{ inputs.deploy-env }} == 'prod' ]] ; then
image_name_with_tag=$image_base_name':${{ inputs.image-tag }}'
elif [[ ${{ inputs.deploy-env }} == 'dev' ]] ; then
image_name_with_tag=$image_base_name'-dev:${{ inputs.image-tag }}'
else
echo "Invalid deploy-env: ${{ inputs.deploy-env }}. Must be 'dev' or 'prod'"
exit 1
fi
echo "DOCKER_IMAGE_NAME_WITH_TAG=$image_name_with_tag" >> $GITHUB_ENV
echo "DetermineImageName: determine_image_name -> outputs -> image_name_with_tag: $image_name_with_tag"
build-docker-image:
name: Build Image
runs-on: ubuntu-latest
needs: [check-deployable, determine-image-name]
steps:
- uses: actions/[email protected]

- name: Log into ghcr registry
uses: docker/[email protected]
with:
registry: ghcr.io
username: ${{ github.actor }} # user that kicked off the action
password: ${{ secrets.GITHUB_TOKEN }} # token created when the action launched (short lived)

- name: Build and push Docker image
id: build-and-push
uses: docker/[email protected]
with:
context: .
push: true
file: Dockerfile
tags: ${{ needs.determine-image-name.outputs.docker-image-name-with-tag }}
labels: |
env=${{ inputs.deploy-env }}
type=${{ inputs.application-type }}
92 changes: 92 additions & 0 deletions .github/workflows/app-deploy-to-azure.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# This workflow will deploy a Docker image in ghcr.io to an Azure WebApp.
name: Deploy docker image to Azure WebApp

on:
workflow_call:
secrets:
AZURE_CREDENTIALS:
description: 'Service principal that has access to the Azure apps (dev and prod) - Defined in org action secrets'
required: true
AZURE_WEBAPP_PUBLISH_PROFILE:
description: 'Publish profile for the Azure WebApp being deployed - Defined in repo action secrets'
required: true
DEPLOY_TOKEN:
description: 'Token that is used to determine if the deployment is allowed - Defined in org action secrets'
required: true
PRODUCTION_DEPLOYERS:
description: 'Name of the team that defines who can deploy to production - Defined in org action secrets'
required: true

inputs:
deploy-env:
description: 'environment to deploy (i.e. dev | prod)'
required: true
type: string
azure-webapp-name:
description: 'Azure application name of application to deploy (i.e. clearlydefined-api | cdcrawler | clearlydefined)'
required: true
type: string
application-version:
description: 'the tag to use for the image (e.g. prod: v1.2.0, dev: v1.2.0+dev:1D3F567890)'
required: true
type: string
image-name-with-tag:
description: 'Docker image name with the tag (e.g. ghcr.io/clearlydefined/clearlydefined-api:v1.2.0)'
required: true
type: string

jobs:
check-deployable:
uses: clearlydefined/operations/.github/workflows/[email protected]
with:
deploy-env: ${{ inputs.deploy-env }}
secrets:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
PRODUCTION_DEPLOYERS: ${{ secrets.PRODUCTION_DEPLOYERS }}

deploy:
name: Deploy to Azure WebApp
runs-on: ubuntu-latest
needs: check-deployable
steps:
- name: Login for Azure cli commands
uses: azure/[email protected]
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}

- name: Set DOCKER configs in Azure web app
uses: azure/[email protected]
with:
app-name: ${{ inputs.azure-webapp-name }}
app-settings-json: |
[
{
"name": "DOCKER_CUSTOM_IMAGE_NAME",
"value": "${{ inputs.image-name-with-tag }}",
"slotSetting": false
},
{
"name": "DOCKER_REGISTRY_SERVER_URL",
"value": "https://ghcr.io",
"slotSetting": false
},
{
"name": "APP_VERSION",
"value": "${{ inputs.application-version }}",
"slotSetting": false
},
{
"name": "BUILD_SHA",
"value": "${{ github.sha }}",
"slotSetting": false
}
]
# v3.0.1 passes when AZURE_WEBAPP_PUBLISH_PROFILE_PROD isn't set, but should fail.
# Added secret check above to ensure it is set.
- name: Deploy to Azure WebApp
uses: azure/[email protected]
with:
app-name: ${{ inputs.azure-webapp-name }}
publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}
images: '${{ inputs.image-name-with-tag }}'
77 changes: 77 additions & 0 deletions .github/workflows/app-is-deployable.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
name: Deployable

on:
workflow_call:
secrets:
DEPLOY_TOKEN:
description: 'Token that is used to determine if the deployment is allowed - Defined in org action secrets'
required: true
PRODUCTION_DEPLOYERS:
description: 'Name of the team that defines who can deploy to production - Defined in org action secrets'
required: true

inputs:
deploy-env:
description: 'environment to deploy to - one of dev, prod'
required: true
type: string

jobs:
confirm-dev:
runs-on: ubuntu-latest
outputs:
is-dev: ${{ env.IS_DEV }}
steps:
# erring on the side of caution by assuming everything is prod unless it is identified as dev and ends in -dev
- id: confirm-dev
shell: bash
run: |
is_dev=false
if [[ "${{ inputs.deploy-env }}" == 'dev' ]]; then
is_dev=true
echo "Deploying to dev environment"
else
echo "Deploying to prod or UNKNOWN environment"
fi
echo "IS_DEV=$is_dev" >> $GITHUB_ENV
echo "Deployable: confirm-dev -> outputs -> is-dev: $is_dev"
deployable:
runs-on: ubuntu-latest
needs: confirm-dev
# run deployable check for anything that is NOT dev (most conservative approach)
if: ${{ needs.confirm-dev.outputs.is-dev != 'true' }}
steps:
- name: Get organization ID
run: |
org_name=${{ github.repository_owner }}
org_info=$(curl \
-H "Authorization: token ${{ secrets.DEPLOY_TOKEN }}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/orgs/$org_name)
org_id=$(echo "$org_info" | jq .id)
echo "ORG_ID=$org_id" >> $GITHUB_ENV
- name: Check team membership
run: |
user="${{ github.actor }}"
org_id=${{ env.ORG_ID }}
org_name=${{ github.repository_owner }}
team_info=$(curl \
-H "Authorization: token ${{ secrets.DEPLOY_TOKEN }}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/orgs/$org_name/teams)
team_id=$(echo "$team_info" | jq '.[] | select(.name=="${{ secrets.PRODUCTION_DEPLOYERS }}") | .id')
membership=$(curl \
-H "Authorization: token ${{ secrets.DEPLOY_TOKEN }}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/orgs/$org_id/team/$team_id/memberships/$user)
if [[ $membership == *"active"* ]]; then
echo "$user is a member of the team"
else
echo "$user does not have permissions to deploy"
exit 1
fi
Loading

0 comments on commit 0d53133

Please sign in to comment.