mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-01-20 16:42:56 +00:00
refactor: extract code into several functions
This commit is contained in:
284
src/common.ts
Normal file
284
src/common.ts
Normal file
@@ -0,0 +1,284 @@
|
||||
import chalk from 'chalk';
|
||||
import {execSync} from 'child_process';
|
||||
import {copyFileSync, existsSync, readFileSync} from 'fs';
|
||||
import {join, resolve, sep} from 'path';
|
||||
import {isDeepStrictEqual} from 'util';
|
||||
import {parse, stringify} from 'yaml';
|
||||
import {EXPECTED_CI_CONFIG, EXPECTED_LICENSES, NEEDED_FILES, NYC_CONFIGURATION, SCRIPTS} from './configuration';
|
||||
|
||||
/**
|
||||
* Wrapper for console.info that outputs every argument in cyan
|
||||
*
|
||||
* @param args Arguments to output
|
||||
*/
|
||||
export function consoleInfo(...args: string[]): void {
|
||||
args.forEach((arg) => {
|
||||
/* tslint:disable-next-line:no-console */
|
||||
console.info('\n' + chalk.cyan(arg));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for console.warn that outputs every argument in red
|
||||
*
|
||||
* @param args Arguments to output
|
||||
*/
|
||||
export function consoleWarn(...args: string[]): void {
|
||||
args.forEach((arg) => {
|
||||
/* tslint:disable-next-line:no-console */
|
||||
console.warn('\n' + chalk.red.bold(arg));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for console.log that outputs every argument in green
|
||||
*
|
||||
* @param args Arguments to output
|
||||
*/
|
||||
export function consoleLog(...args: string[]): void {
|
||||
args.forEach((arg) => {
|
||||
/* tslint:disable-next-line:no-console */
|
||||
console.log('\n' + chalk.green.bold(arg));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that configuration files are extended
|
||||
*
|
||||
* @param path Path, where configuration files are located
|
||||
*/
|
||||
export function checkConfigurationFilesAreExtended(path: string): void {
|
||||
// check if configuration files are extended
|
||||
['tsconfig.json', 'tslint.json'].forEach((file) => {
|
||||
const fileToCheck = resolve(path, file);
|
||||
const expectedPath = `./node_modules/@openstapps/configuration/${file}`;
|
||||
|
||||
if (existsSync(fileToCheck)) {
|
||||
const configFile = JSON.parse(readFileSync(fileToCheck).toString());
|
||||
|
||||
const configFileExtended = (
|
||||
typeof configFile.extends === 'string'
|
||||
&& configFile.extends === expectedPath
|
||||
)
|
||||
|| (
|
||||
file === 'tslint.json'
|
||||
&& Array.isArray(configFile.extends)
|
||||
&& configFile.extends.indexOf(expectedPath) >= 0
|
||||
);
|
||||
|
||||
if (!configFileExtended) {
|
||||
consoleWarn(`File "${fileToCheck}" should extend "${expectedPath}"!
|
||||
|
||||
Example:
|
||||
${readFileSync(resolve(__dirname, '..', 'templates', 'template-' + file))}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check needed files
|
||||
*
|
||||
* @param path Path to files to check
|
||||
* @param replaceFlag Whether or not to replace files
|
||||
* @return Whether or not overwrite is suggested
|
||||
*/
|
||||
export function checkNeededFiles(path: string, replaceFlag: boolean): boolean {
|
||||
let suggestOverwrite = false;
|
||||
|
||||
// copy needed files
|
||||
NEEDED_FILES.forEach((file) => {
|
||||
let destinationFile = file;
|
||||
|
||||
// remove templates directory for destination files
|
||||
if (destinationFile.indexOf('templates') === 0) {
|
||||
destinationFile = destinationFile.split(sep).slice(1).join(sep);
|
||||
file = join('templates', `template-${destinationFile}`);
|
||||
}
|
||||
|
||||
const source = resolve(__dirname, '..', file);
|
||||
const destination = resolve(path, destinationFile);
|
||||
|
||||
// check if file exists or replace flag is set
|
||||
if (!existsSync(destination) || replaceFlag) {
|
||||
copyFileSync(source, destination);
|
||||
consoleInfo(`Copied file "${source}" to "${destination}".`);
|
||||
} else if (destinationFile === '.npmignore') {
|
||||
const npmIgnore = readFileSync(destination).toString();
|
||||
|
||||
const ignoredPatterns = npmIgnore.split('\n');
|
||||
|
||||
let ignoresEverything = false;
|
||||
let unignoresDocs = false;
|
||||
|
||||
for (const ignoredPattern of ignoredPatterns) {
|
||||
if (ignoredPattern === '/*') {
|
||||
ignoresEverything = true;
|
||||
}
|
||||
|
||||
if (ignoredPattern === '!docs') {
|
||||
unignoresDocs = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ignoresEverything) {
|
||||
consoleWarn(`'.npmignore' should have '/*' as first pattern to ignore everything.`);
|
||||
|
||||
suggestOverwrite = true;
|
||||
}
|
||||
|
||||
if (unignoresDocs) {
|
||||
consoleWarn(`'.npmignore' contains '!docs' and thus the package will contain the documentation.
|
||||
Please double check that this is desired behavior since the docs can become huge:
|
||||
https://gitlab.com/openstapps/configuration/issues/11`);
|
||||
|
||||
suggestOverwrite = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return suggestOverwrite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check licenses
|
||||
*
|
||||
* @param packageJson package.json to check license in
|
||||
*/
|
||||
export function checkLicenses(packageJson: any): void {
|
||||
// check if license is one of the expected ones
|
||||
if (EXPECTED_LICENSES.indexOf(packageJson.license) === -1) {
|
||||
consoleWarn(`License should be one of "${EXPECTED_LICENSES.join(', ')}"!`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check NYC configuration
|
||||
*
|
||||
* @param packageJson package.json to check NYC configuration in
|
||||
* @param replaceFlag Whether or not to replace NYC configuration
|
||||
* @return Whether or not package.json was changed and if overwrite is suggested
|
||||
*/
|
||||
export function checkNYCConfiguration(packageJson: any, replaceFlag: boolean): [boolean, boolean] {
|
||||
let packageJsonChanged = false;
|
||||
let suggestOverwrite = false;
|
||||
|
||||
// check if nyc is a dependency
|
||||
if (typeof packageJson.devDependencies === 'object' && Object.keys(packageJson.devDependencies).indexOf('nyc') >= 0) {
|
||||
if (typeof packageJson.nyc === 'undefined' || replaceFlag) {
|
||||
// add NYC configuration
|
||||
packageJson.nyc = NYC_CONFIGURATION;
|
||||
|
||||
packageJsonChanged = true;
|
||||
|
||||
consoleLog(`Added NYC configuration in to 'package.json'.`);
|
||||
} else if (!isDeepStrictEqual(packageJson.nyc, NYC_CONFIGURATION)) {
|
||||
consoleInfo(`NYC configuration in 'package.json' differs from the proposed one. Please check manually.`);
|
||||
|
||||
suggestOverwrite = true;
|
||||
}
|
||||
}
|
||||
|
||||
return [packageJsonChanged, suggestOverwrite];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check scripts
|
||||
*
|
||||
* @param packageJson package.json to check scripts in
|
||||
* @param replaceFlag Whether or not to replace scripts
|
||||
* @return Whether or not the package.json was changed
|
||||
*/
|
||||
export function checkScripts(packageJson: any, replaceFlag: boolean): boolean {
|
||||
let packageJsonChanged = false;
|
||||
|
||||
// check if scripts is a map
|
||||
if (typeof packageJson.scripts !== 'object') {
|
||||
packageJson.scripts = {};
|
||||
|
||||
packageJsonChanged = true;
|
||||
}
|
||||
|
||||
Object.keys(SCRIPTS).forEach((scriptName) => {
|
||||
const scriptToCheck = packageJson.scripts[scriptName];
|
||||
|
||||
// check if script exists
|
||||
if (typeof scriptToCheck === 'undefined' || replaceFlag) {
|
||||
packageJson.scripts[scriptName] = SCRIPTS[scriptName];
|
||||
|
||||
packageJsonChanged = true;
|
||||
|
||||
consoleInfo(`Added '${scriptName}' script to 'package.json'.`);
|
||||
} else if (typeof scriptToCheck === 'string' && scriptToCheck !== SCRIPTS[scriptName]) {
|
||||
consoleWarn(`Script '${scriptName}' in 'package.json' should be:
|
||||
"${SCRIPTS[scriptName].replace('\n', '\\n')}".`);
|
||||
}
|
||||
});
|
||||
|
||||
return packageJsonChanged;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check contributors
|
||||
*
|
||||
* @param packageJson package.json to check contributors in
|
||||
*/
|
||||
export function checkContributors(packageJson: any): void {
|
||||
const execBuffer = execSync('git log --format=\'%aN\' | sort -u');
|
||||
for (let author of execBuffer.toString().split('\n')) {
|
||||
author = author.trim();
|
||||
|
||||
if (author === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
let authorIsAttributed = false;
|
||||
|
||||
authorIsAttributed = authorIsAttributed
|
||||
|| (typeof packageJson.author === 'string' && packageJson.author.indexOf(author) >= 0)
|
||||
|| (Array.isArray(packageJson.contributors) && packageJson.contributors.find((contributor: string) => {
|
||||
return contributor.indexOf(author) >= 0;
|
||||
}));
|
||||
|
||||
if (!authorIsAttributed) {
|
||||
consoleWarn(`'${author}' should be attributed as author or contributor.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check CI config
|
||||
*
|
||||
* @param path Path to CI config
|
||||
*/
|
||||
export function checkCIConfig(path: string): void {
|
||||
// check CI config if it exists
|
||||
const pathToCiConfig = resolve(path, '.gitlab-ci.yml');
|
||||
if (existsSync(pathToCiConfig)) {
|
||||
// read CI config
|
||||
const buffer = readFileSync(pathToCiConfig);
|
||||
try {
|
||||
const ciConfig = parse(buffer.toString());
|
||||
|
||||
// check entries
|
||||
for (const entry in EXPECTED_CI_CONFIG) {
|
||||
if (!EXPECTED_CI_CONFIG.hasOwnProperty(entry)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isDeepStrictEqual(EXPECTED_CI_CONFIG[entry], ciConfig[entry])) {
|
||||
consoleWarn(`Entry '${entry}' in ${pathToCiConfig} is incorrect. Expected value is:`);
|
||||
consoleInfo(stringify((() => {
|
||||
const completeEntry: any = {};
|
||||
completeEntry[entry] = EXPECTED_CI_CONFIG[entry];
|
||||
return completeEntry;
|
||||
})()));
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
consoleWarn(`Could not parse ${pathToCiConfig} because of '${error.message}'.
|
||||
Please ensure consistency of CI config manually.`);
|
||||
consoleInfo(stringify(EXPECTED_CI_CONFIG));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user