Skip to content

Commit

Permalink
Multiple improvements related to the kick process and general code ce…
Browse files Browse the repository at this point in the history
…ntralization.

* Centralizes logic for retrieving members.
* Centralizes dry run logic.
* Safely checks for ISSUE_WITHOUT_MENTION env var.
* Fixes bug where kick action was not checking out the repo, which is required to read the db.json file.
  • Loading branch information
garnertb authored Apr 18, 2023
1 parent 9361572 commit 32a0878
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 48 deletions.
2 changes: 1 addition & 1 deletion .github/actions/audit/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ runs:
with:
path: main
repository: oss-tooling/user-inactivity
ref: v1.1.4
ref: v1.1.5

- uses: actions/checkout@v3
with:
Expand Down
19 changes: 17 additions & 2 deletions .github/actions/kick/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ inputs:
description: the github organization to audit
repo:
description: name of repo where inactive user issues are created
branch:
description: branch to store activity data on
default: main
inactivity-duration:
description: the amount of days a user can be inactive for
default: 30
Expand All @@ -16,12 +19,24 @@ inputs:
description: the app installation id
runs:
using: composite
steps:
steps:
- uses: actions/checkout@v3
with:
ref: ${{ inputs.branch }}
path: activity

- uses: actions/checkout@v3
with:
path: main
repository: oss-tooling/user-inactivity
ref: v1.1.4
ref: v1.1.5

- name: Move db.json
run: |
if test -f "${{ github.workspace }}/activity/db.json"; then
mv ${{ github.workspace }}/activity/db.json ${{ github.workspace }}/main/db.json
fi
shell: bash

- name: Install dependencies
run: npm install
Expand Down
2 changes: 1 addition & 1 deletion .github/actions/report/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ runs:
with:
path: main
repository: oss-tooling/user-inactivity
ref: v1.1.4
ref: v1.1.5

- uses: actions/checkout@v3
with:
Expand Down
22 changes: 21 additions & 1 deletion lib/inactiveUsers.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,27 @@ exports.inactiveUsers = (octokit, options) => {
inactiveUsers: {
audit: audit(octokit, options),
report: report(octokit, options),
kick: kick(octokit, options)
kick: kick(octokit, options),
getOrgMemberData: async (org, issueRepo) => {
const [ members, userIssues, outsideCollaborators ] = await Promise.all([
octokit.paginate(octokit.orgs.listMembers, {
org,
role: 'member',
per_page: 100
}),
octokit.paginate(octokit.issues.listForRepo, {
owner: org,
repo: issueRepo,
state: 'open',
per_page: 100,
}),
octokit.paginate(octokit.orgs.listOutsideCollaborators, {
org,
per_page: 100
})
])
return { members, userIssues, outsideCollaborators }
}
}
}
}
36 changes: 11 additions & 25 deletions lib/kick.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
const database = require('./database')
const { inactiveUserLabel } = require('./utils')
const { dryRun } = require('./utils')

const preserveAccountComment = (user) => {
if (process.env.ISSUE_WITHOUT_MENTION.toLowerCase() === 'true') {
if (process.env.ISSUE_WITHOUT_MENTION && process.env.ISSUE_WITHOUT_MENTION.toLowerCase() === 'true') {
return `Thank you, I will mark your account active. Please remember this ${database.INACTIVE_DURATION} day audit will be part of the continuous monitoring for GitHub, so please maintain activity of one of the following to avoid be pulled as inactive again.
1. Commits
2. Created issue(s)
Expand Down Expand Up @@ -40,7 +40,7 @@ const removeCollaboratorFromOrg = async (client, owner, login) => {
}

const createComment = async (client, owner, repo, number, comment) => {
if (process.env.DRY_RUN.toLowerCase() !== 'true') {
if (!dryRun) {
await client.issues.createComment({
owner: owner,
repo: repo,
Expand All @@ -51,7 +51,7 @@ const createComment = async (client, owner, repo, number, comment) => {
}

const closeIssue = async (client, owner, repo, number) => {
if (process.env.DRY_RUN.toLowerCase() !== 'true') {
if (!dryRun) {
await client.issues.update({
owner: owner,
repo: repo,
Expand All @@ -62,7 +62,7 @@ const closeIssue = async (client, owner, repo, number) => {
}

const addLabels = async (client, owner, repo, number, labels) => {
if (process.env.DRY_RUN.toLowerCase() !== 'true') {
if (!dryRun) {
await client.issues.addLabels({
owner: owner,
repo: repo,
Expand All @@ -73,30 +73,16 @@ const addLabels = async (client, owner, repo, number, labels) => {
}

exports.kick = (octokit) => async (org, repo) => {
const [members, outsideCollaborators, issues] = await Promise.all([
octokit.paginate(octokit.orgs.listMembers, {
org,
role: 'member',
per_page: 100
}),
octokit.paginate(octokit.orgs.listOutsideCollaborators, {
org,
per_page: 100
}, (response) => response.data.map((collaborator) => collaborator.login)),
octokit.paginate(octokit.issues.listForRepo, {
owner: org,
repo,
state: 'open',
labels: [inactiveUserLabel],
sort: 'created',
direction: 'desc',
per_page: 100
})
])
const { members: orgMembers, userIssues: issues, outsideCollaborators: outsideCollaboratorsRaw} = await octokit.inactiveUsers.getOrgMemberData(org, repo)

const members = orgMembers.concat(outsideCollaboratorsRaw)
const outsideCollaborators = outsideCollaboratorsRaw.map(collaborator => collaborator.login)

const _expiredUsers = await database.getExpiredUsers(members)
const expiredUsers = _expiredUsers.map(user => user.login)

console.log(expiredUsers)

const expirationDate = new Date()
expirationDate.setDate(expirationDate.getDate() - 3)

Expand Down
26 changes: 8 additions & 18 deletions lib/report.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,12 @@ const database = require('./database')
const utils = require('./utils')

exports.report = (octokit) => async (org, repo, body) => {
console.log('Retrieving list of all organization users')
const members = await octokit.paginate(octokit.orgs.listMembers, {
org,
role: 'member',
per_page: 100
})

console.log('Retrieving all active issues')
const _issues = await octokit.paginate(octokit.issues.listForRepo, {
owner: org,
repo,
state: 'open',
per_page: 100
})

const usernames = _issues.map(issue => issue.title.toLowerCase())
const { members: orgMembers, userIssues, outsideCollaborators } = await octokit.inactiveUsers.getOrgMemberData(org, repo)

const usersWithIssues = userIssues.map(issue => issue.title.toLowerCase())
const members = orgMembers.concat(outsideCollaborators)

console.log(`${members.length} users found in the organization (${orgMembers.length} members and ${outsideCollaborators.length} outside collaborators)`)

const expiredUsers = await database.getExpiredUsers(members)
console.log(`${expiredUsers.length} users found with no activity in the last ${database.INACTIVE_DURATION} days`)
Expand All @@ -28,12 +18,12 @@ exports.report = (octokit) => async (org, repo, body) => {
console.log(`Skipping: ${expiredUser.login} is a bot account`)
continue
}
if (usernames.includes(expiredUser.login.toLowerCase())) {
if (usersWithIssues.includes(expiredUser.login.toLowerCase())) {
console.log(`Skipping: ${expiredUser.login} already has an issue open`)
continue
}
console.log(`Sending notification for ${expiredUser.login}`)
if (process.env.DRY_RUN.toLowerCase() !== 'true') {
if (!utils.dryRun) {
await octokit.issues.create({
owner: org,
repo,
Expand Down
2 changes: 2 additions & 0 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,5 @@ exports.registerSecrets = async () => {
}

exports.inactiveUserLabel = 'inactive-user'

exports.dryRun = process.env.DRY_RUN ? process.env.DRY_RUN.toLowerCase() == 'true' : false

0 comments on commit 32a0878

Please sign in to comment.