@cleaver/breakcheck 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +225 -0
- package/dist/cli/commands/compare.d.ts +2 -0
- package/dist/cli/commands/compare.js +43 -0
- package/dist/cli/commands/compare.js.map +1 -0
- package/dist/cli/commands/help.d.ts +2 -0
- package/dist/cli/commands/help.js +227 -0
- package/dist/cli/commands/help.js.map +1 -0
- package/dist/cli/commands/list-snapshots.d.ts +2 -0
- package/dist/cli/commands/list-snapshots.js +42 -0
- package/dist/cli/commands/list-snapshots.js.map +1 -0
- package/dist/cli/commands/snapshot.d.ts +2 -0
- package/dist/cli/commands/snapshot.js +68 -0
- package/dist/cli/commands/snapshot.js.map +1 -0
- package/dist/cli/commands/view.d.ts +2 -0
- package/dist/cli/commands/view.js +27 -0
- package/dist/cli/commands/view.js.map +1 -0
- package/dist/cli/utils.d.ts +11 -0
- package/dist/cli/utils.js +21 -0
- package/dist/cli/utils.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/package.json +35 -0
package/README.md
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# Breakcheck
|
|
2
|
+
|
|
3
|
+
**A command-line tool for comparing website states to detect unintended content and structural changes after upgrades, deployments, or migrations.**
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<img src="./breakcheck-logo-notext-sm.png" alt="Breakcheck Logo" width="300">
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
Breakcheck helps developers and QA testers automate visual and structural regression testing. It works by taking a "snapshot" of a website before a change, another snapshot after, and then intelligently comparing them. You can define fine-grained rules to ignore dynamic content like ads, session IDs, or timestamps, ensuring you only get alerted to the changes that matter.
|
|
10
|
+
|
|
11
|
+
## Core Workflow
|
|
12
|
+
|
|
13
|
+
The typical workflow for using Breakcheck involves five main steps:
|
|
14
|
+
|
|
15
|
+
1. **📸 Take a "before" snapshot:** Crawl your production site to save its current state.
|
|
16
|
+
2. **⚙️ Make your changes:** Deploy your update, migrate your CMS, or update your theme.
|
|
17
|
+
3. **📸 Take an "after" snapshot:** Crawl the site again to capture the new state.
|
|
18
|
+
4. **🔍 Compare the snapshots:** Run the comparison using a set of rules to filter out expected dynamic changes.
|
|
19
|
+
5. **📊 View the results:** Launch a local web server to view a detailed diff report.
|
|
20
|
+
|
|
21
|
+
### Example
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# 1. Snapshot the "before" state from your live site
|
|
25
|
+
breakcheck snapshot --url https://my-website.com --name production-live
|
|
26
|
+
|
|
27
|
+
# --- (Deploy your changes here) ---
|
|
28
|
+
|
|
29
|
+
# 2. Snapshot the "after" state
|
|
30
|
+
breakcheck snapshot --url https://my-website.com --name after-deployment
|
|
31
|
+
|
|
32
|
+
# 3. Compare the two snapshots using a rules file
|
|
33
|
+
breakcheck compare --before production-live --after after-deployment --rules ./my-rules --output my-first-comparison
|
|
34
|
+
|
|
35
|
+
# 4. View the results in your browser
|
|
36
|
+
breakcheck view my-first-comparison
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## The Breakcheck Rules DSL
|
|
42
|
+
|
|
43
|
+
To get meaningful comparisons, you need to tell Breakcheck what to ignore. This is done with a simple Domain Specific Language (DSL) in a `rules.breakcheck` file. The DSL allows you to target elements with CSS selectors and apply actions to them before the comparison runs.
|
|
44
|
+
|
|
45
|
+
### Syntax
|
|
46
|
+
|
|
47
|
+
Rules can be a single line for one action or a `do/end` block for multiple actions on the same element. Comments start with `--`.
|
|
48
|
+
|
|
49
|
+
**Single Action:**
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
css:[SELECTOR] do: action [MODIFIERS...]
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Multiple Actions (Block):**
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
css:[SELECTOR] do
|
|
59
|
+
action [MODIFIERS...]
|
|
60
|
+
action [MODIFIERS...]
|
|
61
|
+
end
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Actions & Modifiers
|
|
65
|
+
|
|
66
|
+
- **Actions:**
|
|
67
|
+
|
|
68
|
+
- `exclude`: Removes the selected element entirely.
|
|
69
|
+
- `remove_attr`: Removes a specific attribute from an element.
|
|
70
|
+
- `rewrite_attr`: Rewrites the value of an attribute, useful for normalizing URLs or IDs.
|
|
71
|
+
- `rewrite_content`: Rewrites the text inside an element.
|
|
72
|
+
|
|
73
|
+
- **Modifiers:**
|
|
74
|
+
- `attr:"<attribute_name>"`: Specifies the target attribute (e.g., `attr:"href"`).
|
|
75
|
+
- `regex:"<pattern>"`: A regular expression for matching and capturing.
|
|
76
|
+
- `replace:"<replacement>"`: The string to replace matches with. Can use capture groups like `$1`.
|
|
77
|
+
- `content_regex:"<pattern>"`: Applies the action only if the element's text content matches the regex.
|
|
78
|
+
|
|
79
|
+
### Rules Example (`rules.breakcheck`)
|
|
80
|
+
|
|
81
|
+
Here is an example rules file that demonstrates how to handle common dynamic content:
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
-- Breakcheck Rules File
|
|
85
|
+
|
|
86
|
+
-- Completely remove ad containers and session displays
|
|
87
|
+
css:.ad-container do: exclude
|
|
88
|
+
css:#session-id-display do: exclude
|
|
89
|
+
|
|
90
|
+
-- Exclude an element only if its content matches a pattern
|
|
91
|
+
css:.last-login do: exclude content_regex:"Logged in: \d+ minutes ago"
|
|
92
|
+
|
|
93
|
+
-- For all images, remove dynamic attributes and normalize the CDN host
|
|
94
|
+
css:img do
|
|
95
|
+
remove_attr attr:"srcset"
|
|
96
|
+
remove_attr attr:"sizes"
|
|
97
|
+
rewrite_attr attr:"src" regex:"//cdn\d+\.example\.com/" replace:"//cdn.example.com/"
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
-- Normalize cache-busting query parameters on CSS and JS files
|
|
101
|
+
css:link[rel=stylesheet] do: rewrite_attr attr:"href" regex:"(\?|&)v=\w+" replace:"?v=STATIC"
|
|
102
|
+
css:script do: rewrite_attr attr:"src" regex:"(\?|&)v=\w+" replace:"?v=STATIC"
|
|
103
|
+
|
|
104
|
+
-- Rewrite dynamic timestamps and view counts inside elements
|
|
105
|
+
css:.timestamp do: rewrite_content regex:"\d{2}/\d{2}/\d{4}" replace:"DATE_STAMP"
|
|
106
|
+
css:.view-count do: rewrite_content regex:"\d{1,3}(,\d{3})* views" replace:"VIEW_COUNT views"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Command Reference
|
|
112
|
+
|
|
113
|
+
### `snapshot`
|
|
114
|
+
|
|
115
|
+
Crawls a website and saves its HTML content and structure to a named snapshot.
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
breakcheck snapshot [options]
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
| Option | Description | Default |
|
|
122
|
+
| :---------------------------- | :-------------------------------------------------------------------- | :------------------------------ |
|
|
123
|
+
| `-u, --url <url>` | **(Required)** The base URL to start crawling from. | |
|
|
124
|
+
| `-n, --name <name>` | A unique name for the snapshot. | `snapshot_YYYY-MM-DD_HH-mm-ssZ` |
|
|
125
|
+
| `-d, --depth <number>` | Maximum crawl depth. | `3` |
|
|
126
|
+
| `-c, --concurrency <number>` | Number of concurrent requests to make. | `5` |
|
|
127
|
+
| `-i, --include <patterns...>` | Glob patterns for URLs to include. | |
|
|
128
|
+
| `-e, --exclude <patterns...>` | Glob patterns for URLs to exclude. | |
|
|
129
|
+
| `-t, --type <type>` | The crawler to use (`cheerio` or `playwright`). | `cheerio` |
|
|
130
|
+
| `-w, --write-urls <path>` | Generate a plain text file of all crawled URLs at the specified path. | |
|
|
131
|
+
| `--json-logs` | Output logs in JSON format (useful for automation). | |
|
|
132
|
+
| `--no-json-logs` | Output logs in pretty format (default, user-friendly). | |
|
|
133
|
+
|
|
134
|
+
### `compare`
|
|
135
|
+
|
|
136
|
+
Compares two snapshots, applies rules, and saves the results.
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
breakcheck compare [options]
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
| Option | Description | Default |
|
|
143
|
+
| :-------------------- | :------------------------------------------------------------ | :---------------- |
|
|
144
|
+
| `-b, --before <name>` | **(Required)** The name of the "before" snapshot. | |
|
|
145
|
+
| `-a, --after <name>` | **(Required)** The name of the "after" snapshot. | |
|
|
146
|
+
| `-o, --output <name>` | A name for the comparison output directory. | `compare_default` |
|
|
147
|
+
| `-r, --rules <path>` | Path to the directory containing the `rules.breakcheck` file. | `default` |
|
|
148
|
+
| `--json-logs` | Output logs in JSON format (useful for automation). | |
|
|
149
|
+
| `--no-json-logs` | Output logs in pretty format (default, user-friendly). | |
|
|
150
|
+
|
|
151
|
+
### `view`
|
|
152
|
+
|
|
153
|
+
Starts a local web server to display the results of a comparison in a user-friendly interface.
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
breakcheck view [comparison-name] [options]
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
| Argument | Description | Default |
|
|
160
|
+
| :---------------- | :---------------------------------- | :---------------- |
|
|
161
|
+
| `comparison-name` | The name of the comparison to view. | `compare_default` |
|
|
162
|
+
|
|
163
|
+
| Option | Description | Default |
|
|
164
|
+
| :-------------------- | :----------------------------------------------------- | :------ |
|
|
165
|
+
| `-p, --port <number>` | The port to run the view server on. | `8080` |
|
|
166
|
+
| `--json-logs` | Output logs in JSON format (useful for automation). | |
|
|
167
|
+
| `--no-json-logs` | Output logs in pretty format (default, user-friendly). | |
|
|
168
|
+
|
|
169
|
+
### `list-snapshots`
|
|
170
|
+
|
|
171
|
+
Lists all snapshots that have been saved locally.
|
|
172
|
+
|
|
173
|
+
**Alias:** `lss`
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
breakcheck list-snapshots
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
The command outputs a table of available snapshots:
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
Name | Date | Pages | Errors
|
|
183
|
+
--------------------|---------------------------|-------|-------
|
|
184
|
+
production-live | 2025-06-10T16:05:40.123Z | 152 | 0
|
|
185
|
+
after-deployment | 2025-06-10T17:10:15.456Z | 153 | 1
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Logging Options
|
|
191
|
+
|
|
192
|
+
Breakcheck provides flexible logging options to suit different use cases:
|
|
193
|
+
|
|
194
|
+
### Pretty Logging (Default)
|
|
195
|
+
|
|
196
|
+
By default, Breakcheck uses pretty-printed logs that are human-readable and include colors and formatting:
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
breakcheck snapshot --url https://example.com
|
|
200
|
+
# Output: ✅ Snapshot created successfully: snapshot_2025-01-15_10-30-45Z
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### JSON Logging
|
|
204
|
+
|
|
205
|
+
For automation and integration with log aggregation systems, you can use JSON-formatted logs:
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
breakcheck snapshot --url https://example.com --json-logs
|
|
209
|
+
# Output: {"level":30,"time":1705315845000,"msg":"✅ Snapshot created successfully: snapshot_2025-01-15_10-30-45Z"}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Logging Options
|
|
213
|
+
|
|
214
|
+
All commands support these logging options:
|
|
215
|
+
|
|
216
|
+
| Option | Description | Default |
|
|
217
|
+
| :--------------- | :------------------------------------------------- | :------ |
|
|
218
|
+
| `--json-logs` | Output logs in JSON format (useful for automation) | |
|
|
219
|
+
| `--no-json-logs` | Output logs in pretty format (user-friendly) | ✓ |
|
|
220
|
+
|
|
221
|
+
### Use Cases
|
|
222
|
+
|
|
223
|
+
- **Interactive use**: Use the default pretty logging for easy reading during development and testing
|
|
224
|
+
- **CI/CD pipelines**: Use `--json-logs` for structured logging that can be parsed by log aggregation tools
|
|
225
|
+
- **REST API**: The upcoming REST API will always use JSON logging for consistency
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { runComparison } from "breakcheck-core";
|
|
2
|
+
import { InteractiveCommand } from "interactive-commander";
|
|
3
|
+
import { configureLogger } from "../utils.js";
|
|
4
|
+
export const compareCommand = new InteractiveCommand("compare")
|
|
5
|
+
.description("Compare two snapshots and save the results to disk")
|
|
6
|
+
.requiredOption("-b, --before <name>", 'Name of the "before" snapshot')
|
|
7
|
+
.requiredOption("-a, --after <name>", 'Name of the "after" snapshot')
|
|
8
|
+
.option("-o, --output <name>", "Name for the comparison output directory", "compare_default")
|
|
9
|
+
.option("-r, --rules <path>", "Path to rules file (feature to be implemented)", "default")
|
|
10
|
+
.option("--json-logs", "Output logs in JSON format")
|
|
11
|
+
.option("--no-json-logs", "Output logs in pretty format (default)")
|
|
12
|
+
.action(async (options) => {
|
|
13
|
+
// Configure logger based on options
|
|
14
|
+
const logger = configureLogger(options);
|
|
15
|
+
try {
|
|
16
|
+
const comparisonName = options.output || `compare_${options.before}_vs_${options.after}`;
|
|
17
|
+
const config = {
|
|
18
|
+
beforeSnapshotId: options.before,
|
|
19
|
+
afterSnapshotId: options.after,
|
|
20
|
+
comparisonName, // Pass the name to the config
|
|
21
|
+
ruleset: options.rules,
|
|
22
|
+
};
|
|
23
|
+
logger.info(`🚀 Starting comparison: ${options.before} vs ${options.after}`);
|
|
24
|
+
const summary = await runComparison(config); // API call
|
|
25
|
+
if (summary.status === "completed") {
|
|
26
|
+
logger.info("✅ Comparison complete!");
|
|
27
|
+
logger.info(` - Results saved to: ${summary.resultsPath}`);
|
|
28
|
+
logger.info(` - Total pages compared: ${summary.totalPagesCompared}`);
|
|
29
|
+
logger.info(` - Pages with differences: ${summary.pagesWithDifferences}`);
|
|
30
|
+
logger.info(` - New URLs: ${summary.newUrls.length}`);
|
|
31
|
+
logger.info(` - Removed URLs: ${summary.removedUrls.length}`);
|
|
32
|
+
logger.info(` - Overall result: ${summary.overallResult.toUpperCase()}`);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
logger.error({ errors: summary.comparisonProcessErrors }, "❌ Comparison failed");
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
logger.error({ err: error }, "❌ Error running comparison");
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
//# sourceMappingURL=compare.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compare.js","sourceRoot":"","sources":["../../../src/cli/commands/compare.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,kBAAkB,CAAC,SAAS,CAAC;KAC5D,WAAW,CAAC,oDAAoD,CAAC;KACjE,cAAc,CAAC,qBAAqB,EAAE,+BAA+B,CAAC;KACtE,cAAc,CAAC,oBAAoB,EAAE,8BAA8B,CAAC;KACpE,MAAM,CACL,qBAAqB,EACrB,0CAA0C,EAC1C,iBAAiB,CAClB;KACA,MAAM,CACL,oBAAoB,EACpB,gDAAgD,EAChD,SAAS,CACV;KACA,MAAM,CAAC,aAAa,EAAE,4BAA4B,CAAC;KACnD,MAAM,CAAC,gBAAgB,EAAE,wCAAwC,CAAC;KAClE,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,oCAAoC;IACpC,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IAExC,IAAI,CAAC;QACH,MAAM,cAAc,GAClB,OAAO,CAAC,MAAM,IAAI,WAAW,OAAO,CAAC,MAAM,OAAO,OAAO,CAAC,KAAK,EAAE,CAAC;QAEpE,MAAM,MAAM,GAAqB;YAC/B,gBAAgB,EAAE,OAAO,CAAC,MAAM;YAChC,eAAe,EAAE,OAAO,CAAC,KAAK;YAC9B,cAAc,EAAE,8BAA8B;YAC9C,OAAO,EAAE,OAAO,CAAC,KAAK;SACvB,CAAC;QAEF,MAAM,CAAC,IAAI,CACT,2BAA2B,OAAO,CAAC,MAAM,OAAO,OAAO,CAAC,KAAK,EAAE,CAChE,CAAC;QACF,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW;QAExD,IAAI,OAAO,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YACnC,MAAM,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;YACtC,MAAM,CAAC,IAAI,CAAC,0BAA0B,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;YAC7D,MAAM,CAAC,IAAI,CAAC,8BAA8B,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC;YACxE,MAAM,CAAC,IAAI,CACT,gCAAgC,OAAO,CAAC,oBAAoB,EAAE,CAC/D,CAAC;YACF,MAAM,CAAC,IAAI,CAAC,kBAAkB,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;YACxD,MAAM,CAAC,IAAI,CAAC,sBAAsB,OAAO,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC;YAChE,MAAM,CAAC,IAAI,CACT,wBAAwB,OAAO,CAAC,aAAa,CAAC,WAAW,EAAE,EAAE,CAC9D,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,KAAK,CACV,EAAE,MAAM,EAAE,OAAO,CAAC,uBAAuB,EAAE,EAC3C,qBAAqB,CACtB,CAAC;QACJ,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,4BAA4B,CAAC,CAAC;QAC3D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { InteractiveCommand } from "interactive-commander";
|
|
2
|
+
import { configureLogger } from "../utils.js";
|
|
3
|
+
export const helpCommand = new InteractiveCommand("help")
|
|
4
|
+
.description("Show detailed help for a specific command")
|
|
5
|
+
.argument("[command]", "The command to show help for")
|
|
6
|
+
.option("--json-logs", "Output logs in JSON format")
|
|
7
|
+
.option("--no-json-logs", "Output logs in pretty format (default)")
|
|
8
|
+
.action(async (commandName, options) => {
|
|
9
|
+
// Configure logger based on options
|
|
10
|
+
const logger = configureLogger(options);
|
|
11
|
+
try {
|
|
12
|
+
if (!commandName) {
|
|
13
|
+
showGeneralHelp(logger);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
switch (commandName.toLowerCase()) {
|
|
17
|
+
case "snapshot":
|
|
18
|
+
showSnapshotHelp(logger);
|
|
19
|
+
break;
|
|
20
|
+
case "compare":
|
|
21
|
+
showCompareHelp(logger);
|
|
22
|
+
break;
|
|
23
|
+
case "view":
|
|
24
|
+
showViewHelp(logger);
|
|
25
|
+
break;
|
|
26
|
+
case "list-snapshots":
|
|
27
|
+
case "lss":
|
|
28
|
+
showListSnapshotsHelp(logger);
|
|
29
|
+
break;
|
|
30
|
+
default:
|
|
31
|
+
logger.error(`Unknown command: ${commandName}`);
|
|
32
|
+
logger.info("Available commands: snapshot, compare, view, list-snapshots");
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
logger.error({ err: error }, "❌ Error showing help");
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
function showGeneralHelp(logger) {
|
|
42
|
+
logger.info("Breakcheck - A tool for comparing website states before and after changes");
|
|
43
|
+
logger.info("");
|
|
44
|
+
logger.info("Core Workflow:");
|
|
45
|
+
logger.info(" 1. 📸 Take a 'before' snapshot: breakcheck snapshot --url <url> --name <name>");
|
|
46
|
+
logger.info(" 2. ⚙️ Make your changes (deploy, migrate, etc.)");
|
|
47
|
+
logger.info(" 3. 📸 Take an 'after' snapshot: breakcheck snapshot --url <url> --name <name>");
|
|
48
|
+
logger.info(" 4. 🔍 Compare the snapshots: breakcheck compare --before <name> --after <name>");
|
|
49
|
+
logger.info(" 5. 📊 View the results: breakcheck view <comparison-name>");
|
|
50
|
+
logger.info("");
|
|
51
|
+
logger.info("Available Commands:");
|
|
52
|
+
logger.info(" snapshot Create a snapshot of a website");
|
|
53
|
+
logger.info(" compare Compare two snapshots and save the results");
|
|
54
|
+
logger.info(" view View the results of a comparison in your browser");
|
|
55
|
+
logger.info(" list-snapshots List all available snapshots");
|
|
56
|
+
logger.info(" help Show detailed help for a specific command");
|
|
57
|
+
logger.info("");
|
|
58
|
+
logger.info("Global Options:");
|
|
59
|
+
logger.info(" --json-logs Output logs in JSON format (useful for automation)");
|
|
60
|
+
logger.info(" --no-json-logs Output logs in pretty format (default, user-friendly)");
|
|
61
|
+
logger.info("");
|
|
62
|
+
logger.info("Examples:");
|
|
63
|
+
logger.info(" breakcheck help snapshot");
|
|
64
|
+
logger.info(" breakcheck help compare");
|
|
65
|
+
logger.info(" breakcheck help view");
|
|
66
|
+
logger.info("");
|
|
67
|
+
logger.info("For more information, visit: https://github.com/your-repo/breakcheck");
|
|
68
|
+
}
|
|
69
|
+
function showSnapshotHelp(logger) {
|
|
70
|
+
logger.info("📸 SNAPSHOT COMMAND");
|
|
71
|
+
logger.info("===================");
|
|
72
|
+
logger.info("");
|
|
73
|
+
logger.info("Crawls a website and saves its HTML content and structure to a named snapshot.");
|
|
74
|
+
logger.info("");
|
|
75
|
+
logger.info("Usage:");
|
|
76
|
+
logger.info(" breakcheck snapshot [options]");
|
|
77
|
+
logger.info("");
|
|
78
|
+
logger.info("Required Options:");
|
|
79
|
+
logger.info(" -u, --url <url> The base URL to start crawling from");
|
|
80
|
+
logger.info("");
|
|
81
|
+
logger.info("Optional Options:");
|
|
82
|
+
logger.info(" -n, --name <name> A unique name for the snapshot");
|
|
83
|
+
logger.info(" Default: snapshot_YYYY-MM-DD_HH-mm-ssZ");
|
|
84
|
+
logger.info(" -d, --depth <number> Maximum crawl depth (default: 3)");
|
|
85
|
+
logger.info(" -c, --concurrency <number> Number of concurrent requests (default: 5)");
|
|
86
|
+
logger.info(" -i, --include <patterns...> Glob patterns for URLs to include");
|
|
87
|
+
logger.info(" -e, --exclude <patterns...> Glob patterns for URLs to exclude");
|
|
88
|
+
logger.info(" -t, --type <type> The crawler to use: cheerio or playwright (default: cheerio)");
|
|
89
|
+
logger.info(" -w, --write-urls <path> Generate a plain text file of all crawled URLs");
|
|
90
|
+
logger.info(" --json-logs Output logs in JSON format");
|
|
91
|
+
logger.info(" --no-json-logs Output logs in pretty format (default)");
|
|
92
|
+
logger.info("");
|
|
93
|
+
logger.info("Examples:");
|
|
94
|
+
logger.info(" # Basic snapshot");
|
|
95
|
+
logger.info(" breakcheck snapshot --url https://my-website.com");
|
|
96
|
+
logger.info("");
|
|
97
|
+
logger.info(" # Named snapshot with custom settings");
|
|
98
|
+
logger.info(" breakcheck snapshot --url https://my-website.com --name production-live --depth 5 --concurrency 10");
|
|
99
|
+
logger.info("");
|
|
100
|
+
logger.info(" # Snapshot with URL filtering");
|
|
101
|
+
logger.info(" breakcheck snapshot --url https://my-website.com --include '**/blog/**' --exclude '**/admin/**'");
|
|
102
|
+
logger.info("");
|
|
103
|
+
logger.info(" # Use Playwright crawler for JavaScript-heavy sites");
|
|
104
|
+
logger.info(" breakcheck snapshot --url https://my-website.com --type playwright");
|
|
105
|
+
logger.info("");
|
|
106
|
+
logger.info(" # Generate a URL list file");
|
|
107
|
+
logger.info(" breakcheck snapshot --url https://my-website.com --write-urls ./crawled-urls.txt");
|
|
108
|
+
logger.info("");
|
|
109
|
+
logger.info(" # Use JSON logging for automation");
|
|
110
|
+
logger.info(" breakcheck snapshot --url https://my-website.com --json-logs");
|
|
111
|
+
}
|
|
112
|
+
function showCompareHelp(logger) {
|
|
113
|
+
logger.info("🔍 COMPARE COMMAND");
|
|
114
|
+
logger.info("==================");
|
|
115
|
+
logger.info("");
|
|
116
|
+
logger.info("Compares two snapshots, applies rules, and saves the results to disk.");
|
|
117
|
+
logger.info("");
|
|
118
|
+
logger.info("Usage:");
|
|
119
|
+
logger.info(" breakcheck compare [options]");
|
|
120
|
+
logger.info("");
|
|
121
|
+
logger.info("Required Options:");
|
|
122
|
+
logger.info(" -b, --before <name> The name of the 'before' snapshot");
|
|
123
|
+
logger.info(" -a, --after <name> The name of the 'after' snapshot");
|
|
124
|
+
logger.info("");
|
|
125
|
+
logger.info("Optional Options:");
|
|
126
|
+
logger.info(" -o, --output <name> A name for the comparison output directory (default: compare_default)");
|
|
127
|
+
logger.info(" -r, --rules <path> Path to the directory containing the rules.breakcheck file (default: default)");
|
|
128
|
+
logger.info(" --json-logs Output logs in JSON format");
|
|
129
|
+
logger.info(" --no-json-logs Output logs in pretty format (default)");
|
|
130
|
+
logger.info("");
|
|
131
|
+
logger.info("Examples:");
|
|
132
|
+
logger.info(" # Basic comparison");
|
|
133
|
+
logger.info(" breakcheck compare --before production-live --after after-deployment");
|
|
134
|
+
logger.info("");
|
|
135
|
+
logger.info(" # Comparison with custom output name");
|
|
136
|
+
logger.info(" breakcheck compare --before production-live --after after-deployment --output my-comparison");
|
|
137
|
+
logger.info("");
|
|
138
|
+
logger.info(" # Comparison with custom rules");
|
|
139
|
+
logger.info(" breakcheck compare --before production-live --after after-deployment --rules ./my-rules");
|
|
140
|
+
logger.info("");
|
|
141
|
+
logger.info(" # Use JSON logging for automation");
|
|
142
|
+
logger.info(" breakcheck compare --before production-live --after after-deployment --json-logs");
|
|
143
|
+
logger.info("");
|
|
144
|
+
logger.info("Rules File:");
|
|
145
|
+
logger.info(" The rules file (rules.breakcheck) contains DSL rules to ignore dynamic content.");
|
|
146
|
+
logger.info(" Example rules:");
|
|
147
|
+
logger.info(" css:.ad-container do: exclude");
|
|
148
|
+
logger.info(' css:img do: remove_attr attr:"srcset"');
|
|
149
|
+
logger.info(' css:.timestamp do: rewrite_content regex:"\\d{2}/\\d{2}/\\d{4}" replace:"DATE_STAMP"');
|
|
150
|
+
}
|
|
151
|
+
function showViewHelp(logger) {
|
|
152
|
+
logger.info("📊 VIEW COMMAND");
|
|
153
|
+
logger.info("===============");
|
|
154
|
+
logger.info("");
|
|
155
|
+
logger.info("Starts a local web server to display the results of a comparison in a user-friendly interface.");
|
|
156
|
+
logger.info("");
|
|
157
|
+
logger.info("Usage:");
|
|
158
|
+
logger.info(" breakcheck view [comparison-name] [options]");
|
|
159
|
+
logger.info("");
|
|
160
|
+
logger.info("Arguments:");
|
|
161
|
+
logger.info(" comparison-name The name of the comparison to view (default: compare_default)");
|
|
162
|
+
logger.info("");
|
|
163
|
+
logger.info("Options:");
|
|
164
|
+
logger.info(" -p, --port <number> The port to run the view server on (default: 8080)");
|
|
165
|
+
logger.info(" --json-logs Output logs in JSON format");
|
|
166
|
+
logger.info(" --no-json-logs Output logs in pretty format (default)");
|
|
167
|
+
logger.info("");
|
|
168
|
+
logger.info("Examples:");
|
|
169
|
+
logger.info(" # View default comparison");
|
|
170
|
+
logger.info(" breakcheck view");
|
|
171
|
+
logger.info("");
|
|
172
|
+
logger.info(" # View specific comparison");
|
|
173
|
+
logger.info(" breakcheck view my-comparison");
|
|
174
|
+
logger.info("");
|
|
175
|
+
logger.info(" # View on custom port");
|
|
176
|
+
logger.info(" breakcheck view my-comparison --port 3000");
|
|
177
|
+
logger.info("");
|
|
178
|
+
logger.info(" # Use JSON logging for automation");
|
|
179
|
+
logger.info(" breakcheck view my-comparison --json-logs");
|
|
180
|
+
logger.info("");
|
|
181
|
+
logger.info("After running this command:");
|
|
182
|
+
logger.info(" 1. A local web server will start");
|
|
183
|
+
logger.info(" 2. Your default browser will open automatically");
|
|
184
|
+
logger.info(" 3. You'll see a detailed diff report with all changes");
|
|
185
|
+
logger.info(" 4. Press Ctrl+C to stop the server");
|
|
186
|
+
}
|
|
187
|
+
function showListSnapshotsHelp(logger) {
|
|
188
|
+
logger.info("📋 LIST-SNAPSHOTS COMMAND");
|
|
189
|
+
logger.info("=========================");
|
|
190
|
+
logger.info("");
|
|
191
|
+
logger.info("Lists all snapshots that have been saved locally.");
|
|
192
|
+
logger.info("");
|
|
193
|
+
logger.info("Usage:");
|
|
194
|
+
logger.info(" breakcheck list-snapshots");
|
|
195
|
+
logger.info(" breakcheck lss");
|
|
196
|
+
logger.info("");
|
|
197
|
+
logger.info("Aliases:");
|
|
198
|
+
logger.info(" lss Short alias for list-snapshots");
|
|
199
|
+
logger.info("");
|
|
200
|
+
logger.info("Options:");
|
|
201
|
+
logger.info(" --json-logs Output logs in JSON format");
|
|
202
|
+
logger.info(" --no-json-logs Output logs in pretty format (default)");
|
|
203
|
+
logger.info("");
|
|
204
|
+
logger.info("Output Format:");
|
|
205
|
+
logger.info(" The command outputs a table showing:");
|
|
206
|
+
logger.info(" - Name: The snapshot name");
|
|
207
|
+
logger.info(" - Date: When the snapshot was created");
|
|
208
|
+
logger.info(" - Pages: Number of pages crawled");
|
|
209
|
+
logger.info(" - Errors: Number of pages with errors");
|
|
210
|
+
logger.info("");
|
|
211
|
+
logger.info("Example Output:");
|
|
212
|
+
logger.info(" Name | Date | Pages | Errors");
|
|
213
|
+
logger.info(" --------------------|---------------------------|-------|-------");
|
|
214
|
+
logger.info(" production-live | 2025-06-10T16:05:40.123Z | 152 | 0");
|
|
215
|
+
logger.info(" after-deployment | 2025-06-10T17:10:15.456Z | 153 | 1");
|
|
216
|
+
logger.info("");
|
|
217
|
+
logger.info("Examples:");
|
|
218
|
+
logger.info(" # List all snapshots");
|
|
219
|
+
logger.info(" breakcheck list-snapshots");
|
|
220
|
+
logger.info("");
|
|
221
|
+
logger.info(" # Using the short alias");
|
|
222
|
+
logger.info(" breakcheck lss");
|
|
223
|
+
logger.info("");
|
|
224
|
+
logger.info(" # Use JSON logging for automation");
|
|
225
|
+
logger.info(" breakcheck list-snapshots --json-logs");
|
|
226
|
+
}
|
|
227
|
+
//# sourceMappingURL=help.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"help.js","sourceRoot":"","sources":["../../../src/cli/commands/help.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { listSnapshots } from "breakcheck-core";
|
|
2
|
+
import { InteractiveCommand } from "interactive-commander";
|
|
3
|
+
import { configureLogger } from "../utils.js";
|
|
4
|
+
export const listSnapshotsCommand = new InteractiveCommand("list-snapshots")
|
|
5
|
+
.description("List all available snapshots")
|
|
6
|
+
.alias("lss")
|
|
7
|
+
.option("--json-logs", "Output logs in JSON format")
|
|
8
|
+
.option("--no-json-logs", "Output logs in pretty format (default)")
|
|
9
|
+
.action(async (options) => {
|
|
10
|
+
// Configure logger based on options
|
|
11
|
+
const logger = configureLogger(options);
|
|
12
|
+
try {
|
|
13
|
+
// Get snapshots
|
|
14
|
+
const snapshots = await listSnapshots();
|
|
15
|
+
// Display results
|
|
16
|
+
if (snapshots.length === 0) {
|
|
17
|
+
logger.info("No snapshots found");
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
// Calculate column widths
|
|
21
|
+
const nameWidth = Math.max("Name".length, ...snapshots.map((s) => s.name.length));
|
|
22
|
+
const dateWidth = Math.max("Date".length, ...snapshots.map((s) => s.date.length));
|
|
23
|
+
const pageCountWidth = Math.max("Pages".length, ...snapshots.map((s) => s.pageCount.toString().length));
|
|
24
|
+
const errorCountWidth = Math.max("Errors".length, ...snapshots.map((s) => s.errorCount.toString().length));
|
|
25
|
+
// Print header
|
|
26
|
+
logger.info(`${"Name".padEnd(nameWidth)} | ${"Date".padEnd(dateWidth)} | ${"Pages".padEnd(pageCountWidth)} | ${"Errors".padEnd(errorCountWidth)}`);
|
|
27
|
+
logger.info(`${"-".repeat(nameWidth)}-+-${"-".repeat(dateWidth)}-+-${"-".repeat(pageCountWidth)}-+-${"-".repeat(errorCountWidth)}`);
|
|
28
|
+
// Print snapshots
|
|
29
|
+
snapshots.forEach((snapshot) => {
|
|
30
|
+
logger.info(`${snapshot.name.padEnd(nameWidth)} | ${snapshot.date.padEnd(dateWidth)} | ${snapshot.pageCount
|
|
31
|
+
.toString()
|
|
32
|
+
.padEnd(pageCountWidth)} | ${snapshot.errorCount
|
|
33
|
+
.toString()
|
|
34
|
+
.padEnd(errorCountWidth)}`);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
logger.error({ err: error }, "❌ Error listing snapshots");
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
//# sourceMappingURL=list-snapshots.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-snapshots.js","sourceRoot":"","sources":["../../../src/cli/commands/list-snapshots.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { createSnapshotFromConfig } from "breakcheck-core";
|
|
2
|
+
import { InteractiveCommand } from "interactive-commander";
|
|
3
|
+
import { configureLogger } from "../utils.js";
|
|
4
|
+
export const snapshotCommand = new InteractiveCommand("snapshot")
|
|
5
|
+
.description("Create a snapshot of a website")
|
|
6
|
+
.requiredOption("-u, --url <url>", "Base URL to crawl")
|
|
7
|
+
.option("-n, --name <name>", "Name for the snapshot")
|
|
8
|
+
.option("-d, --depth <number>", "Maximum crawl depth", "3")
|
|
9
|
+
.option("-c, --concurrency <number>", "Number of concurrent requests", "5")
|
|
10
|
+
.option("-i, --include <patterns...>", "URL patterns to include")
|
|
11
|
+
.option("-e, --exclude <patterns...>", "URL patterns to exclude")
|
|
12
|
+
.option("-t, --type <type>", "Crawler type (cheerio or playwright)", "cheerio")
|
|
13
|
+
.option("-w, --write-urls <path>", "Generate a URL list file at the specified path")
|
|
14
|
+
.option("--json-logs", "Output logs in JSON format")
|
|
15
|
+
.option("--no-json-logs", "Output logs in pretty format (default)")
|
|
16
|
+
.action(async (options) => {
|
|
17
|
+
// Configure logger based on options
|
|
18
|
+
const logger = configureLogger(options);
|
|
19
|
+
try {
|
|
20
|
+
// Map CLI options to SnapshotConfig
|
|
21
|
+
const config = {
|
|
22
|
+
baseUrl: options.url,
|
|
23
|
+
name: options.name ||
|
|
24
|
+
`snapshot_${new Date()
|
|
25
|
+
.toISOString()
|
|
26
|
+
.replace(/[:.]/g, "-")
|
|
27
|
+
.replace(/T/, "_")
|
|
28
|
+
.replace(/Z$/, "Z")}`,
|
|
29
|
+
crawlSettings: {
|
|
30
|
+
baseUrl: options.url,
|
|
31
|
+
crawlerType: options.type,
|
|
32
|
+
maxDepth: parseInt(options.depth, 10),
|
|
33
|
+
maxConcurrency: parseInt(options.concurrency, 10),
|
|
34
|
+
includePatterns: options.include,
|
|
35
|
+
excludePatterns: options.exclude,
|
|
36
|
+
},
|
|
37
|
+
urlListPath: options.writeUrls,
|
|
38
|
+
};
|
|
39
|
+
// Call API to create snapshot
|
|
40
|
+
const result = await createSnapshotFromConfig(config);
|
|
41
|
+
// Display results
|
|
42
|
+
if (result.status === "success") {
|
|
43
|
+
logger.info(`✅ Snapshot created successfully: ${result.snapshotId}`);
|
|
44
|
+
logger.info(`📊 Pages crawled: ${result.pageCount}`);
|
|
45
|
+
logger.info(`⏱️ Duration: ${result.metadata.durationMs}ms`);
|
|
46
|
+
if (result.errors.length > 0) {
|
|
47
|
+
logger.warn("\n⚠️ Some pages had errors:");
|
|
48
|
+
result.errors.forEach((error) => {
|
|
49
|
+
logger.warn(` - ${error.url}: ${error.message}`);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
if (result.urlListPath) {
|
|
53
|
+
logger.info(`\n📝 URL list generated: ${result.urlListPath}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
logger.error("❌ Failed to create snapshot");
|
|
58
|
+
result.errors.forEach((error) => {
|
|
59
|
+
logger.error(` - ${error.message}`);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
logger.error({ err: error }, "❌ Error creating snapshot");
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
//# sourceMappingURL=snapshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../../src/cli/commands/snapshot.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,kBAAkB,CAAC,UAAU,CAAC;KAC9D,WAAW,CAAC,gCAAgC,CAAC;KAC7C,cAAc,CAAC,iBAAiB,EAAE,mBAAmB,CAAC;KACtD,MAAM,CAAC,mBAAmB,EAAE,uBAAuB,CAAC;KACpD,MAAM,CAAC,sBAAsB,EAAE,qBAAqB,EAAE,GAAG,CAAC;KAC1D,MAAM,CAAC,4BAA4B,EAAE,+BAA+B,EAAE,GAAG,CAAC;KAC1E,MAAM,CAAC,6BAA6B,EAAE,yBAAyB,CAAC;KAChE,MAAM,CAAC,6BAA6B,EAAE,yBAAyB,CAAC;KAChE,MAAM,CACL,mBAAmB,EACnB,sCAAsC,EACtC,SAAS,CACV;KACA,MAAM,CACL,yBAAyB,EACzB,gDAAgD,CACjD;KACA,MAAM,CAAC,aAAa,EAAE,4BAA4B,CAAC;KACnD,MAAM,CAAC,gBAAgB,EAAE,wCAAwC,CAAC;KAClE,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,oCAAoC;IACpC,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IAExC,IAAI,CAAC;QACH,oCAAoC;QACpC,MAAM,MAAM,GAAmB;YAC7B,OAAO,EAAE,OAAO,CAAC,GAAG;YACpB,IAAI,EACF,OAAO,CAAC,IAAI;gBACZ,YAAY,IAAI,IAAI,EAAE;qBACnB,WAAW,EAAE;qBACb,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC;qBACrB,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC;qBACjB,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE;YACzB,aAAa,EAAE;gBACb,OAAO,EAAE,OAAO,CAAC,GAAG;gBACpB,WAAW,EAAE,OAAO,CAAC,IAAI;gBACzB,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;gBACrC,cAAc,EAAE,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;gBACjD,eAAe,EAAE,OAAO,CAAC,OAAO;gBAChC,eAAe,EAAE,OAAO,CAAC,OAAO;aACjC;YACD,WAAW,EAAE,OAAO,CAAC,SAAS;SAC/B,CAAC;QAEF,8BAA8B;QAC9B,MAAM,MAAM,GAAmB,MAAM,wBAAwB,CAAC,MAAM,CAAC,CAAC;QAEtE,kBAAkB;QAClB,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAChC,MAAM,CAAC,IAAI,CAAC,oCAAoC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;YACrE,MAAM,CAAC,IAAI,CAAC,qBAAqB,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;YACrD,MAAM,CAAC,IAAI,CAAC,gBAAgB,MAAM,CAAC,QAAQ,CAAC,UAAU,IAAI,CAAC,CAAC;YAE5D,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC7B,MAAM,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;gBAC1C,MAAM,CAAC,MAAuB,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;oBAChD,MAAM,CAAC,IAAI,CAAC,OAAO,KAAK,CAAC,GAAG,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;gBACpD,CAAC,CAAC,CAAC;YACL,CAAC;YAED,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;gBACvB,MAAM,CAAC,IAAI,CAAC,4BAA4B,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;YAChE,CAAC;QACH,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;YAC5C,MAAM,CAAC,MAAM,CAAC,OAAO,CACnB,CAAC,KAA+C,EAAE,EAAE;gBAClD,MAAM,CAAC,KAAK,CAAC,OAAO,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YACvC,CAAC,CACF,CAAC;QACJ,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,2BAA2B,CAAC,CAAC;QAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { startCliViewServer } from "breakcheck-core";
|
|
2
|
+
import { InteractiveCommand } from "interactive-commander";
|
|
3
|
+
import { configureLogger } from "../utils.js";
|
|
4
|
+
export const viewCommand = new InteractiveCommand("view")
|
|
5
|
+
.description("View the results of a comparison")
|
|
6
|
+
.argument("[comparison-name]", "Name of the comparison to view", "compare_default")
|
|
7
|
+
.option("-p, --port <number>", "Port to run the view server on", "8080")
|
|
8
|
+
.option("--json-logs", "Output logs in JSON format")
|
|
9
|
+
.option("--no-json-logs", "Output logs in pretty format (default)")
|
|
10
|
+
.action(async (comparisonName, options) => {
|
|
11
|
+
// Configure logger based on options
|
|
12
|
+
const logger = configureLogger(options);
|
|
13
|
+
try {
|
|
14
|
+
logger.info(`🔍 Viewing comparison: ${comparisonName}`);
|
|
15
|
+
const port = parseInt(options.port, 10);
|
|
16
|
+
if (isNaN(port) || port < 1 || port > 65535) {
|
|
17
|
+
logger.error("Port must be a number between 1 and 65535");
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
await startCliViewServer(comparisonName, port);
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
logger.error({ err: error }, "❌ Error starting view server");
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
//# sourceMappingURL=view.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view.js","sourceRoot":"","sources":["../../../src/cli/commands/view.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,kBAAkB,CAAC,MAAM,CAAC;KACtD,WAAW,CAAC,kCAAkC,CAAC;KAC/C,QAAQ,CACP,mBAAmB,EACnB,gCAAgC,EAChC,iBAAiB,CAClB;KACA,MAAM,CAAC,qBAAqB,EAAE,gCAAgC,EAAE,MAAM,CAAC;KACvE,MAAM,CAAC,aAAa,EAAE,4BAA4B,CAAC;KACnD,MAAM,CAAC,gBAAgB,EAAE,wCAAwC,CAAC;KAClE,MAAM,CAAC,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,EAAE;IACxC,oCAAoC;IACpC,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IAExC,IAAI,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,0BAA0B,cAAc,EAAE,CAAC,CAAC;QACxD,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAExC,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC;YAC5C,MAAM,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC;YAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,kBAAkB,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;IACjD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,8BAA8B,CAAC,CAAC;QAC7D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configure the logger for CLI usage based on command options
|
|
3
|
+
*/
|
|
4
|
+
export declare function configureLogger(options: {
|
|
5
|
+
jsonLogs?: boolean;
|
|
6
|
+
noJsonLogs?: boolean;
|
|
7
|
+
}): any;
|
|
8
|
+
/**
|
|
9
|
+
* Get the current CLI logger instance
|
|
10
|
+
*/
|
|
11
|
+
export declare function getLogger(): any;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createLogger, logger } from "breakcheck-core";
|
|
2
|
+
// Global logger instance that can be reconfigured
|
|
3
|
+
let cliLogger = logger;
|
|
4
|
+
/**
|
|
5
|
+
* Configure the logger for CLI usage based on command options
|
|
6
|
+
*/
|
|
7
|
+
export function configureLogger(options) {
|
|
8
|
+
// Determine if we should use JSON logs
|
|
9
|
+
// --json-logs takes precedence over --no-json-logs
|
|
10
|
+
const useJsonLogs = options.jsonLogs || false;
|
|
11
|
+
// Create a new logger instance with the specified configuration
|
|
12
|
+
cliLogger = createLogger({ useJsonLogs });
|
|
13
|
+
return cliLogger;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Get the current CLI logger instance
|
|
17
|
+
*/
|
|
18
|
+
export function getLogger() {
|
|
19
|
+
return cliLogger;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/cli/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEvD,kDAAkD;AAClD,IAAI,SAAS,GAAG,MAAM,CAAC;AAEvB;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,OAG/B;IACC,uCAAuC;IACvC,mDAAmD;IACnD,MAAM,WAAW,GAAG,OAAO,CAAC,QAAQ,IAAI,KAAK,CAAC;IAE9C,gEAAgE;IAChE,SAAS,GAAG,YAAY,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC;IAE1C,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS;IACvB,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env npx tsx
|
|
2
|
+
import { InteractiveCommand } from "interactive-commander";
|
|
3
|
+
import { compareCommand } from "./cli/commands/compare.js";
|
|
4
|
+
import { helpCommand } from "./cli/commands/help.js";
|
|
5
|
+
import { listSnapshotsCommand } from "./cli/commands/list-snapshots.js";
|
|
6
|
+
import { snapshotCommand } from "./cli/commands/snapshot.js";
|
|
7
|
+
import { viewCommand } from "./cli/commands/view.js";
|
|
8
|
+
// Create the main program
|
|
9
|
+
const program = new InteractiveCommand();
|
|
10
|
+
// Configure the program
|
|
11
|
+
program
|
|
12
|
+
.name("breakcheck")
|
|
13
|
+
.description("A tool for comparing website states before and after changes")
|
|
14
|
+
.version("0.0.1");
|
|
15
|
+
// Add the commands to the program
|
|
16
|
+
program.addCommand(snapshotCommand);
|
|
17
|
+
program.addCommand(compareCommand);
|
|
18
|
+
program.addCommand(listSnapshotsCommand);
|
|
19
|
+
program.addCommand(viewCommand);
|
|
20
|
+
program.addCommand(helpCommand);
|
|
21
|
+
// Parse command line arguments
|
|
22
|
+
await program.parseAsync();
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAErD,0BAA0B;AAC1B,MAAM,OAAO,GAAG,IAAI,kBAAkB,EAAE,CAAC;AAEzC,wBAAwB;AACxB,OAAO;KACJ,IAAI,CAAC,YAAY,CAAC;KAClB,WAAW,CAAC,8DAA8D,CAAC;KAC3E,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,kCAAkC;AAClC,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;AACpC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AACnC,OAAO,CAAC,UAAU,CAAC,oBAAoB,CAAC,CAAC;AACzC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAEhC,+BAA+B;AAC/B,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cleaver/breakcheck",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"author": "Cleaver Barnes",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/cleaver/breakcheck.git"
|
|
13
|
+
},
|
|
14
|
+
"homepage": "https://github.com/cleaver/breakcheck",
|
|
15
|
+
"bugs": "https://github.com/cleaver/breakcheck/issues",
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"bin": {
|
|
20
|
+
"breakcheck": "dist/index.js"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsc",
|
|
24
|
+
"start:test-server:before": "node src/__test_server__/server-before.js",
|
|
25
|
+
"start:test-server:after": "node src/__test_server__/server-after.js"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@cleaver/breakcheck-core": "^0.1.0",
|
|
29
|
+
"commander": "^12.1.0",
|
|
30
|
+
"ejs": "^3.1.10",
|
|
31
|
+
"express": "^4.19.2",
|
|
32
|
+
"interactive-commander": "^0.6.0",
|
|
33
|
+
"pino-pretty": "^11.2.1"
|
|
34
|
+
}
|
|
35
|
+
}
|