renovate-log-parser 0.1.2 → 0.3.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 +245 -197
- package/dist/commands/install-analyze-skill.d.ts +0 -1
- package/dist/commands/install-analyze-skill.js +15 -12
- package/dist/commands/install-analyze-skill.js.map +1 -1
- package/dist/core/error-detector.d.ts +1 -1
- package/dist/core/error-detector.js +42 -2
- package/dist/core/error-detector.js.map +1 -1
- package/dist/core/skill-template.js +21 -3
- package/dist/core/skill-template.js.map +1 -1
- package/dist/server/api.d.ts +5 -4
- package/dist/server/api.js +59 -26
- package/dist/server/api.js.map +1 -1
- package/dist/server/log-registry.d.ts +17 -8
- package/dist/server/log-registry.js +44 -36
- package/dist/server/log-registry.js.map +1 -1
- package/package.json +10 -5
- package/web/.output/public/200.html +1 -1
- package/web/.output/public/404.html +1 -1
- package/web/.output/public/_nuxt/B7wga9sP.js +6 -0
- package/web/.output/public/_nuxt/BDNMzG2s.js +1 -0
- package/web/.output/public/_nuxt/BqJkfZTJ.js +3 -0
- package/web/.output/public/_nuxt/CMgYIlaH.js +1 -0
- package/web/.output/public/_nuxt/CWl6nNLj.js +1 -0
- package/web/.output/public/_nuxt/DAvRMvMn.js +3 -0
- package/web/.output/public/_nuxt/DB7E78p3.js +1 -0
- package/web/.output/public/_nuxt/DK3Fl9T5.js +1 -0
- package/web/.output/public/_nuxt/DVm4N3tR.js +28 -0
- package/web/.output/public/_nuxt/ObQDjlGC.js +1 -0
- package/web/.output/public/_nuxt/S1m8Jgsd.js +1 -0
- package/web/.output/public/_nuxt/builds/latest.json +1 -1
- package/web/.output/public/_nuxt/builds/meta/d1ca25cf-550d-4bed-a4d1-2daf0b4cc292.json +1 -0
- package/web/.output/public/_nuxt/entry.C5Sa_xmV.css +2 -0
- package/web/.output/public/_nuxt/error-404.zKZBzOko.css +1 -0
- package/web/.output/public/_nuxt/error-500.DwXcJPfY.css +1 -0
- package/web/.output/public/_nuxt/pages.BDcbBSnU.css +1 -0
- package/web/.output/public/_nuxt/public-sans-latin-400-italic.B1appi_f.woff2 +0 -0
- package/web/.output/public/_nuxt/public-sans-latin-400-italic.DsCWG5h0.woff +0 -0
- package/web/.output/public/_nuxt/public-sans-latin-400-normal.8Rpg0ruU.woff2 +0 -0
- package/web/.output/public/_nuxt/public-sans-latin-400-normal.SBbinRkI.woff +0 -0
- package/web/.output/public/_nuxt/public-sans-latin-500-normal.NlrCPXnF.woff2 +0 -0
- package/web/.output/public/_nuxt/public-sans-latin-500-normal.vCxiVFAq.woff +0 -0
- package/web/.output/public/_nuxt/public-sans-latin-600-normal.BR59oU-I.woff +0 -0
- package/web/.output/public/_nuxt/public-sans-latin-600-normal.Fru-LXNs.woff2 +0 -0
- package/web/.output/public/_nuxt/public-sans-latin-700-normal.BqJmxWdE.woff2 +0 -0
- package/web/.output/public/_nuxt/public-sans-latin-700-normal.Dm-oTPSL.woff +0 -0
- package/web/.output/public/_nuxt/qhIzkFe8.js +1 -0
- package/web/.output/public/favicon-dark.svg +32 -0
- package/web/.output/public/favicon-light.svg +32 -0
- package/web/.output/public/index.html +1 -1
- package/web/.output/public/_fonts/57NSSoFy1VLVs2gqly8Ls9awBnZMFyXGrefpmqvdqmc-zJfbBtpgM4cDmcXBsqZNW79_kFnlpPd62b48glgdydA.woff2 +0 -0
- package/web/.output/public/_fonts/8VR2wSMN-3U4NbWAVYXlkRV6hA0jFBXP-0RtL3X7fko-x2gYI4qfmkRdxyQQUPaBZdZdgl1TeVrquF_TxHeM4lM.woff2 +0 -0
- package/web/.output/public/_fonts/GsKUclqeNLJ96g5AU593ug6yanivOiwjW_7zESNPChw-jHA4tBeM1bjF7LATGUpfBuSTyomIFrWBTzjF7txVYfg.woff2 +0 -0
- package/web/.output/public/_fonts/Ld1FnTo3yTIwDyGfTQ5-Fws9AWsCbKfMvgxduXr7JcY-W25bL8NF1fjpLRSOgJb7RoZPHqGQNwMTM7S9tHVoxx8.woff2 +0 -0
- package/web/.output/public/_fonts/NdzqRASp2bovDUhQT1IRE_EMqKJ2KYQdTCfFcBvL8yw-KhwZiS86o3fErOe5GGMExHUemmI_dBfaEFxjISZrBd0.woff2 +0 -0
- package/web/.output/public/_fonts/iTkrULNFJJkTvihIg1Vqi5IODRH_9btXCioVF5l98I8-AndUyau2HR2felA_ra8V2mutQgschhasE5FD1dXGJX8.woff2 +0 -0
- package/web/.output/public/_nuxt/B4JKWaDj.js +0 -1
- package/web/.output/public/_nuxt/Bs-RnkRE.js +0 -37
- package/web/.output/public/_nuxt/DjtJytwR.js +0 -1
- package/web/.output/public/_nuxt/DlAUqK2U.js +0 -1
- package/web/.output/public/_nuxt/a71R3CFc.js +0 -1
- package/web/.output/public/_nuxt/builds/meta/bc129b23-5172-4e74-875d-2a24574a5dbe.json +0 -1
- package/web/.output/public/_nuxt/entry.9mB-pyEY.css +0 -1
- package/web/.output/public/_nuxt/error-404.B_PvSG-P.css +0 -1
- package/web/.output/public/_nuxt/error-500.CghkKCEr.css +0 -1
- package/web/.output/public/_nuxt/index.BlvAG7F6.css +0 -1
- package/web/.output/public/favicon.ico +0 -0
package/README.md
CHANGED
|
@@ -1,28 +1,61 @@
|
|
|
1
1
|
# renovate-log-parser
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<p align="center"><img src="./renovate-log-parser.webp" width="400" /></p>
|
|
4
|
+
|
|
5
|
+
https://github.com/user-attachments/assets/f99595b5-d8bc-4dca-a662-550e502f05f4
|
|
6
|
+
|
|
7
|
+
`renovate-log-parser` is a CLI and web interface for manual and automated analysis of Renovate Bot debug logs in JSONL format.
|
|
8
|
+
|
|
9
|
+
To get this log: if you use the _hosted_ Mend GitHub app, download a run log from [https://developer.mend.io](https://developer.mend.io). For self-hosted Renovate, set the `LOG_FILE` environment variable.
|
|
4
10
|
|
|
5
11
|
`renovate-log-parser` offers the following commands:
|
|
6
12
|
|
|
7
|
-
- `detect-errors`
|
|
8
|
-
- `analyze`
|
|
9
|
-
- `web` starts a temporary local web server
|
|
13
|
+
- `detect-errors` scans the log for potential problems and warnings. If it finds a problem, it exits with an error and reports the cause. This solves hidden Renovate issues you would otherwise miss.
|
|
14
|
+
- `analyze` reports the log structure. A SKILL.md teaches coding agents to read relevant lines and diagnose Renovate problems with fewer tokens.
|
|
15
|
+
- `web` starts a temporary local web server. The server parses logs of _any_ length and provides an interface for analysis and filtering. This interface replaces manual “grep”-like analysis that can overwhelm a text editor.
|
|
16
|
+
- `install-analyze-skill` writes a SKILL.md to your project or home directory. It can include instructions to get logs from self-hosted Renovate runs in GitHub Actions. Your agent then knows how to get and read a log.
|
|
10
17
|
|
|
11
|
-
|
|
18
|
+
To try it now, download an example log and open it in the web UI:
|
|
12
19
|
|
|
13
|
-
|
|
20
|
+
```bash
|
|
21
|
+
curl -sSLO https://raw.githubusercontent.com/MShekow/renovate-log-parser/main/src/core/__tests__/fixtures/various-issues.jsonl
|
|
22
|
+
npx renovate-log-parser web various-issues.jsonl
|
|
23
|
+
```
|
|
14
24
|
|
|
15
|
-
|
|
16
|
-
|
|
25
|
+
<details>
|
|
26
|
+
<summary>Or use Docker to mount the log in the container and map the port</summary>
|
|
17
27
|
|
|
18
|
-
|
|
28
|
+
```bash
|
|
29
|
+
curl -sSLO https://raw.githubusercontent.com/MShekow/renovate-log-parser/main/src/core/__tests__/fixtures/various-issues.jsonl
|
|
30
|
+
docker run --rm -it -p 3000:3000 -v "$PWD/various-issues.jsonl:/logs/various-issues.jsonl:ro" node:26-alpine \
|
|
31
|
+
npx -y renovate-log-parser web /logs/various-issues.jsonl --host 0.0.0.0 --no-open
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
When the container reports that the server is listening, open the UI from a second terminal:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
xdg-open "http://localhost:3000/?log=/logs/various-issues.jsonl"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The `?log=` parameter contains the path _inside_ the container. This parameter makes the UI load the file immediately. On macOS, use `open` instead of `xdg-open`:
|
|
41
|
+
|
|
42
|
+
</details>
|
|
43
|
+
|
|
44
|
+
## Background (why you need this)
|
|
45
|
+
|
|
46
|
+
This tool solves these problems:
|
|
47
|
+
|
|
48
|
+
- Renovate is easy to configure for projects with many repositories and development teams. However, subtle problems can occur later without notice. For example, Renovate can stop creating PRs for complex reasons. It only adds a small notice block to the _Dependency dashboard_ GitHub issue. Teams that use _Jira_ can miss this notice because they do not read GitHub issues.
|
|
49
|
+
- Developers do not always understand the actions of Renovate Bot. Renovate can omit expected actions or do unwanted actions. Manual analysis is difficult for non-experts because the debug-level log is overly verbose. Important information often occurs in _debug_\-level lines, not warning- or error-level lines. AI agents can miss information in large logs or use many tokens for analysis. Consequently, users accept a suboptimal Renovate configuration or become frustrated with Renovate.
|
|
50
|
+
|
|
51
|
+
This tool automatically detects these subtle problems. It also makes manual and AI-assisted analysis of Renovate log files simpler.
|
|
19
52
|
|
|
20
53
|
## Usage
|
|
21
54
|
|
|
22
|
-
Run directly with `npx
|
|
55
|
+
Run the tool directly with `npx`. You do not have to install it:
|
|
23
56
|
|
|
24
57
|
```bash
|
|
25
|
-
# Detect
|
|
58
|
+
# Detect potential problems in a Renovate JSONL log (CI-friendly)
|
|
26
59
|
npx renovate-log-parser detect-errors path/to/renovate.jsonl
|
|
27
60
|
|
|
28
61
|
# Also write a machine-readable JSON report
|
|
@@ -35,7 +68,7 @@ npx renovate-log-parser analyze path/to/renovate.jsonl
|
|
|
35
68
|
npx renovate-log-parser web path/to/renovate.jsonl
|
|
36
69
|
```
|
|
37
70
|
|
|
38
|
-
|
|
71
|
+
Alternatively, install the tool globally:
|
|
39
72
|
|
|
40
73
|
```bash
|
|
41
74
|
npm install -g renovate-log-parser
|
|
@@ -46,47 +79,49 @@ renovate-log-parser --help
|
|
|
46
79
|
|
|
47
80
|
### `detect-errors <path>`
|
|
48
81
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
to stdout
|
|
82
|
+
This command scans a Renovate debug log (JSONL) for potential problems and warnings. It uses deterministic rules to gate CI.
|
|
83
|
+
|
|
84
|
+
The command prints a readable summary to stdout. With `--out`, it writes a stable JSON report for machine processing. It can be used for comparisons between CI runs.
|
|
52
85
|
|
|
53
86
|
```bash
|
|
54
87
|
renovate-log-parser detect-errors renovate.jsonl [--out report.json] \
|
|
55
88
|
[--ignore-file rules.json] [--fail-on-warn]
|
|
56
89
|
```
|
|
57
90
|
|
|
58
|
-
| Arg / option | Default | Description
|
|
59
|
-
| ---------------- | ----------------------------------- |
|
|
60
|
-
| `<path>` | **required** | Path to the Renovate JSONL log
|
|
61
|
-
| `--out` | (none) |
|
|
62
|
-
| `--ignore-file` | `./renovate-log-parser.ignore.json` | Ignore
|
|
63
|
-
| `--fail-on-warn` | `false` |
|
|
91
|
+
| Arg / option | Default | Description |
|
|
92
|
+
| ---------------- | ----------------------------------- | ------------------------------------------- |
|
|
93
|
+
| `<path>` | **required** | Path to the Renovate JSONL log |
|
|
94
|
+
| `--out` | (none) | Path to the machine-readable JSON report |
|
|
95
|
+
| `--ignore-file` | `./renovate-log-parser.ignore.json` | Ignore file (a missing file means no rules) |
|
|
96
|
+
| `--fail-on-warn` | `false` | Include warning findings in the exit code |
|
|
64
97
|
|
|
65
98
|
**Exit codes:**
|
|
66
99
|
|
|
67
100
|
- `0` = no non-ignored errors
|
|
68
|
-
- `1` = ≥1 non-ignored error (or
|
|
101
|
+
- `1` = ≥1 non-ignored error (or ≥1 non-ignored warning with `--fail-on-warn`)
|
|
69
102
|
- `2` = tool/usage error (bad path, unreadable, bad args, malformed ignore file)
|
|
70
103
|
|
|
71
104
|
**Detected categories**:
|
|
72
105
|
|
|
73
|
-
- **Errors** (
|
|
74
|
-
- `host-error-abort`:
|
|
106
|
+
- **Errors** (conditions that Renovate does _not_ otherwise flag in a PR comment):
|
|
107
|
+
- `host-error-abort`: Renovate skipped PR creation or updates because it was unable to reach one or more well-known registries. The detector looks for a `Repository finished` entry with `result: "external-host-error"`.
|
|
75
108
|
- `log-error`: lines with error level (level=50)
|
|
76
109
|
- `log-fatal`: lines with fatal level (level=60)
|
|
77
|
-
- `config-migration`:
|
|
78
|
-
- `
|
|
110
|
+
- `config-migration`: a repository needs a renovate.json migration. The detector looks for a `Config migration necessary` entry that contains `oldConfig` + `newConfig`.
|
|
111
|
+
- `invalid-config`: a repository's own Renovate config did not parse, or failed validation. Renovate aborts the run during `init`, so it extracts nothing and creates no PR. The detector looks for a `Repository has invalid config` entry and reports the offending file (`validationSource`) with the reason (`validationError`, `validationMessage`). Renovate logs this at warning level and still exits with code 0, which makes it easy to miss.
|
|
112
|
+
- `abandoned-package`: a repository contains one or more abandoned packages for which Renovate does not create a PR. The detector reports one finding per package in an `Abandoned package statistics` entry.
|
|
79
113
|
- **Warnings**:
|
|
80
114
|
- `log-warn`: lines with warning level (level=40)
|
|
81
115
|
- `err-object`: reports lines with an `err` object, such as rawExec errors
|
|
82
|
-
- `repo-problem`: reports entries in `repoProblems` lines
|
|
116
|
+
- `repo-problem`: reports entries in `repoProblems` lines, which contain a string array
|
|
117
|
+
|
|
118
|
+
The `counts` map in the JSON report always lists every category, including zero counts. This structure keeps comparisons between CI runs stable.
|
|
83
119
|
|
|
84
|
-
|
|
120
|
+
**Ignore file**: Use stable keys to hide expected findings because line numbers change as logs grow.
|
|
85
121
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
optional `expires` date are reported to stderr and skipped:
|
|
122
|
+
An active rule must match `category`. If it contains `message` or `repository`, these values must also match.
|
|
123
|
+
|
|
124
|
+
If a rule is past its optional `expires` date, the tool reports it to stderr and skips it:
|
|
90
125
|
|
|
91
126
|
```jsonc
|
|
92
127
|
{
|
|
@@ -103,16 +138,16 @@ optional `expires` date are reported to stderr and skipped:
|
|
|
103
138
|
}
|
|
104
139
|
```
|
|
105
140
|
|
|
106
|
-
Ignored findings
|
|
107
|
-
excluded from the summary counts and the exit code.
|
|
141
|
+
Ignored findings remain in the report with `"ignored": true`. The summary counts and exit code exclude them.
|
|
108
142
|
|
|
109
143
|
### `analyze <path>`
|
|
110
144
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
streams a filtered, line-ranged, limited **JSONL**
|
|
114
|
-
|
|
115
|
-
|
|
145
|
+
This command provides a token-efficient structure for an AI coding agent or a person.
|
|
146
|
+
|
|
147
|
+
Without `--print`, it writes compact, single-line JSON **stats** for the complete log to stdout. With `--print`, it streams a filtered, line-ranged, and limited **JSONL** section. Each entry uses one line.
|
|
148
|
+
|
|
149
|
+
The intended loop is:
|
|
150
|
+
First, read the statistics. Then select the relevant line range. Use `--print` to read only that range.
|
|
116
151
|
|
|
117
152
|
```bash
|
|
118
153
|
# Whole-log stats: level counts + per-repository structure
|
|
@@ -138,43 +173,43 @@ renovate-log-parser analyze renovate.jsonl --print \
|
|
|
138
173
|
| `--filter-with-wildcard` | (none) | `key:pattern` wildcard filter (`*` = any run), case-insensitive, repeatable, AND'd |
|
|
139
174
|
| `--include-original-line` | `false` | Add `_oL` (0-indexed source line) to each object |
|
|
140
175
|
|
|
141
|
-
**Stats mode** reports `levelCounts
|
|
142
|
-
|
|
143
|
-
`branches info extended`
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
leading
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
**Exit codes:** `0` = success · `2` = tool/usage error (bad path, unreadable, bad
|
|
164
|
-
filter token).
|
|
176
|
+
**Stats mode** reports `levelCounts`, which contains the entry count for each numeric level. It also reports a `repos` array.
|
|
177
|
+
|
|
178
|
+
For each repository, this array contains the line range, unique branches, and rowids of `branches info extended` entries. It also contains rowids of `packageFiles with updates` entries, `repoProblems`, and the dependency inventory. This inventory combines root-level `depNames`/`packageNames` keys with the `packageFiles with updates` configuration.
|
|
179
|
+
|
|
180
|
+
**Print mode** selects rows in this order: line range, filters, then `--limit`. The limit selects the first N rows in line order.
|
|
181
|
+
|
|
182
|
+
The output is JSONL on stdout without the ignored root fields. The command never removes `msg`.
|
|
183
|
+
|
|
184
|
+
When the limit restricts the result, the command writes a truncation notice to **stderr**. Therefore, stdout remains a clean stream for pipes.
|
|
185
|
+
|
|
186
|
+
Both filter flags target one root-level key. You can repeat them, and all conditions use AND logic with the line range.
|
|
187
|
+
|
|
188
|
+
`--filter` matches the value **exactly**. The command converts its value to a typed JSON value for comparison.
|
|
189
|
+
|
|
190
|
+
The values `true` and `false` become Boolean values. Plain numbers become numbers, so `level:30` matches the numeric `level`.
|
|
191
|
+
|
|
192
|
+
All other values remain strings. This rule includes values with leading zeros or dots, such as `007` or `1.2.3`.
|
|
193
|
+
|
|
194
|
+
`--filter-with-wildcard` treats `*` as "any run of characters" and uses a case-insensitive match. The characters `?` and `%` remain literal.
|
|
195
|
+
|
|
196
|
+
The command anchors the pattern as written. Use a leading or trailing `*` for prefix, suffix, or contains matches. For example, use `msg:*lock file*`.
|
|
197
|
+
|
|
198
|
+
**Exit codes:** `0` = success · `2` = tool/usage error (bad path, unreadable, bad filter token).
|
|
165
199
|
|
|
166
200
|
### `install-analyze-skill`
|
|
167
201
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
202
|
+
This command writes or updates a `renovate-log-analyzer` **SKILL.md**. The skill teaches an AI coding agent how to use `analyze` with fewer tokens.
|
|
203
|
+
|
|
204
|
+
The agent can be Codex, Copilot, Claude Code, or another coding agent. The skill can include instructions to get logs from self-hosted Renovate workflows in GitHub Actions with the `gh` CLI.
|
|
205
|
+
|
|
206
|
+
By default, the command is interactive. It asks whether to install the skill **locally** or **globally**.
|
|
207
|
+
|
|
208
|
+
It also asks whether to include the GitHub fetch section. This section applies to self-hosted Renovate in a GitHub Actions workflow.
|
|
209
|
+
|
|
210
|
+
If you include this section, provide the repository as `org/repo`, the Renovate workflow filename, and the base URL.
|
|
172
211
|
|
|
173
|
-
|
|
174
|
-
**locally** or **globally**, and whether to include the GitHub-fetch section
|
|
175
|
-
(and if so, the base URL, organization, repository, and Renovate workflow
|
|
176
|
-
filename). All answers can also be supplied as flags to run non-interactively
|
|
177
|
-
(e.g. in CI); any flag you pass skips its prompt.
|
|
212
|
+
Provide all answers as flags to run without prompts. Use these flags in CI. Each provided flag skips its prompt.
|
|
178
213
|
|
|
179
214
|
```bash
|
|
180
215
|
# Interactive
|
|
@@ -183,35 +218,31 @@ npx renovate-log-parser install-analyze-skill
|
|
|
183
218
|
# Non-interactive, local, with a GitHub Enterprise fetch section
|
|
184
219
|
npx renovate-log-parser install-analyze-skill --scope local --with-gh \
|
|
185
220
|
--gh-base-url github.example.com \
|
|
186
|
-
--gh-
|
|
221
|
+
--gh-repo acme/app --gh-workflow renovate.yml
|
|
187
222
|
```
|
|
188
223
|
|
|
189
|
-
The skill is
|
|
190
|
-
`<root>/.agents/skills/renovate-log-analyzer/SKILL.md`, where `<root>` is the
|
|
191
|
-
current working directory (`local`) or your home directory (`global`).
|
|
224
|
+
The command writes the skill to `<root>/.agents/skills/renovate-log-analyzer/SKILL.md`. The `<root>` is the current working directory for `local` scope. It is your home directory for `global` scope.
|
|
192
225
|
|
|
193
|
-
| Arg / option | Default | Description
|
|
194
|
-
| --------------- | -------------- |
|
|
195
|
-
| `--scope` | (prompt) | `local` (`<cwd>/.agents/skills`) or `global` (`~/.agents/skills`)
|
|
196
|
-
| `--with-gh` | (prompt) | Include a "fetch logs from GitHub via `gh`" section
|
|
197
|
-
| `--gh-base-url` | (prompt if gh) | GitHub Enterprise host (
|
|
198
|
-
| `--gh-
|
|
199
|
-
| `--gh-
|
|
200
|
-
| `--
|
|
201
|
-
| `--yes` | `false` | Skip all prompts; fail if a required answer is missing |
|
|
226
|
+
| Arg / option | Default | Description |
|
|
227
|
+
| --------------- | -------------- | ------------------------------------------------------------------------------ |
|
|
228
|
+
| `--scope` | (prompt) | `local` (`<cwd>/.agents/skills`) or `global` (`~/.agents/skills`) |
|
|
229
|
+
| `--with-gh` | (prompt) | Include a "fetch logs from GitHub via `gh`" section |
|
|
230
|
+
| `--gh-base-url` | (prompt if gh) | GitHub Enterprise host (for example, `github.example.com`). Blank = github.com |
|
|
231
|
+
| `--gh-repo` | (prompt if gh) | Repository as `org/repo` (for example, `acme/app`) |
|
|
232
|
+
| `--gh-workflow` | (prompt if gh) | Filename of the workflow that runs Renovate (for example, `renovate.yml`) |
|
|
233
|
+
| `--yes` | `false` | Skip all prompts. Fail if a required answer is missing |
|
|
202
234
|
|
|
203
|
-
**Exit codes:** `0` = success · `2` = tool/usage error (missing required answer
|
|
204
|
-
when non-interactive, or a write failure).
|
|
235
|
+
**Exit codes:** `0` = success · `2` = tool/usage error (missing required answer without prompts, or a write failure).
|
|
205
236
|
|
|
206
237
|
### `web`
|
|
207
238
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
[
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
239
|
+
This command starts the bundled web UI for interactive, filtered log analysis. The UI is a statically rendered [Nuxt](https://nuxt.com) SPA with [Nuxt UI](https://ui.nuxt.com).
|
|
240
|
+
|
|
241
|
+
A small [Express](https://expressjs.com) server provides the UI and exposes the `/api` endpoints. The server keeps the SQLite-backed parsed log on disk. It streams paged rows to the client.
|
|
242
|
+
|
|
243
|
+
You can open more than one log at the same time. Open a second browser tab and pick a different file. Each tab keeps its own log and its own filters. The tab keeps its log in the URL, so a page reload restores it.
|
|
244
|
+
|
|
245
|
+
To open a log automatically, provide its optional path. Otherwise, use the file picker in the UI.
|
|
215
246
|
|
|
216
247
|
| Arg / option | Default | Description |
|
|
217
248
|
| ------------ | ----------- | -------------------------------------------------- |
|
|
@@ -228,30 +259,25 @@ renovate-log-parser web path/to/renovate.jsonl
|
|
|
228
259
|
renovate-log-parser web --port 4000 --no-open
|
|
229
260
|
```
|
|
230
261
|
|
|
231
|
-
**The viewer**
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
- **
|
|
239
|
-
- **
|
|
240
|
-
|
|
241
|
-
- **
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
- **Pills** — dynamic, individually toggleable/removable filters created from row
|
|
247
|
-
and JSON-tree context menus (e.g. show-only/hide a `field`, or a
|
|
248
|
-
`field == value`; nested keys create a scoped "contains" search on their
|
|
249
|
-
top-level ancestor).
|
|
262
|
+
**The viewer** displays every log line in a virtualized list with a fixed height. Each row shows a colored level glyph (`T/D/I/W/E/F`) and the entry `msg`.
|
|
263
|
+
|
|
264
|
+
The arrow in each row opens the details slide-over. The slide-over contains a recursive, collapsible JSON tree of the complete entry.
|
|
265
|
+
|
|
266
|
+
**Filtering**: The UI combines all filters with AND logic and debounces input.
|
|
267
|
+
|
|
268
|
+
- **Log levels**: a dropdown that shows or hides entries by level.
|
|
269
|
+
- **Repositories**: includes or excludes entries by repository. The "Repository-independent" pseudo-group contains entries without a `repository`.
|
|
270
|
+
- **Ignored fields**: hides noisy root keys from the row list. The UI always keeps `msg`.
|
|
271
|
+
- **Free-text search**: a field selector. Its first entry, **Raw search**, matches any key or value in the complete line. Other fields use a case-insensitive `*` wildcard match in that field.
|
|
272
|
+
- **Pills**: dynamic filters from the context menus for rows and JSON trees. You can enable, disable, or remove each filter. For example, show or hide a `field` or a `field == value`. Nested keys create a scoped "contains" search for their top-level ancestor.
|
|
273
|
+
|
|
274
|
+
The UI help explains controls that are not visually apparent. These controls include context menus, pill behavior, search rules, and hidden fields.
|
|
275
|
+
|
|
276
|
+
Select the **Help** button in the header to read this information.
|
|
250
277
|
|
|
251
278
|
## Development
|
|
252
279
|
|
|
253
|
-
This repository is an npm workspace
|
|
254
|
-
server live at the root (`src/`), the Nuxt frontend lives in [`web/`](./web).
|
|
280
|
+
This repository is an npm workspace. The publishable CLI and Express web server are in the root `src/` directory. The Nuxt frontend is in [`web/`](./web).
|
|
255
281
|
|
|
256
282
|
```bash
|
|
257
283
|
# Install all workspace dependencies
|
|
@@ -282,53 +308,71 @@ npm run test:e2e # Packaging E2E tests (slow: builds, packs, installs)
|
|
|
282
308
|
|
|
283
309
|
# One-off, needed by the browser tests inside the E2E suite:
|
|
284
310
|
npx playwright-core install chromium
|
|
311
|
+
|
|
312
|
+
npm run test:e2e:screenshots # + pixel comparison, in Docker
|
|
313
|
+
npm run test:e2e:screenshots:update # rewrite the committed baselines
|
|
285
314
|
```
|
|
286
315
|
|
|
287
|
-
Three suites
|
|
316
|
+
Three suites detect different failure classes:
|
|
288
317
|
|
|
289
|
-
- **Unit tests** (`src/core/__tests__/*.test.ts`)
|
|
290
|
-
|
|
291
|
-
- **Fixture tests** (`src/core/__tests__/fixtures.test.ts`) — the full
|
|
292
|
-
Parser → ErrorDetector/Analyzer pipeline run over _real_ Renovate logs
|
|
293
|
-
captured against
|
|
294
|
-
[`MShekow/renovate-log-parser-test`](https://github.com/MShekow/renovate-log-parser-test)
|
|
295
|
-
and committed under `src/core/__tests__/fixtures/`:
|
|
318
|
+
- **Unit tests** (`src/core/__tests__/*.test.ts`): These tests use synthetic, manually written JSONL logs. Each log tests one detection contract.
|
|
319
|
+
- **Fixture tests** (`src/core/__tests__/fixtures.test.ts`): The complete Parser → ErrorDetector/Analyzer pipeline runs on _real_ Renovate logs. Most come from [`MShekow/renovate-log-parser-test`](https://github.com/MShekow/renovate-log-parser-test). The repository stores them in `src/core/__tests__/fixtures/`:
|
|
296
320
|
|
|
297
321
|
| Fixture | What it demonstrates |
|
|
298
322
|
| ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
299
323
|
| `external-host-error.jsonl` | NPM registry blocked → the run aborts with `result: "external-host-error"` |
|
|
300
|
-
| `various-issues.jsonl` | Abandoned packages, a required
|
|
324
|
+
| `various-issues.jsonl` | Abandoned packages, a required configuration migration, and an npm `lock file error` whose `err.stderr` reports a `Conflicting peer dependency` |
|
|
301
325
|
| `failed-dotnet-install.jsonl` | `builds.dotnet.microsoft.com` blocked → `Datasource connection error` (`DEPTH_ZERO_SELF_SIGNED_CERT`) and `Failed to generate lock file` / "No tool releases found." |
|
|
326
|
+
| `invalid-config.jsonl` | An unparseable `renovate.jsonc` → `Repository has invalid config` at warning level, and `result: "config-validation"` |
|
|
327
|
+
|
|
328
|
+
The `invalid-config` fixture is the exception: Renovate ran with `--platform=local` against a directory, so there is no test repository and the repository is named `local`. Its input is `src/core/__tests__/fixtures/invalid-config-repo/renovate.jsonc`, which is malformed on purpose. Do not reformat that file. It is listed in `.prettierignore`.
|
|
329
|
+
|
|
330
|
+
The assertions are _semantic_, not snapshot-based. A Renovate log contains variable data, such as timestamps, pid, hostname, logContext, and dependency versions. The assertions cover only the signals that each scenario demonstrates.
|
|
331
|
+
|
|
332
|
+
- **Packaging E2E tests** (`e2e/pack-install.e2e.ts`): These tests build and run `npm pack`. They install the tarball in an empty temporary project. Then they run the installed `renovate-log-parser` binary with a fixture. Only this suite detects a missing `package.json#files` entry. When `src/` is adjacent, it also detects a `dist/` import that resolves only in that location.
|
|
333
|
+
|
|
334
|
+
To skip the packaging tests, set `SKIP_E2E=1`.
|
|
335
|
+
|
|
336
|
+
The nested `web UI` block starts the installed `web` command. It controls the real UI in headless Chromium with the `playwright-core` _library_. There is no second test runner or configuration file. The cases use `node:test` in the same file. The cases prove that the shipped server starts and provides the SPA. They do not only inspect the package files.
|
|
337
|
+
|
|
338
|
+
If a browser test fails, the suite writes a screenshot and HTML dump to `e2e-artifacts/`. It also writes the captured console and server output. CI uploads these files as a build artifact.
|
|
339
|
+
|
|
340
|
+
### Screenshot tests
|
|
341
|
+
|
|
342
|
+
There are cases in the `web UI` block comparing the live UI with PNG files in [`e2e/screenshots/`](./e2e/screenshots). These files show the empty state, a loaded log, the Problems slide-over, and the details slide-over.
|
|
343
|
+
|
|
344
|
+
A difference in **one** pixel fails the test. Locator-based assertions cannot detect a broken layout or a level glyph that lost its color. They also cannot detect a Nuxt UI upgrade that changes the header layout. Only this suite detects these changes.
|
|
345
|
+
|
|
346
|
+
Code is not the only factor that changes pixels. The Chromium build, installed font files, and fontconfig rasterization configuration also change the output.
|
|
347
|
+
|
|
348
|
+
A baseline is meaningful only in a fixed environment. Therefore, the comparison runs in the container built from [`e2e/Dockerfile`](./e2e/Dockerfile). The container has a pinned base image and a fixed grayscale antialiasing and hinting configuration. The `playwright-core` version in `package.json` pins the Chromium build.
|
|
349
|
+
|
|
350
|
+
Outside this container, the four cases skip. Therefore, `npm run test:e2e` continues to work as before.
|
|
351
|
+
|
|
352
|
+
```bash
|
|
353
|
+
npm run test:e2e:screenshots # build the image, run the suite, compare
|
|
354
|
+
npm run test:e2e:screenshots:update # same, but rewrite the baselines
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
Both commands build the image, which is cached after the first run. They mount the work tree with your UID. Therefore, they do not leave root-owned files on the host.
|
|
358
|
+
|
|
359
|
+
If the images differ, the commands write the expected, actual, and difference images to `e2e-artifacts/`. CI uploads these images.
|
|
302
360
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
`renovate-log-parser` binary against a fixture. This is the only suite that
|
|
311
|
-
can catch a missing `package.json#files` entry or a `dist/` import that only
|
|
312
|
-
resolved because `src/` sat next to it.
|
|
313
|
-
Set `SKIP_E2E=1` to skip.
|
|
314
|
-
|
|
315
|
-
Its nested `web UI` block starts the installed `web` command and drives the
|
|
316
|
-
real UI in a headless Chromium, using the `playwright-core` _library_ — there
|
|
317
|
-
is no second test runner or config file, these are plain `node:test` cases in
|
|
318
|
-
the same file. Because they run against the installed tarball, they assert
|
|
319
|
-
that the shipped server actually boots and serves the SPA, not merely that its
|
|
320
|
-
files are present. Chromium must be installed once with
|
|
321
|
-
`npx playwright-core install chromium`; when a browser test fails, a
|
|
322
|
-
screenshot, an HTML dump and the captured console/server output are written to
|
|
323
|
-
`e2e-artifacts/` (CI uploads them as a build artifact).
|
|
361
|
+
After an intentional UI change, run the update script. Then **inspect the regenerated PNGs**. Commit them with the change.
|
|
362
|
+
|
|
363
|
+
A baseline difference is part of the review. Do not approve it without inspection.
|
|
364
|
+
|
|
365
|
+
After an upgrade of `@nuxt/ui`, `tailwindcss`, or `playwright-core`, update and inspect the screenshot baselines. All three products may change pixels.
|
|
366
|
+
|
|
367
|
+
For consistent output, the project hosts `Public Sans` with `@fontsource/public-sans` instead of only declaring the font.
|
|
324
368
|
|
|
325
369
|
### Regenerating the log fixtures
|
|
326
370
|
|
|
327
|
-
The [`compose.yml`](./compose.yml) stack runs Renovate against the test
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
adds the hostnames it
|
|
371
|
+
The [`compose.yml`](./compose.yml) stack runs Renovate against the test repository. It includes an NGINX "firewall" for selected hostnames.
|
|
372
|
+
|
|
373
|
+
Docker DNS points these hostnames to the firewall. Therefore, outbound access to these hostnames fails as it does behind a corporate proxy.
|
|
374
|
+
|
|
375
|
+
The base file does not block a hostname. Each scenario adds an override with the hostnames that it must block:
|
|
332
376
|
|
|
333
377
|
```bash
|
|
334
378
|
# Requires a .env with GITHUB_PAT (+ optionally LOCAL_UID / LOCAL_GID)
|
|
@@ -341,23 +385,42 @@ cp container-out-logs/out.log src/core/__tests__/fixtures/<scenario>.jsonl
|
|
|
341
385
|
docker compose ... down -v # discard the generated certificate
|
|
342
386
|
```
|
|
343
387
|
|
|
344
|
-
Renovate must start from a _pristine_ repository
|
|
345
|
-
|
|
346
|
-
|
|
388
|
+
Renovate must start from a _pristine_ repository. Remaining `renovate/*` branches cause the "Branch already exists" code path. That code path skips the work that the fixture records. Before you regenerate a fixture, close the related Renovate PRs and delete their branches.
|
|
389
|
+
|
|
390
|
+
The `invalid-config` fixture does not use this stack. It runs Renovate's [local platform](https://docs.renovatebot.com/modules/platform/local) against a directory, so it needs no test repository, no token and no firewall:
|
|
391
|
+
|
|
392
|
+
```bash
|
|
393
|
+
work="$(mktemp -d)" # must be outside a Git work tree
|
|
394
|
+
cp src/core/__tests__/fixtures/invalid-config-repo/renovate.jsonc "$work/"
|
|
395
|
+
chmod -R a+rwX "$work"
|
|
396
|
+
mkdir -p container-out-logs && chmod 777 container-out-logs
|
|
397
|
+
: > container-out-logs/out.log && chmod 666 container-out-logs/out.log
|
|
398
|
+
|
|
399
|
+
docker run --rm -v "$work":/workspace -w /workspace \
|
|
400
|
+
-v "$PWD/container-out-logs":/logs \
|
|
401
|
+
-e LOG_LEVEL=debug -e LOG_FILE=/logs/out.log -e RENOVATE_PLATFORM=local \
|
|
402
|
+
--entrypoint renovate renovate/renovate:latest
|
|
403
|
+
|
|
404
|
+
cp container-out-logs/out.log src/core/__tests__/fixtures/invalid-config.jsonl
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
Two details matter here. The scratch directory must be outside a Git work tree, because Renovate lists files with `git ls-files` and only falls back to a glob when that command fails. Inside a work tree it succeeds and returns the wrong files. The log file must also be created in advance and made writable, because `--entrypoint renovate` skips the wrapper that normally returns ownership of the log to your user.
|
|
408
|
+
|
|
409
|
+
The [`.github/workflows/verify-fixtures.yml`](./.github/workflows/verify-fixtures.yml) workflow automates this process each week and on demand. It uses one job for each scenario.
|
|
347
410
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
fine-grained PAT
|
|
411
|
+
The jobs that share the test repository run in sequence. Each of these jobs first closes every Renovate PR and deletes every Renovate branch. The `invalid-config` job uses no repository, so it runs in parallel.
|
|
412
|
+
|
|
413
|
+
The workflow overwrites the committed fixture with the new log. Then it runs the fixture tests with this log.
|
|
414
|
+
|
|
415
|
+
If a Renovate release renames a message or removes a field, the workflow fails. It does not commit the new log.
|
|
416
|
+
|
|
417
|
+
Instead, the workflow uploads the log as an artifact for an intentional fixture update. The workflow requires a `TEST_REPO_PAT` secret.
|
|
418
|
+
|
|
419
|
+
This secret is a fine-grained PAT. It requires write access to contents and pull requests in the test repository.
|
|
357
420
|
|
|
358
421
|
### Linting & formatting
|
|
359
422
|
|
|
360
|
-
[ESLint](https://eslint.org)
|
|
423
|
+
[ESLint](https://eslint.org) uses a flat configuration at the workspace root. [Prettier](https://prettier.io) also has its configuration at the workspace root.
|
|
361
424
|
|
|
362
425
|
```bash
|
|
363
426
|
npm run lint # ESLint for src/ (type-aware) + web/ (Nuxt rules)
|
|
@@ -365,42 +428,26 @@ npm run format # Prettier write pass over all non-ignored files
|
|
|
365
428
|
npm run format:check # Prettier check (no writes — useful in CI)
|
|
366
429
|
```
|
|
367
430
|
|
|
368
|
-
- **Root (`src/`)
|
|
369
|
-
- **Web (`web/`)
|
|
370
|
-
|
|
371
|
-
### How it
|
|
372
|
-
|
|
373
|
-
- **CLI
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
SQLite-
|
|
381
|
-
- **Backend** — a plain Express server in [`src/server/`](./src/server),
|
|
382
|
-
compiled by the same `tsc` pass as the CLI. It imports `src/core/` through
|
|
383
|
-
ordinary relative imports (no bundler, no alias), serves the `/api` routes
|
|
384
|
-
from `api.ts`, and serves the static SPA with an `index.html` fallback so
|
|
385
|
-
client-side routing works. `log-registry.ts` holds the process-wide "current
|
|
386
|
-
log" (one open `Parser`/SQLite handle per loaded md5, plus a memoized error
|
|
387
|
-
report). The `web` command spawns `dist/server/server-main.js` as a child
|
|
388
|
-
process; when given a log path it hands it off to the UI via a `?log=` query
|
|
389
|
-
parameter.
|
|
431
|
+
- **Root (`src/`)**: [`eslint.config.mjs`](./eslint.config.mjs) applies the `typescript-eslint` `recommendedTypeChecked` rules to `src/**/*.ts`. It appends `eslint-config-prettier` to disable rules that conflict with Prettier. Prettier uses its defaults: semicolons, double quotes, and trailing commas.
|
|
432
|
+
- **Web (`web/`)**: [`web/eslint.config.mjs`](./web/eslint.config.mjs) uses the generated `@nuxt/eslint` configuration. This configuration covers Vue, TypeScript, and Nuxt-specific rules. The root ESLint and Prettier configurations exclude `web/`. Therefore, the two configurations remain independent.
|
|
433
|
+
|
|
434
|
+
### How it is built
|
|
435
|
+
|
|
436
|
+
- **CLI**: TypeScript compiles to ESM in `dist/` with `tsc`. The CLI uses [`yargs`](https://yargs.js.org) to parse commands.
|
|
437
|
+
- **Frontend**: The Nuxt UI application uses `nuxt generate` and `ssr: false`. It is a client-side SPA. The `web/.output/public` directory contains an application shell and static assets. The package does not include Nitro/h3, and the application does not run it. The frontend shares the filtering model and level metadata from `src/core/` with the CLI. The bundle aliases this code as `renovate-core`.
|
|
438
|
+
|
|
439
|
+
Therefore, the browser and CLI use the same SQLite-backed model.
|
|
440
|
+
|
|
441
|
+
- **Backend**: A plain Express server is in [`src/server/`](./src/server). The same `tsc` pass compiles the backend and CLI. The backend imports `src/core/` through ordinary relative imports without a bundler or alias. It provides the `/api` routes from `api.ts`. It also provides the static SPA with an `index.html` fallback for client-side routing. `log-registry.ts` keeps every loaded log, keyed by its content md5.
|
|
442
|
+
|
|
443
|
+
It keeps one open `Parser`/SQLite handle for each loaded md5 and a memoized error report. The read endpoints are stateless: each `GET` gives the md5 of the log to read in a query parameter. There is no server-side "current log". Therefore, each browser tab can show a different log. The `web` command starts `dist/server/server-main.js` as a child process. When the user provides a log path, the command sends it to the UI in a `?log=` query parameter. The UI then replaces that parameter with `?md5=`, which lets the tab restore its log after a page reload.
|
|
390
444
|
|
|
391
445
|
### What gets published
|
|
392
446
|
|
|
393
|
-
Two `package.json` mechanisms
|
|
447
|
+
Two `package.json` mechanisms include both build outputs in the npm package:
|
|
394
448
|
|
|
395
|
-
- **`files: ["dist", "web/.output/public"]
|
|
396
|
-
|
|
397
|
-
`bin` target, then includes everything matched here — both directories,
|
|
398
|
-
recursively. This list takes precedence over `.gitignore`, which is why
|
|
399
|
-
`web/.output/` (gitignored as a build artifact) is still published.
|
|
400
|
-
- **`prepublishOnly: "npm run build"`** — a lifecycle hook npm runs automatically
|
|
401
|
-
before packing on `npm publish`. It generates the static SPA and compiles the
|
|
402
|
-
CLI + server `dist`, so both directories exist and are current by the time the
|
|
403
|
-
`files` allow-list is evaluated.
|
|
449
|
+
- **`files: ["dist", "web/.output/public"]`**: This allow-list controls the contents of the published tarball. npm always adds `package.json`, `README`, `LICENSE`, and the `bin` target. Then it recursively adds both listed directories. This list takes precedence over `.gitignore`. Therefore, npm publishes `web/.output/` although Git ignores it as a build artifact.
|
|
450
|
+
- **`prepublishOnly: "npm run build"`**: Before npm creates the package for `npm publish`, it automatically runs this lifecycle hook. The hook generates the static SPA and compiles the CLI and server to `dist`. When npm evaluates the `files` allow-list, both directories exist and contain current files.
|
|
404
451
|
|
|
405
452
|
```
|
|
406
453
|
npm publish
|
|
@@ -410,5 +457,6 @@ npm publish
|
|
|
410
457
|
└─ upload to registry
|
|
411
458
|
```
|
|
412
459
|
|
|
413
|
-
The result is a
|
|
414
|
-
|
|
460
|
+
The result is a small, self-contained package. It does not include source files or an unintended `node_modules` directory.
|
|
461
|
+
|
|
462
|
+
Run `npm pack --dry-run` to inspect the package contents.
|