@@ -25237,10 +25237,12 @@ const github = __importStar(__nccwpck_require__(5438));
2523725237const moment_1 = __importDefault(__nccwpck_require__(9623));
2523825238const fs_1 = __nccwpck_require__(7147);
2523925239const artifact = __importStar(__nccwpck_require__(2605));
25240+ const request_error_1 = __nccwpck_require__(537);
2524025241function getInputs() {
2524125242 const result = {};
2524225243 result.token = core.getInput('github-token');
2524325244 result.org = core.getInput('organization');
25245+ result.enterprise = core.getInput('enterprise');
2524425246 result.removeInactive = core.getBooleanInput('remove');
2524525247 result.removefromTeam = core.getBooleanInput('remove-from-team');
2524625248 result.inactiveDays = parseInt(core.getInput('inactive-days'));
@@ -25251,89 +25253,160 @@ function getInputs() {
2525125253exports.getInputs = getInputs;
2525225254const run = () => __awaiter(void 0, void 0, void 0, function* () {
2525325255 const input = getInputs();
25256+ let organizations = [];
25257+ let hasNextPage = false;
25258+ let afterCursor = undefined;
25259+ let allInactiveSeats = [];
25260+ let allRemovedSeatsCount = 0;
25261+ let allSeatsCount = 0;
2525425262 const octokit = github.getOctokit(input.token);
25255- const seats = yield core.group('Fetching GitHub Copilot seats', () => __awaiter(void 0, void 0, void 0, function* ( ) {
25256- let _seats = [], totalSeats = 0, page = 1 ;
25263+ if (input.enterprise && input.enterprise !== null ) {
25264+ core.info(`Fetching all organizations for ${input.enterprise}...`) ;
2525725265 do {
25258- const response = yield octokit.request(`GET /orgs/{org}/copilot/billing/seats?per_page=100&page=${page}`, {
25259- org: input.org
25260- });
25261- totalSeats = response.data.total_seats;
25262- _seats = _seats.concat(response.data.seats);
25263- page++;
25264- } while (_seats.length < totalSeats);
25265- core.info(`Found ${_seats.length} seats`);
25266- core.info(JSON.stringify(_seats, null, 2));
25267- return _seats;
25268- }));
25269- const msToDays = (d) => Math.ceil(d / (1000 * 3600 * 24));
25270- const now = new Date();
25271- const inactiveSeats = seats.filter(seat => {
25272- if (seat.last_activity_at === null || seat.last_activity_at === undefined) {
25273- const created = new Date(seat.created_at);
25274- const diff = now.getTime() - created.getTime();
25266+ const query = `
25267+ query ($enterprise: String!, $after: String) {
25268+ enterprise(slug: $enterprise) {
25269+ organizations(first: 100, after: $after) {
25270+ pageInfo {
25271+ endCursor
25272+ hasNextPage
25273+ }
25274+ nodes {
25275+ login
25276+ }
25277+ }
25278+ }
25279+ }
25280+ `;
25281+ const variables = { "enterprise": input.enterprise, "after": afterCursor };
25282+ const response = yield octokit.graphql(query, variables);
25283+ organizations = organizations.concat(response.enterprise.organizations.nodes.map(org => org.login));
25284+ hasNextPage = response.enterprise.organizations.pageInfo.hasNextPage;
25285+ afterCursor = response.enterprise.organizations.pageInfo.endCursor;
25286+ } while (hasNextPage);
25287+ core.info(`Found ${organizations.length} organizations: ${organizations.join(', ')}`);
25288+ }
25289+ else {
25290+ organizations = input.org.split(',').map(org => org.trim());
25291+ }
25292+ for (const org of organizations) {
25293+ const seats = yield core.group('Fetching GitHub Copilot seats for ' + org, () => __awaiter(void 0, void 0, void 0, function* () {
25294+ let _seats = [], totalSeats = 0, page = 1;
25295+ do {
25296+ try {
25297+ const response = yield octokit.request(`GET /orgs/{org}/copilot/billing/seats?per_page=100&page=${page}`, {
25298+ org: org
25299+ });
25300+ totalSeats = response.data.total_seats;
25301+ _seats = _seats.concat(response.data.seats);
25302+ page++;
25303+ }
25304+ catch (error) {
25305+ if (error instanceof request_error_1.RequestError && error.message === "Copilot Business is not enabled for this organization.") {
25306+ core.error(error.message + ` (${org})`);
25307+ break;
25308+ }
25309+ else if (error instanceof request_error_1.RequestError && error.status === 404) {
25310+ core.error(error.message + ` (${org}). Please ensure that the organization has GitHub Copilot enabled and you are an org owner.`);
25311+ break;
25312+ }
25313+ else {
25314+ throw error;
25315+ }
25316+ }
25317+ } while (_seats.length < totalSeats);
25318+ core.info(`Found ${_seats.length} seats`);
25319+ core.info(JSON.stringify(_seats, null, 2));
25320+ return _seats;
25321+ }));
25322+ const msToDays = (d) => Math.ceil(d / (1000 * 3600 * 24));
25323+ const now = new Date();
25324+ const inactiveSeats = seats.filter(seat => {
25325+ if (seat.last_activity_at === null || seat.last_activity_at === undefined) {
25326+ const created = new Date(seat.created_at);
25327+ const diff = now.getTime() - created.getTime();
25328+ return msToDays(diff) > input.inactiveDays;
25329+ }
25330+ const lastActive = new Date(seat.last_activity_at);
25331+ const diff = now.getTime() - lastActive.getTime();
2527525332 return msToDays(diff) > input.inactiveDays;
25333+ }).sort((a, b) => (a.last_activity_at === null || a.last_activity_at === undefined || b.last_activity_at === null || b.last_activity_at === undefined ?
25334+ -1 : new Date(a.last_activity_at).getTime() - new Date(b.last_activity_at).getTime()));
25335+ const inactiveSeatsWithOrg = inactiveSeats.map(seat => (Object.assign(Object.assign({}, seat), { organization: org })));
25336+ allInactiveSeats = [...allInactiveSeats, ...inactiveSeatsWithOrg];
25337+ allSeatsCount += seats.length;
25338+ if (input.removeInactive) {
25339+ const inactiveSeatsAssignedIndividually = inactiveSeats.filter(seat => !seat.assigning_team);
25340+ if (inactiveSeatsAssignedIndividually.length > 0) {
25341+ core.group('Removing inactive seats', () => __awaiter(void 0, void 0, void 0, function* () {
25342+ const response = yield octokit.request(`DELETE /orgs/{org}/copilot/billing/selected_users`, {
25343+ org: org,
25344+ selected_usernames: inactiveSeatsAssignedIndividually.map(seat => seat.assignee.login),
25345+ });
25346+ core.info(`Removed ${response.data.seats_cancelled} seats`);
25347+ console.log(typeof response.data.seats_cancelled);
25348+ allRemovedSeatsCount += response.data.seats_cancelled;
25349+ }));
25350+ }
2527625351 }
25277- const lastActive = new Date(seat.last_activity_at);
25278- const diff = now.getTime() - lastActive.getTime();
25279- return msToDays(diff) > input.inactiveDays;
25280- }).sort((a, b) => (a.last_activity_at === null || a.last_activity_at === undefined || b.last_activity_at === null || b.last_activity_at === undefined ?
25281- -1 : new Date(a.last_activity_at).getTime() - new Date(b.last_activity_at).getTime()));
25282- core.setOutput('inactive-seats', JSON.stringify(inactiveSeats));
25283- core.setOutput('inactive-seat-count', inactiveSeats.length.toString());
25284- core.setOutput('seat-count', seats.length.toString());
25285- if (input.removeInactive) {
25286- const inactiveSeatsAssignedIndividually = inactiveSeats.filter(seat => !seat.assigning_team);
25287- if (inactiveSeatsAssignedIndividually.length > 0) {
25288- core.group('Removing inactive seats', () => __awaiter(void 0, void 0, void 0, function* () {
25289- const response = yield octokit.request(`DELETE /orgs/{org}/copilot/billing/selected_users`, {
25290- org: input.org,
25291- selected_usernames: inactiveSeatsAssignedIndividually.map(seat => seat.assignee.login),
25292- });
25293- core.info(`Removed ${response.data.seats_cancelled} seats`);
25294- core.setOutput('removed-seats', response.data.seats_cancelled);
25352+ if (input.removefromTeam) {
25353+ const inactiveSeatsAssignedByTeam = inactiveSeats.filter(seat => seat.assigning_team);
25354+ core.group('Removing inactive seats from team', () => __awaiter(void 0, void 0, void 0, function* () {
25355+ for (const seat of inactiveSeatsAssignedByTeam) {
25356+ if (!seat.assigning_team || typeof (seat.assignee.login) !== 'string')
25357+ continue;
25358+ yield octokit.request('DELETE /orgs/{org}/teams/{team_slug}/memberships/{username}', {
25359+ org: org,
25360+ team_slug: seat.assigning_team.slug,
25361+ username: seat.assignee.login
25362+ });
25363+ }
2529525364 }));
2529625365 }
25297- }
25298- if (input.removefromTeam) {
25299- const inactiveSeatsAssignedByTeam = inactiveSeats.filter(seat => seat.assigning_team);
25300- core.group('Removing inactive seats from team', () => __awaiter(void 0, void 0, void 0, function* () {
25301- for (const seat of inactiveSeatsAssignedByTeam) {
25302- if (!seat.assigning_team || typeof (seat.assignee.login) !== 'string')
25303- continue;
25304- yield octokit.request('DELETE /orgs/{org}/teams/{team_slug}/memberships/{username}', {
25305- org: input.org,
25306- team_slug: seat.assigning_team.slug,
25307- username: seat.assignee.login
25308- });
25366+ if (input.jobSummary) {
25367+ yield core.summary
25368+ .addHeading(`${org} - Inactive Seats: ${inactiveSeats.length.toString()} / ${seats.length.toString()}`);
25369+ if (seats.length > 0) {
25370+ core.summary.addTable([
25371+ [
25372+ { data: 'Avatar', header: true },
25373+ { data: 'Login', header: true },
25374+ { data: 'Last Activity', header: true },
25375+ { data: 'Last Editor Used', header: true }
25376+ ],
25377+ ...inactiveSeats.sort((a, b) => {
25378+ const loginA = (a.assignee.login || 'Unknown');
25379+ const loginB = (b.assignee.login || 'Unknown');
25380+ return loginA.localeCompare(loginB);
25381+ }).map(seat => [
25382+ `<img src="${seat.assignee.avatar_url}" width="33" />`,
25383+ seat.assignee.login || 'Unknown',
25384+ seat.last_activity_at === null ? 'No activity' : (0, moment_1.default)(seat.last_activity_at).fromNow(),
25385+ seat.last_activity_editor || 'Unknown'
25386+ ])
25387+ ]);
2530925388 }
25310- }));
25311- }
25312- if (input.jobSummary) {
25313- yield core.summary
25314- .addHeading(`Inactive Seats: ${inactiveSeats.length.toString()} / ${seats.length.toString()}`)
25315- .addTable([
25316- [
25317- { data: 'Avatar', header: true },
25318- { data: 'Login', header: true },
25319- { data: 'Last Activity', header: true },
25320- { data: 'Last Editor Used', header: true }
25321- ],
25322- ...inactiveSeats.map(seat => [
25323- `<img src="${seat.assignee.avatar_url}" width="33" />`,
25324- seat.assignee.login || 'Unknown',
25325- seat.last_activity_at === null ? 'No activity' : (0, moment_1.default)(seat.last_activity_at).fromNow(),
25326- seat.last_activity_editor || 'Unknown'
25327- ])
25328- ])
25329- .addLink('Manage GitHub Copilot seats', `https://github.com/organizations/${input.org}/settings/copilot/seat_management`)
25330- .write();
25389+ core.summary.addLink('Manage GitHub Copilot seats', `https://github.com/organizations/${org}/settings/copilot/seat_management`)
25390+ .write();
25391+ }
2533125392 }
2533225393 if (input.csv) {
2533325394 core.group('Writing CSV', () => __awaiter(void 0, void 0, void 0, function* () {
25395+ const sortedSeats = allInactiveSeats.sort((a, b) => {
25396+ if (a.organization < b.organization)
25397+ return -1;
25398+ if (a.organization > b.organization)
25399+ return 1;
25400+ if (a.assignee.login < b.assignee.login)
25401+ return -1;
25402+ if (a.assignee.login > b.assignee.login)
25403+ return 1;
25404+ return 0;
25405+ });
2533425406 const csv = [
25335- ['Login', 'Last Activity', 'Last Editor Used'],
25336- ...inactiveSeats.map(seat => [
25407+ ['Organization', 'Login', 'Last Activity', 'Last Editor Used'],
25408+ ...sortedSeats.map(seat => [
25409+ seat.organization,
2533725410 seat.assignee.login,
2533825411 seat.last_activity_at === null ? 'No activity' : (0, moment_1.default)(seat.last_activity_at).fromNow(),
2533925412 seat.last_activity_editor || '-'
@@ -25344,6 +25417,10 @@ const run = () => __awaiter(void 0, void 0, void 0, function* () {
2534425417 yield artifactClient.uploadArtifact('inactive-seats', ['inactive-seats.csv'], '.');
2534525418 }));
2534625419 }
25420+ core.setOutput('inactive-seats', JSON.stringify(allInactiveSeats));
25421+ core.setOutput('inactive-seat-count', allInactiveSeats.length.toString());
25422+ core.setOutput('seat-count', allSeatsCount.toString());
25423+ core.setOutput('removed-seats', allRemovedSeatsCount.toString());
2534725424});
2534825425run();
2534925426
0 commit comments