Use JSON polymorphism #708
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
name: deploy | |
on: | |
issue_comment: | |
types: [ created ] | |
env: | |
ARTIFACT_NAME: 'lambda' | |
AWS_ACCOUNT_ID: ${{ vars.AWS_ACCOUNT_ID }} | |
AWS_REGION: ${{ vars.AWS_REGION }} | |
LAMBDA_FUNCTION: 'alexa-london-travel' | |
TERM: xterm | |
permissions: | |
contents: read | |
jobs: | |
setup: | |
runs-on: ubuntu-latest | |
if: | | |
github.event.issue.pull_request != '' && | |
github.event.repository.fork == false && | |
github.triggering_actor == github.event.repository.owner.login && | |
startsWith(github.event.comment.body, '/deploy') | |
outputs: | |
comment-id: ${{ steps.post-comment.outputs.result }} | |
environment-name: ${{ steps.set-outputs.outputs.environment-name }} | |
environment-url: ${{ steps.set-outputs.outputs.environment-url }} | |
function-architectures: ${{ steps.set-outputs.outputs.function-architectures }} | |
function-description: ${{ steps.set-outputs.outputs.function-description }} | |
function-handler: ${{ steps.set-outputs.outputs.function-handler }} | |
function-memory: ${{ steps.set-outputs.outputs.function-memory }} | |
function-name: ${{ steps.set-outputs.outputs.function-name }} | |
function-runtime: ${{ steps.set-outputs.outputs.function-runtime }} | |
function-timeout: ${{ steps.set-outputs.outputs.function-timeout }} | |
ref: ${{ steps.set-outputs.outputs.ref }} | |
run-id: ${{ steps.set-outputs.outputs.run-id }} | |
workflow-url: ${{ steps.set-outputs.outputs.workflow-url }} | |
permissions: | |
actions: read | |
contents: read | |
pull-requests: write | |
steps: | |
- name: Get environment name | |
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 | |
id: get-environment-name | |
with: | |
result-encoding: string | |
script: | | |
const owner = context.payload.repository.owner.login; | |
const repo = context.payload.repository.name; | |
const username = context.payload.comment.user.login; | |
try { | |
await github.rest.repos.checkCollaborator({ | |
owner, | |
repo, | |
username, | |
}); | |
} catch (err) { | |
throw new Error(`Error: @${username} is not a repository collaborator.`); | |
} | |
const comment = context.payload.comment.body; | |
const regex = /^\/deploy(\s+([a-zA-Z\d\-\_]+))?\s*$/; | |
const arguments = regex.exec(comment); | |
if (!arguments || arguments.length < 1) { | |
throw new Error(`Invalid command: ${comment}`); | |
} | |
return arguments[2] || 'dev'; | |
- name: 'Find run for #${{ github.event.issue.number }}' | |
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 | |
id: get-run | |
env: | |
PULL_NUMBER: ${{ github.event.issue.number }} | |
WORKFLOW_NAME: 'build' | |
with: | |
script: | | |
const pull_number = process.env.PULL_NUMBER; | |
const workflowName = process.env.WORKFLOW_NAME; | |
const owner = context.repo.owner; | |
const repo = context.repo.repo; | |
core.debug(`Getting pull request ${owner}/${repo}#${pull_number}`); | |
const { data: pull } = await github.rest.pulls.get({ | |
owner, | |
repo, | |
pull_number, | |
}); | |
if (!pull) { | |
throw new Error(`Pull request ${owner}/${repo}#${pull_number} not found.`); | |
} | |
const head_sha = pull.head.sha; | |
core.debug(`Getting workflow runs for ${owner}/${repo}#${pull_number}@${head_sha}`); | |
const { data: workflows } = await github.rest.actions.listWorkflowRunsForRepo({ | |
owner, | |
repo, | |
event: 'pull_request', | |
head_sha, | |
status: 'success', | |
}); | |
const run = workflows.workflow_runs.find((run) => run.name === workflowName); | |
if (!run) { | |
throw new Error(`No successful workflow run found for ${owner}/${repo}@${head_sha.slice(0, 7)} with name ${workflowName}.`); | |
} | |
core.setOutput('ref', head_sha); | |
core.setOutput('run-id', run.id); | |
core.setOutput('run-number', run.run_number); | |
- name: 'Download artifact from #${{ github.event.issue.number }}' | |
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 | |
with: | |
github-token: ${{ secrets.GITHUB_TOKEN }} | |
name: ${{ env.ARTIFACT_NAME }} | |
run-id: ${{ steps.get-run.outputs.run-id }} | |
- name: Set outputs | |
id: set-outputs | |
env: | |
LAMBDA_ARTIFACT_REF: ${{ steps.get-run.outputs.ref }} | |
LAMBDA_ARTIFACT_RUN_ID: ${{ steps.get-run.outputs.run-id }} | |
LAMBDA_ARTIFACT_RUN_NUMBER: ${{ steps.get-run.outputs.run-number }} | |
LAMBDA_ENVIRONMENT: ${{ steps.get-environment-name.outputs.result }} | |
shell: bash | |
run: | | |
environment_name="${LAMBDA_ENVIRONMENT}" | |
lambda_config="$(unzip -p "${LAMBDA_FUNCTION}.zip" aws-lambda-tools-defaults.json)" | |
if [ "${environment_name}" == "production" ] | |
then | |
function_name="${LAMBDA_FUNCTION}" | |
else | |
function_name="${LAMBDA_FUNCTION}-${environment_name}" | |
fi | |
environment_url="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/deployments/${environment_name}" | |
function_architectures="$(echo "${lambda_config}" | jq -r '."function-architecture"')" | |
function_description="Deploy build ${LAMBDA_ARTIFACT_RUN_NUMBER} to AWS Lambda via GitHub Actions" | |
function_handler="$(echo "${lambda_config}" | jq -r '."function-handler"')" | |
function_memory="$(echo "${lambda_config}" | jq -r '."function-memory-size"')" | |
function_runtime="$(echo "${lambda_config}" | jq -r '."function-runtime"')" | |
function_timeout="$(echo "${lambda_config}" | jq -r '."function-timeout"')" | |
workflow_url="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" | |
{ | |
echo "environment-name=${environment_name}" | |
echo "environment-url=${environment_url}" | |
echo "function-architectures=${function_architectures}" | |
echo "function-description=${function_description}" | |
echo "function-handler=${function_handler}" | |
echo "function-memory=${function_memory}" | |
echo "function-name=${function_name}" | |
echo "function-runtime=${function_runtime}" | |
echo "function-timeout=${function_timeout}" | |
echo "ref=${LAMBDA_ARTIFACT_REF}" | |
echo "run-id=${LAMBDA_ARTIFACT_RUN_ID}" | |
echo "workflow-url=${workflow_url}" | |
} >> "$GITHUB_OUTPUT" | |
- name: Post comment | |
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 | |
id: post-comment | |
env: | |
ENVIRONMENT_NAME: ${{ steps.set-outputs.outputs.environment-name }} | |
ENVIRONMENT_URL: ${{ steps.set-outputs.outputs.environment-url }} | |
WORKFLOW_URL: ${{ steps.set-outputs.outputs.workflow-url }} | |
with: | |
result-encoding: string | |
script: | | |
const owner = context.payload.repository.owner.login; | |
const repo = context.payload.repository.name; | |
const issue_number = context.issue.number; | |
const environment = process.env.ENVIRONMENT_NAME; | |
const environment_url = process.env.ENVIRONMENT_URL; | |
const workflow_url = process.env.WORKFLOW_URL; | |
const { data: comment } = await github.rest.issues.createComment({ | |
owner, | |
repo, | |
issue_number, | |
body: `Starting [deployment](${workflow_url}) to [${environment}](${environment_url}) :rocket:`, | |
}); | |
return comment.id; | |
deploy: | |
name: ${{ needs.setup.outputs.environment-name }} | |
needs: [ setup ] | |
concurrency: '${{ needs.setup.outputs.environment-name }}_environment' | |
runs-on: ubuntu-latest | |
env: | |
FUNCTION_NAME: ${{ needs.setup.outputs.function-name }} | |
LAMBDA_ARCHITECTURES: ${{ needs.setup.outputs.function-architectures }} | |
LAMBDA_DESCRIPTION: ${{ needs.setup.outputs.function-description }} | |
LAMBDA_HANDLER: ${{ needs.setup.outputs.function-handler }} | |
LAMBDA_MEMORY: ${{ needs.setup.outputs.function-memory }} | |
LAMBDA_ROLE: ${{ vars.AWS_LAMBDA_ROLE }} | |
LAMBDA_RUNTIME: ${{ needs.setup.outputs.function-runtime }} | |
LAMBDA_TIMEOUT: ${{ needs.setup.outputs.function-timeout }} | |
environment: | |
name: ${{ needs.setup.outputs.environment-name }} | |
permissions: | |
id-token: write | |
pull-requests: write | |
steps: | |
- name: Download artifacts | |
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 | |
with: | |
github-token: ${{ secrets.GITHUB_TOKEN }} | |
name: ${{ env.ARTIFACT_NAME }} | |
run-id: ${{ needs.setup.outputs.run-id }} | |
- name: Get Lambda environment variables | |
env: | |
SKILL_API_URL: ${{ vars.SKILL_API_URL }} | |
SKILL_ID: ${{ secrets.SKILL_ID }} | |
TFL_APPLICATION_ID: ${{ secrets.TFL_APPLICATION_ID }} | |
TFL_APPLICATION_KEY: ${{ secrets.TFL_APPLICATION_KEY }} | |
VERIFY_SKILL_ID: "true" | |
shell: bash | |
run: | | |
lambda_vars="{\ | |
\"Variables\": {\ | |
\"SSL_CERT_FILE\": \"/tmp/noop\",\ | |
\"Skill__SkillApiUrl\": \"${SKILL_API_URL}\",\ | |
\"Skill__SkillId\": \"${SKILL_ID}\",\ | |
\"Skill__TflApplicationId\": \"${TFL_APPLICATION_ID}\",\ | |
\"Skill__TflApplicationKey\": \"${TFL_APPLICATION_KEY}\",\ | |
\"Skill__VerifySkillId\": \"${VERIFY_SKILL_ID}\"\ | |
}\ | |
}" | |
echo "LAMBDA_ENVIRONMENT_VARIABLES=${lambda_vars}" >> "$GITHUB_ENV" | |
- name: Configure AWS credentials | |
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2 | |
with: | |
role-to-assume: arn:aws:iam::${{ env.AWS_ACCOUNT_ID }}:role/github-actions-deploy | |
role-session-name: ${{ github.event.repository.name }}-${{ github.run_id }}-deploy-${{ needs.setup.outputs.environment-name }} | |
aws-region: ${{ env.AWS_REGION }} | |
- name: Update function code | |
shell: bash | |
run: | | |
aws lambda update-function-code \ | |
--function-name "${FUNCTION_NAME}" \ | |
--architectures "${LAMBDA_ARCHITECTURES}" \ | |
--zip-file "fileb://./${LAMBDA_FUNCTION}.zip" | |
- name: Wait for function code update | |
shell: bash | |
run: | | |
aws lambda wait function-updated-v2 \ | |
--function-name "${FUNCTION_NAME}" | |
- name: Update function configuration | |
shell: bash | |
env: | |
LAMBDA_LAYERS: ${{ vars.AWS_LAMBDA_LAYERS }} | |
LAMBDA_LOGGING_CONFIG: ${{ vars.AWS_LAMBDA_LOGGING_CONFIG }} | |
LAMBDA_TRACING_MODE: ${{ vars.AWS_TRACING_MODE }} | |
run: | | |
aws lambda update-function-configuration \ | |
--function-name "${FUNCTION_NAME}" \ | |
--description "${LAMBDA_DESCRIPTION}" \ | |
--environment "${LAMBDA_ENVIRONMENT_VARIABLES}" \ | |
--handler "${LAMBDA_HANDLER}" \ | |
--layers "${LAMBDA_LAYERS}" \ | |
--logging-config "${LAMBDA_LOGGING_CONFIG}" \ | |
--memory-size "${LAMBDA_MEMORY}" \ | |
--role "${LAMBDA_ROLE}" \ | |
--runtime "${LAMBDA_RUNTIME}" \ | |
--timeout "${LAMBDA_TIMEOUT}" \ | |
--tracing-config "Mode=${LAMBDA_TRACING_MODE}" | |
- name: Wait for function configuration update | |
shell: bash | |
run: | | |
aws lambda wait function-updated-v2 \ | |
--function-name "${FUNCTION_NAME}" | |
- name: Post comment | |
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 | |
if: ${{ !cancelled() }} | |
env: | |
COMMENT_ID: ${{ needs.setup.outputs.comment-id }} | |
ENVIRONMENT_NAME: ${{ needs.setup.outputs.environment-name }} | |
ENVIRONMENT_URL: ${{ needs.setup.outputs.environment-url }} | |
OUTCOME: ${{ job.status }} | |
WORKFLOW_URL: ${{ needs.setup.outputs.workflow-url }} | |
with: | |
script: | | |
const owner = context.payload.repository.owner.login; | |
const repo = context.payload.repository.name; | |
const comment_id = process.env.COMMENT_ID; | |
const environment = process.env.ENVIRONMENT_NAME; | |
const environment_url = process.env.ENVIRONMENT_URL; | |
const workflow_url = process.env.WORKFLOW_URL; | |
const succeeded = process.env.OUTCOME === 'success'; | |
const outcome = succeeded ? 'successful' : 'failed'; | |
const emoji = succeeded ? ':white_check_mark:' : ':x:'; | |
await github.rest.issues.updateComment({ | |
owner, | |
repo, | |
comment_id, | |
body: `[Deployment](${workflow_url}) to [${environment}](${environment_url}) ${outcome} ${emoji}`, | |
}); | |
tests: | |
name: tests-${{ needs.setup.outputs.environment-name }} | |
needs: [ setup, deploy ] | |
runs-on: ubuntu-latest | |
concurrency: '${{ needs.setup.outputs.environment-name }}_environment' | |
env: | |
DOTNET_CLI_TELEMETRY_OPTOUT: true | |
DOTNET_GENERATE_ASPNET_CERTIFICATE: false | |
DOTNET_NOLOGO: true | |
DOTNET_SYSTEM_CONSOLE_ALLOW_ANSI_COLOR_REDIRECTION: 1 | |
NUGET_XMLDOC_MODE: skip | |
permissions: | |
id-token: write | |
pull-requests: write | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 | |
with: | |
ref: ${{ needs.setup.outputs.ref }} | |
- name: Setup .NET SDK | |
uses: actions/setup-dotnet@6bd8b7f7774af54e05809fcc5431931b3eb1ddee # v4.0.1 | |
- name: Configure AWS credentials | |
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2 | |
with: | |
role-to-assume: arn:aws:iam::${{ env.AWS_ACCOUNT_ID }}:role/github-actions-test | |
role-session-name: ${{ github.event.repository.name }}-${{ github.run_id }}-tests-${{ needs.setup.outputs.environment-name }} | |
aws-region: ${{ env.AWS_REGION }} | |
- name: Run end-to-end tests | |
shell: pwsh | |
run: dotnet test ./test/LondonTravel.Skill.EndToEndTests --configuration Release --logger "GitHubActions;report-warnings=false" | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
LAMBDA_FUNCTION_NAME: ${{ needs.setup.outputs.function-name }} | |
LWA_CLIENT_ID: ${{ secrets.LWA_CLIENT_ID }} | |
LWA_CLIENT_SECRET: ${{ secrets.LWA_CLIENT_SECRET }} | |
LWA_REFRESH_TOKEN: ${{ secrets.LWA_REFRESH_TOKEN }} | |
PULL_NUMBER: ${{ github.event.issue.number }} | |
SKILL_ID: ${{ secrets.SKILL_ID }} | |
SKILL_STAGE: development | |
- name: Post comment | |
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 | |
if: ${{ !cancelled() }} | |
env: | |
COMMENT_ID: ${{ needs.setup.outputs.comment-id }} | |
ENVIRONMENT_NAME: ${{ needs.setup.outputs.environment-name }} | |
ENVIRONMENT_URL: ${{ needs.setup.outputs.environment-url }} | |
OUTCOME: ${{ job.status }} | |
WORKFLOW_URL: ${{ needs.setup.outputs.workflow-url }} | |
with: | |
script: | | |
const owner = context.payload.repository.owner.login; | |
const repo = context.payload.repository.name; | |
const comment_id = process.env.COMMENT_ID; | |
const environment = process.env.ENVIRONMENT_NAME; | |
const environment_url = process.env.ENVIRONMENT_URL; | |
const workflow_url = process.env.WORKFLOW_URL; | |
const succeeded = process.env.OUTCOME === 'success'; | |
const outcome = succeeded ? 'passed' : 'failed'; | |
const emoji = succeeded ? ':white_check_mark:' : ':x:'; | |
await github.rest.issues.updateComment({ | |
owner, | |
repo, | |
comment_id, | |
body: `:test_tube: [Tests](${workflow_url}) for deployment to [${environment}](${environment_url}) ${outcome} ${emoji}`, | |
}); |