Skip to content

DEVXT-1965 - #37

Open
MonicaG wants to merge 5 commits into
mainfrom
DEVXT-1965
Open

DEVXT-1965#37
MonicaG wants to merge 5 commits into
mainfrom
DEVXT-1965

Conversation

@MonicaG

@MonicaG MonicaG commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

This PR adds code that reports on users that have not been active within an enterprise for a given amount of days.

  • Outside collaborators are ignored from the activity check
  • Orgs to check for activity in is configurable
  • First check audit log in each org a user is a member of for activity. This is done because some audit logs didn't appear to be logged at the enterprise audit log level
  • If not audit logs for a user, then checks for commits for the user within the org

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new Node.js utility (utils/github/ent-inactive-users) that identifies enterprise members who have been inactive for a configurable period by checking org audit-log activity first, then falling back to recent commit activity, and outputs a CSV report.

Changes:

  • Implements enterprise member retrieval (with outside-collaborator filtering) and per-member activity checks (audit log + commits).
  • Adds a CLI entrypoint with flags for enterprise/org scope and inactivity window.
  • Adds unit tests and documentation for the new utility.

Reviewed changes

Copilot reviewed 13 out of 14 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
utils/github/ent-inactive-users/src/index.js CLI entrypoint and argument validation for enterprise/org/days.
utils/github/ent-inactive-users/src/octokit.js Octokit client creation with throttling + logging hooks.
utils/github/ent-inactive-users/src/logger.js Pino logger setup (silent in tests).
utils/github/ent-inactive-users/src/config.js Centralizes GitHub API version headers.
utils/github/ent-inactive-users/src/enterprise.js Enterprise member discovery and outside-collaborator filtering + org extraction.
utils/github/ent-inactive-users/src/inactive-users.js Inactivity cutoff calculation and audit/commit activity checks.
utils/github/ent-inactive-users/src/report.js CSV report generation for inactive members.
utils/github/ent-inactive-users/test/enterprise.test.js Unit tests for org extraction and outside-collaborator filtering.
utils/github/ent-inactive-users/test/inactive-users.test.js Unit tests for cutoff date and activity-check behavior.
utils/github/ent-inactive-users/README.md Usage docs, requirements, and output description.
utils/github/ent-inactive-users/package.json Package metadata, scripts, dependencies, and Node engine requirement.
utils/github/ent-inactive-users/package-lock.json Dependency lockfile for the new package.
utils/github/ent-inactive-users/.tool-versions Pins Node.js tool version for the utility.
utils/github/ent-inactive-users/.gitignore Ignores generated artifacts (CSV/logs/node_modules).
Files not reviewed (1)
  • utils/github/ent-inactive-users/package-lock.json: Generated file

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread utils/github/ent-inactive-users/src/enterprise.js
Comment thread utils/github/ent-inactive-users/src/enterprise.js
Comment thread utils/github/ent-inactive-users/src/enterprise.js
Comment thread utils/github/ent-inactive-users/src/inactive-users.js
Comment thread utils/github/ent-inactive-users/src/report.js Outdated
Comment thread utils/github/ent-inactive-users/src/index.js Outdated
Comment thread utils/github/ent-inactive-users/README.md Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 14 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • utils/github/ent-inactive-users/package-lock.json: Generated file
Suppressed comments (4)

Previously missed (3) — in code that hasn't changed since the last review.

utils/github/ent-inactive-users/src/report.js:8

  • The JSDoc says the report is written to stdout, but the implementation only writes a CSV file and logs messages. This comment should match the actual behavior to avoid misleading consumers.
/**
 * Writes inactive member results to stdout and a CSV file.
 * @param {Array<import('./enterprise.js').Member>} members
 */

utils/github/ent-inactive-users/src/octokit.js:41

  • onSecondaryRateLimit always returns true, so the client will keep retrying indefinitely on persistent secondary rate limiting. This can cause the script to hang for a long time without a hard stop.
      onSecondaryRateLimit: (retryAfter, options, octokit) => {
        octokit.log.warn(
          `SecondaryRateLimit detected for request ${options.method} ${options.url}. Retrying after ${retryAfter} seconds`
        );
        return true;

utils/github/ent-inactive-users/src/index.js:44

  • parseInt is called without an explicit radix. Passing the radix (10) avoids edge cases and matches common Node.js CLI parsing practices.
  const inactiveDaysInt = inactiveDays ? parseInt(inactiveDays) : 90;

utils/github/ent-inactive-users/src/report.js:20

  • CSV rows are built by joining fields with commas without escaping. If any field contains a comma, quote, or newline, the generated CSV will be malformed and may be parsed incorrectly.
  const rows = ['userName,email,membership,githubVerifiedDomainEmails'];

  for (const { userName, email, membership, githubVerifiedDomainEmails } of members) {
    rows.push([userName, email, membership.join('|'), githubVerifiedDomainEmails.join('|')].join(','));
  }

Comment thread utils/github/ent-inactive-users/src/enterprise.js

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 14 changed files in this pull request and generated no new comments.

Files not reviewed (1)
  • utils/github/ent-inactive-users/package-lock.json: Generated file
Suppressed comments (4)

Previously missed (3) — in code that hasn't changed since the last review.

utils/github/ent-inactive-users/src/index.js:69

  • This module exports main but also executes it unconditionally at import time (await main();). That makes the file unsafe to import (e.g., from tests or other tooling) because it will parse args / require env vars immediately. Consider guarding execution so main() runs only when this file is the entrypoint.
await main();

utils/github/ent-inactive-users/src/logger.js:19

  • Logger output is configured to always write to a local info.log file via pino/file when not running tests. This can break execution in environments where the current working directory is not writable, and it also hides logs from stdout/stderr (which is typically what CLIs expect). Consider defaulting to stdout/stderr and making file logging optional/configurable.
  }, isTest ? undefined : pino.transport({
  target: 'pino/file',
  options: { destination: 'info.log' },
}));

utils/github/ent-inactive-users/src/report.js:8

  • The JSDoc says this function writes results to stdout, but the implementation only writes a CSV file (and logs via logger). This is misleading for callers/readers.

This issue also appears on line 31 of the same file.

 * Writes inactive member results to stdout and a CSV file.

utils/github/ent-inactive-users/src/report.js:38

  • writableStream.on("error") throws from an async event handler. This can surface as an unhandled exception (outside the await pipeline(...) promise chain) and may crash the process instead of rejecting the writeReport call cleanly. stream/promises.pipeline already propagates stream errors via its returned promise, so it’s safer to rely on that and handle logging in a try/catch around pipeline.
  writableStream.on("finish", () => {
     logger.info(`\nReport written to ${filename}`);
  });

  writableStream.on("error", (error) => {
    logger.error("Error writing to file:", error.message);
    throw error;
  });

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants