Preview (deploy) #31669
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: Preview (deploy) | |
on: | |
workflow_run: | |
workflows: | |
- 'Preview (build)' | |
types: | |
- completed | |
jobs: | |
cache-manifests-file: | |
name: Cache Manifests File | |
runs-on: ubuntu-latest | |
if: ${{ github.event.workflow_run.conclusion == 'success' }} | |
permissions: | |
# "If you specify the access for any of these scopes, all of those that are not specified are set to none." | |
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions | |
actions: read # Access cache | |
outputs: | |
manifests-cache-key: ${{ steps.hash.outputs.MANIFESTS_FILE_HASH }} | |
git-ref: ${{ steps.event.outputs.GIT_REF }} | |
pr-number: ${{ steps.event.outputs.PR_NUMBER }} | |
action: ${{ steps.event.outputs.ACTION }} | |
steps: | |
- name: Harden Runner | |
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 | |
with: | |
disable-sudo: true | |
egress-policy: block | |
allowed-endpoints: > | |
api.github.com:443 | |
- name: 'Download artifacts' | |
# Fetch output (zip archive) from the workflow run that triggered this workflow. | |
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 | |
with: | |
script: | | |
let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
run_id: context.payload.workflow_run.id, | |
}); | |
let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => { | |
return artifact.name == "preview-spec" | |
})[0]; | |
if (matchArtifact === undefined) { | |
throw TypeError('Build Artifact not found!'); | |
} | |
let download = await github.rest.actions.downloadArtifact({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
artifact_id: matchArtifact.id, | |
archive_format: 'zip', | |
}); | |
let fs = require('fs'); | |
fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/preview-spec.zip`, Buffer.from(download.data)); | |
- name: 'Accept event from first stage' | |
run: unzip preview-spec.zip event.json | |
- name: Read Event into ENV | |
id: event | |
run: | | |
echo PR_NUMBER=$(jq '.number | tonumber' < event.json) >> $GITHUB_OUTPUT | |
echo ACTION=$(jq --raw-output '.action | tostring | [scan("\\w+")][0]' < event.json) >> $GITHUB_OUTPUT | |
echo GIT_REF=$(jq --raw-output '.pull_request.head.sha | tostring | [scan("\\w+")][0]' < event.json) >> $GITHUB_OUTPUT | |
- name: Hash Rendered Manifests File | |
id: hash | |
# If the previous workflow was triggered by a PR close event, we will not have a manifests file artifact. | |
if: ${{ steps.event.outputs.ACTION != 'closed' }} | |
run: | | |
unzip preview-spec.zip manifests.rendered.yml | |
ls | |
echo "MANIFESTS_FILE_HASH=$(md5sum manifests.rendered.yml | awk '{ print $1 }')" >> $GITHUB_OUTPUT | |
- name: Cache Manifests File | |
if: ${{ steps.event.outputs.ACTION != 'closed' }} | |
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 | |
with: | |
path: manifests.rendered.yml | |
key: ${{ steps.hash.outputs.MANIFESTS_FILE_HASH }} | |
- name: DEBUG - Print Job Outputs | |
if: ${{ runner.debug }} | |
run: | | |
echo "PR number: ${{ steps.event.outputs.PR_NUMBER }}" | |
echo "Git Ref: ${{ steps.event.outputs.GIT_REF }}" | |
echo "Action: ${{ steps.event.outputs.ACTION }}" | |
echo "Manifests file hash: ${{ steps.hash.outputs.MANIFESTS_FILE_HASH }}" | |
cat event.json | |
deploy-uffizzi-preview: | |
name: Deploy to Uffizzi Virtual Cluster | |
needs: | |
- cache-manifests-file | |
if: ${{ github.event.workflow_run.conclusion == 'success' && needs.cache-manifests-file.outputs.action != 'closed' }} | |
permissions: | |
contents: read | |
pull-requests: write | |
id-token: write | |
runs-on: ubuntu-latest | |
steps: | |
- name: Checkout | |
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 | |
# Identify comment to be updated | |
- name: Find comment for Ephemeral Environment | |
uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3 | |
id: find-comment | |
with: | |
issue-number: ${{ needs.cache-manifests-file.outputs.pr-number }} | |
comment-author: 'github-actions[bot]' | |
body-includes: pr-${{ needs.cache-manifests-file.outputs.pr-number }} | |
direction: last | |
# Create/Update comment with action deployment status | |
- name: Create or Update Comment with Deployment Notification | |
id: notification | |
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4 | |
with: | |
comment-id: ${{ steps.find-comment.outputs.comment-id }} | |
issue-number: ${{ needs.cache-manifests-file.outputs.pr-number }} | |
body: | | |
## Uffizzi Ephemeral Environment - Virtual Cluster | |
:cloud: deploying cluster `pr-${{ needs.cache-manifests-file.outputs.pr-number }}` | |
:gear: Updating now by workflow run [${{ github.run_id }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}). | |
Download the Uffizzi CLI to interact with the upcoming virtual cluster | |
https://docs.uffizzi.com/install | |
edit-mode: replace | |
- name: Connect to Virtual Cluster | |
uses: UffizziCloud/cluster-action@main | |
with: | |
cluster-name: pr-${{ needs.cache-manifests-file.outputs.pr-number }} | |
server: https://app.uffizzi.com | |
- name: Fetch cached Manifests File | |
id: cache | |
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4 | |
with: | |
path: manifests.rendered.yml | |
key: ${{ needs.cache-manifests-file.outputs.manifests-cache-key }} | |
- name: Kustomize and Apply Manifests | |
id: prev | |
run: | | |
# Apply kustomized manifests to virtual cluster. | |
export KUBECONFIG=`pwd`/kubeconfig | |
kubectl apply -f manifests.rendered.yml --kubeconfig ./kubeconfig | |
# Allow uffizzi to sync the resources | |
sleep 10 | |
# Get the hostnames assigned by uffizzi | |
export BACKSTAGE_HOST=$(kubectl get ingress backstage --kubeconfig kubeconfig -o json | jq '.spec.rules[0].host' | tr -d '"') | |
export UFFIZZI_CLUSTER_APISERVER=$(kubectl config view --minify | grep server | cut -f 2- -d ":" | tr -d " ") | |
# Patch backstage deployment to use UFFIZZI_URL | |
kubectl patch deployment backstage --kubeconfig kubeconfig -p '{"spec": {"template": {"spec": {"containers": [{"name": "backstage", "args":["-c", "APP_CONFIG_app_baseUrl='https://${BACKSTAGE_HOST}' APP_CONFIG_backend_baseUrl='https://${BACKSTAGE_HOST}' APP_CONFIG_auth_environment='production' node packages/backend --config app-config.yaml"], "env": [{"name": "UFFIZZI_URL", "value": "'https://${BACKSTAGE_HOST}'"}, {"name": "UFFIZZI_CLUSTER_APISERVER", "value": "'${UFFIZZI_CLUSTER_APISERVER}'"}, {"name": "GITHUB_SHA", "value": "'${GITHUB_SHA}'"}, {"name": "REF_NAME", "value": "'${{ needs.cache-manifests-file.outputs.git-ref }}'"}]}]}}}}' | |
if [[ ${RUNNER_DEBUG} == 1 ]]; then | |
kubectl get all --kubeconfig ./kubeconfig | |
fi | |
echo "backstage_url=${BACKSTAGE_HOST}" >> $GITHUB_OUTPUT | |
echo "Access the \`backstage\` endpoint at [\`${BACKSTAGE_HOST}\`](http://${BACKSTAGE_HOST})" >> $GITHUB_STEP_SUMMARY | |
- name: Create or Update Comment with Deployment URL | |
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4 | |
with: | |
comment-id: ${{ steps.notification.outputs.comment-id }} | |
issue-number: ${{ github.event.pull_request.number }} | |
body: | | |
## Uffizzi Ephemeral Environment - Virtual Cluster | |
Your cluster `pr-${{ needs.cache-manifests-file.outputs.pr-number }}` was successfully created. Learn more about [Uffizzi virtual clusters](https://docs.uffizzi.com/topics/virtual-clusters) | |
To connect to this cluster, follow these steps: | |
1. Download and install the Uffizzi CLI from https://docs.uffizzi.com/install | |
2. Login to Uffizzi, then select the `backstage` account and project: | |
``` | |
uffizzi login | |
``` | |
``` | |
Select an account: | |
‣ ${{ github.event.repository.name }} | |
jdoe | |
Select a project or create a new project: | |
‣ ${{ github.event.repository.name }}-6783521 | |
``` | |
3. Update your kubeconfig: `uffizzi cluster update-kubeconfig pr-${{ needs.cache-manifests-file.outputs.pr-number }} --kubeconfig=[PATH_TO_KUBECONFIG]` | |
After updating your kubeconfig, you can manage your cluster with `kubectl`, `kustomize`, `helm`, and other tools that use kubeconfig files: `kubectl get namespace --kubeconfig [PATH_TO_KUBECONFIG]` | |
Access the `backstage` endpoint at [`https://${{ steps.prev.outputs.backstage_url }}`](https://${{ steps.prev.outputs.backstage_url }}) | |
edit-mode: replace | |
delete-uffizzi-preview: | |
permissions: | |
contents: read | |
pull-requests: write | |
id-token: write | |
name: Delete the Uffizzi Virtual Cluster | |
needs: | |
- cache-manifests-file | |
if: ${{ needs.cache-manifests-file.outputs.action == 'closed' }} | |
runs-on: ubuntu-latest | |
steps: | |
- name: Checkout | |
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 | |
- name: Delete Virtual Cluster | |
uses: UffizziCloud/cluster-action@main | |
with: | |
cluster-name: pr-${{ needs.cache-manifests-file.outputs.pr-number }} | |
server: https://app.uffizzi.com | |
action: delete | |
# Identify comment to be updated | |
- name: Find comment for Ephemeral Environment | |
uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3 | |
id: find-comment | |
with: | |
issue-number: ${{ needs.cache-manifests-file.outputs.pr-number }} | |
comment-author: 'github-actions[bot]' | |
body-includes: pr-${{ needs.cache-manifests-file.outputs.pr-number }} | |
direction: last | |
- name: Update Comment with Deletion | |
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4 | |
with: | |
comment-id: ${{ steps.find-comment.outputs.comment-id }} | |
issue-number: ${{ needs.cache-manifests-file.outputs.pr-number }} | |
body: | | |
Uffizzi Cluster `pr-${{ needs.cache-manifests-file.outputs.pr-number }}` was deleted. | |
edit-mode: replace |