Skip to content

Some improvements to preview action #51

Some improvements to preview action

Some improvements to preview action #51

Workflow file for this run

name: Deploy Preview to Kubernetes
on:
pull_request:
types:
- labeled
- unlabeled
- closed
- synchronize
jobs:
deploy-preview:
if: ${{ (github.event.action == 'labeled' && github.event.label.name == 'deploy-preview') || (github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'deploy-preview')) }}
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Wait for Build and Push Docker Image Workflow
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const workflowName = "Build and Push Docker Image";
const { data: workflows } = await github.rest.actions.listRepoWorkflows({
owner: context.repo.owner,
repo: context.repo.repo,
});
const workflow = workflows.workflows.find(w => w.name === workflowName);
if (!workflow) {
throw new Error(`Workflow '${workflowName}' not found.`);
}
const runs = await github.rest.actions.listWorkflowRuns({
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: workflow.id,
branch: context.payload.pull_request.head.ref,
status: 'completed',
});
if (runs.data.total_count === 0) {
throw new Error(`No completed runs found for workflow '${workflowName}' on branch '${context.payload.pull_request.head.ref}'.`);
}
const latestRun = runs.data.workflow_runs[0];
if (latestRun.conclusion !== "success") {
throw new Error(`Latest run of workflow '${workflowName}' failed.`);
}
- name: Create Namespace
uses: actions-hub/kubectl@master
env:
KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }}
with:
args: create namespace killedbypr${{ github.event.pull_request.number }}
- name: Create or Update Resources
run: |
mkdir -p k8s
cat <<EOF > k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: killedby
namespace: killedbypr${{ github.event.pull_request.number }}
spec:
replicas: 1
selector:
matchLabels:
app: killedby
template:
metadata:
labels:
app: killedby
spec:
containers:
- name: killedby
image: bacherik/killedby:pr-${{ github.event.pull_request.number }}
imagePullPolicy: Always
env:
- name: GITHUB_USERNAME
value: "bacherik"
- name: GITHUB_REPOSITORY
value: "killedby.json"
- name: UPDATE_TOKEN
value: "${{ secrets.UPDATE_TOKEN }}"
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: killedby
namespace: killedbypr${{ github.event.pull_request.number }}
spec:
selector:
app: killedby
ports:
- protocol: TCP
port: 80
targetPort: 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: killedby
namespace: killedbypr${{ github.event.pull_request.number }}
annotations:
cert-manager.io/cluster-issuer: "letsencrypt"
ingress.kubernetes.io/whitelist-source-range: "192.168.0.0/16"
spec:
ingressClassName: traefik
tls:
- hosts:
- pr-${{ github.event.pull_request.number }}.killedby.bacherik.de
secretName: pr${{ github.event.pull_request.number }}-killedby-tls
rules:
- host: pr-${{ github.event.pull_request.number }}.killedby.bacherik.de
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: killedby
port:
number: 80
EOF
- name: Deploy Kubernetes Resources
uses: actions-hub/[email protected]
env:
KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }}
with:
args: apply -f k8s/
- name: Delete Existing Comment
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const comments = await github.rest.issues.listComments({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
});
const botComments = comments.data.filter(comment =>
comment.body.includes('Preview is now online') || comment.body.includes('Preview has been deleted')
);
for (const comment of botComments) {
await github.rest.issues.deleteComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: comment.id,
});
}
- name: Write New Comment on PR
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const prNumber = context.payload.pull_request.number;
const url = `https://pr-${prNumber}.killedby.bacherik.de`;
const updatedAt = new Date().toISOString();
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `🎉 **Preview is now online!**\n\n🔗 [Access Preview Here](${url})\n🕒 Last updated: ${updatedAt}`,
});
cleanup:
if: ${{ github.event.action == 'closed' || (github.event.action == 'unlabeled' && github.event.label.name == 'deploy-preview') }}
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- name: Cleanup Kubernetes Resources
uses: actions-hub/[email protected]
env:
KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }}
with:
args: delete namespace killedbypr${{ github.event.pull_request.number }}
- name: Delete Existing Comment
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const comments = await github.rest.issues.listComments({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
});
const botComments = comments.data.filter(comment =>
comment.body.includes('Preview is now online') || comment.body.includes('Preview has been deleted')
);
for (const comment of botComments) {
await github.rest.issues.deleteComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: comment.id,
});
}
- name: Write comment on PR
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '🚨 **Preview has been deleted.**\n\nThe namespace and resources associated with this pull request have been cleaned up.'
})