Skip to content

Commit

Permalink
Post PBB Migration 7079 - Refactor GHA for Moving Closed Issues (hack…
Browse files Browse the repository at this point in the history
…forla#7493)

* implement steps to move closed issues in PBB

* add semicolons

* prep for testing

* error-handling checks

* refactor step 2

* refactor steps 2-4 into step 2 and incorporate into move-closed-issues.js

* add github graphql token

* rename projectItems to projectData, change variable definition

* clean code

* revert to hackforla defaults

* add JSDoc

* remove duplicated variable
  • Loading branch information
DrAcula27 authored Sep 21, 2024
1 parent dc1e1dd commit d8ebc2c
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 42 deletions.
27 changes: 17 additions & 10 deletions .github/workflows/move-closed-issues.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,31 @@ on:
issues:
types:
- closed

jobs:
Move-Closed-Issues:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

# 1: Sort closed issues based on labels
- name: Sort Closed Issues by Label
uses: actions/github-script@v7
id: sort-closed-issues
with:
script: |
const script = require('./github-actions/move-closed-issues/sort-closed-issues.js')
const sortIssues = script({context})
return sortIssues
const script = require('./github-actions/move-closed-issues/sort-closed-issues.js');
const sortIssues = script({context});
return sortIssues;
result-encoding: string

# Post-migration to Projects Beta:
# Move-Closed-Issues to "QA" column by default; OR move to "Done" based on `sort-closed-issues.js`
- name: Move Closed Issues
run: echo "Based on its labels, issue should be sorted to 'status' of '${{ steps.sort-closed-issues.outputs.result }}'"


# 2: Move closed issues
- name: Move Closed Issue
uses: actions/github-script@v7
id: move-closed-issue
with:
github-token: ${{ secrets.HACKFORLA_GRAPHQL_TOKEN }}
script: |
const results = '${{ steps.sort-closed-issues.outputs.result }}';
const script = require('./github-actions/move-closed-issues/move-closed-issues.js');
script({github, context}, results);
19 changes: 19 additions & 0 deletions github-actions/move-closed-issues/move-closed-issues.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Module imports
const statusFieldIds = require('../utils/_data/status-field-ids');
const queryIssueInfo = require('../utils/query-issue-info');
const mutateIssueStatus = require('../utils/mutate-issue-status');

/**
* @description - Changes the closed 'status' of the issue based on `sort-closed-issues.js`
* @param {Object} github - GitHub object from actions/github-script
* @param {Object} context - Context object from actions/github-script
* @param {String} results - Status to which issue will be sorted from previous step
*/
async function main({ github, context }, results) {
const issueNum = context.payload.issue.number;
let statusValue = statusFieldIds(results);
const itemInfo = await queryIssueInfo(github, context, issueNum);
await mutateIssueStatus(github, context, itemInfo.id, statusValue);
}

module.exports = main;
28 changes: 12 additions & 16 deletions github-actions/move-closed-issues/sort-closed-issues.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,34 @@
const obtainLabels = require('../utils/obtain-labels')
const obtainLabels = require('../utils/obtain-labels');

/**
* Check the labels of an issue, and return the 'status' the issue should be sorted into when closed
* @param {Object} context - context object from actions/github-script
* @returns - returns the appropriate 'status', which is passed on to the next action
*/
function main({ context }) {

// Using Projects Beta 'status'
const doneStatus = "Done"
const QAStatus = "QA"
const doneStatus = 'Done';
const QAStatus = 'QA';

const hardLabels = [
"Feature: Refactor CSS",
"Feature: Refactor HTML",
"Feature: Refactor JS / Liquid",
"Feature: Refactor GHA",
'Feature: Refactor CSS',
'Feature: Refactor HTML',
'Feature: Refactor JS / Liquid',
'Feature: Refactor GHA',
];

const softLabels = [
"role: back end/devOps",
"Feature: Analytics",
];
const softLabels = ['role: back end/devOps', 'Feature: Analytics'];

const overrideSoftLabels = ["role: front end"]
const overrideSoftLabels = ['role: front end'];

const issueLabels = obtainLabels(context);

// checks if label is a hard label
const isHardLabel = label => hardLabels.includes(label);
const isHardLabel = (label) => hardLabels.includes(label);
// checks if label is a soft label
const isSoftLabel = label => softLabels.includes(label);
const isSoftLabel = (label) => softLabels.includes(label);
// checks if label is an override label
const isOverrideLabel = label => overrideSoftLabels.includes(label);
const isOverrideLabel = (label) => overrideSoftLabels.includes(label);

/** If issue includes hard labels there should be no visual changes - move to the Done status */
if (issueLabels.some(isHardLabel)) {
Expand Down
18 changes: 11 additions & 7 deletions github-actions/utils/mutate-issue-status.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@
* @param {String} newStatusValue - GraphQL Id value of the 'Status' field that the issue is moving to
*
*/
async function mutateIssueStatus(github, context, itemId, newStatusValue) {

async function mutateIssueStatus(
github,
context,
itemId,
newStatusValue
) {
// Defaults for HfLA Website Project 86
const WEBSITE_PROJECT_ID = "PVT_kwDOALGKNs4Ajuck";
const STATUS_FIELD_ID = "PVTSSF_lADOALGKNs4AjuckzgcCutQ";
const WEBSITE_PROJECT_ID = 'PVT_kwDOALGKNs4Ajuck';
const STATUS_FIELD_ID = 'PVTSSF_lADOALGKNs4AjuckzgcCutQ';

const mutation = `mutation($projectId: ID!, $fieldId: ID!, $itemId: ID!, $value: String!) {
updateProjectV2ItemFieldValue(input: {
Expand All @@ -29,14 +33,14 @@ async function mutateIssueStatus(github, context, itemId, newStatusValue) {
projectId: WEBSITE_PROJECT_ID,
fieldId: STATUS_FIELD_ID,
itemId: itemId,
value: newStatusValue
value: newStatusValue,
};

try {
await github.graphql(mutation, variables);
} catch (error) {
throw new Error(`Error in mutateItemStatus() function: ${error}`);
throw new Error('Error in mutateItemStatus() function: ' + error);
}
}

module.exports = mutateIssueStatus;
module.exports = mutateIssueStatus;
24 changes: 15 additions & 9 deletions github-actions/utils/query-issue-info.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
* @returns {Object} - An object containing the item ID and its status name
*/
async function queryIssueInfo(github, context, issueNum) {
const repoOwner = context.repo.owner;
const repoName = context.repo.repo;

const query = `query($owner: String!, $repo: String!, $issueNum: Int!) {
repository(owner: $owner, name: $repo) {
Expand All @@ -27,28 +29,32 @@ async function queryIssueInfo(github, context, issueNum) {
}`;

const variables = {
owner: context.repo.owner,
repo: context.repo.repo,
issueNum: issueNum
owner: repoOwner,
repo: repoName,
issueNum: issueNum,
};

try {
try {
const response = await github.graphql(query, variables);

// Extract the list of project items associated with the issue
const projectItems = response.repository.issue.projectItems.nodes;
const projectData = response.repository.issue.projectItems.nodes;

// Since there is always one item associated with the issue,
// directly get the item's ID from the first index
const id = projectItems[0].id;
const id = projectData[0].id;

// Iterate through the field values of the first project item
// and find the node that contains the 'name' property, then get its 'name' value
const statusName = projectItems[0].fieldValues.nodes.find(item => item.hasOwnProperty('name')).name;
const statusName = projectData[0].fieldValues.nodes.find((item) =>
item.hasOwnProperty('name')
).name;

return { id, statusName };
} catch(error) {
throw new Error(`Error finding Issue #${issueNum} id and status; error = ${error}`);
} catch (error) {
throw new Error(
`Error finding Issue #${issueNum} id and status; error = ${error}`
);
}
}

Expand Down

0 comments on commit d8ebc2c

Please sign in to comment.