Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat init profile #20

Merged
merged 8 commits into from
Feb 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions apps/sparo-lib/assets/sparo-profile.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
chengcyber marked this conversation as resolved.
Show resolved Hide resolved
"$schema": "https://tiktok.github.io/sparo/schemas/sparo-profile.schema.json",

/**
* A list of Rush project selectors indicating the project folders to be
* included for sparse checkout. The selectors will be combined to make
* the union superset of projects. See the Rush selector docs for details:
* https://rushjs.io/pages/developer/selecting_subsets/
*/
"selections": [
/**
* For example, include all Rush projects tagged with "tag:my-team"
* as well as the dependency workspace projects needed to build them.
*/
// {
// "selector": "--to",
// "argument": "tag:my-team"
// },
/**
* For example, include the project called "my-library", as well as all
* projects that are impacted by changes to it, as well as the dependency
* projects needed to build everything.
*/
// {
// "selector": "--from",
// "argument": "my-library"
// }
],

/**
* A list of arbitrary additional folders to be included, not necessarily
* corresponding to any workspace project.
*/
"includeFolders": [
// "path/to/include"
],

/**
* A list of folders to be excluded. This field takes precedence over
* the "includeFolders" and "selections" fields, guaranteeing that the
* specified path will definitely not be included.
*/
"excludeFolders": [
// "path/to/exclude"
]
}
6 changes: 5 additions & 1 deletion apps/sparo-lib/src/cli/commands/cmd-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,15 @@ import { GitCloneCommand } from './git-clone';
import { GitCheckoutCommand } from './git-checkout';
import { GitFetchCommand } from './git-fetch';
import { GitPullCommand } from './git-pull';
import { InitProfileCommand } from './init-profile';

// When adding new Sparo subcommands, remember to update this doc page:
// https://github.com/tiktok/sparo/blob/main/apps/website/docs/pages/commands/overview.md
export const COMMAND_LIST: Constructable[] = [
chengcyber marked this conversation as resolved.
Show resolved Hide resolved
HelpCommand,
ListProfilesCommand,
AutoConfigCommand,
ListProfilesCommand,
InitProfileCommand,

CloneCommand,
CheckoutCommand,
Expand Down
70 changes: 70 additions & 0 deletions apps/sparo-lib/src/cli/commands/init-profile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { FileSystem } from '@rushstack/node-core-library';
import type { Argv, ArgumentsCamelCase } from 'yargs';

import { Command } from '../../decorator';
import { TerminalService } from '../../services/TerminalService';
import { ICommand } from './base';
import { SparoProfileService } from '../../services/SparoProfileService';
import { inject } from 'inversify';
import { assetsFolderPath } from './util';
import { Colorize } from '@rushstack/terminal';

export interface IInitProjectCommandOptions {
profile: string;
}

@Command()
export class InitProfileCommand implements ICommand<IInitProjectCommandOptions> {
public cmd: string = 'init-profile';
public description: string = 'Initialize a new profile.';

// template section name --> whether it should be commented out
private _commentedBySectionName: Map<string, boolean> = new Map<string, boolean>();

@inject(SparoProfileService) private _sparoProfileService!: SparoProfileService;
@inject(TerminalService) private _terminalService!: TerminalService;

public builder(yargs: Argv<IInitProjectCommandOptions>): void {
yargs.string('profile').demandOption(['profile']);
}

public handler = async (
args: ArgumentsCamelCase<IInitProjectCommandOptions>,
terminalService: TerminalService
): Promise<void> => {
const { profile } = args;

const destinationPath: string = this._sparoProfileService.getProfileFilepathByName(profile);

if (this._sparoProfileService.hasProfileInFS(profile)) {
throw new Error(
`Error: A config file already exists for the profile name "${profile}":\n ` + destinationPath
);
}

const sparoProfileTemplateFilepath: string = `${assetsFolderPath}/sparo-profile.json`;

if (!FileSystem.exists(sparoProfileTemplateFilepath)) {
// THIS SHOULD NEVER HAPPEN
throw new Error(`Unable to find sparo profile template file at ${sparoProfileTemplateFilepath}`);
}

await FileSystem.copyFileAsync({
sourcePath: sparoProfileTemplateFilepath,
destinationPath
});
this._terminalService.terminal.writeLine(
Colorize.green(`Successfully initialized the "${profile}" profile.`)
);
this._terminalService.terminal.writeLine();
this._terminalService.terminal.writeLine(
'Next step: Open this file in your editor and configure the project selectors:'
);
this._terminalService.terminal.writeLine();
this._terminalService.terminal.writeLine(' ' + Colorize.cyan(destinationPath));
};

public getHelp(): string {
return 'init-profile help';
}
}
12 changes: 12 additions & 0 deletions apps/sparo-lib/src/cli/commands/util.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
import { PackageJsonLookup } from '@rushstack/node-core-library';

/**
* The currently-executing sparo-lib package's root folder path.
*/
export const sparoLibFolderRootPath: string = PackageJsonLookup.instance.tryGetPackageFolderFor(__dirname)!;

/**
* The path to the assets folder in rush-lib.
*/
export const assetsFolderPath: string = `${sparoLibFolderRootPath}/assets`;

/**
* The string of cmd here can be "clone <repository> [directory]", this function extracts
* the command name from the string.
Expand Down
12 changes: 12 additions & 0 deletions apps/sparo-lib/src/services/SparoProfileService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,22 @@ export class SparoProfileService {

private get _sparoProfileFolder(): string {
const repoRoot: string = this._gitService.getRepoInfo().root;
if (!repoRoot) {
throw new Error(`Failed to detect git repository. Please check running in a git repository folder.`);
}
const sparoProfileFolder: string = path.resolve(repoRoot, defaultSparoProfileFolder);
return sparoProfileFolder;
}

/**
* Returns the absolute file path where the specified profile name would be stored.
* @remarks
* It is not guaranteed that the file actually exists.
*/
public getProfileFilepathByName(profileName: string): string {
return path.resolve(this._sparoProfileFolder, `${profileName}.json`);
}

private static _getProfileName(profilePath: string): string {
const pathArr: string[] = profilePath.split('/');
const last: string = pathArr[pathArr.length - 1];
Expand Down
1 change: 1 addition & 0 deletions apps/website/docs/pages/commands/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Sparo has four kinds of subcommands:
4. **Auxiliary subcommands** are new subcommands that provide Sparo-specific functionality. They are:
- `sparo purge`
- `sparo list-profiles`
- `sparo init-profile`

## Mirrored commands

Expand Down
10 changes: 10 additions & 0 deletions common/changes/sparo/feat-init-profile_2024-02-23-19-26.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "sparo",
"comment": "Add \"sparo init-profile --profile <name>\" command",
"type": "none"
}
],
"packageName": "sparo"
}
Loading