Skip to content

[Manual Test] {{ test_id }} by {{ user_name }} #57

[Manual Test] {{ test_id }} by {{ user_name }}

[Manual Test] {{ test_id }} by {{ user_name }} #57

Workflow file for this run

name: Manual Test Report
on:
issues:
types: [opened, edited] # run on creation and later edits
permissions:
contents: read
issues: write
pull-requests: write
jobs:
process-manual-test:
if: contains(github.event.issue.title, '[Manual Test]')
runs-on: ubuntu-latest
steps:
# -------------------------------------------------------------------
# 1) Get the repo so the issue‑form template is available
# -------------------------------------------------------------------
- name: Checkout repository
uses: actions/checkout@v3
with:
fetch-depth: 1
# -------------------------------------------------------------------
# 2) Parse the form data out of the issue body
# -------------------------------------------------------------------
- name: Parse issue form
id: parse
uses: issue-ops/[email protected]
with:
body: ${{ github.event.issue.body }}
issue-form-template: .github/ISSUE_TEMPLATE/manual-test-report.yml
workspace: ${{ github.workspace }}
# -------------------------------------------------------------------
# 3) Collect everything we want to push into the project
# -------------------------------------------------------------------
- name: Build field set
id: build
run: |
{
echo "test_id=${{ steps.parse.outputs.numeric_test_id }}"
echo "estimate=${{ steps.parse.outputs.estimate_text }}"
echo "lv_version=${{ steps.parse.outputs.labview_version }}"
echo "bitness=${{ steps.parse.outputs.labview_bitness }}"
echo "os_used=${{ steps.parse.outputs.os_used }}"
echo "test_result=${{ steps.parse.outputs.test_result }}"
echo "notes=${{ steps.parse.outputs.notes }}"
} >> "$GITHUB_OUTPUT"
# -------------------------------------------------------------------
# 4) Update / create fields in organisation project 29
# -------------------------------------------------------------------
- name: Update project fields
uses: actions/github-script@v6
env:
ORG_LOGIN: ni # organisation login
PROJ_NUMBER: 29 # project number from the URL
TEST_ID: ${{ steps.build.outputs.test_id }}
ESTIMATE: ${{ steps.build.outputs.estimate }}
LV_VERSION: ${{ steps.build.outputs.lv_version }}
BITNESS: ${{ steps.build.outputs.bitness }}
OS_USED: ${{ steps.build.outputs.os_used }}
TEST_RESULT: ${{ steps.build.outputs.test_result }}
NOTES: ${{ steps.build.outputs.notes }}
with:
github-token: ${{ secrets.PROJECTS_PAT }}
script: |
const orgLogin = process.env.ORG_LOGIN;
const projectNumber = parseInt(process.env.PROJ_NUMBER,10);
const contentId = context.payload.issue.node_id;
//----------------------------------------------------------------
// Helpers
//----------------------------------------------------------------
const log = (m)=>core.info(` ${m}`);
const warn = (m)=>core.warning(` ${m}`);
//----------------------------------------------------------------
// 1) Resolve organisation‑project node‑ID
//----------------------------------------------------------------
log(`🔍 Looking up Project #${projectNumber} in org “${orgLogin}”`);
const pj = await github.graphql(`
query($org:String!,$num:Int!){
organization(login:$org){
projectV2(number:$num){ id title }
}
}`, {org:orgLogin, num:projectNumber});
const project = pj.organization.projectV2;
if(!project) core.setFailed(`Project #${projectNumber} not found.`);
const projectId = project.id;
log(`➡️ Using project “${project.title}” (ID: ${projectId})`);
//----------------------------------------------------------------
// 2) Ensure an item exists for this issue
//----------------------------------------------------------------
async function ensureItem(){
const initial = await github.graphql(`
query($pid:ID!){
node(id:$pid){
... on ProjectV2{
items(first:100){
nodes{ id content{...on Issue{id}} }
pageInfo{hasNextPage endCursor}
}
}
}
}`, {pid:projectId});
let node = initial.node;
let itemId = node.items.nodes.find(n => n.content?.id===contentId)?.id;
let cursor = node.items.pageInfo.endCursor;
let more = node.items.pageInfo.hasNextPage;
while(!itemId && more){
const nxt = await github.graphql(`
query($pid:ID!,$after:String){
node(id:$pid){
... on ProjectV2{
items(first:100,after:$after){
nodes{ id content{...on Issue{id}} }
pageInfo{hasNextPage endCursor}
}
}
}
}`, {pid:projectId, after:cursor});
node = nxt.node;
itemId = node.items.nodes.find(n => n.content?.id===contentId)?.id;
cursor = node.items.pageInfo.endCursor;
more = node.items.pageInfo.hasNextPage;
}
if(itemId){
log(`ℹ️ Found existing project item ${itemId}`);
return itemId;
}
log('➕ Adding issue to project…');
const add = await github.graphql(`
mutation($pid:ID!, $cid:ID!){
addProjectV2ItemById(input:{projectId:$pid, contentId:$cid}){
item{id}
}
}`, {pid:projectId, cid:contentId});
return add.addProjectV2ItemById.item.id;
}
//----------------------------------------------------------------
// 3) Fetch fields, create any missing, ensure options
//----------------------------------------------------------------
async function fetchFields(){
const res = await github.graphql(`
query($pid:ID!){
node(id:$pid){
... on ProjectV2{
fields(first:100){
nodes{
__typename
... on ProjectV2FieldCommon { id name dataType }
... on ProjectV2SingleSelectField {
id name dataType
options { id name }
}
}
}
}
}
}`, {pid:projectId});
return res.node.fields.nodes;
}
async function createField(name,type){
log(`⚙️ Creating field “${name}”`);
const res = await github.graphql(`
mutation($pid:ID!,$name:String!,$type:ProjectV2CustomFieldDataType!){
createProjectV2Field(input:{
projectId:$pid, name:$name, dataType:$type,
${type==='SINGLE_SELECT'
? 'singleSelectOptions:[{name:"Passed"},{name:"Failed"},{name:"Needs Review"}]'
: ''}
}){
field{
__typename
... on ProjectV2FieldCommon { id name dataType }
... on ProjectV2SingleSelectField {
id name dataType
options { id name }
}
}
}
}`, {pid:projectId, name, type});
return res.createProjectV2Field.field;
}
async function ensureOption(field,optName){
if(field.dataType!=='SINGLE_SELECT') return null;
const found = field.options.find(o=>o.name===optName);
if(found) return found.id;
log(`⚙️ Adding option “${optName}” to “${field.name}”`);
const res = await github.graphql(`
mutation($pid:ID!,$fid:ID!,$name:String!){
createProjectV2SingleSelectFieldOption(input:{
projectId:$pid, fieldId:$fid, name:$name
}){
option{id}
}
}`, {pid:projectId,fid:field.id,name:optName});
return res.createProjectV2SingleSelectFieldOption.option.id;
}
async function setField(itemId,field,val){
let payload;
if(field.dataType==='SINGLE_SELECT'){
const optId = await ensureOption(field,val);
payload = { singleSelectOptionId: optId };
}else{
payload = { text: val };
}
await github.graphql(`
mutation($pid:ID!,$iid:ID!,$fid:ID!,$val:ProjectV2FieldValue!){
updateProjectV2ItemFieldValue(input:{
projectId:$pid, itemId:$iid, fieldId:$fid, value:$val
}){
projectV2Item{id}
}
}`, {pid:projectId,iid:itemId,fid:field.id,val:payload});
log(`✅ “${field.name}” → “${val}”`);
}
//----------------------------------------------------------------
// 4) Execute
//----------------------------------------------------------------
const itemId = await ensureItem();
let fields = await fetchFields();
const toSet = [
{n:'TestID', v:process.env.TEST_ID, t:'TEXT'},
{n:'Estimate', v:process.env.ESTIMATE, t:'TEXT'},
{n:'Operating System', v:process.env.OS_USED, t:'TEXT'},
{n:'LabVIEW Version', v:process.env.LV_VERSION, t:'TEXT'},
{n:'LabVIEW Bitness', v:process.env.BITNESS, t:'TEXT'},
{n:'Notes', v:process.env.NOTES, t:'TEXT'},
{n:'Test Result', v:process.env.TEST_RESULT, t:'SINGLE_SELECT'}
];
log('✏️ Updating project fields');
for(const f of toSet){
if(!f.v){ warn(`Skipping “${f.n}” – empty value`); continue; }
let fld = fields.find(x=>x.name===f.n);
if(!fld){
fld = await createField(f.n,f.t);
fields.push(fld);
}
await setField(itemId,fld,f.v);
}
log('🎉 Project update finished');