Skip to content

Commit

Permalink
feat(authors): scrape authors from github
Browse files Browse the repository at this point in the history
  • Loading branch information
Nikolay Tverdokhlebov authored and moki committed Mar 28, 2023
1 parent f71c655 commit e5c9ddf
Show file tree
Hide file tree
Showing 10 changed files with 122 additions and 20 deletions.
1 change: 1 addition & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ export const REGEXP_INCLUDE_FILE_PATH = /(?<=[(]).+(?=[)])/g;
// Include example: author: authorLogin
// Regexp result: authorLogin
export const REGEXP_AUTHOR = /(?<=author:\s).+(?=\r?\n)/g;
export const REGEXP_CONTRIBUTORS = /(?<=contributors:\s).+(?=\r?\n)*?/g;

export const MIN_CHUNK_SIZE = Number(process.env.MIN_CHUNK_SIZE) || 1000;
export const WORKERS_COUNT = Number(process.env.WORKERS_COUNT) || (os.cpus().length - 1);
Expand Down
2 changes: 2 additions & 0 deletions src/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ export interface Contributor {
login: string;
name: string;
url: string;
date?: string;
hash?: string;
}

export interface Contributors {
Expand Down
52 changes: 45 additions & 7 deletions src/services/authors.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,62 @@
import {replaceDoubleToSingleQuotes} from '../utils';
import {REGEXP_AUTHOR} from '../constants';
import os from 'os';

import {logger, replaceDoubleToSingleQuotes} from '../utils';
import {REGEXP_AUTHOR, REGEXP_CONTRIBUTORS} from '../constants';
import {VCSConnector} from '../vcs-connector/connector-models';
import {isEarlier, parseDataFromJSONString} from './utils';
import {Contributor} from '../models';


export function getContributorArrayFromMetadata(metadata: string[], filePath = '') {
const contributors: Contributor[] = [];

for (const meta of metadata) {
const matchContributors = meta.match(REGEXP_CONTRIBUTORS);
try {
if (matchContributors) {
contributors.push(...parseDataFromJSONString(matchContributors[0]));
}
} catch (err) {
logger.warn(filePath, JSON.stringify(err));
}
}

return contributors;
}

async function updateAuthorMetadataString(defaultMetadata = '', vcsConnector?: VCSConnector): Promise<string> {

async function updateAuthorMetadataString(
fileMetadata = '',
vcsConnector?: VCSConnector,
newMetadatas: string[] = [],
): Promise<string> {
if (!vcsConnector) {
return defaultMetadata;
return fileMetadata;
}

const matchAuthor = defaultMetadata.match(REGEXP_AUTHOR);
const matchAuthor = fileMetadata.match(REGEXP_AUTHOR);

if (matchAuthor && matchAuthor?.length > 0) {
const authorLogin = matchAuthor[0];
const user = await getAuthorDetails(vcsConnector, authorLogin);

if (user) {
return defaultMetadata.replace(authorLogin, user);
return fileMetadata.replace(authorLogin, user);
}
}

const contributors = getContributorArrayFromMetadata(newMetadatas);

if (contributors.length && !matchAuthor) {
contributors.sort((a, b) => isEarlier(a.date, b.date) ? -1 : 1);
const user = await getAuthorDetails(vcsConnector, contributors[0]);

if (user) {
return `${fileMetadata}${os.EOL}author: ${user}`;
}
}

return defaultMetadata;
return fileMetadata;
}

async function getAuthorDetails(vcsConnector: VCSConnector, author: string | object): Promise<string | null> {
Expand Down
6 changes: 5 additions & 1 deletion src/services/metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,11 @@ async function getContentWithUpdatedDynamicMetadata(
const [, fileMetadata, , fileMainContent] = matches;
let updatedDefaultMetadata = '';

updatedDefaultMetadata = await updateAuthorMetadataString(fileMetadata, options.vcsConnector);
updatedDefaultMetadata = await updateAuthorMetadataString(
fileMetadata,
options.vcsConnector,
newMetadatas,
);

return `${getUpdatedMetadataString(newMetadatas, updatedDefaultMetadata)}${fileMainContent}`;
}
Expand Down
17 changes: 17 additions & 0 deletions src/services/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import evalExp from '@doc-tools/transform/lib/liquid/evaluation';
import {Filter, TextItems} from '../models';
import liquid from '@doc-tools/transform/lib/liquid';
import {ArgvService} from './index';
import {replaceSingleToDoubleQuotes} from '../utils';

export interface FilterFilesOptions {
resolveConditions?: boolean;
Expand Down Expand Up @@ -149,3 +150,19 @@ export function liquidField(input: string, vars: Record<string, unknown>, path:
export function isObject(o: unknown): o is object {
return typeof o === 'object' && o !== null;
}

export function isEarlier(oldDate?: string, newDate?: string) {
if (!newDate) {
return false;
}

if (!oldDate) {
return true;
}

return new Date(oldDate) > new Date(newDate);
}

export function parseDataFromJSONString(dataString: string) {
return JSON.parse(replaceSingleToDoubleQuotes(dataString));
}
4 changes: 4 additions & 0 deletions src/utils/markup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,7 @@ export function joinSinglePageResults(singlePageResults: SinglePageResult[], roo
export function replaceDoubleToSingleQuotes(str: string): string {
return str.replace(/"/g, '\'');
}

export function replaceSingleToDoubleQuotes(str: string): string {
return str.replace(/'/g, '"');
}
1 change: 1 addition & 0 deletions src/vcs-connector/connector-models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export interface GithubCommitDTO {
author: {
name: string;
email: string;
date: string;
};
};
author: {
Expand Down
30 changes: 25 additions & 5 deletions src/vcs-connector/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
} from '../constants';
import {addSlashPrefix, execAsync, logger} from '../utils';
import {validateConnectorFields} from './connector-validator';
import {isEarlier} from '../services/utils';

const contributorsByPath: Map<string, FileContributors> = new Map();
const contributorsData: Map<string, Contributor | null> = new Map();
Expand Down Expand Up @@ -146,6 +147,7 @@ async function getContributorDataByHashCommit(httpClientByToken: Octokit, hashCo
login,
name: commit.author.name,
url,
date: commit.author.date,
};
}

Expand Down Expand Up @@ -188,18 +190,36 @@ function addContributorForPath(paths: string[], newContributor: Contributors, ha
contributors: newContributor,
hasIncludes,
});

return;
}

const oldContributors = contributorsByPath.get(normalizePath);
const newContributorKey = Object.keys(newContributor)?.[0];

contributorsByPath.set(normalizePath, {
contributors: {
if (newContributorKey) {
const contributors = {
...oldContributors?.contributors,
...newContributor,
},
hasIncludes,
});
};

if (!oldContributors?.contributors?.[newContributorKey]) {
contributorsByPath.set(normalizePath, {
contributors,
hasIncludes,
});
} else if (
isEarlier(
newContributor[newContributorKey]?.date,
oldContributors?.contributors[newContributorKey]?.date,
)
) {
contributorsByPath.set(normalizePath, {
contributors,
hasIncludes,
});
}
}
});
}

Expand Down
14 changes: 10 additions & 4 deletions tests/integrations/services/metadataContributors.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os from 'os';
import {readFileSync} from 'fs';
import {normalize} from 'path';
import {metadataBorder} from '../../../src/constants';
Expand Down Expand Up @@ -85,6 +86,8 @@ describe('getContentWithUpdatedMetadata (Contributors)', () => {
[contributorFirst.email]: contributorFirst,
[contributorSecond.email]: contributorSecond,
};
const expectedAuthorString: string = replaceDoubleToSingleQuotes(
JSON.stringify(contributorFirst));
const expectedContributorsArray: Contributor[] = Object.values(expectedContributors);
const expectedContributorsString: string =
replaceDoubleToSingleQuotes(JSON.stringify(expectedContributorsArray));
Expand All @@ -99,7 +102,7 @@ describe('getContentWithUpdatedMetadata (Contributors)', () => {

const splitedFiledContent = fileContent.split(metadataBorder);
splitedFiledContent[1] =
`${splitedFiledContent[1]}contributors: ${expectedContributorsString}${сarriage}`;
`${splitedFiledContent[1]}${os.EOL}author: ${expectedAuthorString}${os.EOL}contributors: ${expectedContributorsString}${сarriage}`;
const expectedFileContent = splitedFiledContent.join(metadataBorder);
expect(updatedFileContent).toEqual(expectedFileContent);
});
Expand All @@ -116,6 +119,8 @@ describe('getContentWithUpdatedMetadata (Contributors)', () => {
const expectedContributors: Contributors = {
[contributorFirst.email]: contributorFirst,
};
const expectedAuthorString: string = replaceDoubleToSingleQuotes(
JSON.stringify(contributorFirst));
const expectedContributorsArray: Contributor[] = Object.values(expectedContributors);
const expectedContributorsString: string =
replaceDoubleToSingleQuotes(JSON.stringify(expectedContributorsArray));
Expand All @@ -130,7 +135,7 @@ describe('getContentWithUpdatedMetadata (Contributors)', () => {

const splitedFiledContent = fileContent.split(metadataBorder);
splitedFiledContent[1] =
`${splitedFiledContent[1]}contributors: ${expectedContributorsString}${сarriage}`;
`${splitedFiledContent[1]}${os.EOL}author: ${expectedAuthorString}${os.EOL}contributors: ${expectedContributorsString}${сarriage}`;
const expectedFileContent = splitedFiledContent.join(metadataBorder);
expect(updatedFileContent).toEqual(expectedFileContent);
});
Expand Down Expand Up @@ -195,7 +200,8 @@ describe('getContentWithUpdatedMetadata (Contributors)', () => {
`and includes files and ${item.title}`, async () => {
const expectedContributorsString: string = replaceDoubleToSingleQuotes(
JSON.stringify(item.expectedContributorsArray));

const expectedAuthorString: string = replaceDoubleToSingleQuotes(
JSON.stringify(contributorFirst));
metaDataOptions.vcsConnector.getContributorsByPath = (path: string) => Promise.resolve({
contributors: getFileContributors(path),
hasIncludes: item.getHasIncludes(path),
Expand All @@ -207,7 +213,7 @@ describe('getContentWithUpdatedMetadata (Contributors)', () => {

const splitedFiledContent = fileContent.split(metadataBorder);
splitedFiledContent[1] =
`${splitedFiledContent[1]}contributors: ${expectedContributorsString}${сarriage}`;
`${splitedFiledContent[1]}${os.EOL}author: ${expectedAuthorString}${os.EOL}contributors: ${expectedContributorsString}${сarriage}`;
const expectedFileContent = splitedFiledContent.join(metadataBorder);
expect(updatedFileContent).toEqual(expectedFileContent);
});
Expand Down
15 changes: 12 additions & 3 deletions tests/units/services/authors.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,10 @@ describe('updateAuthorMetadataString', () => {
test('when "defaultMetadata" is empty', async () => {
const expectedMetadata = '';

const authorDetails = await updateAuthorMetadataString(expectedMetadata, defaultVCSConnector);
const authorDetails = await updateAuthorMetadataString(
expectedMetadata,
defaultVCSConnector,
);

expect(authorDetails).toEqual(expectedMetadata);
});
Expand All @@ -111,7 +114,10 @@ describe('updateAuthorMetadataString', () => {

defaultVCSConnector.getUserByLogin = () => Promise.resolve(null);

const updatedMetadata = await updateAuthorMetadataString(expectedMetadata, defaultVCSConnector);
const updatedMetadata = await updateAuthorMetadataString(
expectedMetadata,
defaultVCSConnector,
);

expect(updatedMetadata).toEqual(expectedMetadata);
});
Expand All @@ -125,7 +131,10 @@ describe('updateAuthorMetadataString', () => {
const authorDetails = units.replaceDoubleToSingleQuotes(JSON.stringify(author));
defaultVCSConnector.getUserByLogin = () => Promise.resolve(author);

const updatedMetadata = await updateAuthorMetadataString(defaultMetadata, defaultVCSConnector);
const updatedMetadata = await updateAuthorMetadataString(
defaultMetadata,
defaultVCSConnector,
);

const matchAuthor = defaultMetadata.match(REGEXP_AUTHOR);
const expectedMetadata = defaultMetadata.replace(matchAuthor[0], authorDetails);
Expand Down

0 comments on commit e5c9ddf

Please sign in to comment.