[Manual Test] {{ test_id }} by {{ user_name }} #39
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: process-manual-test | ||
on: | ||
issues: | ||
types: | ||
- opened | ||
- edited | ||
- labeled | ||
permissions: | ||
issues: write | ||
contents: read | ||
pull-requests: write | ||
repository-projects: write | ||
metadata: read | ||
jobs: | ||
process-manual-test: | ||
name: process-manual-test | ||
runs-on: ubuntu-24.04 | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v3 | ||
- name: Parse form | ||
id: parse | ||
uses: issue-ops/[email protected] | ||
with: | ||
body: ${{ github.event.issue.body }} | ||
issue-form-template: manual-test-report.yml | ||
workspace: ${{ github.workspace }} | ||
- name: Detect previous project end date | ||
id: prev | ||
uses: actions/github-script@v6 | ||
env: | ||
CUR_NUMBER: ${{ github.event.issue.number }} | ||
with: | ||
script: | | ||
const {owner,repo} = context.repo; | ||
const cur = parseInt(process.env.CUR_NUMBER,10); | ||
const author = context.payload.issue.user.login; | ||
const query = `repo:${owner}/${repo} label:manual-test author:${author} in:title "[Manual Test]" sort:created-desc`; | ||
const res = await github.graphql(` | ||
query($q:String!){ | ||
search(query:$q,type:ISSUE,first:10){ | ||
nodes{ | ||
... on Issue{ | ||
number | ||
projectItems(first:50){ | ||
nodes{ | ||
fieldValues(first:50){ | ||
nodes{ | ||
__typename | ||
... on ProjectV2ItemFieldDateValue{ | ||
date | ||
field{ ... on ProjectV2FieldCommon{ name } } | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}`, {q: query}); | ||
let prevEnd=''; | ||
for (const n of res.search.nodes){ | ||
if (n.number === cur) continue; | ||
for (const fv of n.projectItems.nodes.flatMap(it=>it.fieldValues.nodes)){ | ||
if (fv.field?.name === 'End Date' && fv.date){ | ||
prevEnd = fv.date; break; | ||
} | ||
} | ||
if (prevEnd) break; | ||
} | ||
core.setOutput('prev_end', prevEnd); | ||
core.info(prevEnd ? `Previous End Date: ${prevEnd}` : 'No previous End Date'); | ||
- name: Validate & update project-item | ||
id: update | ||
uses: actions/github-script@v6 | ||
env: | ||
NUMID: ${{ steps.parse.outputs.numeric_test_id }} | ||
EST: ${{ steps.parse.outputs.estimate_text }} | ||
OS: ${{ steps.parse.outputs.os_used }} | ||
LV: ${{ steps.parse.outputs.labview_version }} | ||
BIT: ${{ steps.parse.outputs.labview_bitness }} | ||
NOTES: ${{ steps.parse.outputs.notes }} | ||
PREV: ${{ steps.prev.outputs.prev_end }} | ||
with: | ||
script: | | ||
const {owner,repo} = context.repo; | ||
const issueNode = context.payload.issue.node_id; | ||
const createdDate = context.payload.issue.created_at.substring(0,19)+'Z'; | ||
// ---------- get existing project items ---------- | ||
const q = await github.graphql(` | ||
query($id:ID!){ | ||
node(id:$id){ | ||
... on Issue{ | ||
projectItems(first:50){ | ||
nodes{ id project{id title} } | ||
} | ||
} | ||
} | ||
}`, {id: issueNode}); | ||
let items = q.node.projectItems.nodes; | ||
// ---------- create project item if none ---------- | ||
if (items.length === 0){ | ||
const pl = await github.graphql(` | ||
query($o:String!,$r:String!){ | ||
repository(owner:$o,name:$r){ | ||
projectsV2(first:1){nodes{id title}} | ||
} | ||
}`, {o: owner, r: repo}); | ||
const proj = pl.repository.projectsV2.nodes[0]; | ||
if (!proj) core.setFailed('No repository project found.'); | ||
const add = await github.graphql(` | ||
mutation($p:ID!,$c:ID!){ | ||
addProjectV2ItemById(input:{projectId:$p,contentId:$c}){item{id}} | ||
}`, {p: proj.id, c: issueNode}); | ||
items = [{id: add.addProjectV2ItemById.item.id, project: proj}]; | ||
core.notice(`Created project item in “${proj.title}”`); | ||
} | ||
// ---------- helper to update one field ---------- | ||
async function setField(pid, iid, fid, value){ | ||
await github.graphql(` | ||
mutation($p:ID!,$i:ID!,$f:ID!,$v:ProjectV2FieldValue!){ | ||
updateProjectV2ItemFieldValue(input:{ | ||
projectId:$p,itemId:$i,fieldId:$f,value:$v | ||
}){ projectV2Item{id} } | ||
}`, {p: pid, i: iid, f: fid, v: value}); | ||
} | ||
// ---------- iterate each project item ---------- | ||
for (const it of items){ | ||
const fv = await github.graphql(` | ||
query($id:ID!){ | ||
node(id:$id){ | ||
... on ProjectV2Item{ | ||
fieldValues(first:50){ | ||
nodes{ | ||
__typename | ||
... on ProjectV2ItemFieldTextValue{ | ||
text | ||
field{ ... on ProjectV2FieldCommon{ id name } } | ||
} | ||
... on ProjectV2ItemFieldDateValue{ | ||
date | ||
field{ ... on ProjectV2FieldCommon{ id name } } | ||
} | ||
... on ProjectV2ItemFieldSingleSelectValue{ | ||
id | ||
name | ||
field{ ... on ProjectV2FieldCommon{ id name } } | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}`, {id: it.id}); | ||
const map = {}; | ||
for (const n of fv.node.fieldValues.nodes){ | ||
// QUICK PATCH: skip nodes lacking a `field` object | ||
if (!n.field || !n.field.name) continue; | ||
map[n.field.name] = { | ||
fieldId : n.field.id, | ||
type : n.__typename, | ||
node : n | ||
}; | ||
} | ||
// End Date (write once) | ||
if (map['End Date'] && !map['End Date'].node.date){ | ||
await setField(it.project.id, it.id, map['End Date'].fieldId, | ||
{date: createdDate}); | ||
} | ||
// Start Date (every run if prev exists) | ||
if (process.env.PREV && map['Start Date']){ | ||
await setField(it.project.id, it.id, map['Start Date'].fieldId, | ||
{date: process.env.PREV}); | ||
} | ||
// plain text fields | ||
const textPairs = [ | ||
['TestID', process.env.NUMID], | ||
['Estimate', process.env.EST], | ||
['Operating System', process.env.OS], | ||
['LabVIEW Version', process.env.LV], | ||
['LabVIEW Bitness', process.env.BIT], | ||
['Notes', process.env.NOTES] | ||
]; | ||
for (const [fname, val] of textPairs){ | ||
if (map[fname]) | ||
await setField(it.project.id, it.id, map[fname].fieldId, {text: val}); | ||
} | ||
// Test Result (single‑select) | ||
if (map['Test Result'] && map['Test Result'].type === 'ProjectV2ItemFieldSingleSelectValue'){ | ||
await setField(it.project.id, it.id, map['Test Result'].fieldId, { | ||
singleSelectOptionId: map['Test Result'].node.id | ||
}); | ||
} | ||
} |