Skip to content

liron demo

liron demo #9

# Dynamic mirrord Preview Environment: detects changed services, builds images,
# and starts a preview for each. Posts a single aggregated PR comment + Slack message.
# Uses metalbear-co/mirrord-preview GitHub Action.
# Requires: GCP_WIF_PROVIDER + GCP_SERVICE_ACCOUNT + SLACK_WEBHOOK_URL secrets,
# mirrord operator with Enterprise license.
name: Preview Environment - Shop (Dynamic)
on:
pull_request:
types: [opened, reopened, closed]
concurrency:
group: preview-shop-${{ github.event.pull_request.number }}
cancel-in-progress: true
env:
PREVIEW_KEY: "${{ github.head_ref }}"
jobs:
# ─── Job 1: Detect which services changed ───
detect-changes:
name: Detect changed services
if: github.event.action != 'closed'
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.build-matrix.outputs.matrix }}
has_changes: ${{ steps.build-matrix.outputs.has_changes }}
services_list: ${{ steps.build-matrix.outputs.services_list }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Detect changed services via git diff
id: build-matrix
run: |
CHANGED_FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD)
CHANGES='[]'
for path in $(jq -r '.services[].path' .github/preview-services.json); do
name=$(jq -r --arg p "$path" '.services[] | select(.path == $p) | .name' .github/preview-services.json)
if echo "$CHANGED_FILES" | grep -q "^${path}/"; then
CHANGES=$(echo "$CHANGES" | jq -c --arg n "$name" '. + [$n]')
fi
done
MATRIX=$(jq -c --argjson changes "$CHANGES" \
'{include: [.services[] | select(.name as $n | $changes | index($n))]}' \
.github/preview-services.json)
SERVICES_LIST=$(jq -r --argjson changes "$CHANGES" \
'[.services[] | select(.name as $n | $changes | index($n)) | .name] | join(", ")' \
.github/preview-services.json)
COUNT=$(echo "$CHANGES" | jq 'length')
echo "matrix=$MATRIX" >> "$GITHUB_OUTPUT"
echo "services_list=$SERVICES_LIST" >> "$GITHUB_OUTPUT"
if [ "$COUNT" -gt 0 ]; then
echo "has_changes=true" >> "$GITHUB_OUTPUT"
else
echo "has_changes=false" >> "$GITHUB_OUTPUT"
fi
echo "Changed services ($COUNT): $SERVICES_LIST"
# ─── Job 2: Build image + start preview for each changed service ───
build-and-preview:
name: Build & Preview (${{ matrix.name }})
needs: detect-changes
if: needs.detect-changes.outputs.has_changes == 'true'
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
matrix: ${{ fromJSON(needs.detect-changes.outputs.matrix) }}
fail-fast: false
permissions:
contents: read
packages: write
id-token: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push image
uses: docker/build-push-action@v5
with:
context: ${{ matrix.path }}
file: ${{ matrix.path }}/Dockerfile
platforms: linux/amd64
push: true
tags: ghcr.io/metalbear-co/playground-${{ matrix.name }}:preview-${{ github.head_ref }}-${{ github.sha }}
build-args: ${{ matrix.build_args }}
cache-from: type=gha,scope=${{ matrix.name }}
cache-to: type=gha,scope=${{ matrix.name }},mode=max
- name: Authenticate to GCP via Workload Identity Federation
uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ secrets.GCP_WIF_PROVIDER }}
service_account: ${{ secrets.GCP_SERVICE_ACCOUNT }}
- name: Get GKE credentials
uses: google-github-actions/get-gke-credentials@v2
with:
cluster_name: playground-cluster-1
location: us-central1-c
project_id: playground-383912
- name: Start mirrord preview
uses: metalbear-co/mirrord-preview@master
with:
action: start
target: deployment/${{ matrix.deployment }}
namespace: ${{ matrix.namespace }}
image: ghcr.io/metalbear-co/playground-${{ matrix.name }}:preview-${{ github.head_ref }}-${{ github.sha }}
mode: steal
filter: 'baggage:\s*[^\n]*\bmirrord={{ key }}\b'
ttl_mins: '120'
key: ${{ env.PREVIEW_KEY }}
extra_config: |
{
"feature": {
"preview": {
"creation_timeout_secs": 600
}
}
}
- name: Write result artifact
if: success()
run: |
mkdir -p /tmp/preview-results
echo '{"name":"${{ matrix.name }}"}' > /tmp/preview-results/${{ matrix.name }}.json
- name: Upload result artifact
if: success()
uses: actions/upload-artifact@v4
with:
name: preview-result-${{ matrix.name }}
path: /tmp/preview-results/${{ matrix.name }}.json
retention-days: 1
# ─── Job 3: Post aggregated PR comment + Slack notification ───
notify:
name: Post notifications
needs: [detect-changes, build-and-preview]
if: needs.detect-changes.outputs.has_changes == 'true' && !cancelled()
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- name: Download all result artifacts
uses: actions/download-artifact@v4
with:
pattern: preview-result-*
path: /tmp/preview-results
merge-multiple: true
- name: Post PR comment with preview details
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const path = require('path');
const key = `${{ env.PREVIEW_KEY }}`;
const url = 'https://playground.metalbear.dev/shop';
// Read all result files to get list of successfully previewed services
const dir = '/tmp/preview-results';
let services = [];
try {
const files = fs.readdirSync(dir).filter(f => f.endsWith('.json'));
services = files.map(f => JSON.parse(fs.readFileSync(path.join(dir, f), 'utf8')));
} catch (e) {
console.log('No preview results found, some or all previews may have failed.');
}
const serviceList = services.length > 0
? services.map(s => `| \`${s.name}\` | \`deployment/${s.name}\` |`).join('\n')
: '| _(no previews succeeded)_ | |';
const body = [
'## mirrord Preview Environment - Metal Mart',
'',
'Preview environments are running for this PR.',
'',
'| Service | Target |',
'|---|---|',
serviceList,
'',
'| | |',
'|---|---|',
`| **Preview URL** | [${url}](${url}) |`,
`| **Header** | \`baggage: mirrord=${key}\` |`,
'',
'To send traffic to this preview:',
`- Use the [mirrord Browser Extension](https://metalbear.com/mirrord/docs/using-mirrord/browser-extension) and set the header for this URL, or`,
`- \`curl -H "baggage: mirrord=${key}" ${url}\``,
'',
'*Preview is stopped when the PR is merged or closed.*',
].join('\n');
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const botComment = comments.find(c => c.body && c.body.includes('## mirrord Preview Environment - Metal Mart'));
if (botComment) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body,
});
}
- name: Post preview link to Slack
uses: slackapi/slack-github-action@v1.27.0
with:
payload: |
{
"blocks": [
{
"type": "header",
"text": { "type": "plain_text", "text": "mirrord Preview Environment - Metal Mart" }
},
{
"type": "section",
"fields": [
{ "type": "mrkdwn", "text": "*PR:*\n<${{ github.event.pull_request.html_url }}|#${{ github.event.pull_request.number }} ${{ github.event.pull_request.title }}>" },
{ "type": "mrkdwn", "text": "*Services:*\n${{ needs.detect-changes.outputs.services_list }}" },
{ "type": "mrkdwn", "text": "*Preview URL:*\n<https://playground.metalbear.dev/shop|Open Preview>" },
{ "type": "mrkdwn", "text": "*Header:*\n`baggage: mirrord=${{ env.PREVIEW_KEY }}`" }
]
}
]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
# ─── Job 4: Stop all previews on merge/close ───
preview-stop:
name: Stop all previews on merge/close
if: github.event.action == 'closed'
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: read
id-token: write
steps:
- name: Authenticate to GCP via Workload Identity Federation
uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ secrets.GCP_WIF_PROVIDER }}
service_account: ${{ secrets.GCP_SERVICE_ACCOUNT }}
- name: Get GKE credentials
uses: google-github-actions/get-gke-credentials@v2
with:
cluster_name: playground-cluster-1
location: us-central1-c
project_id: playground-383912
- name: Stop mirrord preview
uses: metalbear-co/mirrord-preview@master
with:
action: stop
key: ${{ env.PREVIEW_KEY }}