fairsplice
Advanced tools
Comparing version 0.3.1 to 0.4.0
23
index.ts
#!/usr/bin/env bun | ||
import { save } from "./src/commands/save"; | ||
import { select } from "./src/commands/select"; | ||
import { split } from "./src/commands/split"; | ||
import { parseArgs } from "util"; | ||
@@ -18,3 +18,3 @@ | ||
}, | ||
// select options | ||
// split options | ||
pattern: { | ||
@@ -27,5 +27,2 @@ type: "string", | ||
}, | ||
index: { | ||
type: "string", | ||
}, | ||
["replace-from"]: { | ||
@@ -51,3 +48,3 @@ type: "string", | ||
console.log(` | ||
Usage: fairsplice [save|select] [options] | ||
Usage: fairsplice [save|split] [options] | ||
@@ -64,3 +61,3 @@ Make sure the environment variable FAIRSPLICE_REDIS_URL is set. | ||
fairsplice select | ||
fairsplice split | ||
----------------- | ||
@@ -70,8 +67,7 @@ Available options: | ||
--total <total> Total number of workers | ||
--index <index> Worker index | ||
--out <file> File to write selected test files to (newline separated) | ||
--out <file> File to write test files to (JSON) | ||
--replace-from <string> Substring to replace in the file paths (can be used multiple times) | ||
--replace-to <string> Replacement for the substring (can be used multiple times but must match the number of --replace-from) | ||
Example: fairsplice select --pattern "test_*.py" --pattern "tests*.py" --total 3 --index 1 --out selected.txt | ||
Example: fairsplice split --pattern "test_*.py" --pattern "tests*.py" --total 3 --out split.json | ||
`); | ||
@@ -91,7 +87,6 @@ process.exit(0); | ||
process.exit(0); | ||
} else if (command === "select") { | ||
await select({ | ||
} else if (command === "split") { | ||
await split({ | ||
patterns: values.pattern, | ||
total: values.total, | ||
index: values.index, | ||
out: values.out, | ||
@@ -104,5 +99,5 @@ replaceFrom: values["replace-from"], | ||
console.error( | ||
`Invalid command "${command}". Available commands: save, select.` | ||
`Invalid command "${command}". Available commands: save, split.` | ||
); | ||
process.exit(1); | ||
} |
{ | ||
"name": "fairsplice", | ||
"version": "0.3.1", | ||
"version": "0.4.0", | ||
"module": "index.ts", | ||
@@ -5,0 +5,0 @@ "type": "module", |
# Fairsplice | ||
Fairsplice is a CLI tool designed to optimize test distribution across multiple workers. By intelligently selecting and saving test cases, Fairsplice ensures balanced workload distribution for your CI/CD pipelines, making tests run time more predictable. | ||
**Warning: this project is still in very early development!** | ||
Fairsplice is a CLI tool designed to optimize test distribution across multiple workers. By intelligently splitting and saving test cases, Fairsplice ensures a balanced workload distribution for your CI/CD pipelines, making tests run time more predictable. | ||
We found Github Actions lacking when compared to CircleCI which has [tests splitting](https://circleci.com/docs/parallelism-faster-jobs/#how-test-splitting-works) based on timings. | ||
@@ -9,3 +11,3 @@ | ||
This tool uses instead a Redis server to store the last 10 timings for each test file and uses the average of these to select tests. It is easy to setup if you have a Redis server running. | ||
This tool uses instead a Redis server to store the last 10 timings for each test file and uses the average of these to split tests. It is easy to setup if you have a Redis server running. | ||
@@ -33,5 +35,5 @@ ## Installation | ||
Fairsplice supports two main commands: `save` and `select`. | ||
Fairsplice supports two main commands: `save` and `split`. | ||
### Saving Test Results | ||
### Saving test results | ||
@@ -52,8 +54,8 @@ To save test results: | ||
### Selecting Test Cases | ||
### Splitting test cases | ||
To select test cases for execution: | ||
To split test cases for execution: | ||
```bash | ||
fairsplice select --pattern "<pattern>" [--pattern "<anotherPattern>" ...] --total <total> --index <index> | ||
fairsplice split --pattern "<pattern>" [--pattern "<anotherPattern>" ...] --total <total> --out <file> --replace-from <string> --replace-to <string> [--replace-from <other> --replace-to <other>] | ||
``` | ||
@@ -63,4 +65,3 @@ | ||
- `--total <total>`: Total number of workers in the test environment. | ||
- `--index <index>`: Index of the current worker (0-based). | ||
- `--out <file>`: File to write selected test files to (newline separated) | ||
- `--out <file>`: File to write split test files to (newline separated) | ||
- `--replace-from <string>`: Substring to replace in the file paths (can be used multiple times) | ||
@@ -72,3 +73,3 @@ - `--replace-to <string>`: Replacement for the substring (can be used multiple times but must match the number of --replace-from) | ||
```bash | ||
fairsplice select --pattern "test_*.py" --pattern "tests*.py" --total 3 --index 1 | ||
fairsplice split --pattern "test_*.py" --pattern "tests*.py" --total 3 --out split.json | ||
``` | ||
@@ -75,0 +76,0 @@ |
@@ -37,2 +37,23 @@ import { describe, expect, it } from "bun:test"; | ||
}); | ||
it("should have a stable output no matter the order", () => { | ||
const fileTimesMap1 = { | ||
a: 10, | ||
e: 50, | ||
b: 20, | ||
c: 30, | ||
d: 40, | ||
}; | ||
const fileTimesMap2 = { | ||
d: 40, | ||
a: 10, | ||
e: 50, | ||
c: 30, | ||
b: 20, | ||
}; | ||
const [buckets1, bucketTimes1] = splitFiles(fileTimesMap1, 2); | ||
const [buckets2, bucketTimes2] = splitFiles(fileTimesMap2, 2); | ||
expect(bucketTimes1).toEqual(bucketTimes2); | ||
expect(buckets1).toEqual(buckets2); | ||
}); | ||
}); |
@@ -1,3 +0,1 @@ | ||
const DEFAULT_TIMING = 1000; // 1 second | ||
export function splitFiles( | ||
@@ -24,7 +22,3 @@ fileTimesMap: Record<string, number /* in milliseconds */>, | ||
buckets[minBucket].push(file); | ||
if (time === 0) { | ||
bucketTimes[minBucket] += DEFAULT_TIMING; | ||
} else { | ||
bucketTimes[minBucket] += time; | ||
} | ||
bucketTimes[minBucket] += time; | ||
} | ||
@@ -31,0 +25,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
30964
397
103