Skip to content

Commit

Permalink
functionality complete
Browse files Browse the repository at this point in the history
  • Loading branch information
gagoar committed Mar 19, 2023
1 parent 4bc8d89 commit 0e96095
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 25 deletions.
3 changes: 3 additions & 0 deletions __mocks__/CODEOWNERS_POPULATED_OUTPUT
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ scripts/ @myOrg/infraTeam
# Rule extracted from dir1/CODEOWNERS
dir1/*.ts @eeny @meeny
#################################### Generated content - do not edit! ####################################

# Another line here that should be moved to after the generated block without preserve-block-position option enabled
dir2/ @otherTeam
76 changes: 75 additions & 1 deletion __tests__/generate.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,12 @@ describe('Generate', () => {
});

await generateCommand(
{ output: 'CODEOWNERS', customRegenerationCommand: 'yarn codeowners-generator generate', check: true },
{
output: 'CODEOWNERS',
customRegenerationCommand: 'yarn codeowners-generator generate',
check: true,
preserveBlockPosition: true,
},
{ parent: {} }
);
});
Expand Down Expand Up @@ -130,6 +135,9 @@ describe('Generate', () => {
# We might wanna keep an eye on something else, like yml files and workflows.
.github/workflows/ @myOrg/infraTeam
# Another line here that should be moved to after the generated block without preserve-block-position option enabled
dir2/ @otherTeam
#################################### Generated content - do not edit! ####################################
# This block has been generated with codeowners-generator (for more information https://github.com/gagoar/codeowners-generator)
# To re-generate, run \`yarn codeowners-generator generate\`. Don't worry, the content outside this block will be kept.
Expand Down Expand Up @@ -157,6 +165,72 @@ describe('Generate', () => {
]
`);
});

it('should generate a CODEOWNERS file (re-using codeowners content, with preserve-block-position enabled)', async () => {
sync.mockReturnValueOnce(Object.keys(files));

sync.mockReturnValueOnce(['.gitignore']);

const withPopulatedCodeownersFile = {
...withGitIgnore,
CODEOWNERS: '../__mocks__/CODEOWNERS_POPULATED_OUTPUT',
};
existsSync.mockReturnValue(true);
readFile.mockImplementation((file, callback): void => {
const fullPath = path.join(
__dirname,
withPopulatedCodeownersFile[file as keyof typeof withPopulatedCodeownersFile]
);
const content = readFileSync(fullPath);
callback(null, content);
});

await generateCommand(
{
output: 'CODEOWNERS',
customRegenerationCommand: 'yarn codeowners-generator generate',
preserveBlockPosition: true,
},
{ parent: {} }
);
expect(writeFile.mock.calls[0]).toMatchInlineSnapshot(`
Array [
"CODEOWNERS",
"# We are already using CODEOWNERS and we don't want to lose the content of this file.
scripts/ @myOrg/infraTeam
# We might wanna keep an eye on something else, like yml files and workflows.
.github/workflows/ @myOrg/infraTeam
#################################### Generated content - do not edit! ####################################
# This block has been generated with codeowners-generator (for more information https://github.com/gagoar/codeowners-generator)
# To re-generate, run \`yarn codeowners-generator generate\`. Don't worry, the content outside this block will be kept.
# Rule extracted from dir1/CODEOWNERS
/dir1/**/*.ts @eeny @meeny
# Rule extracted from dir1/CODEOWNERS
/dir1/*.ts @miny
# Rule extracted from dir1/CODEOWNERS
/dir1/**/README.md @miny
# Rule extracted from dir1/CODEOWNERS
/dir1/README.md @moe
# Rule extracted from dir2/CODEOWNERS
/dir2/**/*.ts @moe
# Rule extracted from dir2/CODEOWNERS
/dir2/dir3/*.ts @miny
# Rule extracted from dir2/CODEOWNERS
/dir2/**/*.md @meeny
# Rule extracted from dir2/CODEOWNERS
/dir2/**/dir4/ @eeny
# Rule extracted from dir2/dir3/CODEOWNERS
/dir2/dir3/**/*.ts @miny
#################################### Generated content - do not edit! ####################################
# Another line here that should be moved to after the generated block without preserve-block-position option enabled
dir2/ @otherTeam",
]
`);
});
it('should generate a CODEOWNERS FILE with groupSourceComments and customRegenerationCommand', async () => {
sync.mockReturnValueOnce(Object.keys(files));

Expand Down
9 changes: 6 additions & 3 deletions src/commands/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ interface Options {
useMaintainers?: boolean;
useRootMaintainers?: boolean;
groupSourceComments?: boolean;
preserveBlockPosition?: boolean;
includes?: string[];
customRegenerationCommand?: string;
check?: boolean;
Expand All @@ -109,7 +110,7 @@ interface Options {
export const command = async (options: Options, command: Command): Promise<void> => {
const globalOptions = await getGlobalOptions(command);

const { verifyPaths, useMaintainers, useRootMaintainers, check } = options;
const { verifyPaths, useMaintainers, useRootMaintainers, check, preserveBlockPosition } = options;

const { output = globalOptions.output || OUTPUT } = options;

Expand All @@ -124,6 +125,7 @@ export const command = async (options: Options, command: Command): Promise<void>
useMaintainers,
useRootMaintainers,
groupSourceComments,
preserveBlockPosition,
customRegenerationCommand,
output,
});
Expand All @@ -141,8 +143,9 @@ export const command = async (options: Options, command: Command): Promise<void>
const [originalContent, newContent] = await generateOwnersFile(
output,
ownerRules,
customRegenerationCommand,
groupSourceComments
groupSourceComments,
preserveBlockPosition,
customRegenerationCommand
);

if (check) {
Expand Down
58 changes: 42 additions & 16 deletions src/utils/codeowners.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
CONTENT_MARK,
CHARACTER_RANGE_PATTERN,
rulesBlockTemplate,
generatedContentTemplate,
} from './constants';
import { dirname, join } from 'path';
import { readContent } from './readContent';
Expand All @@ -26,27 +27,38 @@ export type ownerRule = {
glob: string;
};

const filterGeneratedContent = (content: string) => {
// to fix this I will have to return an [] and every line there.
// I will have also to return the position where the mark was found.
// later If the flag is set (--preserve-block-position) I will just count the array and when the same index is hit, inject the content.

const filterGeneratedContent = (content: string): [withoutGeneratedCode: string[], blockPosition: number] => {
const lines = content.split('\n');

let skip = false;
return lines
.reduce((memo, line) => {
if (line === CONTENT_MARK) {
skip = !skip;
return memo;
let generatedBlockPosition = -1;

const withoutGeneratedCode = lines.reduce((memo, line, index) => {
if (line === CONTENT_MARK) {
skip = !skip;
if (generatedBlockPosition === -1) {
generatedBlockPosition = index;
}
return memo;
}

return skip ? memo : [...memo, line];
}, [] as string[])
.join('\n');
return skip ? memo : [...memo, line];
}, [] as string[]);

return [withoutGeneratedCode, generatedBlockPosition];
};

type createOwnersFileResponse = [originalContent: string, newContent: string];
export const generateOwnersFile = async (
outputFile: string,
ownerRules: ownerRule[],
customRegenerationCommand?: string,
groupSourceComments = false
groupSourceComments = false,
preserveBlockPosition = false,
customRegenerationCommand?: string
): Promise<createOwnersFileResponse> => {
let originalContent = '';

Expand All @@ -67,12 +79,26 @@ export const generateOwnersFile = async (
} else {
content = ownerRules.map((rule) => rulesBlockTemplate(rule.filePath, [`${rule.glob} ${rule.owners.join(' ')}`]));
}
const [withoutGeneratedCode, blockPosition] = filterGeneratedContent(originalContent);

const normalizedContent = contentTemplate(
content.join('\n'),
filterGeneratedContent(originalContent),
customRegenerationCommand
);
let normalizedContent = '';
// this block should consider the option --preserve-block-position
// contentTemplate should change, maybe to contain this logic? I'm not sure yet.

if (preserveBlockPosition && blockPosition !== -1 && withoutGeneratedCode.length) {
normalizedContent = withoutGeneratedCode
.reduce((memo, line, index) => {
if (index === blockPosition) {
memo += generatedContentTemplate(content.join('\n'), customRegenerationCommand) + '\n';
}
memo += `${line}\n`;

return memo;
}, '')
.trimEnd();
} else {
normalizedContent = contentTemplate(content.join('\n'), withoutGeneratedCode.join('\n'), customRegenerationCommand);
}

return [originalContent, normalizedContent];
};
Expand Down
13 changes: 9 additions & 4 deletions src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,22 @@ export const contentTemplate = (
generatedContent: string,
originalContent: string,
customRegenerationCommand?: string
): string => {
) => {
return stripIndents`
${originalContent && originalContent.trimEnd()}
${originalContentTemplate(originalContent)}
${generatedContentTemplate(generatedContent, customRegenerationCommand)}
`;
};

export const originalContentTemplate = (originalContent: string) => originalContent && originalContent.trimEnd();
export const generatedContentTemplate = (generatedContent: string, customRegenerationCommand?: string) => {
return stripIndents`
${CONTENT_MARK}
${getContentLegend(customRegenerationCommand)}\n
${generatedContent}\n
${CONTENT_MARK}\n
`;
`;
};

export const rulesBlockTemplate = (source: string, entries: string[]): string => {
return stripIndents`
# Rule${entries.length > 1 ? 's' : ''} extracted from ${source}
Expand Down
2 changes: 1 addition & 1 deletion src/utils/getCustomConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export type CustomConfig = {
};

export const getCustomConfiguration = async (): Promise<CustomConfig | void> => {
const loader = ora('Loading available configuration').start();
const loader = ora('Loading configuration').start();

try {
const explorer = cosmiconfig(packageJSON.name);
Expand Down

0 comments on commit 0e96095

Please sign in to comment.