EN-23320 - Adding Teams action in reusable workflows #4
Workflow file for this run
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# The purpose of this reusable job is to run the final steps of a deployment workflow | ||
# which includes updating the github deployments in TechHub and posting a status to Teams. | ||
# Example Usage in a repo's workflow: | ||
# jobs: | ||
# update-github-deployments-and-send-teams-notification: | ||
# uses: im-practices/.github/.github/workflows/im-reusable-finish-deployment-workflow.yml@v3 | ||
# with: | ||
# runs-on: im-linux | ||
# gh-secrets-environment: ${{ inputs.environment-or-target }} | ||
# deployment-environment: ${{ needs.set-vars.outputs.GH_SECRETS_ENVIRONMENT}} | ||
# release-tag: ${{ inputs.tag }} | ||
# title-of-teams-post: 'Deploy ${{ needs.set-vars.outputs.AZ_APP_NAME }} ${{ inputs.tag }} to ${{ inputs.environment-or-target }}' | ||
# post-status-in-deployment-notifications-channel: true | ||
# timezone: america/denver | ||
# custom-facts-for-team-channel: | | ||
# [ | ||
# { "name": "Workflow", "value": "${{ github.workflow }}" }, | ||
# { "name": "Run", "value": "${{ github.run_id }}" }, | ||
# { "name": "Actor", "value": "${{ github.actor }}" }, | ||
# { "name": "Version", "value": "${{ inputs.tag }}" } | ||
# ] | ||
# custom-facts-for-deployment-notifications-channel: | | ||
# [ | ||
# { "name": "Actor", "value": "${{ github.actor }}" }, | ||
# { "name": "Version", "value": "${{ inputs.tag }}" } | ||
# ] | ||
# ms-teams-uri: ${{ vars.MS_TEAMS_URI }} # Use this input (preferred) or the secret | ||
# deploy-notifications-channel: ${{ vars.DEPLOY_NOTIFICATIONS_CHANNEL }} # This is an org-level variable | ||
# entity: ${{ env.TECHHUB_ENTITY }} | ||
# instance: ${{ env.TECHHUB_INSTANCE }} | ||
on: | ||
workflow_call: | ||
inputs: | ||
# Required Inputs | ||
deployment-environment: | ||
description: 'The environment that was deployed to: dev, qa, stage, stage-secondary, uat, demo, prod, prod-secondary.' | ||
required: true | ||
type: string | ||
gh-secrets-environment: | ||
description: 'The GitHub environment secrets should be accessed from: dev, qa, stage, uat, demo, prod.' | ||
required: true | ||
type: string | ||
release-tag: | ||
description: 'The tag of the release being deployed.' | ||
required: true | ||
type: string | ||
title-of-teams-post: | ||
description: 'Title of the Teams post that will be used in the team channel and the Deployment Notifications channel.' | ||
required: true | ||
type: string | ||
deploy-notifications-channel: | ||
description: 'The URI for the notifications channel where a status will be posted.' | ||
required: true | ||
type: string | ||
entity: | ||
description: 'The TechHub entity that is being deployed. This value should match the metadata.name of the entity defined in catalog-info.yml.' | ||
required: true | ||
type: string | ||
instance: | ||
description: | | ||
The value used to create a deployment instance name in the GitHub deployment API. | ||
It represents the specific target deployment location e.g., primary, primary-app-service, testing-slot, failover-slot-2, NA26, NA27-production-slot | ||
Generally some combination of deployment-environment, slot-name and AZ region values. | ||
required: true | ||
type: string | ||
# Optional Inputs | ||
runs-on: | ||
description: 'The runner that this workflow will run on.' | ||
required: false | ||
type: string | ||
default: 'im-linux' | ||
post-status-in-deployment-notifications-channel: | ||
description: 'Flag indicating whether a post should be made to the Deployment Notifications channel.' | ||
required: false | ||
type: boolean | ||
default: true | ||
timezone: | ||
description: 'Timezone for the project. Defaults to america/denver.' | ||
required: false | ||
type: string | ||
default: 'america/denver' | ||
custom-facts-for-team-channel: | ||
description: The custom facts that will be included in the post in the team's channel. By default Workflow, Run, Actor and Version are included. | ||
required: false | ||
type: string | ||
custom-actions-for-team-channel: | ||
description: The custom actions that will be included in the post in the team's channel. | ||
required: false | ||
type: string | ||
custom-facts-for-deployment-notifications-channel: | ||
description: 'The custom facts that will be included in the Deployment Notifications channel.' | ||
required: false | ||
type: string | ||
custome-actions-for-deployment-notifications-channel: | ||
description: 'The custom actions that will be included in the post in the Deployment Notifications channel. By default the actions are 'View in TechHub' and 'View in GitHub'.' | ||
required: false | ||
type: string | ||
ms-teams-uri: | ||
description: The URI for the teams channel where a status will be posted. Either this value or the secret MS_TEAMS_URI must be provided. This input is the preferred way to provide the URI but the secret should be used instead if the value is defined as a secret. | ||
required: false | ||
type: string | ||
secrets: | ||
MS_TEAMS_URI: | ||
description: 'The URI for the teams channel where a status will be posted. Either this value or the input ms-teams-uri must be provided. The input is the preferred way to provide the URI but the secret should be used if the value is defined as a secret.' | ||
required: false | ||
jobs: | ||
finish-deployment-workflow: | ||
runs-on: ${{ inputs.runs-on }} | ||
environment: ${{ inputs.gh-secrets-environment }} | ||
steps: | ||
- name: Check for missing inputs | ||
uses: actions/github-script@v7 | ||
with: | ||
script: | | ||
// Some teams have these as a secret and some as a var, allow both ways but check at least one is present | ||
const teamsUri = '${{ inputs.ms-teams-uri || secrets.MS_TEAMS_URI }}'; | ||
if (!teamsUri || teamsUri.trim().length === 0){ | ||
core.setFailed('The MS_TEAMS_URI secret or the ms-teams-uri input (preferred) must be provided.'); | ||
} | ||
- name: Print inputs | ||
uses: actions/github-script@v7 | ||
with: | ||
script: | | ||
function printInput(inputName, inputValue, isMultilineInput){ | ||
if (!inputValue || inputValue.trim().length === 0){ | ||
core.info(`${inputName}: Not Provided`); | ||
} else if (isMultilineInput){ | ||
console.log(`\n${inputName}:\n${inputValue}`); | ||
} | ||
else { | ||
core.info(`${inputName}: ${inputValue}`); | ||
} | ||
} | ||
core.startGroup('Reusable workflow inputs'); | ||
printInput('deployment-environment', '${{ inputs.deployment-environment }}'); | ||
printInput('gh-secrets-environment', '${{ inputs.gh-secrets-environment }}'); | ||
printInput('release-tag', '${{ inputs.release-tag }}'); | ||
printInput('title-of-teams-post', '${{ inputs.title-of-teams-post }}'); | ||
printInput('runs-on', '${{ inputs.runs-on }}'); | ||
printInput('post-status-in-deployment-notifications-channel', '${{ inputs.post-status-in-deployment-notifications-channel }}'); | ||
printInput('timezone', '${{ inputs.timezone }}'); | ||
printInput('instance', '${{ inputs.instance }}'); | ||
printInput('ms-teams-uri', '${{ inputs.ms-teams-uri }}'); | ||
printInput('deploy-notifications-channel', '${{ inputs.deploy-notifications-channel }}'); | ||
printInput('custom-facts-for-team-channel', process.env.CUSTOM_FACTS_TEAMS, true); | ||
printInput('custom-actions-for-team-channel', process.env.CUSTOM_ACTIONS_TEAMS, true); | ||
printInput('custom-facts-for-deployment-notifications-channel', process.env.CUSTOM_FACTS_DEPLOY, true); | ||
printInput('custom-actions-for-deployment-notifications-channel', process.env.CUSTOM_ACTIONS_DEPLOY, true); | ||
core.endGroup(); | ||
core.startGroup('Reusable workflow secrets'); | ||
printInput('MS_TEAMS_URI', '${{ secrets.MS_TEAMS_URI }}'); | ||
core.endGroup(); | ||
env: | ||
CUSTOM_FACTS_TEAMS: ${{ inputs.custom-facts-for-team-channel }} | ||
CUSTOM_ACTIONS_TEAMS: ${{ inputs.custom-actions-for-team-channel }} | ||
CUSTOM_FACTS_DEPLOY: ${{ inputs.custom-facts-for-deployment-notifications-channel }} | ||
CUSTOM_ACTIONS_DEPLOY: ${{ inputs.custom-actions-for-deployment-notifications-channel }} | ||
- uses: im-open/[email protected] | ||
id: conclusion | ||
with: | ||
github-token: ${{ secrets.GITHUB_TOKEN }} | ||
# Only run this step if TechHub metadata.name value | ||
# and a metadata.instance value are provided | ||
- name: Create GitHub Deployment for TechHub | ||
uses: im-open/[email protected] | ||
with: | ||
workflow-actor: ${{ github.actor }} # This will add the user who kicked off the workflow to the deployment payload | ||
token: ${{ secrets.GITHUB_TOKEN }} # Special per-job token generated by GH for interacting with the repo | ||
environment: ${{ inputs.deployment-environment }} | ||
release-ref: ${{ inputs.release-tag }} | ||
deployment-status: ${{ steps.conclusion.outputs.workflow_conclusion }} | ||
deployment-description: 'Deployment to the ${{ inputs.deployment-environment }} environment of ${{ inputs.release-tag }}' | ||
entity: ${{ inputs.entity }} | ||
instance: ${{ inputs.instance }} | ||
- name: Configure facts for team's notification channel | ||
if: always() | ||
id: team-channel-facts | ||
uses: actions/github-script@v7 | ||
with: | ||
script: | | ||
const rawFacts = process.env.FACTS; | ||
console.log(`"${rawFacts}"`); | ||
let facts = rawFacts && rawFacts.trim().length > 0 ? JSON.parse(rawFacts) : null; | ||
if (!facts || facts.length === 0){ | ||
console.log(`Custom facts were not provided for the Team's Notification channel, use the default facts:`); | ||
facts = [ | ||
{ name: 'Workflow', value: '${{ github.workflow }}'}, | ||
{ name: 'Run', value: '${{ github.run_id }}'}, | ||
{ name: 'Actor', value: '${{ github.actor }}'}, | ||
{ name: 'Version', value: '${{ inputs.release-tag }}'} | ||
] | ||
} | ||
else { | ||
console.log(`Custom facts were supplied as an argument, using those in the Team's Notification channel:`); | ||
} | ||
console.log(facts); | ||
core.setOutput('facts', facts); | ||
env: | ||
FACTS: ${{ inputs.custom-facts-for-team-channel }} | ||
- name: Send status to team's notification channel | ||
if: always() | ||
uses: im-open/[email protected] | ||
with: | ||
title: ${{ inputs.title-of-teams-post }} | ||
workflow-status: ${{ steps.conclusion.outputs.workflow_conclusion }} | ||
workflow-type: Deploy | ||
teams-uri: ${{ inputs.ms-teams-uri || secrets.MS_TEAMS_URI }} | ||
timezone: ${{ inputs.timezone }} | ||
custom-facts: ${{ steps.team-channel-facts.outputs.facts }} | ||
custom-actions: ${{ inputs.custom-actions-for-team-channel }} | ||
- name: Determine if a post should be made in Deployment Notifications channel | ||
if: always() | ||
id: post-to-deployment-channel | ||
uses: actions/github-script@v7 | ||
with: | ||
script: | | ||
const postInProd = ${{ inputs.post-status-in-deployment-notifications-channel }}; | ||
const deployEnv = '${{ inputs.deployment-environment }}'; | ||
const workflowConclusion = '${{ steps.conclusion.outputs.workflow_conclusion }}'; | ||
const isProdEnv = deployEnv === 'prod' || deployEnv === 'prod-secondary'; | ||
const post = postInProd && isProdEnv && workflowConclusion === 'success'; | ||
core.setOutput('post', post); | ||
const message = `Values used to determine if a Deployment Notifications post will be made: | ||
\tpost-status-in-deployment-notifications-channel input: ${postInProd}\t(must be true to post) | ||
\tWorkflow Conclusion: ${workflowConclusion} \t\t(must be 'success' to post) | ||
\tEnvironment: ${deployEnv} \t(must be 'prod' or 'prod-secondary' to post)`; | ||
console.log(message); | ||
if (!post) { | ||
console.log('The conditions were not satisfied and a post will not be made in the Deployment Notifications channel.'); | ||
} else { | ||
console.log('The conditions were statisfied so a post will be made in the Deployment Notifications channel.'); | ||
} | ||
- name: Configure facts for Deployment Notifications channel | ||
if: always() && steps.post-to-deployment-channel.outputs.post == 'true' | ||
id: deployment-channel-facts | ||
uses: actions/github-script@v7 | ||
with: | ||
script: | | ||
const rawFacts = process.env.FACTS; | ||
let facts = rawFacts && rawFacts.trim().length > 0 ? JSON.parse(rawFacts) : null; | ||
if (!facts || facts.length === 0){ | ||
console.log('Custom facts were not provided for the Deployment Notifications channel, use the default facts:'); | ||
facts = [ | ||
{ name: 'Actor', value: '${{ github.actor }}'}, | ||
{ name: 'Version', value: '${{ inputs.release-tag }}'} | ||
] | ||
} | ||
else { | ||
console.log('Custom facts were supplied as an argument, using those in the Deployment Notifications channel:'); | ||
} | ||
console.log(facts); | ||
core.setOutput('facts', facts); | ||
env: | ||
FACTS: ${{ inputs.custom-facts-for-deployment-notifications-channel }} | ||
- name: Send Status to Deployment Notifications Channel for Prod Deploys | ||
if: always() && steps.post-to-deployment-channel.outputs.post == 'true' | ||
uses: im-open/[email protected] | ||
with: | ||
title: ${{ inputs.title-of-teams-post }} | ||
workflow-status: ${{ steps.conclusion.outputs.workflow_conclusion }} | ||
workflow-type: Deploy | ||
teams-uri: ${{ inputs.deploy-notifications-channel }} | ||
timezone: ${{ inputs.timezone }} | ||
include-default-facts: false # This cuts down on the message size for the prod room | ||
custom-facts: ${{ steps.deployment-channel-facts.outputs.facts }} | ||
custom-actions: ${{ inputs.custom-actions-for-deployment-notifications-channel }} |