@@ -1,133 +0,0 @@
|
||||
name: Preview (build)
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, closed]
|
||||
paths-ignore:
|
||||
- '.changeset/**'
|
||||
- 'contrib/**'
|
||||
- 'docs/**'
|
||||
- 'microsite/**'
|
||||
- 'beps/**'
|
||||
- 'scripts/**'
|
||||
- 'storybook/**'
|
||||
- '**/*.test.*'
|
||||
- '**/package.json'
|
||||
- '*.md'
|
||||
|
||||
jobs:
|
||||
build-backstage:
|
||||
env:
|
||||
NODE_OPTIONS: --max-old-space-size=4096
|
||||
UFFIZZI_URL: https://app.uffizzi.com
|
||||
name: Build PR image
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event_name != 'pull_request' || github.event.action != 'closed' }}
|
||||
outputs:
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: checkout
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
|
||||
- name: setup-node
|
||||
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
with:
|
||||
node-version: 18.x
|
||||
registry-url: https://registry.npmjs.org/
|
||||
|
||||
- name: yarn install
|
||||
uses: backstage/actions/yarn-install@af61233abb88019335b07ab855873d991f43d25a # v0.6.7
|
||||
with:
|
||||
cache-prefix: linux-v18
|
||||
|
||||
- name: Use Uffizzi's backstage app config
|
||||
run: |
|
||||
cp -f ./.github/uffizzi/uffizzi.production.app-config.yaml ./app-config.yaml
|
||||
|
||||
- name: backstage build
|
||||
run: |
|
||||
yarn workspace example-backend build
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb # v3.3.0
|
||||
|
||||
- name: Generate UUID image name
|
||||
id: uuid
|
||||
run: echo "UUID_TAG_APP=backstage-$(uuidgen --time)" >> $GITHUB_ENV
|
||||
|
||||
- name: Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.1
|
||||
with:
|
||||
images: registry.uffizzi.com/${{ env.UUID_TAG_APP }}
|
||||
tags: type=raw,value=60d
|
||||
|
||||
- name: Build Image
|
||||
uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 # v5.3.0
|
||||
with:
|
||||
context: .
|
||||
file: packages/backend/Dockerfile
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
push: true
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
render-kustomize:
|
||||
name: Render Kustomize Manifests
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- build-backstage
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout git repo
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- name: Render Compose File
|
||||
run: |
|
||||
# update image after the build above
|
||||
cd ./.github/uffizzi/k8s/manifests
|
||||
kustomize edit set image backstage=${{ needs.build-backstage.outputs.tags }}
|
||||
kustomize build . > manifests.rendered.yml
|
||||
cat manifests.rendered.yml
|
||||
|
||||
- name: clone artifacts into current directory
|
||||
run: |
|
||||
cat ${{ github.event_path }} > event.json
|
||||
cp ./.github/uffizzi/k8s/manifests/manifests.rendered.yml manifests.rendered.yml
|
||||
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4
|
||||
with:
|
||||
name: preview-spec
|
||||
path: |
|
||||
manifests.rendered.yml
|
||||
event.json
|
||||
retention-days: 2
|
||||
overwrite: true
|
||||
|
||||
delete-preview:
|
||||
name: Call for Preview Deletion
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.action == 'closed' }}
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
# If this PR is closing, we will not render a compose file nor pass it to the next workflow.
|
||||
- name: Upload PR Event as Artifact
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
with:
|
||||
name: preview-spec
|
||||
path: ${{ github.event_path }}
|
||||
retention-days: 2
|
||||
overwrite: true
|
||||
@@ -1,238 +0,0 @@
|
||||
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@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
|
||||
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
|
||||
Reference in New Issue
Block a user