mirror of
https://github.com/go-vikunja/vikunja.git
synced 2026-05-23 03:01:32 -05:00
The docker/metadata-action uses github.sha for the SHA tag, which for pull_request_target events is the base branch commit, not the PR head. The comment step was independently constructing SHA tags from the PR head SHA, causing preview URLs that didn't match any actual docker image tag. Now reads the actual tags from docker meta output instead.
152 lines
6.2 KiB
YAML
152 lines
6.2 KiB
YAML
name: Preview
|
|
|
|
on:
|
|
# pull_request_target gives write access to GHCR even for PRs from forks.
|
|
# This is safe because:
|
|
# 1. We explicitly checkout the PR's head commit (no base branch code execution)
|
|
# 2. We ONLY build a Docker image (isolated container, no workflow scripts from PR)
|
|
# 3. The github-script step only uses safe PR metadata (number, SHA) — no PR-supplied
|
|
# text (title, body, commit messages) is interpolated, so there is no injection risk
|
|
# 4. Build happens in isolated Docker container with well-defined Dockerfile
|
|
pull_request_target:
|
|
|
|
jobs:
|
|
docker:
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
packages: write
|
|
contents: read
|
|
pull-requests: write
|
|
steps:
|
|
- name: Free Disk Space
|
|
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1
|
|
with:
|
|
large-packages: false
|
|
docker-images: false
|
|
swap-storage: false
|
|
- name: Checkout
|
|
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
|
|
with:
|
|
# For pull_request_target, we need to explicitly fetch the PR ref from forks
|
|
# since the PR's commit SHA is not reachable in the base repository.
|
|
# This is safe because no PR code is executed in workflow context.
|
|
# Only Docker build uses the PR code (isolated in container).
|
|
ref: refs/pull/${{ github.event.pull_request.number }}/head
|
|
- name: Git describe
|
|
id: ghd
|
|
uses: proudust/gh-describe@v2
|
|
- name: Login to GHCR
|
|
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3
|
|
with:
|
|
registry: ghcr.io
|
|
username: ${{ github.repository_owner }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
|
|
with:
|
|
version: latest
|
|
- name: Docker meta
|
|
id: meta
|
|
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5
|
|
with:
|
|
images: ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}
|
|
tags: |
|
|
type=ref,event=pr
|
|
type=sha,format=long
|
|
- name: Build and push PR image
|
|
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
|
|
with:
|
|
context: .
|
|
platforms: linux/amd64
|
|
push: true
|
|
tags: ${{ steps.meta.outputs.tags }}
|
|
labels: ${{ steps.meta.outputs.labels }}
|
|
cache-from: type=gha
|
|
cache-to: type=gha,mode=max
|
|
build-args: |
|
|
RELEASE_VERSION=${{ steps.ghd.outputs.describe }}
|
|
- name: Comment on PR
|
|
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
|
|
env:
|
|
DOCKER_META_TAGS: ${{ steps.meta.outputs.tags }}
|
|
with:
|
|
script: |
|
|
const prNumber = context.payload.pull_request.number;
|
|
const base = 'preview.vikunja.dev';
|
|
const image = `ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}`;
|
|
const marker = '<!-- vikunja-preview-comment -->';
|
|
|
|
// Extract the SHA tag from docker meta output (the actual tag pushed to GHCR)
|
|
const metaTags = process.env.DOCKER_META_TAGS.split('\n').map(t => t.trim()).filter(Boolean);
|
|
const shaImageRef = metaTags.find(t => t.includes(':sha-'));
|
|
const shaTag = shaImageRef ? shaImageRef.split(':').pop() : null;
|
|
const shortSha = shaTag ? shaTag.replace('sha-', '').substring(0, 7) : context.payload.pull_request.head.sha.substring(0, 7);
|
|
|
|
const prTag = `pr-${prNumber}`;
|
|
const newShaRow = shaTag
|
|
? `| https://${shaTag}.${base} | \`${image}:${shaTag}\` | \`${shortSha}\` |`
|
|
: '';
|
|
|
|
// Collect previous SHA rows from existing comment
|
|
let previousShaRows = [];
|
|
const { data: comments } = await github.rest.issues.listComments({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: prNumber,
|
|
});
|
|
const existing = comments.find(c => c.body.includes(marker));
|
|
|
|
if (existing) {
|
|
previousShaRows = existing.body
|
|
.split('\n')
|
|
.filter(l => l.includes(`sha-`) && l.includes(`.${base}`));
|
|
}
|
|
|
|
// Remove duplicate if this SHA was already recorded
|
|
if (shaTag) {
|
|
previousShaRows = previousShaRows.filter(r => !r.includes(shaTag));
|
|
}
|
|
|
|
const allShaRows = [newShaRow, ...previousShaRows].filter(Boolean).join('\n');
|
|
|
|
const body = [
|
|
marker,
|
|
`### Preview Deployment`,
|
|
``,
|
|
`Preview deployments for this PR are available at:`,
|
|
``,
|
|
`| URL | Tag | Commit |`,
|
|
`| --- | --- | --- |`,
|
|
`| https://${prTag}.${base} | \`${image}:${prTag}\` | latest |`,
|
|
allShaRows,
|
|
``,
|
|
`The preview environment will start automatically on first visit. Subsequent pushes to this PR will update the \`${prTag}\` image — the preview picks up the new version on restart. The per-commit URLs point to a specific version and will not change.`,
|
|
``,
|
|
`<details>`,
|
|
`<summary>Run locally with Docker</summary>`,
|
|
``,
|
|
'```bash',
|
|
`docker pull ${image}:${prTag}`,
|
|
`docker run -p 3456:3456 ${image}:${prTag}`,
|
|
'```',
|
|
`</details>`,
|
|
``,
|
|
`_Last updated for commit ${shortSha}_`,
|
|
].join('\n');
|
|
|
|
if (existing) {
|
|
await github.rest.issues.updateComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
comment_id: existing.id,
|
|
body,
|
|
});
|
|
} else {
|
|
await github.rest.issues.createComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: prNumber,
|
|
body,
|
|
});
|
|
}
|