fix(core): update

This commit is contained in:
2024-06-21 19:48:43 +02:00
commit 84a10a89de
109 changed files with 11639 additions and 0 deletions

8
ts/00_commitinfo_data.ts Normal file
View File

@@ -0,0 +1,8 @@
/**
* autocreated commitinfo by @pushrocks/commitinfo
*/
export const commitinfo = {
name: '@git.zone/cli',
version: '1.9.95',
description: 'A CLI toolbelt to streamline local development cycles by using various gitzone utilities.'
}

View File

@@ -0,0 +1,47 @@
import * as plugins from './plugins.js';
import * as paths from './paths.js';
export type TGitzoneProjectType = 'npm' | 'service' | 'wcc' | 'website';
/**
* type of the actual gitzone data
*/
export interface IGitzoneConfigData {
projectType: TGitzoneProjectType;
module: {
githost: string;
gitscope: string;
gitrepo: string;
description: string;
npmPackageName: string;
license: string;
projectDomain: string;
};
copy: {[key: string]: string}
npmciOptions: {
npmAccessLevel: 'public' | 'private';
};
}
/**
* gitzone config
*/
export class GitzoneConfig {
public static async fromCwd() {
const gitzoneConfig = new GitzoneConfig();
await gitzoneConfig.readConfigFromCwd();
return gitzoneConfig;
}
public data: IGitzoneConfigData;
public async readConfigFromCwd() {
const npmextraInstance = new plugins.npmextra.Npmextra(paths.cwd);
this.data = npmextraInstance.dataFor<IGitzoneConfigData>('gitzone', {});
this.data.npmciOptions = npmextraInstance.dataFor<IGitzoneConfigData['npmciOptions']>('npmci', {
npmAccessLevel: 'public',
});
}
constructor() {}
}

28
ts/classes.project.ts Normal file
View File

@@ -0,0 +1,28 @@
import * as plugins from './plugins.js'
import * as paths from './paths.js';
import { GitzoneConfig } from './classes.gitzoneconfig.js';
import type { TGitzoneProjectType } from './classes.gitzoneconfig.js';
/**
* the Project class is a tool to work with a gitzone project
*/
export class Project {
public static async fromCwd() {
const gitzoneConfig = await GitzoneConfig.fromCwd();
const project = new Project(gitzoneConfig);
if (!project.gitzoneConfig.data.projectType) {
throw new Error('Please define a project type');
}
return project;
}
public gitzoneConfig: GitzoneConfig;
public get type(): TGitzoneProjectType {
return this.gitzoneConfig.data.projectType;
}
constructor(gitzoneConfigArg: GitzoneConfig) {
this.gitzoneConfig = gitzoneConfigArg;
}
}

101
ts/gitzone.cli.ts Normal file
View File

@@ -0,0 +1,101 @@
import * as plugins from './plugins.js';
import * as paths from './paths.js';
import { GitzoneConfig } from './classes.gitzoneconfig.js';
const gitzoneSmartcli = new plugins.smartcli.Smartcli();
export let run = async () => {
const done = plugins.smartpromise.defer();
// get packageInfo
const projectInfo = new plugins.projectinfo.ProjectInfo(paths.packageDir);
// check for updates
const smartupdateInstance = new plugins.smartupdate.SmartUpdate();
await smartupdateInstance.check(
'gitzone',
projectInfo.npm.version,
'http://gitzone.gitlab.io/gitzone/changelog.html'
);
console.log('---------------------------------------------');
gitzoneSmartcli.addVersion(projectInfo.npm.version);
// ======> Standard task <======
/**
* standard task
*/
gitzoneSmartcli.standardCommand().subscribe(async (argvArg) => {
const modStandard = await import('./mod_standard/index.js');
await modStandard.run();
});
// ======> Specific tasks <======
/**
* commit something
*/
gitzoneSmartcli.addCommand('commit').subscribe(async (argvArg) => {
const modCommit = await import('./mod_commit/index.js');
await modCommit.run(argvArg);
});
/**
* deprecate a package on npm
*/
gitzoneSmartcli.addCommand('deprecate').subscribe(async (argvArg) => {
const modDeprecate = await import('./mod_deprecate/index.js');
await modDeprecate.run();
});
/**
* Update all files that comply with the gitzone standard
*/
gitzoneSmartcli.addCommand('format').subscribe(async (argvArg) => {
const config = GitzoneConfig.fromCwd();
const modFormat = await import('./mod_format/index.js');
await modFormat.run();
});
/**
* run meta commands
*/
gitzoneSmartcli.addCommand('meta').subscribe(async (argvArg) => {
const config = GitzoneConfig.fromCwd();
const modMeta = await import('./mod_meta/index.js');
modMeta.run(argvArg);
});
/**
* open assets
*/
gitzoneSmartcli.addCommand('open').subscribe(async (argvArg) => {
const modOpen = await import('./mod_open/index.js');
modOpen.run(argvArg);
});
/**
* add a readme to a project
*/
gitzoneSmartcli.addCommand('template').subscribe(async (argvArg) => {
const modTemplate = await import('./mod_template/index.js');
modTemplate.run(argvArg);
});
/**
* start working on a project
*/
gitzoneSmartcli.addCommand('start').subscribe(async (argvArg) => {
const modTemplate = await import('./mod_start/index.js');
modTemplate.run(argvArg);
});
gitzoneSmartcli.addCommand('helpers').subscribe(async (argvArg) => {
const modHelpers = await import('./mod_helpers/index.js');
modHelpers.run(argvArg);
});
// start parsing of the cli
gitzoneSmartcli.startParse();
return await done.promise;
};

15
ts/gitzone.logging.ts Normal file
View File

@@ -0,0 +1,15 @@
import * as plugins from './plugins.js';
export const logger = new plugins.smartlog.Smartlog({
minimumLogLevel: 'silly',
logContext: {
company: 'Task Venture Capital GmbH',
companyunit: 'Lossless Cloud',
containerName: 'local',
environment: 'local',
runtime: 'node',
zone: 'gitzone',
},
});
logger.addLogDestination(new plugins.smartlogDestinationLocal.DestinationLocal());

9
ts/index.ts Normal file
View File

@@ -0,0 +1,9 @@
export const runCli = async () => {
const early = await import('@push.rocks/early');
early.start('gitzone');
const plugins = await import('./plugins.js');
const gitzoneCli = await import('./gitzone.cli.js');
early.stop().then(() => {
gitzoneCli.run();
});
};

1
ts/mod_audit/index.ts Normal file
View File

@@ -0,0 +1 @@
import * as paths from '../paths.js';

73
ts/mod_commit/index.ts Normal file
View File

@@ -0,0 +1,73 @@
// this file contains code to create commits in a consistent way
import * as plugins from './mod.plugins.js';
import * as paths from '../paths.js';
import { logger } from '../gitzone.logging.js';
export const run = async (argvArg: any) => {
const commitInteract = new plugins.smartinteract.SmartInteract();
commitInteract.addQuestions([
{
type: 'list',
name: `commitType`,
message: `Choose TYPE of the commit:`,
choices: [`fix`, `feat`, `BREAKING CHANGE`],
default: `fix`,
},
{
type: 'input',
name: `commitScope`,
message: `What is the SCOPE of the commit:`,
default: `core`,
},
{
type: `input`,
name: `commitDescription`,
message: `What is the DESCRIPTION of the commit?`,
default: `update`,
},
{
type: 'confirm',
name: `pushToOrigin`,
message: `Do you want to push this version now?`,
default: true,
},
]);
const answerBucket = await commitInteract.runQueue();
const commitString = createCommitStringFromAnswerBucket(answerBucket);
const commitVersionType = (() => {
switch (answerBucket.getAnswerFor('commitType')) {
case 'fix':
return 'patch';
case 'feat':
return 'minor';
case 'BREAKING CHANGE':
return 'major';
}
})();
logger.log('info', `OK! Creating commit with message '${commitString}'`);
const smartshellInstance = new plugins.smartshell.Smartshell({
executor: 'bash',
sourceFilePaths: [],
});
logger.log('info', `Baking commitinfo into code`);
const commitInfo = new plugins.commitinfo.CommitInfo(paths.cwd, commitVersionType);
await commitInfo.writeIntoPotentialDirs();
logger.log('info', `Staging files for commit:`);
await smartshellInstance.exec(`git add -A`);
await smartshellInstance.exec(`git commit -m "${commitString}"`);
await smartshellInstance.exec(`npm version ${commitVersionType}`);
if (answerBucket.getAnswerFor('pushToOrigin') && !(process.env.CI === 'true')) {
await smartshellInstance.exec(`git push origin master --follow-tags`);
}
};
const createCommitStringFromAnswerBucket = (answerBucket: plugins.smartinteract.AnswerBucket) => {
const commitType = answerBucket.getAnswerFor('commitType');
const commitScope = answerBucket.getAnswerFor('commitScope');
const commitDescription = answerBucket.getAnswerFor('commitDescription');
return `${commitType}(${commitScope}): ${commitDescription}`;
};

View File

@@ -0,0 +1,7 @@
export * from '../plugins.js';
import * as commitinfo from '@push.rocks/commitinfo';
import * as smartinteract from '@push.rocks/smartinteract';
import * as smartshell from '@push.rocks/smartshell';
export { commitinfo, smartinteract, smartshell };

37
ts/mod_deprecate/index.ts Normal file
View File

@@ -0,0 +1,37 @@
import * as plugins from './mod.plugins.js';
import { logger } from '../gitzone.logging.js';
export const run = async () => {
const smartInteract = new plugins.smartinteract.SmartInteract([
{
name: `oldPackageName`,
message: `Whats the name of the OLD package?`,
type: `input`,
default: ``,
validate: (stringInput) => {
return stringInput !== '' && !process.env.CI;
},
},
{
name: `newPackageName`,
message: `Whats the name of the NEW package?`,
type: `input`,
default: ``,
validate: (stringInput) => {
return stringInput !== '' && !process.env.CI;
},
},
]);
const answerBucket = await smartInteract.runQueue();
const oldPackageName = answerBucket.getAnswerFor(`oldPackageName`);
const newPackageName = answerBucket.getAnswerFor(`newPackageName`);
logger.log('info', `Deprecating package ${oldPackageName} in favour of ${newPackageName}`);
const smartshellInstance = new plugins.smartshell.Smartshell({
executor: 'bash',
});
await smartshellInstance.exec(
`npm deprecate ${oldPackageName}@* ` +
`"${oldPackageName} has been deprecated in favour of ${newPackageName} - please upgrade asap!!!"`
);
};

View File

@@ -0,0 +1,6 @@
export * from '../plugins.js';
import * as smartinteract from '@push.rocks/smartinteract';
import * as smartshell from '@push.rocks/smartshell';
export { smartinteract, smartshell };

View File

@@ -0,0 +1,19 @@
import * as plugins from './mod.plugins.js';
import * as paths from '../paths.js';
import { logger } from '../gitzone.logging.js';
import { Project } from '../classes.project.js';
const filesToDelete = ['defaults.yml', 'yarn.lock', 'package-lock.json', 'tslint.json'];
export const run = async (projectArg: Project) => {
for (const relativeFilePath of filesToDelete) {
const fileExists = plugins.smartfile.fs.fileExistsSync(relativeFilePath);
if (fileExists) {
logger.log('info', `Found ${relativeFilePath}! Removing it!`);
plugins.smartfile.fs.removeSync(plugins.path.join(paths.cwd, relativeFilePath));
} else {
logger.log('info', `Project is free of ${relativeFilePath}`);
}
}
};

View File

@@ -0,0 +1,6 @@
import type { Project } from '../classes.project.js';
import * as plugins from '../plugins.js';
export const run = async (projectArg: Project) => {
const gitzoneConfig = await projectArg.gitzoneConfig;
}

View File

@@ -0,0 +1,21 @@
import * as plugins from './mod.plugins.js';
import * as paths from '../paths.js';
import { Project } from '../classes.project.js';
import { logger } from '../gitzone.logging.js';
const gitignorePath = plugins.path.join(paths.cwd, './.gitignore');
export const run = async (projectArg: Project) => {
const gitignoreExists = await plugins.smartfile.fs.fileExists(gitignorePath);
const templateModule = await import('../mod_template/index.js');
const ciTemplate = await templateModule.getTemplate('gitignore');
if (gitignoreExists) {
// lets get the existing gitignore file
const existingGitIgnoreString = plugins.smartfile.fs.toStringSync(gitignorePath);
let customPart = existingGitIgnoreString.split('# custom\n')[1];
customPart ? null : (customPart = '');
}
ciTemplate.writeToDisk(paths.cwd);
logger.log('info', 'Added a .gitignore!');
};

View File

@@ -0,0 +1,24 @@
import * as plugins from './mod.plugins.js';
import * as paths from '../paths.js';
import { Project } from '../classes.project.js';
import { logger } from '../gitzone.logging.js';
const incompatibleLicenses: string[] = [
"AGPL",
"GPL",
"SSPL",
];
export const run = async (projectArg: Project) => {
const licenseChecker = await plugins.smartlegal.createLicenseChecker();
const licenseCheckResult = await licenseChecker.excludeLicenseWithinPath(paths.cwd, incompatibleLicenses);
if (licenseCheckResult.failingModules.length === 0) {
logger.log('info', 'Success -> licenses passed!');
} else {
logger.log('error', 'Error -> licenses failed. Here is why:');
for (const failedModule of licenseCheckResult.failingModules) {
console.log(`${failedModule.name} fails with license ${failedModule.license}`);
}
}
};

View File

@@ -0,0 +1,70 @@
import * as plugins from './mod.plugins.js';
import * as paths from '../paths.js';
import * as gulpFunction from '@push.rocks/gulp-function';
import { Project } from '../classes.project.js';
/**
* runs the npmextra file checking
*/
export const run = async (projectArg: Project) => {
const formatSmartstream = new plugins.smartstream.StreamWrapper([
plugins.smartgulp.src([`npmextra.json`]),
gulpFunction.forEach(async (fileArg: plugins.smartfile.SmartFile) => {
const fileString = fileArg.contents.toString();
const npmextraJson = JSON.parse(fileString);
if (!npmextraJson.gitzone) {
npmextraJson.gitzone = {};
}
const expectedRepoInformation: string[] = [
'projectType',
'module.githost',
'module.gitscope',
'module.gitrepo',
'module.description',
'module.npmPackagename',
'module.license',
];
const interactInstance = new plugins.smartinteract.SmartInteract();
for (const expectedRepoInformationItem of expectedRepoInformation) {
if (!plugins.smartobject.smartGet(npmextraJson.gitzone, expectedRepoInformationItem)) {
interactInstance.addQuestions([
{
message: `What is the value of ${expectedRepoInformationItem}`,
name: expectedRepoInformationItem,
type: 'input',
default: 'undefined variable',
},
]);
}
}
const answerbucket = await interactInstance.runQueue();
for (const expectedRepoInformationItem of expectedRepoInformation) {
const cliProvidedValue = answerbucket.getAnswerFor(expectedRepoInformationItem);
if (cliProvidedValue) {
plugins.smartobject.smartAdd(
npmextraJson.gitzone,
expectedRepoInformationItem,
cliProvidedValue
);
}
}
// delete obsolete
// tbd
if (!npmextraJson.npmci) {
npmextraJson.npmci = {};
}
fileArg.setContentsFromString(JSON.stringify(npmextraJson, null, 2));
}),
plugins.smartgulp.replace(),
]);
await formatSmartstream.run().catch((error) => {
console.log(error);
});
};

View File

@@ -0,0 +1,120 @@
import * as plugins from './mod.plugins.js';
import * as paths from '../paths.js';
import * as gulpFunction from '@push.rocks/gulp-function';
import { Project } from '../classes.project.js';
import { logger } from '../gitzone.logging.js';
/**
* ensures a certain dependency
*/
const ensureDependency = async (
packageJsonObjectArg: any,
position: 'dep' | 'devDep' | 'everywhere',
constraint: 'exclude' | 'include' | 'latest',
dependencyArg: string
) => {};
export const run = async (projectArg: Project) => {
const formatStreamWrapper = new plugins.smartstream.StreamWrapper([
plugins.smartgulp.src([`package.json`]),
gulpFunction.forEach(async (fileArg: plugins.smartfile.SmartFile) => {
const npmextraConfig = new plugins.npmextra.Npmextra(paths.cwd);
const gitzoneData: any = npmextraConfig.dataFor('gitzone', {});
const fileString = fileArg.contents.toString();
const packageJson = JSON.parse(fileString);
// metadata
packageJson.repository = {
"type": "git",
"url": `git+https://${gitzoneData.module.githost}/${gitzoneData.module.gitscope}/${gitzoneData.module.gitrepo}.git`
};
packageJson.bugs = {
"url": `https://${gitzoneData.module.githost}/${gitzoneData.module.gitscope}/${gitzoneData.module.gitrepo}/issues`
},
packageJson.homepage = `https://${gitzoneData.module.githost}/${gitzoneData.module.gitscope}/${gitzoneData.module.gitrepo}#readme`;
// Check for module type
if (!packageJson.type) {
logger.log('info', `setting packageJson.type to "module"`);
packageJson.type = 'module';
}
// Check for private or public
if (packageJson.private !== undefined) {
logger.log('info', 'Success -> found private/public info in package.json!');
} else {
logger.log('error', 'found no private boolean! Setting it to private for now!');
packageJson.private = true;
}
// Check for license
if (packageJson.license) {
logger.log('info', 'Success -> found license in package.json!');
} else {
logger.log('error', 'found no license! Setting it to UNLICENSED for now!');
packageJson.license = 'UNLICENSED';
}
// Check for build script
if (packageJson.scripts.build) {
logger.log('info', 'Success -> found build script in package.json!');
} else {
logger.log('error', 'found no build script! Putting a placeholder there for now!');
packageJson.scripts.build = `echo "Not needed for now"`;
}
// Check for buildDocs script
if (!packageJson.scripts.buildDocs) {
logger.log('info', 'found no buildDocs script! Putting tsdoc script there now.');
packageJson.scripts.buildDocs = `tsdoc`;
}
// check package.json
if (!packageJson.main) {
logger.log('error', 'no "main" property');
process.exit(0);
}
if (!packageJson.typings) {
logger.log('error', 'no "typings" property');
process.exit(0);
}
if (!packageJson.browserslist) {
packageJson.browserslist = ['last 1 chrome versions'];
}
if (!packageJson.main.includes('dist_') || !packageJson.typings.includes('dist_')) {
logger.log('error', 'check packagesJson main and typings');
process.exit(0);
}
// check for files
packageJson.files = [
'ts/**/*',
'ts_web/**/*',
'dist/**/*',
'dist_*/**/*',
'dist_ts/**/*',
'dist_ts_web/**/*',
'assets/**/*',
'cli.js',
'npmextra.json',
'readme.md',
];
// check for dependencies
await ensureDependency(packageJson, 'devDep', 'latest', '@push.rocks/tapbundle');
await ensureDependency(packageJson, 'devDep', 'latest', '@git.zone/tstest');
await ensureDependency(packageJson, 'devDep', 'latest', '@git.zone/tsbuild');
// exclude
// TODO
fileArg.setContentsFromString(JSON.stringify(packageJson, null, 2));
}),
plugins.smartgulp.replace(),
]);
await formatStreamWrapper.run().catch((error) => {
console.log(error);
});
};

View File

@@ -0,0 +1,58 @@
import * as plugins from './mod.plugins.js';
import prettier from 'prettier';
import { Project } from '../classes.project.js';
import { logger } from '../gitzone.logging.js';
const prettierDefaultTypeScriptConfig: prettier.Options = {
printWidth: 100,
parser: 'typescript',
singleQuote: true,
};
const prettierDefaultMarkdownConfig: prettier.Options = {
singleQuote: true,
printWidth: 100,
parser: 'markdown',
};
const filesToFormat = [`ts/**/*.ts`, `test/**/*.ts`, `readme.md`, `docs/**/*.md`];
const choosePrettierConfig = (fileArg: plugins.smartfile.SmartFile) => {
switch (fileArg.parsedPath.ext) {
case '.ts':
return prettierDefaultTypeScriptConfig;
case '.md':
return prettierDefaultMarkdownConfig;
default:
return {};
}
};
const prettierTypeScriptPipestop = plugins.through2.obj(
async (fileArg: plugins.smartfile.SmartFile, enc, cb) => {
const fileString = fileArg.contentBuffer.toString();
const chosenConfig = choosePrettierConfig(fileArg);
const filePasses = prettier.check(fileString, chosenConfig);
if (filePasses) {
logger.log('info', `OK! -> ${fileArg.path} passes!`);
cb(null);
} else {
logger.log('info', `${fileArg.path} is being reformated!`);
const formatedFileString = await prettier.format(fileString, chosenConfig);
fileArg.setContentsFromString(formatedFileString);
cb(null, fileArg);
}
}
);
export const run = async (projectArg: Project) => {
const formatStreamWrapper = new plugins.smartstream.StreamWrapper([
plugins.smartgulp.src(filesToFormat),
prettierTypeScriptPipestop,
plugins.smartgulp.replace(),
]);
await formatStreamWrapper.run().catch((error) => {
console.log(error);
});
};

View File

@@ -0,0 +1,47 @@
import * as plugins from './mod.plugins.js';
import * as paths from '../paths.js';
import { GitzoneConfig } from '../classes.gitzoneconfig.js';
import { Project } from '../classes.project.js';
export const run = async (projectArg: Project) => {
const readmePath = plugins.path.join(paths.cwd, 'readme.md');
const readmeFile = await plugins.smartfile.SmartFile.fromFilePath(readmePath);
// lets do our transformation
let usageInfo: string = '';
const gitzoneConfig = await GitzoneConfig.fromCwd();
if (readmeFile) {
const readmeFileString = readmeFile.contentBuffer.toString();
const stringArray1 = readmeFileString.split('## Usage\n');
if (stringArray1[1]) {
const stringArray2 = stringArray1[1].split(
'\nFor further information read the linked docs at the top of this readme.'
);
const stringArray3 = stringArray2[0].split('\n\n## Contribution');
usageInfo = stringArray3[0];
}
}
if (gitzoneConfig.data.module && gitzoneConfig.data.module.license === 'MIT') {
usageInfo +=
'\n\n## Contribution\n\n' +
'We are always happy for code contributions. If you are not the code contributing type that is ok. ' +
'Still, maintaining Open Source repositories takes considerable time and thought. ' +
'If you like the quality of what we do and our modules are useful to you we would appreciate a little monthly contribution: ' +
'You can [contribute one time](https://lossless.link/contribute-onetime) or [contribute monthly](https://lossless.link/contribute). :)\n';
}
const templateModule = await import('../mod_template/index.js');
const readmeTemplate = await templateModule.getTemplate('readme');
console.log(gitzoneConfig.data);
await readmeTemplate.supplyVariables({
module: {
...gitzoneConfig.data.module,
},
usageInfo,
});
await readmeTemplate.askCliForMissingVariables();
await readmeTemplate.writeToDisk(paths.cwd);
};

View File

@@ -0,0 +1,71 @@
import * as plugins from './mod.plugins.js';
import * as paths from '../paths.js';
import { logger } from '../gitzone.logging.js';
import { Project } from '../classes.project.js';
/**
* takes care of updating files from templates
*/
export const run = async (project: Project) => {
const templateModule = await import('../mod_template/index.js');
// update tslint
// getting template
const tslintTemplate = await templateModule.getTemplate('tslint');
await tslintTemplate.writeToDisk(paths.cwd);
logger.log('info', 'Updated tslint.json!');
// update vscode
const vscodeTemplate = await templateModule.getTemplate('vscode');
await vscodeTemplate.writeToDisk(paths.cwd);
logger.log('info', `Updated vscode template!`);
// update gitlab ci and Dockerfile
switch (project.gitzoneConfig.data.projectType) {
case 'npm':
case 'wcc':
if (project.gitzoneConfig.data.npmciOptions.npmAccessLevel === 'public') {
const ciTemplateDefault = await templateModule.getTemplate('ci_default');
ciTemplateDefault.writeToDisk(paths.cwd);
} else {
const ciTemplateDefault = await templateModule.getTemplate('ci_default_private');
ciTemplateDefault.writeToDisk(paths.cwd);
}
logger.log('info', 'Updated .gitlabci.yml!');
break;
case 'service':
case 'website':
const ciTemplateDocker = await templateModule.getTemplate('ci_docker');
await ciTemplateDocker.writeToDisk(paths.cwd);
logger.log('info', 'Updated .gitlabci.yml!');
// lets care about docker
const dockerTemplate = await templateModule.getTemplate('dockerfile_service');
dockerTemplate.writeToDisk(paths.cwd);
logger.log('info', 'Updated Dockerfile!');
// lets care about cli
const cliTemplate = await templateModule.getTemplate('cli');
await cliTemplate.writeToDisk(paths.cwd);
logger.log('info', 'Updated cli.ts.js and cli.js!');
break;
default:
break;
}
// update html
if (project.gitzoneConfig.data.projectType === 'website') {
const websiteUpdateTemplate = await templateModule.getTemplate('website_update');
await websiteUpdateTemplate.writeToDisk(paths.cwd);
logger.log('info', `Updated html for website!`);
} else if (project.gitzoneConfig.data.projectType === 'service') {
const websiteUpdateTemplate = await templateModule.getTemplate('service_update');
await websiteUpdateTemplate.writeToDisk(paths.cwd);
logger.log('info', `Updated html for element template!`);
} else if (project.gitzoneConfig.data.projectType === 'wcc') {
const wccUpdateTemplate = await templateModule.getTemplate('wcc_update');
await wccUpdateTemplate.writeToDisk(paths.cwd);
logger.log('info', `Updated html for wcc template!`);
}
};

38
ts/mod_format/index.ts Normal file
View File

@@ -0,0 +1,38 @@
import * as plugins from './mod.plugins.js';
import { Project } from '../classes.project.js';
export let run = async (write: boolean = true): Promise<any> => {
const project = await Project.fromCwd();
// cleanup
const formatCleanup = await import('./format.cleanup.js');
await formatCleanup.run(project);
// npmextra
const formatNpmextra = await import('./format.npmextra.js');
await formatNpmextra.run(project);
// license
const formatLicense = await import('./format.license.js');
await formatLicense.run(project);
// format package.json
const formatPackageJson = await import('./format.packagejson.js');
await formatPackageJson.run(project);
// format .gitlab-ci.yml
const formatTemplates = await import('./format.templates.js');
await formatTemplates.run(project);
// format .gitignore
const formatGitignore = await import('./format.gitignore.js');
await formatGitignore.run(project);
// format TypeScript
const formatPrettier = await import('./format.prettier.js');
await formatPrettier.run(project);
// format readme.md
const formatReadme = await import('./format.readme.js');
// await formatReadme.run();
};

View File

@@ -0,0 +1,13 @@
export * from '../plugins.js';
import * as lik from '@push.rocks/lik';
import * as smartfile from '@push.rocks/smartfile';
import * as smartgulp from '@push.rocks/smartgulp';
import * as smartinteract from '@push.rocks/smartinteract';
import * as smartlegal from '@push.rocks/smartlegal';
import * as smartobject from '@push.rocks/smartobject';
import * as smartnpm from '@push.rocks/smartnpm';
import * as smartstream from '@push.rocks/smartstream';
import * as through2 from 'through2';
export { lik, smartfile, smartgulp, smartinteract, smartlegal, smartobject, smartnpm, smartstream, through2 };

10
ts/mod_helpers/index.ts Normal file
View File

@@ -0,0 +1,10 @@
import * as plugins from './mod.plugins.js';
export const run = async (argvArg) => {
const command = argvArg._[1];
switch (command) {
case 'shortid':
console.log('Here is new shortid');
console.log(plugins.smartunique.shortId());
}
};

View File

@@ -0,0 +1,5 @@
export * from '../plugins.js';
import * as smartunique from '@push.rocks/smartunique';
export { smartunique };

26
ts/mod_meta/index.ts Normal file
View File

@@ -0,0 +1,26 @@
import * as plugins from './meta.plugins.js';
import * as paths from '../paths.js';
import { Meta } from './meta.classes.meta.js';
import { logger } from '../gitzone.logging.js';
export const run = async (argvArg) => {
const command = argvArg._[1];
const metaInstance = new Meta(paths.cwd);
switch (true) {
case command === 'update':
await metaInstance.updateLocalRepos();
break;
case command === 'add':
await metaInstance.addProject(argvArg._[2], argvArg._[3]);
break;
case command === 'remove':
await metaInstance.removeProject(argvArg._[2]);
break;
case command === 'init':
await metaInstance.initProject();
break;
default:
logger.log('error', `You have to specify a command!`);
}
};

View File

@@ -0,0 +1,234 @@
import * as plugins from './meta.plugins.js';
import * as paths from '../paths.js';
import * as interfaces from './meta.interfaces.js';
import { logger } from '../gitzone.logging.js';
export class Meta {
public cwd: string;
public dirName: string;
public filePaths: {
metaJson: string;
gitIgnore: string;
packageJson: string;
};
constructor(cwdArg: string) {
this.cwd = cwdArg;
this.dirName = plugins.path.basename(this.cwd);
this.filePaths = {
metaJson: plugins.path.join(this.cwd, './.meta.json'),
gitIgnore: plugins.path.join(this.cwd, './.gitignore'),
packageJson: plugins.path.join(this.cwd, './package.json'),
};
}
/**
* the meta repo data
*/
public metaRepoData: interfaces.IMetaRepoData;
public smartshellInstance = new plugins.smartshell.Smartshell({
executor: 'bash',
});
/**
* sorts the metaRepoData
*/
public async sortMetaRepoData() {
const stringifiedMetadata = plugins.smartjson.stringify(this.metaRepoData, []);
this.metaRepoData = plugins.smartjson.parse(stringifiedMetadata);
}
/**
* reads the meta file from disk
*/
public async readDirectory() {
await this.syncToRemote(true);
logger.log('info', `reading directory`);
const metaFileExists = plugins.smartfile.fs.fileExistsSync(this.filePaths.metaJson);
if (!metaFileExists) {
throw new Error(`meta file does not exist at ${this.filePaths.metaJson}`);
}
this.metaRepoData = plugins.smartfile.fs.toObjectSync(this.filePaths.metaJson);
}
/**
* generates the gitignore file and stores it on disk
*/
public async generateGitignore(): Promise<string> {
await this.sortMetaRepoData();
let gitignoreString = `# ignored repo directories\n`;
gitignoreString += `.nogit/\n`;
gitignoreString += `.pnpm-store/\n`;
for (const key of Object.keys(this.metaRepoData.projects)) {
gitignoreString = `${gitignoreString}${key}\n`;
}
return gitignoreString;
}
/**
* write to disk
*/
public async writeToDisk() {
// write .meta.json to disk
plugins.smartfile.memory.toFsSync(
JSON.stringify(this.metaRepoData, null, 2),
this.filePaths.metaJson
);
// write .gitignore to disk
plugins.smartfile.memory.toFsSync(await this.generateGitignore(), this.filePaths.gitIgnore);
}
/**
* push to remote
*/
public async syncToRemote(gitCleanArg = false) {
logger.log('info', `syncing from origin master`);
await this.smartshellInstance.exec(`cd ${this.cwd} && git pull origin master`);
if (gitCleanArg) {
logger.log('info', `cleaning the repository from old directories`);
await this.smartshellInstance.exec(`cd ${this.cwd} && git clean -fd`);
}
logger.log('info', `syncing to remote origin master`);
await this.smartshellInstance.exec(`cd ${this.cwd} && git push origin master`);
}
/**
* update the locally cloned repositories
*/
public async updateLocalRepos() {
await this.syncToRemote();
const projects = plugins.smartfile.fs.toObjectSync(this.filePaths.metaJson).projects;
const preExistingFolders = plugins.smartfile.fs.listFoldersSync(this.cwd);
for (const preExistingFolderArg of preExistingFolders) {
if (
preExistingFolderArg !== '.git' &&
!Object.keys(projects).find((projectFolder) =>
projectFolder.startsWith(preExistingFolderArg)
)
) {
const response = await plugins.smartinteraction.SmartInteract.getCliConfirmation(
`Do you want to delete superfluous directory >>${preExistingFolderArg}<< ?`,
true
);
if (response) {
logger.log('warn', `Deleting >>${preExistingFolderArg}<<!`);
} else {
logger.log('warn', `Not deleting ${preExistingFolderArg} by request!`);
}
}
}
await this.readDirectory();
await this.sortMetaRepoData();
const missingRepos: string[] = [];
for (const key of Object.keys(this.metaRepoData.projects)) {
plugins.smartfile.fs.isDirectory(key)
? logger.log('ok', `${key} -> is already cloned`)
: missingRepos.push(key);
}
logger.log('info', `found ${missingRepos.length} missing repos`);
for (const missingRepo of missingRepos) {
await this.smartshellInstance.exec(
`cd ${this.cwd} && git clone ${this.metaRepoData.projects[missingRepo]} ${missingRepo}`
);
}
logger.log('info', `write changes to disk`);
await this.writeToDisk();
logger.log('info', `persist changes with a git commit`);
await this.smartshellInstance.exec(
`cd ${this.cwd} && git add -A && git commit -m "updated structure"`
);
await this.syncToRemote();
// go recursive
const folders = await plugins.smartfile.fs.listFolders(this.cwd);
const childMetaRepositories: string[] = [];
for (const folder of folders) {
logger.log('info', folder);
}
console.log('Recursion still needs to be implemented');
}
// project manipulation
/**
* init a new meta project
*/
public async initProject() {
await this.syncToRemote(true);
const fileExists = await plugins.smartfile.fs.fileExists(this.filePaths.metaJson);
if (!fileExists) {
await plugins.smartfile.memory.toFs(
JSON.stringify({
projects: {},
}),
this.filePaths.metaJson
);
logger.log(`success`, `created a new .meta.json in directory ${this.cwd}`);
await plugins.smartfile.memory.toFs(
JSON.stringify({
name: this.dirName,
version: '1.0.0',
}),
this.filePaths.packageJson
);
logger.log(`success`, `created a new package.json in directory ${this.cwd}`);
} else {
logger.log(`error`, `directory ${this.cwd} already has a .metaJson file. Doing nothing.`);
}
await this.smartshellInstance.exec(
`cd ${this.cwd} && git add -A && git commit -m "feat(project): init meta project for ${this.dirName}"`
);
await this.updateLocalRepos();
}
/**
* adds a project
*/
public async addProject(projectNameArg: string, gitUrlArg) {
await this.readDirectory();
const existingProject = this.metaRepoData.projects[projectNameArg];
if (existingProject) {
throw new Error('Project already exists! Please remove it first before adding it again.');
}
this.metaRepoData.projects[projectNameArg] = gitUrlArg;
await this.sortMetaRepoData();
await this.writeToDisk();
await this.smartshellInstance.exec(
`cd ${this.cwd} && git add -A && git commit -m "feat(project): add ${projectNameArg}"`
);
await this.updateLocalRepos();
}
/**
* removes a project
*/
public async removeProject(projectNameArg: string) {
await this.readDirectory();
const existingProject = this.metaRepoData.projects[projectNameArg];
if (!existingProject) {
logger.log('error', `Project ${projectNameArg} does not exist! So it cannot be removed`);
return;
}
delete this.metaRepoData.projects[projectNameArg];
logger.log('info', 'removing project from .meta.json');
await this.sortMetaRepoData();
await this.writeToDisk();
logger.log('info', 'removing directory from cwd');
await plugins.smartfile.fs.remove(plugins.path.join(paths.cwd, projectNameArg));
await this.updateLocalRepos();
}
}

View File

@@ -0,0 +1,3 @@
export interface IMetaRepoData {
projects: { [key: string]: string };
}

View File

@@ -0,0 +1,8 @@
export * from '../plugins.js';
import * as smartfile from '@push.rocks/smartfile';
import * as smartinteraction from '@push.rocks/smartinteract';
import * as smartjson from '@push.rocks/smartjson';
import * as smartshell from '@push.rocks/smartshell';
export { smartfile, smartinteraction, smartjson, smartshell };

15
ts/mod_open/index.ts Normal file
View File

@@ -0,0 +1,15 @@
import * as plugins from './mod.plugins.js';
import * as paths from '../paths.js';
export let run = (argvArg) => {
let projectInfo = new plugins.projectinfo.ProjectInfo(paths.cwd);
if (argvArg._[1] === 'ci') {
plugins.smartopen.openUrl(
`https://gitlab.com/${projectInfo.git.gituser}/${projectInfo.git.gitrepo}/settings/ci_cd`
);
} else if (argvArg._[1] === 'pipelines') {
plugins.smartopen.openUrl(
`https://gitlab.com/${projectInfo.git.gituser}/${projectInfo.git.gitrepo}/pipelines`
);
}
};

View File

@@ -0,0 +1,5 @@
export * from '../plugins.js';
import * as smartopen from '@push.rocks/smartopen';
import * as projectinfo from '@push.rocks/projectinfo';
export { projectinfo, smartopen };

29
ts/mod_standard/index.ts Normal file
View File

@@ -0,0 +1,29 @@
/* -----------------------------------------------
* executes as standard task
* ----------------------------------------------- */
import * as plugins from './mod.plugins.js';
import * as paths from '../paths.js';
import { logger } from '../gitzone.logging.js';
export let run = () => {
const done = plugins.smartpromise.defer();
logger.log('warn', 'no action specified');
logger.log(
'info',
`
You can do one of the following things:
* create a new project with 'gitzone template [template]'
the following templates exist: ${(() => {
let projects = `\n`;
for (const template of plugins.smartfile.fs.listFoldersSync(paths.templatesDir)) {
projects += ` - ${template}\n`;
}
return projects;
})()}
* format a project with 'gitzone format'
`
);
done.resolve();
return done.promise;
};

View File

@@ -0,0 +1,4 @@
export * from '../plugins.js';
import * as smartfile from '@push.rocks/smartfile';
export { smartfile };

26
ts/mod_start/index.ts Normal file
View File

@@ -0,0 +1,26 @@
import * as plugins from './mod.plugins.js';
import * as paths from '../paths.js';
import { logger } from '../gitzone.logging.js';
/**
* executes basic project setup for continuing to work.
* TODO: switch to smartgit
* @param argvArg
*/
export const run = async (argvArg: any) => {
logger.log('info', `preparing the project at ${paths.cwd} for development`);
const smartshellInstance = new plugins.smartshell.Smartshell({
executor: 'bash',
});
await smartshellInstance.execStrict(`cd ${paths.cwd} && git checkout master`);
await smartshellInstance.execStrict(`cd ${paths.cwd} && git pull origin master`);
await smartshellInstance.execStrict(`cd ${paths.cwd} && npm ci`);
await provideNoGitFiles();
};
const provideNoGitFiles = async () => {
logger.log('warn', 'nogit provision not yet implemented!');
};

View File

@@ -0,0 +1,6 @@
export * from '../plugins.js';
// pushrocks scope
import * as smartshell from '@push.rocks/smartshell';
export { smartshell };

52
ts/mod_template/index.ts Normal file
View File

@@ -0,0 +1,52 @@
import * as plugins from './mod.plugins.js';
import * as paths from '../paths.js';
import { logger } from '../gitzone.logging.js';
export const getTemplatePath = (templateNameArg: string) => {
return plugins.path.join(paths.templatesDir, templateNameArg);
};
/**
* receives a template name and returns wether there is a corresponding template
*/
export const isTemplate = async (templateNameArg: string) => {
return plugins.smartfile.fs.isDirectory(getTemplatePath(templateNameArg));
};
export const getTemplate = async (templateNameArg: string) => {
if (isTemplate(templateNameArg)) {
const localScafTemplate = new plugins.smartscaf.ScafTemplate(getTemplatePath(templateNameArg));
await localScafTemplate.readTemplateFromDir();
return localScafTemplate;
} else {
return null;
}
};
export const run = async (argvArg: any) => {
let chosenTemplate: string = argvArg._[1];
if (!chosenTemplate) {
const smartinteract = new plugins.smartinteract.SmartInteract();
const answerBucket = await smartinteract.askQuestion({
type: 'list',
default: 'npm',
message: 'What template do you want to scaffold? (Only showing mpost common options)',
name: 'templateName',
choices: ['npm', 'service', 'wcc', 'website'],
});
chosenTemplate = answerBucket.value;
}
if (await isTemplate(chosenTemplate)) {
logger.log('info', `found requested template ${chosenTemplate}`);
} else {
logger.log('error', `Template ${chosenTemplate} not available`);
return;
}
const localScafTemplate = await getTemplate(chosenTemplate);
await localScafTemplate.askCliForMissingVariables();
await localScafTemplate.writeToDisk(paths.cwd);
};

View File

@@ -0,0 +1,7 @@
export * from '../plugins.js';
import * as smartfile from '@push.rocks/smartfile';
import * as smartinteract from '@push.rocks/smartinteract';
import * as smartscaf from '@push.rocks/smartscaf';
export { smartfile, smartinteract, smartscaf };

9
ts/paths.ts Normal file
View File

@@ -0,0 +1,9 @@
import * as plugins from './plugins.js';
export let packageDir = plugins.path.join(
plugins.smartpath.get.dirnameFromImportMetaUrl(import.meta.url),
'../'
);
export let assetsDir = plugins.path.join(packageDir, './assets');
export let templatesDir = plugins.path.join(assetsDir, 'templates');
export let cwd = process.cwd();

21
ts/plugins.ts Normal file
View File

@@ -0,0 +1,21 @@
import * as smartlog from '@push.rocks/smartlog';
import * as smartlogDestinationLocal from '@push.rocks/smartlog-destination-local';
import * as npmextra from '@push.rocks/npmextra';
import * as path from 'path';
import * as projectinfo from '@push.rocks/projectinfo';
import * as smartcli from '@push.rocks/smartcli';
import * as smartpath from '@push.rocks/smartpath';
import * as smartpromise from '@push.rocks/smartpromise';
import * as smartupdate from '@push.rocks/smartupdate';
export {
smartlog,
smartlogDestinationLocal,
npmextra,
path,
projectinfo,
smartcli,
smartpath,
smartpromise,
smartupdate,
};