Skip to content

Commit

Permalink
feat: script should support more than 1 local git repository gf-589 (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
Artem Zahorodniuk authored and Artem Zahorodniuk committed Oct 2, 2024
1 parent 33d95b3 commit 5ec5526
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const SetupAnalyticsModal = ({
const apiKey = project.apiKey as string;
const userId = String(authenticatedUser.id);

return `npx @git-fit/analytics@latest track ${apiKey} ${userId} <project-path>`;
return `npx @git-fit/analytics@latest track ${apiKey} ${userId} <project-path-1> <project-path-2> ...`;
}, [hasProjectApiKey, hasAuthenticatedUser, project, authenticatedUser]);

const { control, errors, handleSubmit, handleValueSet } = useAppForm({
Expand Down Expand Up @@ -233,8 +233,9 @@ const SetupAnalyticsModal = ({
Prepare the script.
</span>
<p className={styles["list-item-text"]}>
Copy the command below and replace &lt;project-path&gt;
placeholder with your local repository&apos;s path:
Copy the command below and replace &lt;project-path-1&gt;,
&lt;project-path-2&gt;, ... placeholder with your local
repositories paths:
</p>
<Input
control={control}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ class BaseAnalyticsCli {

private setupCommands(): void {
this.program
.command("track <apiKey> <userId> <repoPath>")
.command("track <apiKey> <userId> <repoPaths...>")
.description("Start the background job for collecting statistics")
.action(async (apiKey: string, userId: string, repoPath: string) => {
if (!apiKey || !userId || !repoPath) {
.action(async (apiKey: string, userId: string, repoPaths: string[]) => {
if (!apiKey || !userId || repoPaths.length === 0) {
this.logger.error("Not all command arguments are provided.");

return;
Expand Down Expand Up @@ -80,7 +80,7 @@ class BaseAnalyticsCli {

pm2.start(
{
args: [apiKey, userId, repoPath],
args: [apiKey, userId, ...repoPaths],
autorestart: false,
error: `${project.projectName}-err.log`,
name: project.projectName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,15 @@ import {
CRON_SCHEDULE,
} from "./libs/constants/constants.js";

const [apiKey, userId, repoPath] = process.argv.slice(ARGUMENT_START_INDEX) as [
string,
string,
string,
];
const [apiKey, userId, ...repoPaths] = process.argv.slice(
ARGUMENT_START_INDEX,
) as [string, string, string];

const analyticsService = new AnalyticsService({
analyticsApi,
apiKey,
gitService,
repoPath,
repoPaths,
userId,
});

Expand Down
78 changes: 65 additions & 13 deletions scripts/analytics/src/modules/analytics/analytics.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,37 +17,37 @@ type Constructor = {
analyticsApi: typeof analyticsApi;
apiKey: string;
gitService: GITService;
repoPath: string;
repoPaths: string[];
userId: string;
};

class AnalyticsService {
private analyticsApi: typeof analyticsApi;
private apiKey: string;
private gitService: GITService;
private repoPath: string;
private repoPaths: string[];
private userId: string;

public constructor({
analyticsApi,
apiKey,
gitService,
repoPath,
repoPaths,
userId,
}: Constructor) {
this.analyticsApi = analyticsApi;
this.apiKey = apiKey;
this.gitService = gitService;
this.repoPath = repoPath;
this.repoPaths = repoPaths;
this.userId = userId;
}

private async collectStatsByRepository(): Promise<
ActivityLogCreateItemRequestDto[]
> {
private async collectStatsByRepository(
repoPath: string,
): Promise<ActivityLogCreateItemRequestDto[]> {
const stats: ActivityLogCreateItemRequestDto[] = [];
const shortLogResult = await executeCommand(
this.gitService.getShortLogCommand(this.repoPath, "midnight"),
this.gitService.getShortLogCommand(repoPath, "midnight"),
);

const commitItems: CommitStatistics[] = [];
Expand Down Expand Up @@ -77,15 +77,21 @@ class AnalyticsService {
return stats;
}

private async fetchRepository(): Promise<void> {
await executeCommand(this.gitService.getFetchCommand(this.repoPath));
logger.info(`Fetched latest updates for repo at path: ${this.repoPath}`);
private async fetchRepository(repoPath: string): Promise<void> {
await executeCommand(this.gitService.getFetchCommand(repoPath));
logger.info(`Fetched latest updates for repo at path: ${repoPath}`);
}

public async collectAndSendStats(): Promise<void> {
try {
await this.fetchRepository();
const stats = await this.collectStatsByRepository();
const statsAll = [];

for (const repoPath of this.repoPaths) {
await this.fetchRepository(repoPath);
statsAll.push(...(await this.collectStatsByRepository(repoPath)));
}

const stats = mergeStats(statsAll);

if (
stats[FIRST_ARRAY_INDEX] &&
Expand Down Expand Up @@ -116,4 +122,50 @@ class AnalyticsService {
}
}

function mergeStats(
statsAll: ActivityLogCreateItemRequestDto[],
): ActivityLogCreateItemRequestDto[] {
return mergeByCriteria(
statsAll,
(item1, item2) => item1.date === item2.date,
(mergedItem, item) =>
(mergedItem.items = mergeStatsItems([
...mergedItem.items,
...item.items,
])),
);
}

function mergeStatsItems(items: CommitStatistics[]): CommitStatistics[] {
return mergeByCriteria(
items,
(item1, item2) =>
item1.authorEmail === item2.authorEmail &&
item1.authorName === item2.authorName,
(mergedItem, item) => (mergedItem.commitsNumber += item.commitsNumber),
);
}

function mergeByCriteria<T>(
items: T[],
compareFunction: (item1: T, item2: T) => boolean,
mergeFunction: (mergedItem: T, item: T) => void,
): T[] {
const mergedItems: T[] = [];

for (const item of items) {
const mergedItem = mergedItems.find((mergedItem) =>
compareFunction(mergedItem, item),
);

if (mergedItem) {
mergeFunction(mergedItem, item);
} else {
mergedItems.push(item);
}
}

return mergedItems;
}

export { AnalyticsService };

0 comments on commit 5ec5526

Please sign in to comment.