Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
166 changes: 166 additions & 0 deletions __tests__/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
getRepositoryCount,
getRepositories,
getPullRequestsCount,
processPullRequestsInBatches,
generateBadges,
validateRequiredInput
} from '../src/index.js';
Expand Down Expand Up @@ -274,6 +275,171 @@ describe('getPullRequestsCount', () => {
});
});

describe('processPullRequestsInBatches', () => {
const filterDate = '2024-01-01';

it('should process multiple repositories in batches', async () => {
const mockGraphqlClient = jest
.fn()
// repo1
.mockResolvedValueOnce({
repository: {
pullRequests: {
nodes: [
{
createdAt: '2024-01-15T10:00:00Z',
mergedAt: '2024-01-20T10:00:00Z',
state: 'MERGED'
}
],
pageInfo: { endCursor: null, hasNextPage: false }
}
}
})
// repo2
.mockResolvedValueOnce({
repository: {
pullRequests: {
nodes: [
{
createdAt: '2024-01-10T10:00:00Z',
mergedAt: null,
state: 'OPEN'
}
],
pageInfo: { endCursor: null, hasNextPage: false }
}
}
});

const repos = ['repo1', 'repo2'];
const result = await processPullRequestsInBatches('test-org', repos, filterDate, mockGraphqlClient, 10);

expect(result.totalOpenPRs).toBe(2);
expect(result.totalMergedPRs).toBe(1);
expect(mockGraphqlClient).toHaveBeenCalledTimes(2);
});

it('should process repositories in multiple batches', async () => {
const mockGraphqlClient = jest
.fn()
// batch 1: repo1, repo2
.mockResolvedValueOnce({
repository: {
pullRequests: {
nodes: [
{
createdAt: '2024-01-15T10:00:00Z',
mergedAt: '2024-01-20T10:00:00Z',
state: 'MERGED'
}
],
pageInfo: { endCursor: null, hasNextPage: false }
}
}
})
.mockResolvedValueOnce({
repository: {
pullRequests: {
nodes: [
{
createdAt: '2024-01-10T10:00:00Z',
mergedAt: null,
state: 'OPEN'
}
],
pageInfo: { endCursor: null, hasNextPage: false }
}
}
})
// batch 2: repo3
.mockResolvedValueOnce({
repository: {
pullRequests: {
nodes: [
{
createdAt: '2024-01-12T10:00:00Z',
mergedAt: '2024-01-14T10:00:00Z',
state: 'MERGED'
}
],
pageInfo: { endCursor: null, hasNextPage: false }
}
}
});

const repos = ['repo1', 'repo2', 'repo3'];
const result = await processPullRequestsInBatches('test-org', repos, filterDate, mockGraphqlClient, 2);

expect(result.totalOpenPRs).toBe(3);
expect(result.totalMergedPRs).toBe(2);
expect(mockGraphqlClient).toHaveBeenCalledTimes(3);
});

it('should handle empty repository list', async () => {
const mockGraphqlClient = jest.fn();
const repos = [];
const result = await processPullRequestsInBatches('test-org', repos, filterDate, mockGraphqlClient, 10);

expect(result.totalOpenPRs).toBe(0);
expect(result.totalMergedPRs).toBe(0);
expect(mockGraphqlClient).not.toHaveBeenCalled();
});

it('should use default batch size of 10', async () => {
const mockGraphqlClient = jest.fn().mockResolvedValue({
repository: {
pullRequests: {
nodes: [],
pageInfo: { endCursor: null, hasNextPage: false }
}
}
});

const repos = Array.from({ length: 25 }, (_, i) => `repo${i}`);
await processPullRequestsInBatches('test-org', repos, filterDate, mockGraphqlClient);

// With batch size 10, should process all 25 repos concurrently in 3 batches
expect(mockGraphqlClient).toHaveBeenCalledTimes(25);
});

it('should aggregate PR counts correctly across batches', async () => {
const mockGraphqlClient = jest.fn().mockImplementation((_, { repo }) => {
// repo1 and repo2 have PRs, others don't
if (repo === 'repo1' || repo === 'repo2') {
return Promise.resolve({
repository: {
pullRequests: {
nodes: [
{
createdAt: '2024-01-15T10:00:00Z',
mergedAt: '2024-01-20T10:00:00Z',
state: 'MERGED'
}
],
pageInfo: { endCursor: null, hasNextPage: false }
}
}
});
}
return Promise.resolve({
repository: {
pullRequests: {
nodes: [],
pageInfo: { endCursor: null, hasNextPage: false }
}
}
});
});

const repos = ['repo1', 'repo2', 'repo3', 'repo4'];
const result = await processPullRequestsInBatches('test-org', repos, filterDate, mockGraphqlClient, 2);

expect(result.totalOpenPRs).toBe(2);
expect(result.totalMergedPRs).toBe(2);
});
});

describe('generateBadges', () => {
beforeEach(() => {
jest.clearAllMocks();
Expand Down
8 changes: 0 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 25 additions & 8 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,30 @@ export const getPullRequestsCount = async (org, repo, prFilterDate, graphqlClien
};
};

export const processPullRequestsInBatches = async (org, repos, prFilterDate, client, batchSize = 10) => {
let totalOpenPRs = 0;
let totalMergedPRs = 0;

// Process repositories in batches
for (let i = 0; i < repos.length; i += batchSize) {
const batch = repos.slice(i, i + batchSize);

// Process each batch concurrently
const results = await Promise.all(batch.map(repo => getPullRequestsCount(org, repo, prFilterDate, client)));

// Aggregate results from the batch
for (const { total, merged } of results) {
totalOpenPRs += total;
totalMergedPRs += merged;
}
}

return {
totalOpenPRs,
totalMergedPRs
};
};

export const generateBadges = async (orgParam, tokenParam, daysParam, graphqlClient, badgeColor, badgeLabelColor) => {
const org = orgParam || organization;
const numDays = daysParam || days;
Expand All @@ -215,19 +239,12 @@ export const generateBadges = async (orgParam, tokenParam, daysParam, graphqlCli
const repoCount = repos.length;
core.info(`Total repositories: ${repoCount}`);
// pull requests
let totalOpenPRs = 0;
let totalMergedPRs = 0;

const date = new Date();
date.setUTCDate(date.getUTCDate() - numDays);
const prFilterDate = date.toISOString();
core.debug(`Filtering PRs created after ${prFilterDate}`);

for (const repo of repos) {
const { total, merged } = await getPullRequestsCount(org, repo, prFilterDate, client);
totalOpenPRs += total;
totalMergedPRs += merged;
}
const { totalOpenPRs, totalMergedPRs } = await processPullRequestsInBatches(org, repos, prFilterDate, client);

core.info(`Total pull requests created in last ${numDays} days for ${org}: ${totalOpenPRs}`);
core.info(`Total merged pull requests in last ${numDays} days for ${org}: ${totalMergedPRs}`);
Expand Down