feat: introduce sparo-lib

This commit is contained in:
Cheng Liu 2024-02-21 10:56:19 -08:00
parent c48b5c0cec
commit 9765cdc30f
No known key found for this signature in database
GPG key ID: EEC8452F7DB85CD6
56 changed files with 305 additions and 107 deletions

View file

@ -0,0 +1,19 @@
// This is a workaround for https://github.com/eslint/eslint/issues/3458
require('@rushstack/heft-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution');
// This is a workaround for https://github.com/microsoft/rushstack/issues/3021
require('@rushstack/heft-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names');
module.exports = {
extends: [
'@rushstack/heft-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool',
'@rushstack/heft-node-rig/profiles/default/includes/eslint/mixins/friendly-locals'
],
parserOptions: { tsconfigRootDir: __dirname },
overrides: [
{
files: ['*.ts', '*.tsx'],
rules: {}
}
]
};

32
apps/sparo-lib/.npmignore Normal file
View file

@ -0,0 +1,32 @@
# THIS IS A STANDARD TEMPLATE FOR .npmignore FILES IN THIS REPO.
# Ignore all files by default, to avoid accidentally publishing unintended files.
*
# Use negative patterns to bring back the specific things we want to publish.
!/bin/**
!/lib/**
!/lib-*/**
!/dist/**
!ThirdPartyNotice.txt
# Ignore certain patterns that should not get published.
/dist/*.stats.*
/lib/**/test/
/lib-*/**/test/
*.test.js
# NOTE: These don't need to be specified, because NPM includes them automatically.
#
# package.json
# README (and its variants)
# CHANGELOG (and its variants)
# LICENSE / LICENCE
#--------------------------------------------
# DO NOT MODIFY THE TEMPLATE ABOVE THIS LINE
#--------------------------------------------
# (Add your project-specific overrides here)
!/assets/**
/lib-*/**

21
apps/sparo-lib/LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) TikTok Pte. Ltd.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

6
apps/sparo-lib/README.md Normal file
View file

@ -0,0 +1,6 @@
## sparo-lib
This is a companion package for the Sparo tool.
The **sparo-lib** version number is always exactly equal
to the **sparo** version number that it depends on.

View file

@ -0,0 +1,19 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
"mainEntryPointFilePath": "<projectFolder>/lib/index.d.ts",
"apiReport": {
"enabled": true,
"reportFolder": "../../../common/reviews/api"
},
"docModel": {
"enabled": true,
"apiJsonFilePath": "../../../common/temp/api/<unscopedPackageName>.api.json"
},
"dtsRollup": {
"enabled": true
}
}

View file

@ -0,0 +1,3 @@
{
"extends": "@rushstack/heft-node-rig/profiles/default/config/jest.config.json"
}

View file

@ -0,0 +1,5 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
"rigPackageName": "@rushstack/heft-node-rig"
}

View file

@ -0,0 +1,31 @@
{
"name": "sparo-lib",
"version": "0.0.0",
"description": "A library for writing scripts that interact with the Sparo",
"license": "MIT",
"main": "lib/index.js",
"typings": "dist/sparo-lib.d.ts",
"scripts": {
"_phase:build": "heft run --only build -- --clean",
"_phase:test": "heft run --only test -- --clean",
"test": "heft test --clean",
"build": "heft build --clean"
},
"dependencies": {
"@rushstack/node-core-library": "~3.64.2",
"git-repo-info": "~2.1.1",
"inversify": "~6.0.2",
"reflect-metadata": "~0.2.1",
"winston": "~3.11.0",
"yargs": "~17.7.2"
},
"devDependencies": {
"@rushstack/heft": "0.64.3",
"@rushstack/heft-node-rig": "2.4.5",
"@types/heft-jest": "1.0.6",
"@types/node": "20.11.16",
"@types/yargs": "17.0.32",
"eslint": "8.56.0",
"typescript": "~5.3.3"
}
}

View file

@ -0,0 +1,19 @@
import { SparoCommandLine } from '../cli/SparoCommandLine';
import { SparoCICommandLine } from '../cli/SparoCICommandLine';
/**
* General operations for Sparo engine.
*
* @public
*/
export class Sparo {
private constructor() {}
public static async launchSparoAsync(): Promise<void> {
await SparoCommandLine.launchAsync();
}
public static async launchSparoCIAsync(): Promise<void> {
await SparoCICommandLine.launchAsync();
}
}

View file

@ -1,18 +1,21 @@
import 'reflect-metadata';
import { getFromContainer, registerClass } from '../di/container';
import { CommandService } from '../services/CommandService';
import { CI_COMMAND_LIST } from '../commands/cmd-list';
import { ICommand } from '../commands/base';
import { CI_COMMAND_LIST } from './commands/cmd-list';
import { ICommand } from './commands/base';
import { ArgvService } from '../services/ArgvService';
import { CIHelpCommand } from '../commands/ci-help';
import { CIHelpCommand } from './commands/ci-help';
import { GitVersionCompatibility } from '../logic/GitVersionCompatibility';
class SparoCI {
export class SparoCICommandLine {
private _commandsMap: Set<string> = new Set<string>();
private constructor() {}
public static async launchAsync(): Promise<void> {
const sparoCI: SparoCI = new SparoCI();
await GitVersionCompatibility.ensureGitVersionAsync();
const sparoCI: SparoCICommandLine = new SparoCICommandLine();
await sparoCI.prepareCommandAsync();
await sparoCI.runAsync();
}
@ -45,5 +48,3 @@ class SparoCI {
return this._commandsMap.has(commandName);
}
}
export { SparoCI };

View file

@ -3,17 +3,20 @@ import { getFromContainer, registerClass } from '../di/container';
import { GitService } from '../services/GitService';
import { CommandService } from '../services/CommandService';
import { ArgvService } from '../services/ArgvService';
import { COMMAND_LIST } from '../commands/cmd-list';
import { HelpCommand } from '../commands/help';
import { ICommand } from '../commands/base';
import { COMMAND_LIST } from './commands/cmd-list';
import { HelpCommand } from './commands/help';
import { ICommand } from './commands/base';
import { GitVersionCompatibility } from '../logic/GitVersionCompatibility';
class Sparo {
export class SparoCommandLine {
private _commandsMap: Set<string> = new Set<string>();
private constructor() {}
public static async launchAsync(): Promise<void> {
const sparo: Sparo = new Sparo();
await GitVersionCompatibility.ensureGitVersionAsync();
const sparo: SparoCommandLine = new SparoCommandLine();
await sparo.prepareCommandAsync();
await sparo.runAsync();
}
@ -54,5 +57,3 @@ class Sparo {
return this._commandsMap.has(commandName);
}
}
export { Sparo };

View file

@ -1,9 +1,9 @@
import { Argv } from 'yargs';
import { Command } from '../decorator';
import { Command } from '../../decorator';
import { inject } from 'inversify';
import { GitService } from '../services/GitService';
import { GitService } from '../../services/GitService';
import type { ArgumentsCamelCase } from 'yargs';
import type { LogService } from '../services/LogService';
import type { LogService } from '../../services/LogService';
import type { ICommand } from './base';
import type { GitRepoInfo } from 'git-repo-info';

View file

@ -1,5 +1,5 @@
import type { Argv, ArgumentsCamelCase } from 'yargs';
import type { LogService } from '../services/LogService';
import type { LogService } from '../../services/LogService';
export interface ICommand<O extends {}> {
/**

View file

@ -1,10 +1,10 @@
import { inject } from 'inversify';
import { Command } from '../decorator';
import { GitSparseCheckoutService } from '../services/GitSparseCheckoutService';
import { GitCloneService, ICloneOptions } from '../services/GitCloneService';
import { Command } from '../../decorator';
import { GitSparseCheckoutService } from '../../services/GitSparseCheckoutService';
import { GitCloneService, ICloneOptions } from '../../services/GitCloneService';
import type { Argv, ArgumentsCamelCase } from 'yargs';
import type { ICommand } from './base';
import type { LogService } from '../services/LogService';
import type { LogService } from '../../services/LogService';
export interface ICloneCommandOptions {
full?: boolean;

View file

@ -1,4 +1,4 @@
import { Command } from '../decorator';
import { Command } from '../../decorator';
import type { Argv } from 'yargs';
import type { ICommand } from './base';

View file

@ -1,8 +1,8 @@
import { inject } from 'inversify';
import type { Argv, ArgumentsCamelCase } from 'yargs';
import { ICommand } from './base';
import { Command } from '../decorator';
import { GitSparseCheckoutService } from '../services/GitSparseCheckoutService';
import { Command } from '../../decorator';
import { GitSparseCheckoutService } from '../../services/GitSparseCheckoutService';
export interface ICISparseCommandOptions {
to?: string[];

View file

@ -1,11 +1,11 @@
import { inject } from 'inversify';
import { Command } from '../decorator';
import { Command } from '../../decorator';
import { executeSelfCmd } from './util';
import { GitSparseCheckoutService } from '../services/GitSparseCheckoutService';
import { GitCloneService, ICloneOptions } from '../services/GitCloneService';
import { GitSparseCheckoutService } from '../../services/GitSparseCheckoutService';
import { GitCloneService, ICloneOptions } from '../../services/GitCloneService';
import type { Argv, ArgumentsCamelCase } from 'yargs';
import type { ICommand } from './base';
import type { LogService } from '../services/LogService';
import type { LogService } from '../../services/LogService';
export interface ICloneCommandOptions {
full?: boolean;

View file

@ -1,4 +1,4 @@
import { Constructable } from '../di/types';
import { Constructable } from '../../di/types';
import { CloneCommand } from './clone';
import { HelpCommand } from './help';
import { SparseCommand } from './sparse';

View file

@ -1,11 +1,11 @@
import { inject } from 'inversify';
import { Command } from '../decorator';
import { GitService } from '../services/GitService';
import { Command } from '../../decorator';
import { GitService } from '../../services/GitService';
import type { Argv, ArgumentsCamelCase } from 'yargs';
import type { GitRepoInfo } from 'git-repo-info';
import type { ICommand } from './base';
import type { LogService } from '../services/LogService';
import type { LogService } from '../../services/LogService';
export interface IFetchCommandOptions {
all?: boolean;

View file

@ -1,4 +1,4 @@
import { Command } from '../decorator';
import { Command } from '../../decorator';
import { Argv } from 'yargs';
import type { ICommand } from './base';

View file

@ -2,9 +2,9 @@ import { inject } from 'inversify';
import { type ArgumentsCamelCase } from 'yargs';
import { ICommand } from './base';
import { Command } from '../decorator';
import { GitSparseCheckoutService } from '../services/GitSparseCheckoutService';
import { LocalState } from '../logic/LocalState';
import { Command } from '../../decorator';
import { GitSparseCheckoutService } from '../../services/GitSparseCheckoutService';
import { LocalState } from '../../logic/LocalState';
export interface ISparseCommandOptions {
profile: string[];

View file

@ -2,8 +2,8 @@ import { inject } from 'inversify';
import type { Argv, ArgumentsCamelCase } from 'yargs';
import { ICommand } from './base';
import { Command } from '../decorator';
import { GitSparseCheckoutService } from '../services/GitSparseCheckoutService';
import { Command } from '../../decorator';
import { GitSparseCheckoutService } from '../../services/GitSparseCheckoutService';
export interface ISparseCommandOptions {
profile: string;

View file

@ -1,11 +1,11 @@
import childProcess from 'child_process';
import type { Argv, ArgumentsCamelCase } from 'yargs';
import { SparseProfileService } from '../services/SparseProfileService';
import { SparseProfileService } from '../../services/SparseProfileService';
import { ICommand } from './base';
import { Command } from '../decorator';
import { Command } from '../../decorator';
import { inject } from 'inversify';
import { GitSparseCheckoutService } from '../services/GitSparseCheckoutService';
import type { LogService } from '../services/LogService';
import { GitSparseCheckoutService } from '../../services/GitSparseCheckoutService';
import type { LogService } from '../../services/LogService';
export interface IProject {
name: string;

View file

@ -1,8 +1,8 @@
import { inject } from 'inversify';
import type { Argv, ArgumentsCamelCase } from 'yargs';
import { ICommand } from './base';
import { Command } from '../decorator';
import { GitSparseCheckoutService } from '../services/GitSparseCheckoutService';
import { Command } from '../../decorator';
import { GitSparseCheckoutService } from '../../services/GitSparseCheckoutService';
export interface ISparseCommandOptions {
profile: string[];

View file

@ -0,0 +1 @@
export { Sparo } from './api/Sparo';

View file

@ -0,0 +1,25 @@
import 'reflect-metadata';
import { getFromContainer } from '../di/container';
import { GitService } from '../services/GitService';
/**
* This class provides the useful function to check git version.
*/
export class GitVersionCompatibility {
private constructor() {}
public static async ensureGitVersionAsync(): Promise<void> {
const gitService: GitService = await getFromContainer(GitService);
const gitVersion: [number, number, number] | undefined = gitService.getGitVersion();
if (!gitVersion) {
throw new Error(`Fail to get git version`);
}
const [major, minor, patch] = gitVersion;
if (major < 2 || minor < 32) {
throw new Error(
`git version is too low. The minimal git version is >=2.32.0. Your git version is ${major}.${minor}.${patch}. Please upgrade git.`
);
}
}
}

View file

@ -1,6 +1,6 @@
import { inject } from 'inversify';
import type { Argv } from 'yargs';
import type { ICommand } from '../commands/base';
import type { ICommand } from '../cli/commands/base';
import { HelpTextService } from './HelpTextService';
import { LogService } from './LogService';
import { Service } from '../decorator';

View file

@ -0,0 +1,9 @@
{
"$schema": "http://json.schemastore.org/tsconfig",
"extends": "./node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json",
"compilerOptions": {
"resolveJsonModule": true,
"types": ["node", "heft-jest"]
}
}

View file

@ -1,2 +1,2 @@
#!/usr/bin/env node
require('../lib-commonjs/start.js');
require('../lib/start.js');

View file

@ -1,2 +1,2 @@
#!/usr/bin/env node
require('../lib-commonjs/start.js');
require('../lib/start.js');

View file

@ -1,17 +1,3 @@
{
"extends": "@rushstack/heft-node-rig/profiles/default/config/jest.config.json",
"roots": ["<rootDir>/lib-commonjs"],
"testMatch": ["<rootDir>/lib-commonjs/**/*.test.js"],
"collectCoverageFrom": [
"lib-commonjs/**/*.js",
"!lib-commonjs/**/*.d.ts",
"!lib-commonjs/**/*.test.js",
"!lib-commonjs/**/test/**",
"!lib-commonjs/**/__tests__/**",
"!lib-commonjs/**/__fixtures__/**",
"!lib-commonjs/**/__mocks__/**"
]
"extends": "@rushstack/heft-node-rig/profiles/default/config/jest.config.json"
}

View file

@ -31,23 +31,18 @@
"scripts": {
"_phase:build": "heft run --only build -- --clean",
"_phase:test": "heft run --only test -- --clean",
"test": "heft test --clean",
"build": "heft build --clean"
},
"dependencies": {
"@rushstack/node-core-library": "~3.64.2",
"git-repo-info": "~2.1.1",
"inversify": "~6.0.2",
"reflect-metadata": "~0.2.1",
"winston": "~3.11.0",
"yargs": "~17.7.2"
"sparo-lib": "workspace:*"
},
"devDependencies": {
"@rushstack/heft": "~0.64.3",
"@rushstack/heft-node-rig": "~2.4.5",
"@rushstack/heft": "0.64.3",
"@rushstack/heft-node-rig": "2.4.5",
"@types/heft-jest": "1.0.6",
"@types/node": "20.11.16",
"@types/yargs": "17.0.32",
"eslint": "~8.56.0",
"eslint": "8.56.0",
"typescript": "~5.3.3"
},
"preferGlobal": true

View file

@ -1,44 +1,24 @@
import * as path from 'path';
import 'reflect-metadata';
import { Sparo } from './api/Sparo';
import { SparoCI } from './api/SparoCI';
import { GitService } from './services/GitService';
import { getFromContainer } from './di/container';
import { Sparo } from 'sparo-lib';
type CommandName = 'sparo' | 'sparo-ci' | undefined;
export class SparoCommandSelector {
public static async executeAsync(): Promise<void> {
await SparoCommandSelector._ensureGitVersionAsync();
const commandName: CommandName = SparoCommandSelector._getCommandName();
switch (commandName) {
case 'sparo-ci': {
await SparoCI.launchAsync();
await Sparo.launchSparoCIAsync();
break;
}
default: {
await Sparo.launchAsync();
await Sparo.launchSparoAsync();
break;
}
}
}
private static async _ensureGitVersionAsync(): Promise<void> {
const gitService: GitService = await getFromContainer(GitService);
const gitVersion: [number, number, number] | undefined = gitService.getGitVersion();
if (!gitVersion) {
throw new Error(`Fail to get git version`);
}
const [major, minor, patch] = gitVersion;
if (major < 2 || minor < 32) {
throw new Error(
`git version is too low. The minimal git version is >=2.32.0. Your git version is ${major}.${minor}.${patch}. Please upgrade git.`
);
}
}
private static _getCommandName(): CommandName {
if (process.argv.length >= 2) {
// Example:

View file

@ -4,7 +4,6 @@
"extends": "./node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json",
"compilerOptions": {
"resolveJsonModule": true,
"outDir": "lib-commonjs",
"types": ["node", "heft-jest"]
}
}

View file

@ -9,6 +9,31 @@ importers:
.: {}
../../apps/sparo:
dependencies:
sparo-lib:
specifier: workspace:*
version: link:../sparo-lib
devDependencies:
'@rushstack/heft':
specifier: 0.64.3
version: 0.64.3(@types/node@20.11.16)
'@rushstack/heft-node-rig':
specifier: 2.4.5
version: 2.4.5(@rushstack/heft@0.64.3)(@types/node@20.11.16)
'@types/heft-jest':
specifier: 1.0.6
version: 1.0.6
'@types/node':
specifier: 20.11.16
version: 20.11.16
eslint:
specifier: 8.56.0
version: 8.56.0
typescript:
specifier: ~5.3.3
version: 5.3.3
../../apps/sparo-lib:
dependencies:
'@rushstack/node-core-library':
specifier: ~3.64.2
@ -30,10 +55,10 @@ importers:
version: 17.7.2
devDependencies:
'@rushstack/heft':
specifier: ~0.64.3
specifier: 0.64.3
version: 0.64.3(@types/node@20.11.16)
'@rushstack/heft-node-rig':
specifier: ~2.4.5
specifier: 2.4.5
version: 2.4.5(@rushstack/heft@0.64.3)(@types/node@20.11.16)
'@types/heft-jest':
specifier: 1.0.6
@ -45,7 +70,7 @@ importers:
specifier: 17.0.32
version: 17.0.32
eslint:
specifier: ~8.56.0
specifier: 8.56.0
version: 8.56.0
typescript:
specifier: ~5.3.3
@ -545,7 +570,7 @@ packages:
'@jest/console': 29.7.0
'@jest/reporters': 29.5.0
'@jest/test-result': 29.7.0
'@jest/transform': 29.5.0
'@jest/transform': 29.7.0
'@jest/types': 29.6.3
'@types/node': 20.11.16
ansi-escapes: 4.3.2
@ -558,11 +583,11 @@ packages:
jest-haste-map: 29.7.0
jest-message-util: 29.7.0
jest-regex-util: 29.6.3
jest-resolve: 29.5.0
jest-resolve: 29.7.0
jest-resolve-dependencies: 29.7.0
jest-runner: 29.7.0
jest-runtime: 29.7.0
jest-snapshot: 29.5.0
jest-snapshot: 29.7.0
jest-util: 29.7.0
jest-validate: 29.7.0
jest-watcher: 29.7.0
@ -639,7 +664,7 @@ packages:
'@bcoe/v8-coverage': 0.2.3
'@jest/console': 29.7.0
'@jest/test-result': 29.7.0
'@jest/transform': 29.5.0
'@jest/transform': 29.7.0
'@jest/types': 29.6.3
'@jridgewell/trace-mapping': 0.3.22
'@types/node': 20.11.16
@ -2897,7 +2922,7 @@ packages:
jest-environment-node: 29.7.0
jest-get-type: 29.6.3
jest-regex-util: 29.6.3
jest-resolve: 29.5.0
jest-resolve: 29.7.0
jest-runner: 29.7.0
jest-util: 29.7.0
jest-validate: 29.7.0
@ -3168,7 +3193,7 @@ packages:
'@babel/traverse': 7.23.9
'@babel/types': 7.23.9
'@jest/expect-utils': 29.7.0
'@jest/transform': 29.5.0
'@jest/transform': 29.7.0
'@jest/types': 29.6.3
'@types/babel__traverse': 7.20.5
'@types/prettier': 2.7.3

0
common/git-hooks/pre-commit Normal file → Executable file
View file

View file

@ -0,0 +1,17 @@
## API Report File for "sparo-lib"
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
// @public
export class Sparo {
// (undocumented)
static launchSparoAsync(): Promise<void>;
// (undocumented)
static launchSparoCIAsync(): Promise<void>;
}
// (No @packageDocumentation comment for this package)
```

View file

@ -437,6 +437,10 @@
{
"packageName": "sparo",
"projectFolder": "apps/sparo"
},
{
"packageName": "sparo-lib",
"projectFolder": "apps/sparo-lib"
}
]
}