Skip to content

Commit 89922f8

Browse files
Merge pull request #6 from kubesphere/fix/workflow-project-status
fix: correct GraphQL type for single-select field
2 parents ef16bc6 + 0b73d29 commit 89922f8

1 file changed

Lines changed: 141 additions & 41 deletions

File tree

Lines changed: 141 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,168 @@
11
name: Add Label on Project Status Change
22

3-
permissions:
4-
issues: write
5-
projects: read
6-
73
on:
84
workflow_dispatch:
9-
projects_v2_item:
10-
types: [edited]
5+
inputs:
6+
project_ids:
7+
description: 'Project IDs (comma-separated, e.g., PVT_xxx,PVT_yyy)'
8+
required: true
9+
default: 'PVT_kwDOAjmOms4BMOXr'
10+
status_value:
11+
description: 'Status value to match'
12+
required: false
13+
default: 'Need To Verify'
14+
label_to_add:
15+
description: 'Label to add'
16+
required: false
17+
default: 'kind/need-to-verify'
18+
schedule:
19+
- cron: '0 * * * *' # Every hour
1120

1221
jobs:
1322
add-label:
1423
runs-on: ubuntu-latest
1524
steps:
16-
- name: Check project item status and add label
25+
- name: Check project items with specific status and add label
1726
uses: actions/github-script@v7
27+
env:
28+
PROJECT_IDS: ${{ github.event.inputs.project_ids || 'PVT_kwDOAjmOms4BMOXr' }}
29+
STATUS_VALUE: ${{ github.event.inputs.status_value || 'Need To Verify' }}
30+
LABEL_TO_ADD: ${{ github.event.inputs.label_to_add || 'kind/need-to-verify' }}
1831
with:
1932
script: |
20-
try {
21-
const { data: item } = await github.graphql(`
33+
const projectIds = process.env.PROJECT_IDS.split(',').map(p => p.trim());
34+
const statusValue = process.env.STATUS_VALUE;
35+
const labelToAdd = process.env.LABEL_TO_ADD;
36+
37+
console.log(`Projects: ${projectIds.join(', ')}`);
38+
console.log(`Status: ${statusValue}, Label: ${labelToAdd}`);
39+
40+
for (const projectId of projectIds) {
41+
console.log(`\n=== Processing project: ${projectId} ===`);
42+
43+
// Get the Status field ID
44+
const fieldQuery = `
2245
query($id: ID!) {
2346
node(id: $id) {
24-
... on ProjectV2Item {
25-
content {
26-
... on Issue {
27-
number
28-
repository {
47+
... on ProjectV2 {
48+
fields(first: 20) {
49+
nodes {
50+
... on ProjectV2Field {
51+
id
2952
name
30-
owner { login }
53+
}
54+
... on ProjectV2SingleSelectField {
55+
id
56+
name
57+
options {
58+
id
59+
name
60+
}
3161
}
3262
}
3363
}
34-
fieldValues(first: 10) {
64+
}
65+
}
66+
}
67+
`;
68+
69+
const { data: project } = await github.graphql(fieldQuery, { id: projectId });
70+
if (!project || !project.fields) {
71+
console.log(`Could not fetch project ${projectId}, skipping`);
72+
continue;
73+
}
74+
75+
const statusField = project.fields.nodes.find(f => f.name === "Status");
76+
77+
if (!statusField) {
78+
console.log("Status field not found in project");
79+
continue;
80+
}
81+
82+
// Find the option ID for the target status
83+
const statusOption = statusField.options?.find(o => o.name === statusValue);
84+
if (!statusOption) {
85+
console.log(`Status option "${statusValue}" not found`);
86+
continue;
87+
}
88+
89+
console.log(`Status field ID: ${statusField.id}`);
90+
91+
// Query items in the project
92+
const itemsQuery = `
93+
query($id: ID!) {
94+
node(id: $id) {
95+
... on ProjectV2 {
96+
items(first: 50) {
3597
nodes {
36-
... on ProjectV2ItemFieldValue {
37-
field { name }
38-
value
98+
id
99+
content {
100+
... on Issue {
101+
number
102+
title
103+
state
104+
repository {
105+
name
106+
owner { login }
107+
}
108+
labels {
109+
nodes {
110+
name
111+
}
112+
}
113+
}
114+
}
115+
fieldValues(first: 20) {
116+
nodes {
117+
... on ProjectV2ItemFieldSingleSelectValue {
118+
field { id }
119+
name
120+
}
121+
}
39122
}
40123
}
41124
}
42125
}
43126
}
44127
}
45-
`, { id: context.payload.projects_v2_item.node_id });
46-
47-
const statusField = item.fieldValues.nodes.find(f => f.field.name === "Status");
48-
console.log("current status:", statusField?.value);
49-
50-
if (
51-
statusField?.value === "Need To Verify" &&
52-
item.content?.number
53-
) {
54-
const issue = item.content;
55-
await github.rest.issues.addLabels({
56-
owner: issue.repository.owner.login,
57-
repo: issue.repository.name,
58-
issue_number: issue.number,
59-
labels: ["kind/need-to-verify"]
60-
});
61-
console.log("✅ Label added:kind/need-to-verify");
62-
} else {
63-
console.log("ℹ️ Not a matching item, skip");
128+
`;
129+
130+
const { data: projectWithItems } = await github.graphql(itemsQuery, { id: projectId });
131+
132+
// Filter items with matching status and without the label
133+
const items = projectWithItems.items.nodes;
134+
console.log(`Found ${items.length} items in project`);
135+
136+
let labelAdded = 0;
137+
for (const item of items) {
138+
const statusFieldValue = item.fieldValues.nodes.find(
139+
f => f.field?.id === statusField.id
140+
);
141+
142+
if (statusFieldValue?.name === statusValue && item.content && item.content.state === 'OPEN') {
143+
const issue = item.content;
144+
const hasLabel = issue.labels.nodes.some(l => l.name === labelToAdd);
145+
146+
if (!hasLabel) {
147+
console.log(`Adding label to issue #${issue.number}: ${issue.title}`);
148+
try {
149+
await github.rest.issues.addLabels({
150+
owner: issue.repository.owner.login,
151+
repo: issue.repository.name,
152+
issue_number: issue.number,
153+
labels: [labelToAdd]
154+
});
155+
labelAdded++;
156+
} catch (e) {
157+
console.error(`Failed to add label to #${issue.number}: ${e.message}`);
158+
}
159+
} else {
160+
console.log(`Issue #${issue.number} already has label, skip`);
161+
}
162+
}
64163
}
65-
} catch (error) {
66-
console.error("❌ Action failed:", error.message);
67-
throw error;
164+
165+
console.log(`Project ${projectId}: Added label to ${labelAdded} issues`);
68166
}
167+
168+
console.log('\n=== Done ===');

0 commit comments

Comments
 (0)