1+ name : Check PR Project Assignment
2+
3+ on :
4+ pull_request :
5+ types : [opened, synchronize, reopened]
6+
7+ jobs :
8+ check-project :
9+ name : Verify PR is in project with iteration
10+ runs-on : ubuntu-latest
11+
12+ steps :
13+ - name : Check project assignment
14+ uses : actions/github-script@v7
15+ with :
16+ github-token : ${{ secrets.PROJECT_PAT }}
17+ script : |
18+ const owner = 'o1-labs';
19+ const projectNumber = 24; // Rust node project number
20+
21+ // Get PR details
22+ const pr = context.payload.pull_request;
23+ console.log(`Checking PR #${pr.number}: ${pr.title}`);
24+
25+ // GraphQL query to check if PR is in project with iteration
26+ const query = `
27+ query($owner: String!, $number: Int!, $prId: ID!) {
28+ organization(login: $owner) {
29+ projectV2(number: $number) {
30+ id
31+ title
32+ items(first: 100) {
33+ nodes {
34+ id
35+ content {
36+ ... on PullRequest {
37+ id
38+ number
39+ title
40+ }
41+ }
42+ fieldValues(first: 20) {
43+ nodes {
44+ ... on ProjectV2ItemFieldIterationValue {
45+ field {
46+ ... on ProjectV2IterationField {
47+ name
48+ }
49+ }
50+ title
51+ startDate
52+ duration
53+ }
54+ }
55+ }
56+ }
57+ }
58+ }
59+ }
60+ }
61+ `;
62+
63+ try {
64+ const result = await github.graphql(query, {
65+ owner: owner,
66+ number: projectNumber,
67+ prId: pr.node_id
68+ });
69+
70+ const project = result.organization.projectV2;
71+ console.log(`Found project: ${project.title}`);
72+
73+ // Find this PR in the project
74+ const projectItem = project.items.nodes.find(item =>
75+ item.content &&
76+ item.content.number === pr.number
77+ );
78+
79+ if (!projectItem) {
80+ core.setFailed(`❌ PR #${pr.number} is not added to the "${project.title}" project.\n\n` +
81+ `Please add this PR to the project at: https://github.com/orgs/${owner}/projects/${projectNumber}\n\n` +
82+ `Instructions:\n` +
83+ `1. Go to the project board\n` +
84+ `2. Click "Add item" button\n` +
85+ `3. Search for this PR (#${pr.number})\n` +
86+ `4. Add it to the project\n` +
87+ `5. Set an iteration for the PR`);
88+ return;
89+ }
90+
91+ console.log('PR found in project, checking for iteration...');
92+
93+ // Check if PR has an iteration assigned
94+ const iterationField = projectItem.fieldValues.nodes.find(field =>
95+ field.field && field.field.name === 'Iteration'
96+ );
97+
98+ if (!iterationField || !iterationField.title) {
99+ core.setFailed(`❌ PR #${pr.number} is in the project but has no iteration assigned.\n\n` +
100+ `Please assign an iteration to this PR in the project at: https://github.com/orgs/${owner}/projects/${projectNumber}\n\n` +
101+ `Instructions:\n` +
102+ `1. Go to the project board\n` +
103+ `2. Find this PR (#${pr.number})\n` +
104+ `3. Click on the Iteration field for this item\n` +
105+ `4. Select the appropriate iteration`);
106+ return;
107+ }
108+
109+ console.log(`✅ PR #${pr.number} is in project "${project.title}" with iteration: ${iterationField.title}`);
110+ core.notice(`PR is properly assigned to project with iteration: ${iterationField.title}`);
111+
112+ } catch (error) {
113+ console.error('Error checking project:', error);
114+ core.setFailed(`Failed to check project assignment: ${error.message}\n\n` +
115+ `This might happen if:\n` +
116+ `- The PROJECT_PAT secret is not configured correctly\n` +
117+ `- The project number (${projectNumber}) is incorrect\n` +
118+ `- There are API permission issues`);
119+ }
0 commit comments