Skip to content

Commit 3e60dc4

Browse files
feat: add support for GitHub projects in action-pull-request
1 parent 241f5d6 commit 3e60dc4

2 files changed

Lines changed: 139 additions & 1 deletion

File tree

.github/workflows/e2e-action-pull-request.yml

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,139 @@ jobs:
266266
fi
267267
git push origin --delete test/e2e-pr-custom-${{ github.run_id }} 2>/dev/null || true
268268
269+
pull-request-with-project:
270+
name: Pull request with project assignment
271+
needs: [preflight]
272+
if: ${{ vars.E2E_ACTION_PULL_REQUEST_PROJECT != '' }}
273+
runs-on: ubuntu-latest
274+
env:
275+
GH_PROJECT_TOKEN: ${{ secrets.GH_PROJECT_TOKEN }}
276+
PROJECT_TITLE: ${{ vars.E2E_ACTION_PULL_REQUEST_PROJECT }}
277+
steps:
278+
- name: Skip when project token is not configured
279+
if: ${{ env.GH_PROJECT_TOKEN == '' }}
280+
run: echo "Skipping project assignment E2E because GH_PROJECT_TOKEN is not configured."
281+
282+
- name: Checkout repository
283+
if: ${{ env.GH_PROJECT_TOKEN != '' }}
284+
uses: actions/checkout@v6
285+
with:
286+
fetch-depth: 0
287+
288+
- name: Create test branch with a commit
289+
if: ${{ env.GH_PROJECT_TOKEN != '' }}
290+
run: |
291+
git config user.name "github-actions[bot]"
292+
git config user.email "github-actions[bot]@users.noreply.github.com"
293+
git checkout -b test/e2e-pr-project-${{ github.run_id }}
294+
echo "E2E PR project test $(date -u)" > e2e-pr-project-test.txt
295+
git add -f e2e-pr-project-test.txt
296+
git commit -m "test(pull-request): project assignment PR test"
297+
git push origin test/e2e-pr-project-${{ github.run_id }}
298+
299+
- name: Checkout action under test
300+
if: ${{ env.GH_PROJECT_TOKEN != '' && inputs.mode == 'ref' }}
301+
uses: actions/checkout@v6
302+
with:
303+
repository: devops-infra/action-pull-request
304+
ref: ${{ inputs.action_ref }}
305+
path: .tmp/action-pull-request
306+
307+
- name: Create pull request with project assignment
308+
if: ${{ env.GH_PROJECT_TOKEN != '' && inputs.mode == 'ref' }}
309+
id: pr
310+
uses: ./.tmp/action-pull-request
311+
with:
312+
github_token: ${{ env.GH_PROJECT_TOKEN }}
313+
title: "test(pull-request): project assignment test - safe to close"
314+
body: "Automated end-to-end test for project assignment."
315+
target_branch: master
316+
project: ${{ env.PROJECT_TITLE }}
317+
318+
- name: Create pull request via docker image
319+
if: ${{ env.GH_PROJECT_TOKEN != '' && inputs.mode == 'image' }}
320+
env:
321+
ACTION_IMAGE: devopsinfra/action-pull-request:${{ inputs.image_tag }}
322+
run: |
323+
if [ -z "${{ inputs.image_tag }}" ]; then
324+
echo "image_tag is required when mode=image"
325+
exit 1
326+
fi
327+
mkdir -p .tmp
328+
: > .tmp/e2e-pr-project.outputs
329+
docker pull "${ACTION_IMAGE}"
330+
docker run --rm \
331+
-e GITHUB_TOKEN="${GH_PROJECT_TOKEN}" \
332+
-e GITHUB_REPOSITORY="${{ github.repository }}" \
333+
-e GITHUB_WORKSPACE=/github/workspace \
334+
-e GITHUB_ACTOR="${{ github.actor }}" \
335+
-e GITHUB_OUTPUT=/github/workspace/.tmp/e2e-pr-project.outputs \
336+
-e INPUT_GITHUB_TOKEN="${GH_PROJECT_TOKEN}" \
337+
-e INPUT_SOURCE_BRANCH="test/e2e-pr-project-${{ github.run_id }}" \
338+
-e INPUT_TITLE="test(pull-request): project assignment test - safe to close" \
339+
-e INPUT_BODY="Automated end-to-end test for project assignment." \
340+
-e INPUT_TARGET_BRANCH=master \
341+
-e INPUT_PROJECT="${PROJECT_TITLE}" \
342+
-v "$PWD:/github/workspace" \
343+
-w /github/workspace \
344+
"${ACTION_IMAGE}"
345+
346+
- name: Verify outputs
347+
if: ${{ env.GH_PROJECT_TOKEN != '' && inputs.mode == 'ref' }}
348+
run: |
349+
echo "url=${{ steps.pr.outputs.url }}"
350+
echo "pr_number=${{ steps.pr.outputs.pr_number }}"
351+
test -n "${{ steps.pr.outputs.url }}"
352+
test -n "${{ steps.pr.outputs.pr_number }}"
353+
354+
- name: Verify outputs from docker image
355+
if: ${{ env.GH_PROJECT_TOKEN != '' && inputs.mode == 'image' }}
356+
run: |
357+
URL="$(sed -n 's/^url=//p' .tmp/e2e-pr-project.outputs | tail -1)"
358+
PR_NUMBER="$(sed -n 's/^pr_number=//p' .tmp/e2e-pr-project.outputs | tail -1)"
359+
echo "url=${URL}"
360+
echo "pr_number=${PR_NUMBER}"
361+
test -n "${URL}"
362+
test -n "${PR_NUMBER}"
363+
364+
- name: Verify project assignment
365+
if: ${{ env.GH_PROJECT_TOKEN != '' }}
366+
env:
367+
GH_TOKEN: ${{ env.GH_PROJECT_TOKEN }}
368+
run: |
369+
PR_NUMBER="${{ steps.pr.outputs.pr_number }}"
370+
if [ -z "$PR_NUMBER" ] && [ -f .tmp/e2e-pr-project.outputs ]; then
371+
PR_NUMBER="$(sed -n 's/^pr_number=//p' .tmp/e2e-pr-project.outputs | tail -1)"
372+
fi
373+
test -n "${PR_NUMBER}"
374+
375+
PROJECT_FOUND="$(
376+
gh pr view "$PR_NUMBER" --repo "${{ github.repository }}" --json projectItems,projectCards \
377+
| jq -r --arg title "${PROJECT_TITLE}" \
378+
'([.projectItems[]?.project.title?, .projectCards[]?.project.name?, .projectCards[]?.project.title?]
379+
| any(. == $title))'
380+
)"
381+
382+
test "${PROJECT_FOUND}" = "true"
383+
384+
- name: Cleanup - remove project assignment, close PR, and delete test branch
385+
if: ${{ always() }}
386+
env:
387+
GH_TOKEN: ${{ env.GH_PROJECT_TOKEN }}
388+
run: |
389+
if [ -z "${GH_TOKEN}" ]; then
390+
exit 0
391+
fi
392+
PR_NUMBER="${{ steps.pr.outputs.pr_number }}"
393+
if [ -z "$PR_NUMBER" ] && [ -f .tmp/e2e-pr-project.outputs ]; then
394+
PR_NUMBER="$(sed -n 's/^pr_number=//p' .tmp/e2e-pr-project.outputs | tail -1)"
395+
fi
396+
if [ -n "$PR_NUMBER" ]; then
397+
gh pr edit "$PR_NUMBER" --repo "${{ github.repository }}" --remove-project "${PROJECT_TITLE}" 2>/dev/null || true
398+
gh pr close "$PR_NUMBER" --repo "${{ github.repository }}" 2>/dev/null || true
399+
fi
400+
git push origin --delete test/e2e-pr-project-${{ github.run_id }} 2>/dev/null || true
401+
269402
pull-request-with-repository-path:
270403
name: Pull request using custom checkout path and explicit repository
271404
needs: [preflight]

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ In Slavic mythology, Triglav represents three realms. That maps well to this fra
2525
| Action | Workflow | Test Coverage |
2626
|------------------------------------------------|-------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
2727
| `devops-infra/action-commit-push` | `.github/workflows/e2e-action-commit-push.yml` | branch creation/push, custom message/prefix, custom commit name/email, empty commit mode, amend with force-with-lease, GPG and SSH signed commits, output verification, cleanup |
28-
| `devops-infra/action-pull-request` | `.github/workflows/e2e-action-pull-request.yml` | PR creation/update paths, custom title/body, draft + `get_diff`, `repository` + `repository_path`, output verification, cleanup |
28+
| `devops-infra/action-pull-request` | `.github/workflows/e2e-action-pull-request.yml` | PR creation/update paths, custom title/body, project assignment, draft + `get_diff`, `repository` + `repository_path`, output verification, cleanup |
2929
| `devops-infra/action-format-hcl` | `.github/workflows/e2e-action-format-hcl.yml` | check mode pass/fail, write mode, list/diff mode, malformed input detection |
3030
| `devops-infra/action-container-structure-test` | `.github/workflows/e2e-action-container-structure-test.yml` | text/json/junit output modes, report file creation, multi-config execution, output counters |
3131
| `devops-infra/action-terraform-copy-vars` | `.github/workflows/e2e-action-terraform-copy-vars.yml` | variable propagation across modules, custom path inputs, strict missing-variable failure mode |
@@ -93,6 +93,11 @@ task e2e:run WORKFLOW=e2e-action-tflint.yml MODE=image IMAGE_TAG=v1.2.3-test
9393
This repository primarily relies on the built-in `${{ secrets.GITHUB_TOKEN }}` in workflow runs.
9494
If future scenarios require elevated credentials, define additional secrets in repository settings and document them in the specific workflow file.
9595

96+
`e2e-action-pull-request.yml` now has an optional project-assignment scenario.
97+
Enable it by setting:
98+
- secret `GH_PROJECT_TOKEN` with GitHub project access for `gh`
99+
- variable `E2E_ACTION_PULL_REQUEST_PROJECT` with the target project title
100+
96101
## Input Coverage Gate
97102

98103
- Coverage report: `task test:coverage:report`

0 commit comments

Comments
 (0)