Skip to content

Commit 13f0d56

Browse files
authored
Set up JSDoc strings for the code (#24)
* Add eslint-plugin-jsdoc and fix ESLint plugin config * Fix all the "strict" eslint errors * Add JSDoc strings for all the checkers * Create a typedef for more accurate docs * Split typedefs out to their own module for global reference * Add documentation for the membership config loading * Add documentation for the fixers * Document the documentation! <inception gong>
1 parent e1732db commit 13f0d56

10 files changed

+306
-3
lines changed

.eslintrc

+6-3
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22
"root": true,
33
"extends": [
44
"godaddy",
5-
"plugin:mocha/recommended"
5+
"plugin:jsdoc/recommended",
6+
"plugin:mocha/recommended",
7+
"plugin:node/recommended"
68
],
79
"plugins": [
8-
"eslint-plugin-mocha",
9-
"eslint-plugin-node"
10+
"jsdoc",
11+
"mocha",
12+
"node"
1013
],
1114
"env": {
1215
"node": true

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# `orglinter`
22

33
- Fixed #16 - New users were causing an error in findPromotions
4+
- Fixed #20 - Added full JSDoc coverage across the code
45

56
## 0.1.0
67

bin/cli.js

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#!/usr/bin/env node
22
/* eslint-disable no-console, no-process-env, max-statements */
3+
'use strict';
34

45
require('dotenv').config();
56
const path = require('path');

package-lock.json

+129
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"assume": "^2.3.0",
2929
"eslint": "^7.15.0",
3030
"eslint-config-godaddy": "^4.0.1",
31+
"eslint-plugin-jsdoc": "^31.6.1",
3132
"eslint-plugin-mocha": "^6.3.0",
3233
"eslint-plugin-node": "^11.1.0",
3334
"mocha": "^8.2.1",

src/lib/checkers.js

+46
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,44 @@
11
/* eslint-disable no-console */
2+
'use strict';
23

4+
const typedefs = require('./typedefs');
5+
6+
/**
7+
* Find users who currently belong to the organization, but not who are not
8+
* expected by config.
9+
*
10+
* @param {string[]} configured - An array of usernames expected to exist in the org
11+
* @param {string[]} retrieved - An array of usernames actually belong to the org currently
12+
* @returns {string[]} An array of usernames which are not expected to belong to the org
13+
*/
314
function findUndocumentedMembers(configured, retrieved) {
415
const undocumented = retrieved.filter(member => !configured.includes(member));
516
console.log(`${undocumented.length} undocumented memberships found: `, undocumented);
617
return undocumented;
718
}
819

20+
/**
21+
* Find users who are expected by config, but who do not (yet) belong to the
22+
* organization.
23+
*
24+
* @param {string[]} configured - An array of usernames expected to exist in the org
25+
* @param {string[]} retrieved - An array of usernames actually belong to the org currently
26+
* @returns {string[]} An array of usernames which are expected to belong to the org
27+
*/
928
function findNewMembers(configured, retrieved) {
1029
const newMembers = configured.filter(member => !retrieved.includes(member));
1130
console.log(`${newMembers.length} new memberships requested: `, newMembers);
1231
return newMembers;
1332
}
1433

34+
/**
35+
* Find users who are currently admins of the org, but should not be, according
36+
* to config.
37+
*
38+
* @param {object.<string, string>} configured - Configured usernames and their associated roles
39+
* @param {typedefs.MemberSet} retrieved - User list retrieved from GitHub
40+
* @returns {string[]} An array of usernames who are admins, but should not be
41+
*/
1542
function findDemotions(configured, retrieved) {
1643
const demotions = Object.keys(retrieved).filter(
1744
(member) => retrieved[member].role === 'ADMIN' && configured[member] === 'MEMBER'
@@ -20,6 +47,13 @@ function findDemotions(configured, retrieved) {
2047
return demotions;
2148
}
2249

50+
/**
51+
* Find users who are currently regular members of the org, but are configured as admins
52+
*
53+
* @param {object.<string, string>} configured - Configured usernames and their associated roles
54+
* @param {typedefs.MemberSet} retrieved - User list retrieved from GitHub
55+
* @returns {string[]} An array of usernames who are not admins, but should be
56+
*/
2357
function findPromotions(configured, retrieved) {
2458
const promotions = Object.keys(configured).filter(
2559
(member) => configured[member] === 'ADMIN' && retrieved[member] && retrieved[member].role === 'MEMBER'
@@ -28,12 +62,24 @@ function findPromotions(configured, retrieved) {
2862
return promotions;
2963
}
3064

65+
/**
66+
* Find org members who do not have two-factor authentication enabled
67+
*
68+
* @param {typedefs.MemberSet} members - User list retrieved from GitHub
69+
* @returns {string[]} An array of usernames who are 2FA violators.
70+
*/
3171
function validateTwoFactor(members) {
3272
const violators = Object.keys(members).filter((member) => members[member].twoFactorAuth === false);
3373
console.log(`${violators.length} two factor auth violators found: `, violators);
3474
return violators;
3575
}
3676

77+
/**
78+
* Ensure that the org's current settings match those expected by the config
79+
*
80+
* @param {object.<string, *>} organization - The full collection of org settings collected from GitHub
81+
* @param {object.<string, *>} config - The full collection of org settings expected by config
82+
*/
3783
function validateOrgSettings(organization, config) {
3884
let failed = false;
3985
for (const key of Object.keys(config)) {

src/lib/fixers.js

+39
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
/* eslint-disable no-console */
2+
'use strict';
3+
24
const { request } = require('@octokit/request');
35

6+
/**
7+
* Invite a user to join an org
8+
*
9+
* @param {object} invitation - The details of the user invitation to be sent
10+
* @param {string} invitation.username - The username to be invited
11+
* @param {string} invitation.organization - The login name of the org where the user will be invited
12+
* @param {string} invitation.token - A personal access token for interacting with the GitHub API
13+
* @param {string} [invitation.role=member] - The role to invite the user as; "admin" or "member"
14+
* @param {boolean} [invitation.dryRun=false] - If true, don't actually execute this operation
15+
*/
416
async function inviteUser({ username, organization, token, role = 'member', dryRun = false }) {
517
console.log(`Setting ${username} up as a(n) ${role} for ${organization}.`);
618
if (dryRun) return;
@@ -20,6 +32,15 @@ async function inviteUser({ username, organization, token, role = 'member', dryR
2032
}
2133
}
2234

35+
/**
36+
* Remove a user from an org
37+
*
38+
* @param {object} removal - The details of the user removal to be initiated
39+
* @param {string} removal.username - The username to be removed from the org
40+
* @param {string} removal.organization - The login name of the org to remove the user from
41+
* @param {string} removal.token - A personal access token for interacting with the GitHub API
42+
* @param {boolean} removal.dryRun - If true, don't actally execute this operation
43+
*/
2344
async function removeMember({ username, organization, token, dryRun = false }) {
2445
console.log(`Removing ${username} from ${organization}.`);
2546
if (dryRun === true) return;
@@ -38,13 +59,31 @@ async function removeMember({ username, organization, token, dryRun = false }) {
3859
}
3960
}
4061

62+
/**
63+
* Promote a user from member to admin of an org
64+
*
65+
* @param {object} promotion - The details of the user promotion to be sent
66+
* @param {string} promotion.username - The username to be promoted
67+
* @param {string} promotion.organization - The login name of the org to promote the user in
68+
* @param {string} promotion.token - A personal access token for interacting with the GitHub API
69+
* @param {boolean} promotion.dryRun - If true, don't actally execute this operation
70+
*/
4171
async function promoteMember({ username, organization, token, dryRun = false }) {
4272
console.log(`Promoting ${username} to admin in ${organization}.`);
4373
if (dryRun) return;
4474
// Do the thing!
4575
await inviteUser({ username, organization, token, role: 'admin' });
4676
}
4777

78+
/**
79+
* Demote a user from admin to member of an org
80+
*
81+
* @param {object} demotion - The details of the user demotion to be sent
82+
* @param {string} demotion.username - The username to be demoted
83+
* @param {string} demotion.organization - The login name of the org to demote the user in
84+
* @param {string} demotion.token - A personal access token for interacting with the GitHub API
85+
* @param {boolean} demotion.dryRun - If true, don't actally execute this operation
86+
*/
4887
async function demoteMember({ username, organization, token, dryRun = false }) {
4988
console.log(`Demoting ${username} to member in ${organization}.`);
5089
if (dryRun) return;

0 commit comments

Comments
 (0)