GHA Schedule Monthly Workflow
GitHub Actions Workflow for Identity and Access Management

Schedule Monthly &
WR Schedule Monthly
Workflows
Summary
The schedule-monthly.yml
and wr-schedule-monthly.yml
workflows together are intended to monitor the individual activities of each member of the ‘website-write’ team. Members that have been inactive (as described below) for over two months are removed from the ‘website-write’ team. Members that have been inactive for over one month (and shy of two months) are notified that the bot will remove their team membership in the next month if the member does not resume activity. Specific details and functionalities are described below.
Trigger
- Workflow runs at 11:00 UTC/ 4:00 PDT, on the 1st day of every month (except January and August)
Labels Used by Workflow
- labelKey: ‘complexity2’,
Complexity: Small
- labelKey: ‘size025pt’,
size: 0.25pt
- labelKey: ‘readyForDevLead’,
ready for dev lead
- labelKey: ‘roleDevLeads’,
role: dev leads
- labelKey: ‘featureAdministrative’,
Feature: Administrative
Tokens Used by Workflow
HACKFORLA_ADMIN_TOKEN
( used in schedule-monthly.yml )HACKFORLA_BOT_PA_TOKEN
( used in wr-schedule-monthly.yml )
Workflow Files
- schedule-monthly.yml
- get-contributors-data.js (in list-inactive-members folder)
- get-timeline.js (in utils folder)
- get-team-members.js (in utils folder)
- trim-inactive-members.js (in list-inactive-members folder)
- get-team-members.js (in utils folder)
- add-team-member.js (in utils folder)
- inactive-members.json (in utils/data folder)
- get-contributors-data.js (in list-inactive-members folder)
- wr-schedule-monthly.yml
- create-new-issue.js (in list-inactive-members folder)
- issue-template-parser.js (in utils folder)
- inactive-members.md (in list-inactive-members folder)
- post-issue-comment.js (in utils folder)
- create-new-issue.js (in list-inactive-members folder)
Support File Folders:
Process:
- The schedule-monthly.yml workflow is triggered on a cron schedule at 11:00 UTC / 4:00 am PDT on the first day of every month, except January and August. (January and August are omitted because the ‘website’ team takes off December and July. The time limits discussed below are adjusted to account for this expected inactivity during the break.) This workflow consists of the job “Trim_Contributors” with three main steps:
- “Get Contributors” calls get-contributors-data.js:
- The function
fetchContributors()
queries GitHub for data about all user contributions to the ‘hackforla/website’ repo:- If a user made any contribution due to 1. commits, 2. comments, or 3. issue assignments.
- All user contributions within the last month (first run,
allContributorsSinceOneMonthAgo
) and within the last two months (second run,allContributorsSinceTwoMonthsAgo
) are recorded. - Note that members of the ‘website-admin’ team as well as three Hack for LA bot accounts are considered ‘permanent contributors’ and are automatically included in these two lists regardless of contributions.
- This function also records any open issue whose assignee does not show any activity within the last two months, and whether the issue is a “Skills Issue”-
inactiveWithOpenIssue
.
- The function
- “Trim Inactive Members” calls trim-inactive-members.js:
- The function
readPreviousNotifyList()
retrieves the list of ‘notified members’ from the previous month aspreviouslyNotified
. - The function
getTeamMembers()
records all current ‘website-write’ team members ascurrentTeamMembers
. - The function
removeInactiveMembers()
iterates through the list of current team members and checks whether the member is listed on theallContributorsSinceTwoMonthsAgo
list. If the team member does not show any activity in the last two months, the function then checks:- Whether the team member is listed on the ‘website’ team; if not the person is added. (We want to make sure that the member is on the ‘website’ team before they are removed from ‘website-write’ team)
- Whether the team member is on the list of
inactiveWithOpenIssue
and the issue is not a “Skills Issue” or “Pre-work Checklist”, if so their name and issue are added tocannotRemoveYet
. (We want to review open assignments before the inactive member is removed) - Whether or not the team member was notified of their inactivity in the last month, i.e. whether their name is on the
previouslyNotified
list. If not, they will not be removed in the current month. (We want to give people a notification prior to removing them from the ‘website-write’ team) - Otherwise, the team member will be removed from the ‘website-write’ as well as the ‘website-merge’ teams if applicable.
- If the member that was just removed has an open “Skills Issue” or “Pre-work Checklist”, this issue is closed by the bot via
closePrework()
. - The lists of
removedContributors
and members wecannotRemoveYet
are returned.
- Next, the function
getTeamMembers()
runs a second time to update the list ofupdatedTeamMembers
. - The function
notifyInactiveMembers()
iterates through the list of updated team members and checks whether the member is listed on theallContributorsSinceOneMonthAgo
list. If the member does not show any activity within the last month, the function checks:- Whether the member cloned HfLA’s repo within last month. If so, then the member might be new and are still setting up, and they will not be notified of inactivity yet.
- Otherwise, the member is added to the list of members to be notified.
- The list of
notifiedContributors
is returned.
- Using
fs.writeFile()
, the lists ofremovedContributors
,notifiedContributors
, andcannotRemoveYet
are grouped asinactiveMemberLists
then written to disk asinactive-members.json
.
- The function
- “Update Inactive Members JSON” uses
stefanzweifel/git-auto-commit-action@v5.0.1
to commit the record ofinactive-members.json
to the repo to finish the “Schedule Monthly” workflow.
- “Get Contributors” calls get-contributors-data.js:
- The “WR Schedule Monthly” post workflow file wr-schedule-monthly.yml runs if
schedule-monthly.yml
is successful. It includes:- The job “Create-New-Issue” and related Step call to create-new-issue.js:
- The function
createIssue()
writes the lists of removed members and members to be notified to the template inactive-members.md and posts a new issue titled “Review Inactive Team Members” to the Project Board. - The function
postComment()
posts a comment to the Monday Dev Meeting Agenda issue #2607, informing that the workflow has run, linking to the issue that was created, and if applicable listing members with open issues (and issue numbers) via the post-issue-comment.js module.
- The function
- Finally, the job “Close-New-Issue” gathers the pertinent data and then as a last step closes the just-generated “Review Inactive Team Members” issue.
- The job “Create-New-Issue” and related Step call to create-new-issue.js:
Data auto-generated by Google Sheets worksheets (maintained in the “hackforla-bot@hackforla.org” account) complement this workflow:
- On a daily trigger, a Google Apps Script queries the GitHub repo for the current ‘website-write’ team members and updates the team Roster with members’ statuses.
- On a weekly trigger, an Google Apps Script compares the list of active team members with the list of Current Google Drive (Website) Registrants. If a member is not listed as active (or is not on a separate “Safe List”), they are removed from access to the Google Drive.
Test Procedure
Important note: line numbers and specific code references may have changed slightly since the time of this Wiki- verify with the actual files.
- You will need to have a functioning test environment on your local repo. Refer to Hack for LA’s GitHub Actions, especially Tips 6, 7, & 8.
- IMPORTANT: In addition to the ‘files changed’ in the PR, there are additional changes that you should make to help with testing. If you do not make these edits, you might delete or mis-edit Hack for LA data, delete team members, generate false or junk notifications, and/or create junk issues on HfLA’s live Project Board.
- In
schedule-monthly.yml
, you will need to activate two personal tokens (see Hack for LA’s GitHub Actions)HACKFORLA_BOT_PA_TOKEN
scopes: admin:org_hook, public_repoHACKFORLA_ADMIN_TOKEN
scopes: admin:org_hook, repo, write:org- In the same file, around line 12, replace ‘hackforla’ with your personal repo.
- Finally, add the line
workflow_dispatch:
underon:
(in line withschedule:
)
- In
get-contributors-data.js
- Near line 84 replace with
owner: 'hackforla',
- Near line 85 replace with
repo: 'website',
(unless your repo is ‘website’)
- Near line 84 replace with
- In
trim-inactive-members.js
:- IMPORTANT: Disable the following by replacing:
1 2 3 4 5 6
await github.request('DELETE /orgs/{org}/teams/{team_slug}/memberships/{username}', { org: context.repo.owner, team_slug: team, username: username, }); }
with:
1 2 3 4 5 6 7
console.log('Would be removed: ' + username); // await github.request('DELETE /orgs/{org}/teams/{team_slug}/memberships/{username}', { // org: context.repo.owner, // team_slug: team, // username: username, // }); }
- IMPORTANT: Disable the entirety of the
closePrework()
function, starting around ln 110:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
async function closePrework(member, issueNum){ // Close the assignee's "Pre-work Checklist" and add comment // await github.request('PATCH /repos/{owner}/{repo}/issues/{issue_number}', { // owner: org, // repo: repo, // issue_number: issueNum, // state: 'closed' // }); console.log(`Would be closing "Skills Issue" issue number ${issueNum} for ${member}`); // // Add comment to issue // await github.request('POST /repos/{owner}/{repo}/issues/{issue_number}/comments', { // owner: org, // repo: repo, // issue_number: issueNum, // body: 'The Hack for LA Bot has closed this issue due to member inactivity.' // }); }
- IMPORTANT: Disable the following by replacing:
- In
create-new-issue.js
:- For
const AGENDA_ISSUE_NUM =
replace with an existing issue number in your repo - The variables for
const owner
andconst repo
are ok as is- do not replace. - IMPORTANT: replace the following lines exactly as shown:
1 2
let removedList = removeList.map(x => "@ " + x).join("\n"); // important to add space let notifiedList = notifyList.map(x => "@ " + x).join("\n"); // important to add space
- Towards the end of the files, comment out:
// let milestone = parseInt(issueObject['milestone']);
- And next:
// milestone,
- For
- In
/utils/get-team-members.js
:- Ln 16, replace with
org: 'hackforla',
- Ln 16, replace with
- In
/utils/add-team-member.js
:- Ln 11, replace with
org: 'hackforla',
- Ln 18, replace with
org: 'hackforla',
- Ln 11, replace with
- In
/utils/get-timeline.js
:- Ln 16, replace with
owner: 'hackforla',
- Ln 17, replace with
repo: 'website',
- Ln 16, replace with
- In
/utils/post-issue-comment.js
:- Ln 9, replace with
owner: ' <your name> ',
NOT ‘hackforla’ - Ln 10, replace with
repo: 'website',
or however you named your repo
- Ln 9, replace with