mirror of
https://github.com/tiktok/sparo.git
synced 2024-11-14 19:35:12 -05:00
feat: code changes according to code review
This commit is contained in:
parent
32b3d07f5e
commit
e494e3cf3a
16 changed files with 54 additions and 81 deletions
11
build-tests/sparo-output-test/README.md
Normal file
11
build-tests/sparo-output-test/README.md
Normal file
|
@ -0,0 +1,11 @@
|
|||
# sparo-output-test
|
||||
|
||||
Building this project tests sparo command outputs
|
||||
|
||||
# Details
|
||||
|
||||
`lib/start-test.js` is run after building the project. This scripts generate the output text files under `temp/etc`. In local builds, those files are copied to `etc` folder. During a CI build, the files under these two folders are compared and the CI build fails if they are different. This ensures that files under `etc` folder must be up to date in the PR, and people who review the PR must approve any changes.
|
||||
|
||||
# How to fix the build errors
|
||||
|
||||
Run `rush build -t sparo-output-test` to regenerate files under `etc` folder and commit them into Git.
|
|
@ -14,7 +14,7 @@
|
|||
"pluginPackage": "@rushstack/heft",
|
||||
|
||||
"options": {
|
||||
"scriptPath": "lib/generateOutputs.js"
|
||||
"scriptPath": "lib/start-test.js"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +1,16 @@
|
|||
{
|
||||
"name": "sparo-outputs",
|
||||
"name": "sparo-output-test",
|
||||
"description": "Building this project tests sparo command outputs",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"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",
|
||||
"sparo": "workspace:*"
|
||||
"sparo": "workspace:*",
|
||||
"jest-diff": "~29.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rushstack/heft": "0.64.3",
|
|
@ -1,5 +1,6 @@
|
|||
import * as path from 'path';
|
||||
import { Async, Executable, FileSystem, type FolderItem, Text } from '@rushstack/node-core-library';
|
||||
import { diff } from 'jest-diff';
|
||||
import type { SpawnSyncReturns } from 'child_process';
|
||||
import type { IRunScriptOptions } from '@rushstack/heft';
|
||||
|
||||
|
@ -57,33 +58,31 @@ export async function runAsync(runScriptOptions: IRunScriptOptions): Promise<voi
|
|||
];
|
||||
|
||||
/**
|
||||
* Run each scenario and generate outputs in parallel
|
||||
*
|
||||
* NOTE: please make sure the commands can be run in parallel
|
||||
* Run each scenario and generate outputs
|
||||
*/
|
||||
await FileSystem.ensureEmptyFolderAsync(tempFolder);
|
||||
await Async.forEachAsync(
|
||||
scenarios,
|
||||
async (scenario: IScenarioDefinition) => {
|
||||
const { name, args } = scenario;
|
||||
const result: SpawnSyncReturns<string> = Executable.spawnSync(binPath, args);
|
||||
|
||||
if (result.status !== 0) {
|
||||
throw new Error(
|
||||
`Failed to run "sparo ${args.join(' ')}" with exit code ${result.status}\n${result.stderr}`
|
||||
);
|
||||
for (const scenario of scenarios) {
|
||||
const { name, args } = scenario;
|
||||
const result: SpawnSyncReturns<string> = Executable.spawnSync(binPath, args, {
|
||||
environment: {
|
||||
...process.env
|
||||
// Always use color for the output
|
||||
// FORCE_COLOR: 'true'
|
||||
}
|
||||
});
|
||||
|
||||
const outputPath: string = path.join(tempFolder, `${name}.txt`);
|
||||
FileSystem.writeFile(
|
||||
outputPath,
|
||||
`Running "sparo ${args.join(' ')}":\n${processVersionString(result.stdout)}`
|
||||
if (result.status !== 0) {
|
||||
throw new Error(
|
||||
`Failed to run "sparo ${args.join(' ')}" with exit code ${result.status}\n${result.stderr}`
|
||||
);
|
||||
},
|
||||
{
|
||||
concurrency: 10
|
||||
}
|
||||
);
|
||||
|
||||
const outputPath: string = path.join(tempFolder, `${name}.txt`);
|
||||
FileSystem.writeFile(
|
||||
outputPath,
|
||||
`Running "sparo ${args.join(' ')}":\n${processVersionString(result.stdout)}`
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Files under outFolderPath are tracked by Git, files under inFolderPath are temporary files. During a local build,
|
||||
|
@ -106,6 +105,7 @@ export async function runAsync(runScriptOptions: IRunScriptOptions): Promise<voi
|
|||
}
|
||||
|
||||
const nonMatchingFiles: string[] = [];
|
||||
const nonMatchingFileErrorMessages: Map<string, string> = new Map<string, string>();
|
||||
await Async.forEachAsync(
|
||||
inFolderPaths,
|
||||
async (folderItemPath: string) => {
|
||||
|
@ -130,6 +130,13 @@ export async function runAsync(runScriptOptions: IRunScriptOptions): Promise<voi
|
|||
|
||||
if (normalizedSourceFileContents !== normalizedOutFileContents) {
|
||||
nonMatchingFiles.push(outFilePath);
|
||||
if (production) {
|
||||
// Display diff only when running in production mode, mostly for CI build
|
||||
nonMatchingFileErrorMessages.set(
|
||||
outFilePath,
|
||||
diff(normalizedOutFileContents, normalizedSourceFileContents) || ''
|
||||
);
|
||||
}
|
||||
if (!production) {
|
||||
await FileSystem.writeFileAsync(outFilePath, normalizedSourceFileContents, {
|
||||
ensureFolderExists: true
|
||||
|
@ -159,6 +166,10 @@ export async function runAsync(runScriptOptions: IRunScriptOptions): Promise<voi
|
|||
const errorLines: string[] = [];
|
||||
for (const nonMatchingFile of nonMatchingFiles.sort()) {
|
||||
errorLines.push(` ${nonMatchingFile}`);
|
||||
const errorMessage: string | undefined = nonMatchingFileErrorMessages.get(nonMatchingFile);
|
||||
if (errorMessage) {
|
||||
errorLines.push(`${errorMessage}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (production) {
|
|
@ -1,43 +0,0 @@
|
|||
# Sparo
|
||||
|
||||
<div>
|
||||
<br />
|
||||
<a href="https://tiktok.github.io/sparo/">
|
||||
<img width="380" src="https://tiktok.github.io/sparo/images/site/sparo-logo.svg" alt="Sparo" />
|
||||
</a>
|
||||
<p />
|
||||
</div>
|
||||
|
||||
## Is Git too slow in your frontend monorepo?
|
||||
|
||||
By default `git clone` will download every file in your Git repository, as well as the complete history of every file. For small repositories, that's no big deal. But as your monorepo accumulates projects and years of history, Git operations become slower and slower, until one day `git status` is taking 10 seconds or more. What to do?
|
||||
|
||||
<!-- Text below this line should stay in sync with the website index.md -->
|
||||
<!-- ------------------------------------------------------------------ -->
|
||||
|
||||
## Clone faster!
|
||||
|
||||
Sparo optimizes performance of Git operations for your large frontend monorepo.
|
||||
|
||||
## Key features
|
||||
|
||||
- **Familiar interface:** The `sparo` command-line interface (CLI) wrapper offers **better defaults** and **performance suggestions** without altering the familiar `git` syntax. (The native `git` CLI is also supported.)
|
||||
- **A proven solution:** Git provides [quite a lot of ingredients](https://tiktok.github.io/sparo/pages/reference/git_optimization/) for optimizing very large repos; Sparo is your recipe for combining these features intelligently.
|
||||
- **Simplified sparse checkout:** Work with sparse checkout [profiles](https://tiktok.github.io/sparo/pages/guide/sparo_profiles/) instead of confusing "cones" and globs
|
||||
- **Frontend integration:** Sparo leverages [Rush](https://rushjs.io/) and [PNPM](https://pnpm.io/) workspace configurations, including the ability to automatically checkout project dependencies
|
||||
- **Dual workflows:** The `sparo-ci` tool implements a specialized checkout model optimized for continuous integration (CI) pipelines
|
||||
- **Extra safeguards**: Avoid common Git mistakes such as checkouts with staged files outside the active view
|
||||
- **Go beyond Git hooks:** Optionally collect anonymized Git timing metrics in your monorepo, enabling your build team to set data-driven goals for _local_ developer experience (not just CI!)
|
||||
|
||||
_(Metrics are transmitted to your own service and are not accessible by any other party.)_
|
||||
|
||||
<!-- ------------------------------------------------------------------ -->
|
||||
<!-- Text above this line should stay in sync with the website index.md -->
|
||||
|
||||
## Links
|
||||
|
||||
- [Quick demo](https://tiktok.github.io/sparo/#quick-demo): See for yourself in 3 minutes!
|
||||
- [Getting Started](https://tiktok.github.io/sparo/pages/guide/getting_started/): Step by step instructions
|
||||
- [CHANGELOG.md](
|
||||
https://github.com/tiktok/sparo/blob/main/apps/sparo/CHANGELOG.md): Find
|
||||
out what's new in the latest version
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"extends": "@rushstack/heft-node-rig/profiles/default/config/jest.config.json"
|
||||
}
|
|
@ -149,11 +149,14 @@ importers:
|
|||
specifier: ~5.3.3
|
||||
version: 5.3.3
|
||||
|
||||
../../build-tests/sparo-outputs:
|
||||
../../build-tests/sparo-output-test:
|
||||
dependencies:
|
||||
'@rushstack/node-core-library':
|
||||
specifier: ~3.64.2
|
||||
version: 3.64.2(@types/node@20.11.16)
|
||||
jest-diff:
|
||||
specifier: ~29.7.0
|
||||
version: 29.7.0
|
||||
sparo:
|
||||
specifier: workspace:*
|
||||
version: link:../../apps/sparo
|
||||
|
@ -4205,7 +4208,6 @@ packages:
|
|||
/ansi-styles@5.2.0:
|
||||
resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
|
||||
engines: {node: '>=10'}
|
||||
dev: true
|
||||
|
||||
/ansi-styles@6.2.1:
|
||||
resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
|
||||
|
@ -5512,7 +5514,6 @@ packages:
|
|||
/diff-sequences@29.6.3:
|
||||
resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
|
||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||
dev: true
|
||||
|
||||
/dir-glob@3.0.1:
|
||||
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
|
||||
|
@ -7775,7 +7776,6 @@ packages:
|
|||
diff-sequences: 29.6.3
|
||||
jest-get-type: 29.6.3
|
||||
pretty-format: 29.7.0
|
||||
dev: true
|
||||
|
||||
/jest-docblock@29.7.0:
|
||||
resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==}
|
||||
|
@ -7822,7 +7822,6 @@ packages:
|
|||
/jest-get-type@29.6.3:
|
||||
resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==}
|
||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||
dev: true
|
||||
|
||||
/jest-haste-map@29.7.0:
|
||||
resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==}
|
||||
|
@ -10031,7 +10030,6 @@ packages:
|
|||
'@jest/schemas': 29.6.3
|
||||
ansi-styles: 5.2.0
|
||||
react-is: 18.2.0
|
||||
dev: true
|
||||
|
||||
/pretty-time@1.1.0:
|
||||
resolution: {integrity: sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==}
|
||||
|
@ -10263,7 +10261,6 @@ packages:
|
|||
|
||||
/react-is@18.2.0:
|
||||
resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
|
||||
dev: true
|
||||
|
||||
/react-json-view-lite@1.2.1(react@18.2.0):
|
||||
resolution: {integrity: sha512-Itc0g86fytOmKZoIoJyGgvNqohWSbh3NXIKNgH6W6FT9PC1ck4xas1tT3Rr/b3UlFXyA9Jjaw9QSXdZy2JwGMQ==}
|
||||
|
@ -12303,6 +12300,7 @@ time:
|
|||
/eslint@8.56.0: '2023-12-15T22:55:11.833Z'
|
||||
/git-repo-info@2.1.1: '2019-10-18T15:12:09.674Z'
|
||||
/inversify@6.0.2: '2023-10-20T23:35:39.918Z'
|
||||
/jest-diff@29.7.0: '2023-09-12T06:43:43.883Z'
|
||||
/lunr@2.3.9: '2020-08-19T20:30:07.948Z'
|
||||
/prism-react-renderer@2.3.1: '2023-12-18T14:23:38.265Z'
|
||||
/prismjs@1.29.0: '2022-08-23T10:42:14.395Z'
|
||||
|
|
|
@ -437,8 +437,8 @@
|
|||
|
||||
// Build tests
|
||||
{
|
||||
"packageName": "sparo-outputs",
|
||||
"projectFolder": "build-tests/sparo-outputs"
|
||||
"packageName": "sparo-output-test",
|
||||
"projectFolder": "build-tests/sparo-output-test"
|
||||
},
|
||||
|
||||
// Sparo
|
||||
|
|
Loading…
Reference in a new issue