Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix bug and consolidate "Schedule Thursday" into "Schedule Monthly" 4788 #5467

Merged
merged 37 commits into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
a36c11d
Update schedule-monthly.yml
t-will-gillis Sep 9, 2023
6354f0c
Update contributors-data.js
t-will-gillis Sep 9, 2023
fa8230e
Update create-new-issue.js
t-will-gillis Sep 9, 2023
62afa80
Update comment-issue.js
t-will-gillis Sep 9, 2023
35d92d1
Update create-new-issue.js
t-will-gillis Sep 9, 2023
14fe8d7
Delete github-actions/trigger-schedule/list-inactive-members/get-list.js
t-will-gillis Sep 9, 2023
d224138
Delete .github/workflows/schedule-monthly-PREV.yml
t-will-gillis Sep 9, 2023
f703c75
Update create-new-issue.js
t-will-gillis Sep 12, 2023
0d5ace4
Update create-new-issue.js
t-will-gillis Sep 22, 2023
e72113d
Update create-new-issue.js
t-will-gillis Oct 22, 2023
96cbc39
Update schedule-monthly.yml
t-will-gillis Oct 30, 2023
158a553
Update contributors-data.js
t-will-gillis Oct 30, 2023
a958b05
Update create-new-issue.js
t-will-gillis Oct 30, 2023
e6e9896
Update create-new-issue.js
t-will-gillis Nov 2, 2023
bdf2661
Create schedule-monthly-PREV.yml
t-will-gillis Nov 13, 2023
35c28c6
Delete .github/workflows/schedule-monthly-PREV.yml
t-will-gillis Nov 13, 2023
b3c65a8
Create schedule-monthly-PREV.yml
t-will-gillis Nov 13, 2023
aac81dc
Update create-new-issue.js
t-will-gillis Nov 22, 2023
1329b56
Update contributors-data.js
t-will-gillis Nov 22, 2023
603e95b
Update contributors-data.js
t-will-gillis Nov 22, 2023
c349364
Update schedule-monthly.yml
t-will-gillis Nov 22, 2023
9e63e0e
Create wr-schedule-monthly.yml
t-will-gillis Nov 23, 2023
1a1329f
Update create-new-issue.js
t-will-gillis Nov 23, 2023
f4f0b03
Create schedule-monthly-reopen.yml
t-will-gillis Nov 23, 2023
2ad2ad2
Update schedule-monthly-PREV.yml
t-will-gillis Nov 23, 2023
fe5ef55
Update schedule-monthly.yml
t-will-gillis Nov 24, 2023
9b8b853
Update contributors-data.js
t-will-gillis Nov 24, 2023
8d005d4
Update wr-schedule-monthly.yml
t-will-gillis Nov 27, 2023
2641e6b
Update schedule-monthly-reopen.yml
t-will-gillis Nov 27, 2023
c3a5f9b
Update issue-trigger.yml
t-will-gillis Nov 29, 2023
f2d3cda
Delete .github/workflows/schedule-monthly-reopen.yml
t-will-gillis Nov 29, 2023
42aac70
Update check-labels.js
t-will-gillis Nov 29, 2023
de7000a
Update create-new-issue.js
t-will-gillis Nov 29, 2023
e9ac3fe
Merge branch 'gh-pages' into fix-sch-monthly-4788
t-will-gillis Nov 29, 2023
afc6a0e
Update create-new-issue.js
t-will-gillis Nov 30, 2023
19006c8
Update contributors-data.js
t-will-gillis Dec 1, 2023
4193a1e
Update create-new-issue.js
t-will-gillis Dec 1, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 58 additions & 4 deletions .github/workflows/schedule-monthly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,19 @@ name: Schedule Monthly
on:
schedule:
- cron: 0 11 1 * *
workflow_dispatch:

jobs:
trim_contributors:
Trim_Contributors:
runs-on: ubuntu-latest
if: github.repository == 'hackforla/website'

steps:
# Checkout repo
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
token: ${{ secrets.HACKFORLA_BOT_PA_TOKEN }}

# Setup node
- name: Setup node
Expand All @@ -29,8 +30,61 @@ jobs:
run: npm install
working-directory: ./github-actions/trigger-schedule/github-data

# Run js file- check action logs for inactive members and removes from 'website-write'
# Run js file: checks contributor activity logs, removes two-month inactive members from
# 'website-write' team, then compiles list of one-month inactive members for notification
- name: Trim Members
env:
token: ${{ secrets.HACKFORLA_BOT_PA_TOKEN }}
run: node github-actions/trigger-schedule/github-data/contributors-data.js

# Upload artifact file to allow list sharing with next job "Create_New_Issue"
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: trim_job_artifact
path: inactive-Members.json


Create_New_Issue:
needs: Trim_Contributors
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

# Download artifact file from "Trim_Contributors"
- name: Download artifact
id: download-artifact
uses: actions/download-artifact@v3
with:
name: trim_job_artifact

# Extract and save artifact in usable form for next steps
- name: Extract artifact
id: extract-artifact
run: |
jq -c . inactive-Members.json > out-inactive-Members.json
echo "TRIM_LISTS=$(cat out-inactive-Members.json)" >> $GITHUB_ENV

# Creates a new issue in 'hackforla/website' repo with the saved lists
- name: Create new issue
uses: actions/github-script@v6
id: create-new-issue
with:
github-token: ${{ secrets.HACKFORLA_BOT_PA_TOKEN }}
script: |
const artifactContent = process.env.TRIM_LISTS;
const script = require('./github-actions/trigger-schedule/list-inactive-members/create-new-issue.js');
const createNewIssue = script({g: github, c: context}, artifactContent);
return createNewIssue;

# Comments on issue #2607, notifying leads that the above issue has been created
- name: Comment issue
uses: actions/github-script@v6
id: comment-issue
with:
github-token: ${{ secrets.HACKFORLA_BOT_PA_TOKEN }}
script: |
const script = require('./github-actions/trigger-schedule/list-inactive-members/comment-issue.js');
const newIssueNumber = ${{ steps.create-new-issue.outputs.result }};
script({g: github, c: context}, newIssueNumber);

87 changes: 61 additions & 26 deletions github-actions/trigger-schedule/github-data/contributors-data.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const fs = require("fs");
const { Octokit } = require("@octokit/rest");
const trueContributorsMixin = require("true-github-contributors");

Expand Down Expand Up @@ -45,13 +46,15 @@ twoMonthsAgo = twoMonthsAgo.toISOString();
console.log('Notified members from ' + team + ' inactive since ' + oneMonthAgo.slice(0, 10) + ':');
console.log(notifiedContributors);

writeData(removedContributors, notifiedContributors);
})();



/**
* Function to fetch list of contributors with comments/commits/issues since date
* @return {Object} [List of active contributors]
* @returns {Object} allContributorsSinceOneMonthAgo - List of active contributors since one month ago
* @returns {Object} allContributorsSinceTwoMonthsAgo - List of active contributors since two months ago
*/
async function fetchContributors(){
let allContributorsSinceOneMonthAgo = {};
Expand Down Expand Up @@ -79,7 +82,7 @@ async function fetchContributors(){
page: pageNum
})

// If the API call returns an empty array, break out of loop- there is no additional data on that page.
// If the API call returns an empty array, break out of loop- there is no additional data.
// Else if data is returned, push it to `result` and increase the page number (`pageNum`)
if(!contributors.data.length){
break;
Expand All @@ -89,8 +92,8 @@ async function fetchContributors(){
}
}

// Once we have looked at all pages and collected all the data, we create key-value pairs
// of recent contributors and store them in `allContributorsSince` object
// Once we have looked at all pages and collected all the data, we create key-value
// pairs of recent contributors and store them in `allContributorsSince` object

// The data that comes back from APIs is stored differently, i.e. `author.login`
// vs `user.login`, all we want is to extract the username of a contributor
Expand All @@ -101,9 +104,9 @@ async function fetchContributors(){
} else if(contributorInfo.user){
allContributorsSince[contributorInfo.user.login] = true;

// This check is done for "issues" API (3rd element in the APIs array). Sometimes a user who created
// an issue is not the same as the user assigned to that issue- we want to make sure that we count
// all assignees as active contributors as well.
// This check is done for "issues" API (3rd element in the APIs array). Sometimes a
// user who created an issue is not the same as the user assigned to that issue- we
// want to make sure that we count all assignees as active contributors as well.
if(contributorInfo.assignees && contributorInfo.assignees.length){
contributorInfo.assignees.forEach(user => allContributorsSince[user.login] = true);
}
Expand All @@ -125,7 +128,7 @@ async function fetchContributors(){

/**
* Function to return list of current team members
* @return {Array} [Current team members]
* @returns {Array} allMembers - Current team members
*/
async function fetchTeamMembers(){

Expand All @@ -141,7 +144,7 @@ async function fetchTeamMembers(){
page: pageNum
})

// If the API call returns an empty array, break out of loop- there is no additional data on that page.
// If the API call returns an empty array, break out of loop- there is no additional data.
// Else if data is returned, push it to `result` and increase the page number (`pageNum`)
if(!teamMembers.data.length){
break;
Expand All @@ -161,9 +164,9 @@ async function fetchTeamMembers(){

/**
* Function to return list of contributors that have been inactive since twoMonthsAgo
* @param {Object} allMembers [List of active team]
* @param {Object} recentContributors [List of active contributors]
* @return {Array} [removed members]
* @param {Object} currentTeamMembers - List of active team members
* @param {Object} recentContributors - List of active contributors
* @returns {Array} removed members - List of members that were removed
*/
async function removeInactiveMembers(currentTeamMembers, recentContributors){
const removedMembers = [];
Expand All @@ -189,47 +192,49 @@ async function removeInactiveMembers(currentTeamMembers, recentContributors){

/**
* Function to check if a member is set for removal
* @param {String} member [member's username]
* @return {Boolean} [true/false]
* @param {String} member - Member's username
* @returns {Boolean} - true/false
*/
async function toRemove(member){
// collect user's repos and see if they recently joined hackforla/website;
// Collect user's repos and see if they recently joined hackforla/website;
// Note: user might have > 100 repos, the code below will need adjustment (see 'flip' pages);
const repos = await octokit.request('GET /users/{username}/repos', {
username: member,
per_page: 100
})

// if a user recently cloned 'website' repo (within the last 30 days), they are
// not consider for removal as they are new;
// If a user recently* cloned the 'website' repo (*within the last 30 days), then
// they are new members and are not considered for notification or removal.
for(const repository of repos.data){
// if repo is recently cloned, return 'false' or member is not be removed;
// If repo is recently cloned, return 'false' so that member is not removed
if(repository.name === repo && repository.created_at > oneMonthAgo){
return false;
}
}

// get user's membership status
// Get user's membership status
const userMembership = await octokit.request('GET /orgs/{org}/teams/{team_slug}/memberships/{username}', {
org: org,
team_slug: team,
username: member,
})

// if a user is the team's maintainer, return 'false'. We do not remove maintainers;
if(userMembership.data.role === 'maintainer') return false;

// else this user is an inactive member of the team thus remove;
// If a user is a team 'maintainer', log their name and return 'false'. We do not remove maintainers
if(userMembership.data.role === 'maintainer'){
console.log("This inactive member is a 'Maintainer': " + member);
return false;
}
// Else this user is an inactive member of the team and should be notified or removed
return true;
}



/**
* Function to return list of contributors that have been inactive since oneMonthAgo
* @param {Object} teamMembers [List of team members]
* @param {Object} recentContributors [List of active contributors]
* @return {Array} [removed members]
* @param {Array} updatedTeamMembers - List of updated team members
* @param {Array} recentContributors - List of recent contributors
* @returns {Array} - List of members to be notified (that they are on the list to be removed)
*/
async function notifyInactiveMembers(updatedTeamMembers, recentContributors){
const notifiedMembers = [];
Expand All @@ -245,3 +250,33 @@ async function notifyInactiveMembers(updatedTeamMembers, recentContributors){
}
return notifiedMembers;
}




/**
* Function to save inactive members list to local for use in next job
* @param {Array} removedContributors - List of removed contributors
* @param {Array} notifiedContributors - List of contributors to be notified
* @returns {void}
*/
function writeData(removedContributors, notifiedContributors){

// Combine removed and notified contributor lists into one dict
let inactiveMemberLists = {};
inactiveMemberLists["removedContributors"] = removedContributors;
inactiveMemberLists["notifiedContributors"] = notifiedContributors;


fs.writeFile('inactive-Members.json', JSON.stringify(inactiveMemberLists, null, 2), (err) => {
if (err) throw err;
console.log('-------------------------------------------------------');
console.log("File 'inactive-Members.json' saved successfully!");
});

fs.readFile('inactive-Members.json', (err, data) => {
if (err) throw err;
console.log("File 'inactive-Members.json' read successfully!");
});

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,20 @@ async function main({ g, c }, newIssueNumber) {
github = g;
context = c;

// Issue #2607 is the `Dev/PM Agenda and Notes`
let agendaAndNotesIssueNumber = 2607;
await commentOnIssue(agendaAndNotesIssueNumber, newIssueNumber);
}

// Add a link to the `Review Inactive Team Members` issue
const commentOnIssue = async (agendaAndNotesIssueNumber, newIssueNumber) => {
const owner = "hackforla";
const repo = "website";
await github.rest.issues.createComment({
owner,
repo,
issue_number: agendaAndNotesIssueNumber,
body: `**Review Inactive Members:** #${newIssueNumber}`,
body: `**Review Inactive Team Members:** #${newIssueNumber}`,
});
};

Expand Down
Loading