-
-
Notifications
You must be signed in to change notification settings - Fork 1
feat(tasks): add inline assignees and due dates to page tasks #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 11 commits
a16c6c3
a44a13d
217c5d7
9f529df
1bdb862
3e168d9
ceef02d
2574662
9247fe8
0c94dcc
29c110e
4a69d4a
9f55dd5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| name: Deploy PR Preview | ||
|
|
||
| on: | ||
| pull_request: | ||
| types: [opened, synchronize, reopened] | ||
|
|
||
| permissions: | ||
| contents: write | ||
| pull-requests: write | ||
|
|
||
| concurrency: | ||
| group: pages-branch | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
| deploy-preview: | ||
| if: github.event.pull_request.head.repo.full_name == github.repository | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| ref: ${{ github.event.pull_request.head.sha }} | ||
|
|
||
| - uses: ./.github/actions/setup | ||
|
|
||
| - name: Build packages | ||
| run: pnpm build | ||
|
|
||
| - name: Build web app preview | ||
| run: pnpm --filter xnet-web build | ||
| env: | ||
| VITE_BASE_PATH: /pr/${{ github.event.pull_request.number }}/app/ | ||
| VITE_USE_HASH_ROUTER: 'true' | ||
|
|
||
| - name: Prepare preview tree | ||
| run: | | ||
| rm -rf /tmp/xnet-pr-preview | ||
| mkdir -p /tmp/xnet-pr-preview | ||
| cp -R apps/web/dist/. /tmp/xnet-pr-preview/ | ||
| cp /tmp/xnet-pr-preview/index.html /tmp/xnet-pr-preview/404.html | ||
|
|
||
| - name: Publish preview to gh-pages | ||
| run: | | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | ||
|
|
||
| rm -rf /tmp/xnet-gh-pages | ||
| git fetch origin gh-pages || true | ||
|
|
||
| if git ls-remote --exit-code --heads origin gh-pages >/dev/null 2>&1; then | ||
| git worktree add -B gh-pages /tmp/xnet-gh-pages origin/gh-pages | ||
| else | ||
| git worktree add -B gh-pages /tmp/xnet-gh-pages HEAD | ||
| find /tmp/xnet-gh-pages -mindepth 1 -maxdepth 1 ! -name '.git' -exec rm -rf {} + | ||
| cp site/public/CNAME /tmp/xnet-gh-pages/CNAME | ||
| touch /tmp/xnet-gh-pages/.nojekyll | ||
| fi | ||
|
|
||
| preview_dir="/tmp/xnet-gh-pages/pr/${{ github.event.pull_request.number }}/app" | ||
| mkdir -p "$preview_dir" | ||
| rsync -a --delete /tmp/xnet-pr-preview/ "$preview_dir/" | ||
|
|
||
| cd /tmp/xnet-gh-pages | ||
| git add -A | ||
|
|
||
| if git diff --cached --quiet; then | ||
| echo "No preview changes to publish." | ||
| exit 0 | ||
| fi | ||
|
|
||
| git commit -m "deploy(preview): publish PR #${{ github.event.pull_request.number }} preview" | ||
| git push origin HEAD:gh-pages | ||
|
|
||
| - name: Comment preview link | ||
| uses: actions/github-script@v7 | ||
| with: | ||
| script: | | ||
| const body = [ | ||
| '<!-- xnet-pr-preview -->', | ||
| `Preview: https://xnet.fyi/pr/${context.payload.pull_request.number}/app/` | ||
| ].join('\n') | ||
|
|
||
| const comments = await github.paginate(github.rest.issues.listComments, { | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: context.payload.pull_request.number | ||
| }) | ||
|
|
||
| const existing = comments.find((comment) => | ||
| comment.user?.login === 'github-actions[bot]' && | ||
| comment.body?.includes('<!-- xnet-pr-preview -->') | ||
| ) | ||
|
|
||
| if (existing) { | ||
| await github.rest.issues.updateComment({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| comment_id: existing.id, | ||
| body | ||
| }) | ||
| return | ||
| } | ||
|
|
||
| await github.rest.issues.createComment({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: context.payload.pull_request.number, | ||
| body | ||
| }) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,19 +12,18 @@ on: | |
| workflow_dispatch: | ||
|
|
||
| permissions: | ||
|
Comment on lines
12
to
14
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The previous implementation used For the site deploy (triggered by pushes to Consider splitting the token scope more tightly, or documenting the accepted risk: permissions:
contents: write # Required to push to gh-pages branch only
pull-requests: write # Required to post preview link commentsGitHub doesn't yet offer a |
||
| contents: read | ||
| pages: write | ||
| id-token: write | ||
| contents: write | ||
|
|
||
| concurrency: | ||
| group: pages | ||
| group: pages-branch | ||
| cancel-in-progress: true | ||
|
Comment on lines
+18
to
19
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🌐 Web query:
💡 Result: In GitHub Actions, concurrency groups are scoped at the repository level, so different workflows share the same concurrency “slot” if they use the same What happens when multiple workflows share a groupFor a given concurrency group, GitHub ensures at most 1 running and 1 pending run/job at a time. If a new run is queued into the same group while another is running, the new one becomes How
|
||
|
|
||
| jobs: | ||
| build: | ||
| deploy: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - uses: ./.github/actions/setup | ||
|
|
||
| - name: Build packages | ||
|
|
@@ -51,25 +50,41 @@ jobs: | |
| run: pnpm build | ||
| working-directory: site | ||
|
|
||
| - name: Copy web app to site/dist/app | ||
| - name: Prepare production site tree | ||
| run: | | ||
| mkdir -p site/dist/app | ||
| cp -r apps/web/dist/* site/dist/app/ | ||
| # SPA fallback for GitHub Pages | ||
| cp site/dist/app/index.html site/dist/app/404.html | ||
| rm -rf /tmp/xnet-pages-root | ||
| mkdir -p /tmp/xnet-pages-root/app | ||
| cp -R site/dist/. /tmp/xnet-pages-root/ | ||
| cp -R apps/web/dist/. /tmp/xnet-pages-root/app/ | ||
| cp /tmp/xnet-pages-root/app/index.html /tmp/xnet-pages-root/app/404.html | ||
| cp site/public/CNAME /tmp/xnet-pages-root/CNAME | ||
| touch /tmp/xnet-pages-root/.nojekyll | ||
|
|
||
| - name: Upload Pages artifact | ||
| uses: actions/upload-pages-artifact@v3 | ||
| with: | ||
| path: site/dist | ||
| - name: Publish production site to gh-pages | ||
| run: | | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | ||
|
|
||
| deploy: | ||
| needs: build | ||
| runs-on: ubuntu-latest | ||
| environment: | ||
| name: github-pages | ||
| url: ${{ steps.deployment.outputs.page_url }} | ||
| steps: | ||
| - name: Deploy to GitHub Pages | ||
| id: deployment | ||
| uses: actions/deploy-pages@v4 | ||
| rm -rf /tmp/xnet-gh-pages | ||
| git fetch origin gh-pages || true | ||
|
|
||
| if git ls-remote --exit-code --heads origin gh-pages >/dev/null 2>&1; then | ||
| git worktree add -B gh-pages /tmp/xnet-gh-pages origin/gh-pages | ||
| else | ||
| git worktree add -B gh-pages /tmp/xnet-gh-pages HEAD | ||
| find /tmp/xnet-gh-pages -mindepth 1 -maxdepth 1 ! -name '.git' -exec rm -rf {} + | ||
| fi | ||
|
|
||
| rsync -a --delete --exclude pr /tmp/xnet-pages-root/ /tmp/xnet-gh-pages/ | ||
| mkdir -p /tmp/xnet-gh-pages/pr | ||
|
|
||
| cd /tmp/xnet-gh-pages | ||
| git add -A | ||
|
|
||
| if git diff --cached --quiet; then | ||
| echo "No production site changes to publish." | ||
| exit 0 | ||
| fi | ||
|
|
||
| git commit -m "deploy(site): publish production site" | ||
| git push origin HEAD:gh-pages | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| name: Remove PR Preview | ||
|
|
||
| on: | ||
| pull_request: | ||
| types: [closed] | ||
|
|
||
| permissions: | ||
| contents: write | ||
| pull-requests: write | ||
|
|
||
| concurrency: | ||
| group: pages-branch | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
| remove-preview: | ||
| if: github.event.pull_request.head.repo.full_name == github.repository | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Remove preview from gh-pages | ||
| run: | | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | ||
|
|
||
| rm -rf /tmp/xnet-gh-pages | ||
| git fetch origin gh-pages || true | ||
|
|
||
| if ! git ls-remote --exit-code --heads origin gh-pages >/dev/null 2>&1; then | ||
| echo "gh-pages branch does not exist yet." | ||
| exit 0 | ||
| fi | ||
|
|
||
| git worktree add -B gh-pages /tmp/xnet-gh-pages origin/gh-pages | ||
|
|
||
| target="/tmp/xnet-gh-pages/pr/${{ github.event.pull_request.number }}" | ||
|
|
||
| if [ ! -d "$target" ]; then | ||
| echo "Preview path already absent." | ||
| exit 0 | ||
| fi | ||
|
|
||
| rm -rf "$target" | ||
|
|
||
| cd /tmp/xnet-gh-pages | ||
| git add -A | ||
|
|
||
| if git diff --cached --quiet; then | ||
| echo "No preview cleanup changes to publish." | ||
| exit 0 | ||
| fi | ||
|
|
||
| git commit -m "deploy(preview): remove PR #${{ github.event.pull_request.number }} preview" | ||
| git push origin HEAD:gh-pages | ||
|
|
||
| - name: Comment preview removal | ||
| uses: actions/github-script@v7 | ||
| with: | ||
| script: | | ||
| const body = [ | ||
| '<!-- xnet-pr-preview -->', | ||
| `Preview removed for PR #${context.payload.pull_request.number}.` | ||
| ].join('\n') | ||
|
|
||
| const comments = await github.paginate(github.rest.issues.listComments, { | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: context.payload.pull_request.number | ||
| }) | ||
|
|
||
| const existing = comments.find((comment) => | ||
| comment.user?.login === 'github-actions[bot]' && | ||
| comment.body?.includes('<!-- xnet-pr-preview -->') | ||
| ) | ||
|
|
||
| if (existing) { | ||
| await github.rest.issues.updateComment({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| comment_id: existing.id, | ||
| body | ||
| }) | ||
| return | ||
| } | ||
|
|
||
| await github.rest.issues.createComment({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: context.payload.pull_request.number, | ||
| body | ||
| }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shared concurrency group cancels cross-workflow deployments
All four workflows (
deploy-pr-preview.yml,deploy-site.yml,remove-pr-preview.yml,undeploy-site.yml) sharegroup: pages-branchwithcancel-in-progress: true. This means a push tomainwill cancel any in-flight PR preview deployment (and vice versa).In the worst case: a PR preview run is mid-way through the
rsync+git addsteps when amainpush triggers the site deploy and cancels it. The gh-pages worktree at/tmp/xnet-gh-pagesis abandoned mid-edit, but since the push hadn't happened yet, the remotegh-pagesbranch is unaffected. The PR preview simply never gets published, with no error surfaced to the PR author.A safer pattern is to use separate concurrency groups for PR previews and site deploys — they both operate on
gh-pagesbut write to distinct subdirectories (/pr/<N>/vs everything else):The
rsync --exclude prindeploy-site.ymlandrsync -a --deleteinside/pr/<N>/in the preview workflows already keep them isolated at the file level, so separate groups would not introduce write conflicts.This same issue is present in
.github/workflows/remove-pr-preview.yml(line 17) and.github/workflows/undeploy-site.yml(line 12).