Skip to content

Commit

Permalink
create reusable workflows for primary apps deploy
Browse files Browse the repository at this point in the history
  • Loading branch information
elrayle committed Apr 13, 2024
1 parent 669ab1e commit 6d69a41
Show file tree
Hide file tree
Showing 4 changed files with 424 additions and 0 deletions.
112 changes: 112 additions & 0 deletions .github/workflows/app-build-and-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# This workflow will build a docker image, push it to ghcr.io, and deploy it to an Azure WebApp.
name: Build and Deploy to prod service app

on:
workflow_call:
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)'
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: ''
is-release:
description: 'whether this is a release deployment'
type: boolean
default: false

# Secrets required for publish to ghcr and deploy to Azure.
#
# Passed Secrets:
# AZURE_WEBAPP_PUBLISH_PROFILE: publish profile for the Azure WebApp being deployed
# AZURE_SECONDARY_WEBAPP_PUBLISH_PROFILE: publish profile for a secondary Azure WebApp if being deployed
#
# Org Secrets:
# AZURE_CREDENTIALS: service principal that has access to the Azure apps (dev and prod)
# DEPLOY_TOKEN: token that is used to determine if the deployment is allowed (prod only)
# PRODUCTION_DEPLOYERS: name of the team that defines who can deploy to production (prod only)

jobs:
get-version:
name: Get version from package-lock.json
runs-on: ubuntu-latest
outputs:
version: ${{ env.VERSION }}
steps:
- 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
short_sha=$(echo "${{ github.sha }}" | cut -c 1-10)
version=$version'+dev:'$short_sha // e.g. v1.2.0+dev:1234567890
fi
// validate the version when triggered by a release
if [[ ${{ inputs.is-release }} == 'true' ]]; then
if [[ $version != 'v'${{ 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
echo "VERSION=$version" >> $GITHUB_ENV
build-and-publish-image:
name: Build and publish Docker image
needs: get-version
uses: clearlydefined/operations/.github/workflows/app-build-docker-image.yml@elr/reusable-deploy-workflow
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/app-deploy-to-azure.yml@elr/reusable-deploy-workflow
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 }}
application-type: ${{ inputs.application-type }}
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/app-deploy-to-azure.yml@elr/reusable-deploy-workflow
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 }}
application-type: ${{ inputs.application-type }}
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:
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:1D3F567 -- number is first 7 char in sha)'
required: true
type: string

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

# Secrets required for publish to ghcr.
#
# Org Secrets:
# DEPLOY_TOKEN: token that is used to determine if the deployment is allowed
# PRODUCTION_DEPLOYERS: name of the team that defines who can deploy to production
#
# Environment Variables:
# DOCKER_IMAGE_BASE_NAME: base name of the Docker image that is being built and pushed to ghcr.io.

env:
DOCKER_IMAGE_BASE_NAME: ghcr.io/${{ github.repository }} # e.g. ghcr.io/clearlydefined/service

jobs:
check-deployable:
uses: clearlydefined/operations/.github/workflows/app-is-deployable.yml@elr/reusable-deploy-workflow
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: |
if [[ env.DEPLOY_ENV == "prod" ]] ; then
echo "DOCKER_IMAGE_NAME_WITH_TAG=${{ env.DOCKER_IMAGE_BASE_NAME }}:${{ inputs.image-tag }}" >> $GITHUB_ENV
else if [[ env.DEPLOY_ENV == "dev" ]] ; then
echo "DOCKER_IMAGE_NAME_WITH_TAG=${{ env.DOCKER_IMAGE_BASE_NAME }}-dev:${{ inputs.image-tag }}" >> $GITHUB_ENV
else
echo "DOCKER_IMAGE_NAME_WITH_TAG=${{ env.DOCKER_IMAGE_BASE_NAME }}-unknown:${{ inputs.image-tag }}" >> $GITHUB_ENV
fi
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 }}
122 changes: 122 additions & 0 deletions .github/workflows/app-deploy-to-azure.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# This workflow will deploy a Docker image in ghcr.io to an Azure WebApp.
name: Deploy docker image to Azure WebApp

on:
workflow_call:
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)'
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: 'application version (e.g. sha for dev env, version for prod env in the format: v1.2.0)'
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

# Secrets required for deploy to Azure.
#
# Passed Secrets:
# AZURE_WEBAPP_PUBLISH_PROFILE: publish profile for the Azure WebApp being deployed
#
# Org Secrets:
# AZURE_CREDENTIALS: service principal that has access to the Azure app being deployed
# DEPLOY_TOKEN: token that is used to determine if the deployment is allowed
# PRODUCTION_DEPLOYERS: name of the team that defines who can deploy to production

jobs:
check-deployable:
uses: clearlydefined/operations/.github/workflows/app-is-deployable.yml@elr/reusable-deploy-workflow
with:
deploy-env: ${{ inputs.deploy-env }}
secrets:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
PRODUCTION_DEPLOYERS: ${{ secrets.PRODUCTION_DEPLOYERS }}

verify-secrets:
name: Secrets Verification
runs-on: ubuntu-latest
steps:
- name: Check secrets
shell: bash
run: |
missing=false
secret_value=$(echo '${{ secrets.AZURE_CREDENTIALS }}')
single_line_value=$(echo -n "$secret_value" | tr -d '\n')
len=${#single_line_value}
if [[ ${len} -le 0 ]]; then
echo "Secret AZURE_CREDENTIALS does not have a value"
missing=true
fi
secret_value=$(echo '${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}')
single_line_value=$(echo -n "$secret_value" | tr -d '\n')
len=${#single_line_value}
if [[ ${len} -le 0 ]]; then
echo "Secret AZURE_WEBAPP_PUBLISH_PROFILE does not have a value"
missing=true
fi
if [[ $missing == true ]]; then
exit 1
fi
echo "Required secrets all have values"
deploy:
name: Deploy to Azure WebApp
runs-on: ubuntu-latest
needs: [ check-deployable, verify-secrets ]
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 }}'
Loading

0 comments on commit 6d69a41

Please sign in to comment.