chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"GlobalSettings": {
|
||||
"isCrossAccountBackupEnabled": "false",
|
||||
"isDelegatedAdministratorEnabled": "false",
|
||||
"isMpaEnabled": "false"
|
||||
},
|
||||
"LastUpdateTime": "2026-05-28T09:52:17.525000+02:00"
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
Determining projects to restore...
|
||||
All projects are up-to-date for restore.
|
||||
/private/tmp/RtkDotnetSmoke/Broken.cs(7,17): error CS1525: Invalid expression term ';' [/private/tmp/RtkDotnetSmoke/RtkDotnetSmoke.csproj]
|
||||
|
||||
Build FAILED.
|
||||
|
||||
/private/tmp/RtkDotnetSmoke/Broken.cs(7,17): error CS1525: Invalid expression term ';' [/private/tmp/RtkDotnetSmoke/RtkDotnetSmoke.csproj]
|
||||
0 Warning(s)
|
||||
1 Error(s)
|
||||
|
||||
Time Elapsed 00:00:00.76
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
[
|
||||
{
|
||||
"FileName": "Program.cs",
|
||||
"FilePath": "src/Program.cs",
|
||||
"FileChanges": [
|
||||
{
|
||||
"LineNumber": 42,
|
||||
"CharNumber": 17,
|
||||
"DiagnosticId": "WHITESPACE",
|
||||
"FormatDescription": "Fix whitespace"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"FileName": "Utils.cs",
|
||||
"FilePath": "src/Utils.cs",
|
||||
"FileChanges": [
|
||||
{
|
||||
"LineNumber": 15,
|
||||
"CharNumber": 8,
|
||||
"DiagnosticId": "IDE0055",
|
||||
"FormatDescription": "Fix formatting"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"FileName": "Tests.cs",
|
||||
"FilePath": "tests/Tests.cs",
|
||||
"FileChanges": []
|
||||
}
|
||||
]
|
||||
+1
@@ -0,0 +1 @@
|
||||
[]
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
[
|
||||
{
|
||||
"FileName": "Program.cs",
|
||||
"FilePath": "src/Program.cs",
|
||||
"FileChanges": []
|
||||
},
|
||||
{
|
||||
"FileName": "Utils.cs",
|
||||
"FilePath": "src/Utils.cs",
|
||||
"FileChanges": []
|
||||
}
|
||||
]
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
Determining projects to restore...
|
||||
All projects are up-to-date for restore.
|
||||
RtkDotnetSmoke -> /private/tmp/RtkDotnetSmoke/bin/Debug/net10.0/RtkDotnetSmoke.dll
|
||||
Test run for /private/tmp/RtkDotnetSmoke/bin/Debug/net10.0/RtkDotnetSmoke.dll (.NETCoreApp,Version=v10.0)
|
||||
VSTest version 18.0.1 (arm64)
|
||||
|
||||
Starting test execution, please wait...
|
||||
A total of 1 test files matched the specified pattern.
|
||||
[xUnit.net 00:00:00.11] RtkDotnetSmoke.UnitTest1.Test1 [FAIL]
|
||||
Failed RtkDotnetSmoke.UnitTest1.Test1 [4 ms]
|
||||
Error Message:
|
||||
Assert.Equal() Failure: Values differ
|
||||
Expected: 2
|
||||
Actual: 3
|
||||
Stack Trace:
|
||||
at RtkDotnetSmoke.UnitTest1.Test1() in /private/tmp/RtkDotnetSmoke/UnitTest1.cs:line 8
|
||||
|
||||
Failed! - Failed: 1, Passed: 0, Skipped: 0, Total: 1, Duration: 13 ms - RtkDotnetSmoke.dll (net10.0)
|
||||
Vendored
+54
@@ -0,0 +1,54 @@
|
||||
section_start:1711234567:prepare_executor[0K
|
||||
Running with gitlab-runner 16.9.0 (656c1943)
|
||||
on runner-abc123 system ID: r_defGHI456
|
||||
Using Docker executor with image node:20-alpine ...
|
||||
Preparing the "docker" executor
|
||||
Using Docker executor with image node:20-alpine ...
|
||||
Running on runner-abc123-project-42-concurrent-0 via runner-host...
|
||||
section_end:1711234570:prepare_executor[0K
|
||||
section_start:1711234570:get_sources[0K
|
||||
Getting source from Git repository
|
||||
Fetching changes with git depth set to 20...
|
||||
Initialized empty Git repository in /builds/acme/toolkit/.git/
|
||||
Created fresh repository.
|
||||
Checking out abc12345 as main...
|
||||
Skipping Git submodules setup
|
||||
section_end:1711234575:get_sources[0K
|
||||
section_start:1711234575:download_artifacts[0K
|
||||
Downloading artifacts for build (job_id=98765)...
|
||||
Downloading artifacts from coordinator... ok host=runner-host id=98765 responseStatus=200 OK token=abc123
|
||||
section_end:1711234578:download_artifacts[0K
|
||||
section_start:1711234578:build_script[0K
|
||||
$ npm ci
|
||||
added 847 packages in 12s
|
||||
$ npm run build
|
||||
> acme-toolkit@3.2.1 build
|
||||
> tsc && vite build
|
||||
[36;1mvite v5.2.0[0m building for production...
|
||||
[32m✓[0m 142 modules transformed.
|
||||
[33m⚠[0m Some chunks are larger than 500 kB after minification.
|
||||
dist/index.html 0.45 kB │ gzip: 0.29 kB
|
||||
dist/assets/main-a1b2c3.js 156.78 kB │ gzip: 48.23 kB
|
||||
dist/assets/style-d4e5f6.css 12.34 kB │ gzip: 3.45 kB
|
||||
[32m✓[0m built in 4.56s
|
||||
$ npm test
|
||||
> acme-toolkit@3.2.1 test
|
||||
> vitest run
|
||||
[32m✓[0m src/utils.test.ts (3 tests) 45ms
|
||||
[32m✓[0m src/api.test.ts (7 tests) 123ms
|
||||
[31m✗[0m src/auth.test.ts (2 tests) 67ms
|
||||
FAIL src/auth.test.ts > validateToken > should reject expired tokens
|
||||
AssertionError: expected true to be false
|
||||
at src/auth.test.ts:42:18
|
||||
Test Files 1 failed | 2 passed | 3 total
|
||||
Tests 1 failed | 11 passed | 12 total
|
||||
Duration 0.89s
|
||||
section_end:1711234600:build_script[0K
|
||||
section_start:1711234600:upload_artifacts[0K
|
||||
Uploading artifacts...
|
||||
Uploading artifacts as "archive" to coordinator... ok id=98765 responseStatus=201 Created token=abc123
|
||||
section_end:1711234605:upload_artifacts[0K
|
||||
section_start:1711234605:cleanup_file_variables[0K
|
||||
Cleaning up project directory and file based variables
|
||||
section_end:1711234606:cleanup_file_variables[0K
|
||||
[31;1mERROR: Job failed: exit code 1[0m
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
[
|
||||
{
|
||||
"iid": 156,
|
||||
"title": "Support glab CI pipeline filtering",
|
||||
"state": "opened",
|
||||
"author": {"username": "alice_dev", "name": "Alice Developer", "id": 42},
|
||||
"web_url": "https://gitlab.example.com/acme/toolkit/-/issues/156",
|
||||
"created_at": "2026-03-01T10:00:00Z",
|
||||
"updated_at": "2026-03-05T14:30:00Z",
|
||||
"labels": ["enhancement", "glab"],
|
||||
"assignees": [{"username": "alice_dev"}],
|
||||
"description": "## Request\n\nAdd support for `glab ci` pipeline filtering.\n\n<!-- internal tracking: PROJ-789 -->\n\n### Acceptance Criteria\n- [ ] `rtk glab ci list` shows compact pipeline summary\n- [ ] `rtk glab ci status` shows current pipeline status\n- [ ] Token savings >= 80%\n\n---\n\n[](https://example.com)\n"
|
||||
},
|
||||
{
|
||||
"iid": 150,
|
||||
"title": "rtk cargo test shows full output when no failures",
|
||||
"state": "opened",
|
||||
"author": {"username": "bob_report", "name": "Bob Reporter", "id": 100},
|
||||
"web_url": "https://gitlab.example.com/acme/toolkit/-/issues/150",
|
||||
"created_at": "2026-02-28T08:00:00Z",
|
||||
"updated_at": "2026-03-02T16:00:00Z",
|
||||
"labels": ["bug", "cargo"],
|
||||
"assignees": [{"username": "dave_fix"}],
|
||||
"description": "When all tests pass, `rtk cargo test` still shows verbose compilation output instead of just the summary line.\n\n### Steps to Reproduce\n1. Run `rtk cargo test` in a project with all passing tests\n2. Observe that compiler output is included\n\n### Expected\nOnly show test summary when all tests pass.\n\n### Actual\nFull compiler warnings and test output shown."
|
||||
},
|
||||
{
|
||||
"iid": 145,
|
||||
"title": "Add Helm CLI support",
|
||||
"state": "opened",
|
||||
"author": {"username": "carol_infra", "name": "Carol Infra", "id": 200},
|
||||
"web_url": "https://gitlab.example.com/acme/toolkit/-/issues/145",
|
||||
"created_at": "2026-02-25T12:00:00Z",
|
||||
"updated_at": "2026-03-04T09:00:00Z",
|
||||
"labels": ["enhancement", "infra"],
|
||||
"assignees": [],
|
||||
"description": "Helm CLI outputs are verbose. Would be great to have RTK support for:\n- `helm list` (compact table)\n- `helm status` (summary only)\n- `helm install/upgrade` (ok confirmation)\n\nSimilar to how `rtk kubectl` works."
|
||||
},
|
||||
{
|
||||
"iid": 140,
|
||||
"title": "Binary size increased 30% after Python/Go modules",
|
||||
"state": "opened",
|
||||
"author": {"username": "eve_perf", "name": "Eve Performance", "id": 300},
|
||||
"web_url": "https://gitlab.example.com/acme/toolkit/-/issues/140",
|
||||
"created_at": "2026-02-20T15:00:00Z",
|
||||
"updated_at": "2026-02-22T10:00:00Z",
|
||||
"labels": ["performance", "build"],
|
||||
"assignees": [{"username": "frank_contrib"}],
|
||||
"description": "After merging Python and Go support, stripped release binary went from 3.2MB to 4.1MB.\n\nInvestigate if we can:\n- Use feature flags to make modules optional\n- Reduce regex count (share patterns across modules)\n- Review serde usage (maybe avoid full JSON parsing for simple cases)"
|
||||
},
|
||||
{
|
||||
"iid": 135,
|
||||
"title": "rtk gain --history shows wrong dates on macOS",
|
||||
"state": "closed",
|
||||
"author": {"username": "george_mac", "name": "George Mac", "id": 400},
|
||||
"web_url": "https://gitlab.example.com/acme/toolkit/-/issues/135",
|
||||
"created_at": "2026-02-15T09:00:00Z",
|
||||
"updated_at": "2026-02-18T11:00:00Z",
|
||||
"labels": ["bug", "macos"],
|
||||
"assignees": [{"username": "alice_dev"}],
|
||||
"description": "On macOS, `rtk gain --history` shows dates in UTC instead of local timezone.\n\nFixed in v0.23.1."
|
||||
},
|
||||
{
|
||||
"iid": 130,
|
||||
"title": "Support TOML-based filter DSL",
|
||||
"state": "opened",
|
||||
"author": {"username": "heidi_arch", "name": "Heidi Architect", "id": 500},
|
||||
"web_url": "https://gitlab.example.com/acme/toolkit/-/issues/130",
|
||||
"created_at": "2026-02-10T08:00:00Z",
|
||||
"updated_at": "2026-02-12T16:00:00Z",
|
||||
"labels": ["enhancement", "architecture"],
|
||||
"assignees": [],
|
||||
"description": "Instead of writing Rust code for each new filter, allow users to define filters in TOML.\n\n```toml\n[[filter]]\ncommand = \"terraform plan\"\npattern = \"^(Plan|Apply|Error):\"\nformat = \"compact\"\n```\n\nThis would make RTK extensible without recompilation."
|
||||
},
|
||||
{
|
||||
"iid": 125,
|
||||
"title": "Improve error messages for missing commands",
|
||||
"state": "closed",
|
||||
"author": {"username": "ivan_docs", "name": "Ivan Writer", "id": 600},
|
||||
"web_url": "https://gitlab.example.com/acme/toolkit/-/issues/125",
|
||||
"created_at": "2026-02-05T14:00:00Z",
|
||||
"updated_at": "2026-02-06T09:00:00Z",
|
||||
"labels": ["enhancement", "ux"],
|
||||
"assignees": [{"username": "ivan_docs"}],
|
||||
"description": "When the underlying command is not installed (e.g., `rtk glab mr list` without glab), the error message is confusing:\n\n```\nError: Failed to run glab mr list\n```\n\nShould say something like:\n```\nError: glab not found. Install it: https://gitlab.com/gitlab-org/cli\n```"
|
||||
},
|
||||
{
|
||||
"iid": 120,
|
||||
"title": "Add rtk completion command for shell completions",
|
||||
"state": "opened",
|
||||
"author": {"username": "judy_shell", "name": "Judy Shell", "id": 700},
|
||||
"web_url": "https://gitlab.example.com/acme/toolkit/-/issues/120",
|
||||
"created_at": "2026-02-01T11:00:00Z",
|
||||
"updated_at": "2026-02-03T15:00:00Z",
|
||||
"labels": ["enhancement", "shell"],
|
||||
"assignees": [],
|
||||
"description": "Clap supports generating shell completions via `clap_complete`. Add a `rtk completion bash/zsh/fish` command.\n\nThis would help discoverability of available commands."
|
||||
},
|
||||
{
|
||||
"iid": 115,
|
||||
"title": "rtk read crashes on binary files",
|
||||
"state": "closed",
|
||||
"author": {"username": "karl_refactor", "name": "Karl Refactorer", "id": 800},
|
||||
"web_url": "https://gitlab.example.com/acme/toolkit/-/issues/115",
|
||||
"created_at": "2026-01-28T10:00:00Z",
|
||||
"updated_at": "2026-01-30T12:00:00Z",
|
||||
"labels": ["bug", "crash"],
|
||||
"assignees": [{"username": "dave_fix"}],
|
||||
"description": "Running `rtk read /path/to/binary.exe` panics with:\n```\nthread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Utf8Error'\n```\n\nShould detect binary files and skip filtering."
|
||||
},
|
||||
{
|
||||
"iid": 110,
|
||||
"title": "Track savings per project directory",
|
||||
"state": "opened",
|
||||
"author": {"username": "lisa_feat", "name": "Lisa Feature", "id": 900},
|
||||
"web_url": "https://gitlab.example.com/acme/toolkit/-/issues/110",
|
||||
"created_at": "2026-01-25T09:00:00Z",
|
||||
"updated_at": "2026-01-27T14:00:00Z",
|
||||
"labels": ["enhancement", "analytics"],
|
||||
"assignees": [],
|
||||
"description": "Currently `rtk gain` shows global stats. It would be useful to see savings broken down by project directory.\n\nProposal: store `cwd` in the tracking database and add `rtk gain --by-project` flag."
|
||||
}
|
||||
]
|
||||
Vendored
+182
@@ -0,0 +1,182 @@
|
||||
[
|
||||
{
|
||||
"iid": 314,
|
||||
"title": "feat(glab): add GitLab CLI (glab) command support",
|
||||
"state": "opened",
|
||||
"author": {"username": "alice_dev", "name": "Alice Developer", "id": 42},
|
||||
"web_url": "https://gitlab.example.com/acme/toolkit/-/merge_requests/314",
|
||||
"created_at": "2026-03-01T10:00:00Z",
|
||||
"updated_at": "2026-03-05T14:30:00Z",
|
||||
"source_branch": "feat/glab-support",
|
||||
"target_branch": "master",
|
||||
"merge_status": "can_be_merged",
|
||||
"draft": false,
|
||||
"labels": ["enhancement", "cli"],
|
||||
"assignees": [{"username": "alice_dev", "name": "Alice Developer"}],
|
||||
"reviewers": [{"username": "bob_review"}, {"username": "carol_review"}],
|
||||
"description": "## Summary\n\nAdd GitLab CLI support.\n\n<!-- auto-generated -->\n\n## Changes\n- New module\n- MR/issue/CI filtering\n- Token savings 80-87%\n\n---\n\n[](https://ci.example.com)\n",
|
||||
"head_pipeline": {"id": 98765, "status": "success", "ref": "feat/glab-support"}
|
||||
},
|
||||
{
|
||||
"iid": 310,
|
||||
"title": "fix(git): handle merge commits in compact diff",
|
||||
"state": "merged",
|
||||
"author": {"username": "dave_fix", "name": "Dave Fixer", "id": 100},
|
||||
"web_url": "https://gitlab.example.com/acme/toolkit/-/merge_requests/310",
|
||||
"created_at": "2026-02-28T08:00:00Z",
|
||||
"updated_at": "2026-03-02T16:00:00Z",
|
||||
"source_branch": "fix/merge-commits",
|
||||
"target_branch": "master",
|
||||
"merge_status": "can_be_merged",
|
||||
"draft": false,
|
||||
"labels": ["bug", "git"],
|
||||
"assignees": [{"username": "dave_fix"}],
|
||||
"reviewers": [{"username": "eve_review"}],
|
||||
"description": "Fix handling of merge commits in `compact_diff`. Previously, merge commits were being skipped entirely which lost context.\n\n### Test Plan\n- [x] Unit tests added\n- [x] Manual verification with merge-heavy repos\n",
|
||||
"head_pipeline": {"id": 98700, "status": "success", "ref": "fix/merge-commits"}
|
||||
},
|
||||
{
|
||||
"iid": 305,
|
||||
"title": "feat(aws): add AWS CLI module with token-optimized output",
|
||||
"state": "opened",
|
||||
"author": {"username": "frank_contrib", "name": "Frank Contributor", "id": 200},
|
||||
"web_url": "https://gitlab.example.com/acme/toolkit/-/merge_requests/305",
|
||||
"created_at": "2026-02-25T12:00:00Z",
|
||||
"updated_at": "2026-03-04T09:00:00Z",
|
||||
"source_branch": "feat/aws-cli",
|
||||
"target_branch": "master",
|
||||
"merge_status": "cannot_be_merged",
|
||||
"draft": true,
|
||||
"labels": ["enhancement", "infra"],
|
||||
"assignees": [],
|
||||
"reviewers": [{"username": "grace_review"}, {"username": "heidi_review"}],
|
||||
"description": "Add AWS CLI support.\n\n\n\n## Commands\n- `rtk aws s3 ls`\n- `rtk aws ec2 describe-instances`\n- `rtk aws ecs list-services`\n\n## Token Savings\n| Command | Savings |\n|---------|--------|\n| s3 ls | 75% |\n| ec2 describe | 85% |\n| ecs list | 80% |\n",
|
||||
"head_pipeline": {"id": 98650, "status": "failed", "ref": "feat/aws-cli"}
|
||||
},
|
||||
{
|
||||
"iid": 302,
|
||||
"title": "chore(master): release 0.24.0",
|
||||
"state": "merged",
|
||||
"author": {"username": "release-bot", "name": "Release Bot", "id": 1},
|
||||
"web_url": "https://gitlab.example.com/acme/toolkit/-/merge_requests/302",
|
||||
"created_at": "2026-02-20T00:00:00Z",
|
||||
"updated_at": "2026-02-20T01:00:00Z",
|
||||
"source_branch": "release-please--branches--master",
|
||||
"target_branch": "master",
|
||||
"merge_status": "can_be_merged",
|
||||
"draft": false,
|
||||
"labels": ["release"],
|
||||
"assignees": [],
|
||||
"reviewers": [],
|
||||
"description": "## [0.24.0](https://example.com/compare/v0.23.0...v0.24.0)\n\n### Features\n* feat(aws): add AWS CLI module\n* feat(psql): add PostgreSQL module\n\n### Bug Fixes\n* fix(playwright): fix JSON parser\n",
|
||||
"head_pipeline": {"id": 98600, "status": "success", "ref": "release-please--branches--master"}
|
||||
},
|
||||
{
|
||||
"iid": 298,
|
||||
"title": "docs: update README with Python and Go command examples",
|
||||
"state": "merged",
|
||||
"author": {"username": "ivan_docs", "name": "Ivan Writer", "id": 300},
|
||||
"web_url": "https://gitlab.example.com/acme/toolkit/-/merge_requests/298",
|
||||
"created_at": "2026-02-18T15:00:00Z",
|
||||
"updated_at": "2026-02-19T10:00:00Z",
|
||||
"source_branch": "docs/python-go-examples",
|
||||
"target_branch": "master",
|
||||
"merge_status": "can_be_merged",
|
||||
"draft": false,
|
||||
"labels": ["documentation"],
|
||||
"assignees": [{"username": "ivan_docs"}],
|
||||
"reviewers": [{"username": "judy_review"}],
|
||||
"description": "Update README.md with comprehensive examples for:\n- Python commands (ruff, pytest, pip)\n- Go commands (go test, go build, golangci-lint)\n\nAll examples tested manually.",
|
||||
"head_pipeline": null
|
||||
},
|
||||
{
|
||||
"iid": 295,
|
||||
"title": "refactor: extract parser module from runner.rs",
|
||||
"state": "closed",
|
||||
"author": {"username": "karl_refactor", "name": "Karl Refactorer", "id": 400},
|
||||
"web_url": "https://gitlab.example.com/acme/toolkit/-/merge_requests/295",
|
||||
"created_at": "2026-02-15T09:00:00Z",
|
||||
"updated_at": "2026-02-16T11:00:00Z",
|
||||
"source_branch": "refactor/parser-module",
|
||||
"target_branch": "master",
|
||||
"merge_status": "can_be_merged",
|
||||
"draft": false,
|
||||
"labels": ["refactor"],
|
||||
"assignees": [{"username": "karl_refactor"}],
|
||||
"reviewers": [],
|
||||
"description": "Extract parser logic from runner.rs into dedicated parser/ module.\n\n---\n\nThis was superseded by #300 which took a different approach.\n\n***\n",
|
||||
"head_pipeline": {"id": 98500, "status": "canceled", "ref": "refactor/parser-module"}
|
||||
},
|
||||
{
|
||||
"iid": 290,
|
||||
"title": "feat(tee): save raw output on failure for LLM re-read",
|
||||
"state": "merged",
|
||||
"author": {"username": "lisa_feat", "name": "Lisa Feature", "id": 500},
|
||||
"web_url": "https://gitlab.example.com/acme/toolkit/-/merge_requests/290",
|
||||
"created_at": "2026-02-10T08:00:00Z",
|
||||
"updated_at": "2026-02-12T16:00:00Z",
|
||||
"source_branch": "feat/tee-output",
|
||||
"target_branch": "master",
|
||||
"merge_status": "can_be_merged",
|
||||
"draft": false,
|
||||
"labels": ["enhancement"],
|
||||
"assignees": [{"username": "lisa_feat"}],
|
||||
"reviewers": [{"username": "mike_review"}],
|
||||
"description": "## Tee Output Recovery\n\nSave raw unfiltered output on command failure.\nPrint one-line hint so LLMs can re-read instead of re-run.\n\n### Configuration\n```toml\n[tee]\nenabled = true\ndir = \"~/.local/share/rtk/tee\"\nmax_files = 20\nmax_size = 1048576\n```\n",
|
||||
"head_pipeline": {"id": 98400, "status": "success", "ref": "feat/tee-output"}
|
||||
},
|
||||
{
|
||||
"iid": 285,
|
||||
"title": "ci: add ARM64 Linux build to release workflow",
|
||||
"state": "merged",
|
||||
"author": {"username": "nancy_ci", "name": "Nancy CI", "id": 600},
|
||||
"web_url": "https://gitlab.example.com/acme/toolkit/-/merge_requests/285",
|
||||
"created_at": "2026-02-05T14:00:00Z",
|
||||
"updated_at": "2026-02-06T09:00:00Z",
|
||||
"source_branch": "ci/arm64-build",
|
||||
"target_branch": "master",
|
||||
"merge_status": "can_be_merged",
|
||||
"draft": false,
|
||||
"labels": ["ci"],
|
||||
"assignees": [{"username": "nancy_ci"}],
|
||||
"reviewers": [{"username": "oscar_review"}],
|
||||
"description": "Add ARM64 Linux target to the release workflow.\n\n- Uses `cross` for cross-compilation\n- Generates `.deb` and `.rpm` packages\n- Tested on Raspberry Pi 4 and AWS Graviton",
|
||||
"head_pipeline": {"id": 98300, "status": "success", "ref": "ci/arm64-build"}
|
||||
},
|
||||
{
|
||||
"iid": 280,
|
||||
"title": "fix(vitest): handle watch mode output gracefully",
|
||||
"state": "opened",
|
||||
"author": {"username": "peter_bugfix", "name": "Peter Bugfix", "id": 700},
|
||||
"web_url": "https://gitlab.example.com/acme/toolkit/-/merge_requests/280",
|
||||
"created_at": "2026-02-01T11:00:00Z",
|
||||
"updated_at": "2026-02-03T15:00:00Z",
|
||||
"source_branch": "fix/vitest-watch",
|
||||
"target_branch": "master",
|
||||
"merge_status": "unchecked",
|
||||
"draft": false,
|
||||
"labels": ["bug", "vitest"],
|
||||
"assignees": [{"username": "peter_bugfix"}],
|
||||
"reviewers": [],
|
||||
"description": "When vitest runs in watch mode, output is continuous and doesn't have a clear end marker. This fix detects watch mode and falls back to passthrough.\n\n<!-- TODO: add unit test -->\n",
|
||||
"head_pipeline": {"id": 98200, "status": "running", "ref": "fix/vitest-watch"}
|
||||
},
|
||||
{
|
||||
"iid": 275,
|
||||
"title": "feat(discover): add rtk discover command for missed savings analysis",
|
||||
"state": "merged",
|
||||
"author": {"username": "quinn_dev", "name": "Quinn Developer", "id": 800},
|
||||
"web_url": "https://gitlab.example.com/acme/toolkit/-/merge_requests/275",
|
||||
"created_at": "2026-01-28T10:00:00Z",
|
||||
"updated_at": "2026-01-30T12:00:00Z",
|
||||
"source_branch": "feat/discover",
|
||||
"target_branch": "master",
|
||||
"merge_status": "can_be_merged",
|
||||
"draft": false,
|
||||
"labels": ["enhancement", "analytics"],
|
||||
"assignees": [{"username": "quinn_dev"}],
|
||||
"reviewers": [{"username": "rachel_review"}, {"username": "sam_review"}],
|
||||
"description": "Add `rtk discover` command that scans Claude Code JSONL sessions and reports missed savings opportunities.\n\n## Features\n- Classifies commands as Supported/Unsupported/Ignored\n- Groups by category with estimated token savings\n- Reports top missed commands\n\n## Example\n```\n$ rtk discover\nAnalyzed 1,234 commands across 45 sessions\n\nMissed savings by category:\n Git: 234 commands, ~16,800 tokens\n Cargo: 89 commands, ~7,120 tokens\n```\n",
|
||||
"head_pipeline": {"id": 98100, "status": "success", "ref": "feat/discover"}
|
||||
}
|
||||
]
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
Showing 10 releases on acme/toolkit.
|
||||
|
||||
Name Tag Created
|
||||
v3.2.1 v3.2.1 about 2 days ago
|
||||
v3.2.0 v3.2.0 about 1 week ago
|
||||
v3.1.0 v3.1.0 about 3 weeks ago
|
||||
v3.0.0 v3.0.0 about 1 month ago
|
||||
v2.5.0 v2.5.0 about 3 months ago
|
||||
v2.4.1 v2.4.1 about 5 months ago
|
||||
v2.4.0 v2.4.0 about 6 months ago
|
||||
v2.3.0 v2.3.0 about 9 months ago
|
||||
v2.2.0 v2.2.0 about 1 year ago
|
||||
v2.1.0 v2.1.0 about 2 years ago
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
Test Release v2.0
|
||||
alice_dev released this 3 days ago
|
||||
abc1234 - v2.0.0
|
||||
|
||||
## What's Changed
|
||||
|
||||
- Added widget support
|
||||
- Fixed authentication bug
|
||||
|
||||
### Contributors
|
||||
|
||||
@alice_dev @bob_dev
|
||||
|
||||
--------
|
||||
|
||||
Image: logo → https://example.com/logo.png
|
||||
|
||||
<!-- internal tracking: PROJ-123 -->
|
||||
|
||||
|
||||
ASSETS
|
||||
There are no assets for this release
|
||||
SOURCES
|
||||
https://gitlab.example.com/acme/toolkit/-/archive/v2.0.0/toolkit-v2.0.0.zip
|
||||
https://gitlab.example.com/acme/toolkit/-/archive/v2.0.0/toolkit-v2.0.0.tar.gz
|
||||
https://gitlab.example.com/acme/toolkit/-/archive/v2.0.0/toolkit-v2.0.0.tar.bz2
|
||||
https://gitlab.example.com/acme/toolkit/-/archive/v2.0.0/toolkit-v2.0.0.tar
|
||||
|
||||
|
||||
View this release on GitLab at https://gitlab.example.com/acme/toolkit/-/releases/v2.0.0
|
||||
Vendored
+144
@@ -0,0 +1,144 @@
|
||||
{
|
||||
"Issues": [
|
||||
{
|
||||
"FromLinter": "errcheck",
|
||||
"Text": "Error return value of `foo` is not checked",
|
||||
"Severity": "error",
|
||||
"SourceLines": [
|
||||
" if err := foo(); err != nil {",
|
||||
" return err",
|
||||
" }"
|
||||
],
|
||||
"Pos": {
|
||||
"Filename": "pkg/handler/server.go",
|
||||
"Line": 42,
|
||||
"Column": 5,
|
||||
"Offset": 1024
|
||||
},
|
||||
"Replacement": null,
|
||||
"ExpectNoLint": false,
|
||||
"ExpectedNoLintLinter": ""
|
||||
},
|
||||
{
|
||||
"FromLinter": "errcheck",
|
||||
"Text": "Error return value of `bar` is not checked",
|
||||
"Severity": "error",
|
||||
"SourceLines": [
|
||||
" bar()",
|
||||
" return nil",
|
||||
"}"
|
||||
],
|
||||
"Pos": {
|
||||
"Filename": "pkg/handler/server.go",
|
||||
"Line": 55,
|
||||
"Column": 2,
|
||||
"Offset": 2048
|
||||
},
|
||||
"Replacement": null,
|
||||
"ExpectNoLint": false,
|
||||
"ExpectedNoLintLinter": ""
|
||||
},
|
||||
{
|
||||
"FromLinter": "gosimple",
|
||||
"Text": "S1003: should replace strings.Index with strings.Contains",
|
||||
"Severity": "warning",
|
||||
"SourceLines": [
|
||||
" if strings.Index(s, sub) >= 0 {",
|
||||
" return true",
|
||||
" }"
|
||||
],
|
||||
"Pos": {
|
||||
"Filename": "pkg/utils/strings.go",
|
||||
"Line": 15,
|
||||
"Column": 2,
|
||||
"Offset": 512
|
||||
},
|
||||
"Replacement": null,
|
||||
"ExpectNoLint": false,
|
||||
"ExpectedNoLintLinter": ""
|
||||
},
|
||||
{
|
||||
"FromLinter": "govet",
|
||||
"Text": "printf: Sprintf format %s has arg of wrong type int",
|
||||
"Severity": "error",
|
||||
"SourceLines": [
|
||||
" fmt.Sprintf(\"%s\", 42)"
|
||||
],
|
||||
"Pos": {
|
||||
"Filename": "cmd/main/main.go",
|
||||
"Line": 10,
|
||||
"Column": 3,
|
||||
"Offset": 256
|
||||
},
|
||||
"Replacement": null,
|
||||
"ExpectNoLint": false,
|
||||
"ExpectedNoLintLinter": ""
|
||||
},
|
||||
{
|
||||
"FromLinter": "unused",
|
||||
"Text": "func `unusedHelper` is unused",
|
||||
"Severity": "warning",
|
||||
"SourceLines": [
|
||||
"func unusedHelper() {",
|
||||
" // implementation",
|
||||
"}"
|
||||
],
|
||||
"Pos": {
|
||||
"Filename": "internal/helpers.go",
|
||||
"Line": 100,
|
||||
"Column": 1,
|
||||
"Offset": 4096
|
||||
},
|
||||
"Replacement": null,
|
||||
"ExpectNoLint": false,
|
||||
"ExpectedNoLintLinter": ""
|
||||
},
|
||||
{
|
||||
"FromLinter": "errcheck",
|
||||
"Text": "Error return value of `close` is not checked",
|
||||
"Severity": "error",
|
||||
"SourceLines": [
|
||||
" defer file.Close()"
|
||||
],
|
||||
"Pos": {
|
||||
"Filename": "pkg/handler/server.go",
|
||||
"Line": 120,
|
||||
"Column": 10,
|
||||
"Offset": 3072
|
||||
},
|
||||
"Replacement": null,
|
||||
"ExpectNoLint": false,
|
||||
"ExpectedNoLintLinter": ""
|
||||
},
|
||||
{
|
||||
"FromLinter": "gosimple",
|
||||
"Text": "S1005: should omit nil check",
|
||||
"Severity": "warning",
|
||||
"SourceLines": [
|
||||
" if m != nil {",
|
||||
" for k, v := range m {",
|
||||
" process(k, v)",
|
||||
" }",
|
||||
" }"
|
||||
],
|
||||
"Pos": {
|
||||
"Filename": "pkg/utils/strings.go",
|
||||
"Line": 45,
|
||||
"Column": 1,
|
||||
"Offset": 1536
|
||||
},
|
||||
"Replacement": null,
|
||||
"ExpectNoLint": false,
|
||||
"ExpectedNoLintLinter": ""
|
||||
}
|
||||
],
|
||||
"Report": {
|
||||
"Warnings": [],
|
||||
"Linters": [
|
||||
{"Name": "errcheck", "Enabled": true, "EnabledByDefault": true},
|
||||
{"Name": "gosimple", "Enabled": true, "EnabledByDefault": true},
|
||||
{"Name": "govet", "Enabled": true, "EnabledByDefault": true},
|
||||
{"Name": "unused", "Enabled": true, "EnabledByDefault": true}
|
||||
]
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
> Configure project :app
|
||||
> Task :app:preBuild UP-TO-DATE
|
||||
> Task :app:generateDebugBuildConfig UP-TO-DATE
|
||||
> Task :app:compileDebugKotlin FAILED
|
||||
|
||||
FAILURE: Build failed with an exception.
|
||||
|
||||
* What went wrong:
|
||||
Execution failed for task ':app:compileDebugKotlin'.
|
||||
> A failure occurred while executing org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork
|
||||
> Compilation error. See log for more details
|
||||
|
||||
e: /Users/user/MyApp/app/src/main/java/com/example/myapp/MainActivity.kt: (42, 5): Unresolved reference: MyService
|
||||
e: /Users/user/MyApp/app/src/main/java/com/example/myapp/MainActivity.kt: (56, 17): Type mismatch: inferred type is String but Int was expected
|
||||
|
||||
* Try:
|
||||
> Run with --stacktrace option to get the stack trace.
|
||||
> Run with --info or --debug option to get more log output.
|
||||
> Run with --scan to get full insights.
|
||||
|
||||
* Get more help at https://help.gradle.org
|
||||
|
||||
BUILD FAILED in 12s
|
||||
2 actionable tasks: 2 executed
|
||||
Vendored
+33
@@ -0,0 +1,33 @@
|
||||
Starting a Gradle Daemon (subsequent builds will be faster)
|
||||
Daemon will be stopped at the end of the build after running out of JVM memory
|
||||
|
||||
> Configure project :app
|
||||
> Task :app:preBuild UP-TO-DATE
|
||||
> Task :app:generateDebugBuildConfig UP-TO-DATE
|
||||
> Task :app:generateDebugResValues UP-TO-DATE
|
||||
> Task :app:generateDebugResources UP-TO-DATE
|
||||
> Task :app:mergeDebugResources UP-TO-DATE
|
||||
> Task :app:processDebugMainManifest UP-TO-DATE
|
||||
> Task :app:processDebugManifest UP-TO-DATE
|
||||
> Task :app:processDebugManifestForPackage UP-TO-DATE
|
||||
> Task :app:processDebugResources UP-TO-DATE
|
||||
> Task :app:compileDebugKotlin UP-TO-DATE
|
||||
> Task :app:compileDebugJavaWithJavac UP-TO-DATE
|
||||
> Task :app:compileDebugSources UP-TO-DATE
|
||||
> Task :app:lintVitalAnalyzeDebug UP-TO-DATE
|
||||
> Task :app:mergeDebugShaders UP-TO-DATE
|
||||
> Task :app:compileDebugShaders UP-TO-DATE
|
||||
> Task :app:generateDebugAssets UP-TO-DATE
|
||||
> Task :app:mergeDebugAssets UP-TO-DATE
|
||||
> Task :app:mergeDebugJniLibFolders UP-TO-DATE
|
||||
> Task :app:mergeDebugNativeLibs NO-SOURCE
|
||||
> Task :app:stripDebugDebugSymbols NO-SOURCE
|
||||
> Task :app:validateSigningDebug UP-TO-DATE
|
||||
> Task :app:writeDebugAppMetadata UP-TO-DATE
|
||||
> Task :app:writeDebugSigningConfigVersions UP-TO-DATE
|
||||
> Task :app:packageDebug UP-TO-DATE
|
||||
> Task :app:createDebugApkListingFileRedirect UP-TO-DATE
|
||||
> Task :app:assembleDebug UP-TO-DATE
|
||||
|
||||
BUILD SUCCESSFUL in 3s
|
||||
28 actionable tasks: 28 up-to-date
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
Starting 2 tests on Pixel_6_API_33(AVD) - 13
|
||||
Installing APK 'app-debug.apk' on 'Pixel_6_API_33(AVD) - 13'...
|
||||
Installing APK 'app-debug-androidTest.apk' on 'Pixel_6_API_33(AVD) - 13'...
|
||||
|
||||
> Task :app:connectedDebugAndroidTest
|
||||
INSTRUMENTATION_STATUS: class=com.example.myapp.MainActivityTest
|
||||
INSTRUMENTATION_STATUS: current=1
|
||||
INSTRUMENTATION_STATUS: id=AndroidJUnitRunner
|
||||
INSTRUMENTATION_STATUS: numtests=2
|
||||
INSTRUMENTATION_STATUS: stream=
|
||||
INSTRUMENTATION_STATUS: test=exampleInstrumentedTest
|
||||
INSTRUMENTATION_STATUS_CODE: 1
|
||||
INSTRUMENTATION_STATUS: class=com.example.myapp.MainActivityTest
|
||||
INSTRUMENTATION_STATUS: current=1
|
||||
INSTRUMENTATION_STATUS: id=AndroidJUnitRunner
|
||||
INSTRUMENTATION_STATUS: numtests=2
|
||||
INSTRUMENTATION_STATUS: stream=
|
||||
.
|
||||
INSTRUMENTATION_STATUS: test=exampleInstrumentedTest
|
||||
INSTRUMENTATION_STATUS_CODE: 0
|
||||
com.example.myapp.MainActivityTest > exampleInstrumentedTest[Pixel_6_API_33(AVD) - 13] PASSED
|
||||
INSTRUMENTATION_STATUS: class=com.example.myapp.MainActivityTest
|
||||
INSTRUMENTATION_STATUS: current=2
|
||||
INSTRUMENTATION_STATUS: test=anotherTest
|
||||
INSTRUMENTATION_STATUS_CODE: 1
|
||||
com.example.myapp.MainActivityTest > anotherTest[Pixel_6_API_33(AVD) - 13] PASSED
|
||||
INSTRUMENTATION_STATUS_CODE: 0
|
||||
INSTRUMENTATION_RESULT: stream=
|
||||
Tests run: 2, Failures: 0
|
||||
INSTRUMENTATION_CODE: -1
|
||||
|
||||
BUILD SUCCESSFUL in 45s
|
||||
3 actionable tasks: 1 executed, 2 up-to-date
|
||||
Vendored
+48
@@ -0,0 +1,48 @@
|
||||
Starting a Gradle Daemon (subsequent builds will be faster)
|
||||
Daemon will be stopped at the end of the build after running out of JVM memory
|
||||
|
||||
> Configure project :app
|
||||
> Configure project :core
|
||||
|
||||
> Task :app:preBuild UP-TO-DATE
|
||||
> Task :app:preDebugBuild UP-TO-DATE
|
||||
> Task :app:compileDebugAidl NO-SOURCE
|
||||
> Task :app:compileDebugRenderscript NO-SOURCE
|
||||
> Task :app:generateDebugBuildConfig UP-TO-DATE
|
||||
> Task :app:generateDebugResValues UP-TO-DATE
|
||||
> Task :app:generateDebugResources UP-TO-DATE
|
||||
> Task :app:mergeDebugResources UP-TO-DATE
|
||||
> Task :app:processDebugMainManifest UP-TO-DATE
|
||||
> Task :app:processDebugManifest UP-TO-DATE
|
||||
> Task :app:processDebugManifestForPackage UP-TO-DATE
|
||||
> Task :app:processDebugResources UP-TO-DATE
|
||||
> Task :app:compileDebugKotlin UP-TO-DATE
|
||||
> Task :app:compileDebugJavaWithJavac UP-TO-DATE
|
||||
> Task :app:lintVitalAnalyzeDebug UP-TO-DATE
|
||||
> Task :app:lint
|
||||
Ran lint on variant debug: 0 issues found
|
||||
|
||||
Wrote HTML report to file:///Users/user/MyApp/app/build/reports/lint-results-debug.html
|
||||
Wrote XML report to file:///Users/user/MyApp/app/build/reports/lint-results-debug.xml
|
||||
|
||||
> Task :app:lintDebug
|
||||
|
||||
Ran lint on variant debug: 3 issues found
|
||||
|
||||
src/main/java/com/example/myapp/MainActivity.kt:45: Error: Format string invalid [StringFormatInvalid]
|
||||
String.format(getString(R.string.template), arg1, arg2)
|
||||
^
|
||||
This format string placeholder index (2) does not correspond to an argument
|
||||
|
||||
src/main/java/com/example/myapp/Utils.kt:89: Warning: HardcodedText [HardcodedText]
|
||||
return "Hello World"
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
src/main/res/layout/activity_main.xml:15: Warning: Missing contentDescription attribute on image [ContentDescription]
|
||||
<ImageView
|
||||
|
||||
Wrote HTML report to file:///Users/user/MyApp/app/build/reports/lint-results-debug.html
|
||||
Wrote XML report to file:///Users/user/MyApp/app/build/reports/lint-results-debug.xml
|
||||
|
||||
BUILD FAILED in 8s
|
||||
3 actionable tasks: 2 executed, 1 up-to-date
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
> Task :app:testDebugUnitTest
|
||||
com.example.myapp.CalculatorTest > testAddition PASSED
|
||||
com.example.myapp.CalculatorTest > testSubtraction FAILED
|
||||
java.lang.AssertionError: expected:<3> but was:<-1>
|
||||
at org.junit.Assert.fail(Assert.java:89)
|
||||
at org.junit.Assert.assertEquals(Assert.java:197)
|
||||
at com.example.myapp.CalculatorTest.testSubtraction(CalculatorTest.kt:25)
|
||||
com.example.myapp.CalculatorTest > testMultiplication PASSED
|
||||
com.example.myapp.MainViewModelTest > loadDataSuccess PASSED
|
||||
com.example.myapp.MainViewModelTest > loadDataError FAILED
|
||||
kotlin.NotImplementedError: An operation is not implemented: TODO
|
||||
at com.example.myapp.MainViewModelTest.loadDataError(MainViewModelTest.kt:45)
|
||||
|
||||
5 tests completed, 2 failed
|
||||
|
||||
There were failing tests. See the report at: file:///Users/user/MyApp/app/build/reports/tests/testDebugUnitTest/index.html
|
||||
|
||||
BUILD FAILED in 22s
|
||||
4 actionable tasks: 1 executed, 3 up-to-date
|
||||
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
> Task :app:testDebugUnitTest
|
||||
com.example.myapp.CalculatorTest > testAddition PASSED
|
||||
com.example.myapp.CalculatorTest > testSubtraction PASSED
|
||||
com.example.myapp.CalculatorTest > testMultiplication PASSED
|
||||
com.example.myapp.CalculatorTest > testDivision PASSED
|
||||
com.example.myapp.MainViewModelTest > loadDataSuccess PASSED
|
||||
com.example.myapp.MainViewModelTest > loadDataError PASSED
|
||||
|
||||
6 tests completed, 0 failed
|
||||
|
||||
BUILD SUCCESSFUL in 18s
|
||||
4 actionable tasks: 1 executed, 3 up-to-date
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.example.rtk</groupId>
|
||||
<artifactId>multi-module-skeleton</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>child-a</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
</project>
|
||||
@@ -0,0 +1 @@
|
||||
public class Empty {}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.example.rtk</groupId>
|
||||
<artifactId>multi-module-skeleton</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>child-b</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
</project>
|
||||
@@ -0,0 +1 @@
|
||||
public class Empty {}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.example.rtk</groupId>
|
||||
<artifactId>multi-module-skeleton</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>child-a</module>
|
||||
<module>child-b</module>
|
||||
</modules>
|
||||
<properties>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
</project>
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.example.rtk</groupId>
|
||||
<artifactId>multifail-skeleton</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
<properties>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>5.11.4</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.5.5</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.example.rtk;
|
||||
|
||||
public class Calc {
|
||||
public int add(int a, int b) {
|
||||
return a + b;
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package com.example.rtk;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class BoomTest {
|
||||
@Test
|
||||
void boom() {
|
||||
throw new IllegalStateException("boom: errors-only class for fixture capture");
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.example.rtk;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class CalcTest {
|
||||
private final Calc calc = new Calc();
|
||||
|
||||
@Test
|
||||
void failOne() {
|
||||
assertEquals(5, calc.add(2, 2), "failOne: addition should equal five");
|
||||
}
|
||||
|
||||
@Test
|
||||
void failTwo() {
|
||||
throw new IllegalStateException("failTwo: induced error for fixture capture");
|
||||
}
|
||||
|
||||
@Test
|
||||
void passes() {
|
||||
assertEquals(4, calc.add(2, 2));
|
||||
}
|
||||
}
|
||||
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
[INFO] Scanning for projects...
|
||||
[INFO]
|
||||
[INFO] -----------------------< com.example:myapp >------------------------
|
||||
[INFO] Building myapp 1.0.0
|
||||
[INFO] from pom.xml
|
||||
[INFO] --------------------------------[ jar ]---------------------------------
|
||||
[INFO]
|
||||
[INFO] --- clean:3.2.0:clean (default-clean) @ myapp ---
|
||||
[INFO] Deleting /path/to/project/target
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] BUILD SUCCESS
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] Total time: 0.853 s
|
||||
[INFO] Finished at: 2026-01-15T10:30:00Z
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
[INFO] Scanning for projects...
|
||||
[INFO]
|
||||
[INFO] ----------------------< commons-cli:commons-cli >-----------------------
|
||||
[INFO] Building Apache Commons CLI 1.11.1-SNAPSHOT
|
||||
[INFO] from pom.xml
|
||||
[INFO] --------------------------------[ jar ]---------------------------------
|
||||
[INFO]
|
||||
[INFO] --- compiler:3.15.0:compile (default-compile) @ commons-cli ---
|
||||
[INFO] Recompiling the module because of changed source code.
|
||||
[INFO] Compiling 37 source files with javac [debug release 8] to target/classes
|
||||
[INFO] -------------------------------------------------------------
|
||||
[WARNING] COMPILATION WARNING :
|
||||
[INFO] -------------------------------------------------------------
|
||||
[WARNING] source value 8 is obsolete and will be removed in a future release
|
||||
[WARNING] target value 8 is obsolete and will be removed in a future release
|
||||
[WARNING] To suppress warnings about obsolete options, use -Xlint:-options.
|
||||
[INFO] 3 warnings
|
||||
[INFO] -------------------------------------------------------------
|
||||
[INFO] -------------------------------------------------------------
|
||||
[ERROR] COMPILATION ERROR :
|
||||
[INFO] -------------------------------------------------------------
|
||||
[ERROR] src/main/java/org/apache/commons/cli/CompileBreaker.java:[21,16] cannot find symbol
|
||||
symbol: variable bar
|
||||
location: class org.apache.commons.cli.CompileBreaker
|
||||
[INFO] 1 error
|
||||
[INFO] -------------------------------------------------------------
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] BUILD FAILURE
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] Total time: 30.631 s
|
||||
[INFO] Finished at: 2026-05-21T14:59:46Z
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.15.0:compile (default-compile) on project commons-cli: Compilation failure
|
||||
BIN
Binary file not shown.
+44
@@ -0,0 +1,44 @@
|
||||
[INFO] Scanning for projects...
|
||||
[INFO]
|
||||
[INFO] ----------------------< commons-cli:commons-cli >-----------------------
|
||||
[INFO] Building Apache Commons CLI 1.11.1-SNAPSHOT
|
||||
[INFO] from pom.xml
|
||||
[INFO] --------------------------------[ jar ]---------------------------------
|
||||
[INFO]
|
||||
[INFO] --- compiler:3.15.0:compile (default-compile) @ commons-cli ---
|
||||
[INFO] Recompiling the module because of changed source code.
|
||||
[INFO] Compiling 47 source files with javac [debug parameters release 11] to target/classes
|
||||
[INFO]
|
||||
[INFO] --- compiler:3.15.0:testCompile (default-testCompile) @ commons-cli ---
|
||||
[INFO] Recompiling the module because of changed dependency.
|
||||
[INFO] Compiling 52 source files with javac [debug parameters release 11] to target/test-classes
|
||||
[INFO]
|
||||
[INFO] --- surefire:3.5.5:test (default-test) @ commons-cli ---
|
||||
[INFO]
|
||||
[INFO] -------------------------------------------------------
|
||||
[INFO] T E S T S
|
||||
[INFO] -------------------------------------------------------
|
||||
[INFO] Running org.apache.commons.cli.help.UtilTest
|
||||
[INFO] Tests run: 34, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.023 s -- in org.apache.commons.cli.help.UtilTest
|
||||
[INFO] Running org.apache.commons.cli.DefaultParserTest
|
||||
[WARNING] Tests run: 87, Failures: 0, Errors: 0, Skipped: 2, Time elapsed: 1.023 s -- in org.apache.commons.cli.DefaultParserTest
|
||||
[INFO] Running org.apache.commons.cli.AlreadySelectedExceptionTest
|
||||
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.014 s -- in org.apache.commons.cli.AlreadySelectedExceptionTest
|
||||
[INFO]
|
||||
[INFO] Results:
|
||||
[INFO]
|
||||
[INFO] Tests run: 977, Failures: 0, Errors: 0, Skipped: 61
|
||||
[INFO]
|
||||
[INFO] --- jar:3.5.0:jar (default-jar) @ commons-cli ---
|
||||
[INFO] Building jar: target/commons-cli-1.11.1-SNAPSHOT.jar
|
||||
[INFO]
|
||||
[INFO] --- install:3.1.4:install (default-install) @ commons-cli ---
|
||||
[INFO] Installing pom.xml to /root/.m2/repository/commons-cli/commons-cli/1.11.1-SNAPSHOT/commons-cli-1.11.1-SNAPSHOT.pom
|
||||
[INFO] Installing target/commons-cli-1.11.1-SNAPSHOT.jar to /root/.m2/repository/commons-cli/commons-cli/1.11.1-SNAPSHOT/commons-cli-1.11.1-SNAPSHOT.jar
|
||||
[INFO] Installing target/commons-cli-1.11.1-SNAPSHOT-sources.jar to /root/.m2/repository/commons-cli/commons-cli/1.11.1-SNAPSHOT/commons-cli-1.11.1-SNAPSHOT-sources.jar
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] BUILD SUCCESS
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] Total time: 01:29 min
|
||||
[INFO] Finished at: 2026-05-21T15:13:00Z
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
[INFO] Recherche des projets...
|
||||
[INFO]
|
||||
[INFO] -----------------------< com.example:myapp >------------------------
|
||||
[INFO] Construction de myapp 1.0.0
|
||||
[INFO] de pom.xml
|
||||
[INFO] --------------------------------[ jar ]---------------------------------
|
||||
[INFO]
|
||||
[INFO] --- clean:3.2.0:clean (default-clean) @ myapp ---
|
||||
[INFO] Suppression de /path/to/project/target
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] BUILD ÉCHEC
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] Temps total: 0.713 s
|
||||
[INFO] Termine a: 2026-01-15T10:30:00Z
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
[INFO] Scanning for projects...
|
||||
[ERROR] The goal you specified requires a project to execute but there is no POM in this directory (/tmp). Please verify you invoked Maven from the correct directory. -> [Help 1]
|
||||
[ERROR]
|
||||
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
|
||||
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
|
||||
[ERROR]
|
||||
[ERROR] For more information about the errors and possible solutions, please read the following articles:
|
||||
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MissingProjectException
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
[ERROR] Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.069 s <<< FAILURE! -- in x.FailTest
|
||||
[ERROR] x.FailTest.this_will_fail -- Time elapsed: 0.030 s <<< FAILURE!
|
||||
org.opentest4j.AssertionFailedError: deliberate failure for rtk -q filter testing ==> expected: <1> but was: <2>
|
||||
at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
|
||||
at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
|
||||
at org.junit.jupiter.api.AssertEquals.failNotEqual(AssertEquals.java:197)
|
||||
at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:150)
|
||||
at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:563)
|
||||
at x.FailTest.this_will_fail(FailTest.java:9)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
|
||||
|
||||
[ERROR] Failures:
|
||||
[ERROR] FailTest.this_will_fail:9 deliberate failure for rtk -q filter testing ==> expected: <1> but was: <2>
|
||||
[ERROR] Tests run: 6, Failures: 1, Errors: 0, Skipped: 0
|
||||
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:3.5.5:test (default-test) on project mvnq: There are test failures.
|
||||
[ERROR]
|
||||
[ERROR] See /tmp/mvnq/target/surefire-reports for the individual test results.
|
||||
[ERROR] See dump files (if any exist) [date].dump, [date]-jvmRun[N].dump and [date].dumpstream.
|
||||
[ERROR] -> [Help 1]
|
||||
[ERROR]
|
||||
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
|
||||
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
|
||||
[ERROR]
|
||||
[ERROR] For more information about the errors and possible solutions, please read the following articles:
|
||||
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
[INFO] Scanning for projects...
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] Reactor Build Order:
|
||||
[INFO]
|
||||
[INFO] multi-module-skeleton [pom]
|
||||
[INFO] child-a [jar]
|
||||
[INFO] child-b [jar]
|
||||
[INFO]
|
||||
[INFO] ---------------< com.example.rtk:multi-module-skeleton >----------------
|
||||
[INFO] Building multi-module-skeleton 1.0.0-SNAPSHOT [1/3]
|
||||
[INFO] from pom.xml
|
||||
[INFO] --------------------------------[ pom ]---------------------------------
|
||||
[INFO]
|
||||
[INFO] --- install:3.1.2:install (default-install) @ multi-module-skeleton ---
|
||||
[INFO] Installing /tmp/rtk-reactor/pom.xml to /home/vcyber/.m2/repository/com/example/rtk/multi-module-skeleton/1.0.0-SNAPSHOT/multi-module-skeleton-1.0.0-SNAPSHOT.pom
|
||||
[INFO]
|
||||
[INFO] ----------------------< com.example.rtk:child-a >-----------------------
|
||||
[INFO] Building child-a 1.0.0-SNAPSHOT [2/3]
|
||||
[INFO] from child-a/pom.xml
|
||||
[INFO] --------------------------------[ jar ]---------------------------------
|
||||
[INFO]
|
||||
[INFO] --- resources:3.3.1:resources (default-resources) @ child-a ---
|
||||
[INFO] skip non existing resourceDirectory /tmp/rtk-reactor/child-a/src/main/resources
|
||||
[INFO]
|
||||
[INFO] --- compiler:3.13.0:compile (default-compile) @ child-a ---
|
||||
[INFO] Nothing to compile - all classes are up to date.
|
||||
[INFO]
|
||||
[INFO] --- resources:3.3.1:testResources (default-testResources) @ child-a ---
|
||||
[INFO] skip non existing resourceDirectory /tmp/rtk-reactor/child-a/src/test/resources
|
||||
[INFO]
|
||||
[INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ child-a ---
|
||||
[INFO] No sources to compile
|
||||
[INFO]
|
||||
[INFO] --- surefire:2.17:test (default-test) @ child-a ---
|
||||
[INFO] No tests to run.
|
||||
[INFO]
|
||||
[INFO] --- jar:3.1.2:jar (default-jar) @ child-a ---
|
||||
[INFO]
|
||||
[INFO] --- install:3.1.2:install (default-install) @ child-a ---
|
||||
[INFO] Installing /tmp/rtk-reactor/child-a/pom.xml to /home/vcyber/.m2/repository/com/example/rtk/child-a/1.0.0-SNAPSHOT/child-a-1.0.0-SNAPSHOT.pom
|
||||
[INFO] Installing /tmp/rtk-reactor/child-a/target/child-a-1.0.0-SNAPSHOT.jar to /home/vcyber/.m2/repository/com/example/rtk/child-a/1.0.0-SNAPSHOT/child-a-1.0.0-SNAPSHOT.jar
|
||||
[INFO]
|
||||
[INFO] ----------------------< com.example.rtk:child-b >-----------------------
|
||||
[INFO] Building child-b 1.0.0-SNAPSHOT [3/3]
|
||||
[INFO] from child-b/pom.xml
|
||||
[INFO] --------------------------------[ jar ]---------------------------------
|
||||
[INFO]
|
||||
[INFO] --- resources:3.3.1:resources (default-resources) @ child-b ---
|
||||
[INFO] skip non existing resourceDirectory /tmp/rtk-reactor/child-b/src/main/resources
|
||||
[INFO]
|
||||
[INFO] --- compiler:3.13.0:compile (default-compile) @ child-b ---
|
||||
[INFO] Recompiling the module because of changed source code.
|
||||
[INFO] Compiling 1 source file with javac [debug target 21] to target/classes
|
||||
[INFO] -------------------------------------------------------------
|
||||
[ERROR] COMPILATION ERROR :
|
||||
[INFO] -------------------------------------------------------------
|
||||
[ERROR] /tmp/rtk-reactor/child-b/src/main/java/Empty.java:[1,22] cannot find symbol
|
||||
symbol: class BogusType
|
||||
location: class Empty
|
||||
[INFO] 1 error
|
||||
[INFO] -------------------------------------------------------------
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] Reactor Summary for multi-module-skeleton 1.0.0-SNAPSHOT:
|
||||
[INFO]
|
||||
[INFO] multi-module-skeleton .............................. SUCCESS [ 0.369 s]
|
||||
[INFO] child-a ............................................ SUCCESS [ 1.657 s]
|
||||
[INFO] child-b ............................................ FAILURE [ 0.940 s]
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] BUILD FAILURE
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] Total time: 3.193 s
|
||||
[INFO] Finished at: 2026-05-25T12:11:41-03:00
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.13.0:compile (default-compile) on project child-b: Compilation failure
|
||||
[ERROR] /tmp/rtk-reactor/child-b/src/main/java/Empty.java:[1,22] cannot find symbol
|
||||
[ERROR] symbol: class BogusType
|
||||
[ERROR] location: class Empty
|
||||
[ERROR] -> [Help 1]
|
||||
[ERROR]
|
||||
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
|
||||
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
|
||||
[ERROR]
|
||||
[ERROR] For more information about the errors and possible solutions, please read the following articles:
|
||||
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
|
||||
[ERROR]
|
||||
[ERROR] After correcting the problems, you can resume the build with the command
|
||||
[ERROR] mvn <args> -rf :child-b
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
[INFO] Scanning for projects...
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] Reactor Build Order:
|
||||
[INFO]
|
||||
[INFO] multi-module-skeleton [pom]
|
||||
[INFO] child-a [jar]
|
||||
[INFO] child-b [jar]
|
||||
[INFO]
|
||||
[INFO] ---------------< com.example.rtk:multi-module-skeleton >----------------
|
||||
[INFO] Building multi-module-skeleton 1.0.0-SNAPSHOT [1/3]
|
||||
[INFO] from pom.xml
|
||||
[INFO] --------------------------------[ pom ]---------------------------------
|
||||
[INFO]
|
||||
[INFO] --- install:3.1.2:install (default-install) @ multi-module-skeleton ---
|
||||
[INFO] Installing /tmp/rtk-reactor/pom.xml to /home/vcyber/.m2/repository/com/example/rtk/multi-module-skeleton/1.0.0-SNAPSHOT/multi-module-skeleton-1.0.0-SNAPSHOT.pom
|
||||
[INFO]
|
||||
[INFO] ----------------------< com.example.rtk:child-a >-----------------------
|
||||
[INFO] Building child-a 1.0.0-SNAPSHOT [2/3]
|
||||
[INFO] from child-a/pom.xml
|
||||
[INFO] --------------------------------[ jar ]---------------------------------
|
||||
[INFO]
|
||||
[INFO] --- resources:3.3.1:resources (default-resources) @ child-a ---
|
||||
[INFO] skip non existing resourceDirectory /tmp/rtk-reactor/child-a/src/main/resources
|
||||
[INFO]
|
||||
[INFO] --- compiler:3.13.0:compile (default-compile) @ child-a ---
|
||||
[INFO] Nothing to compile - all classes are up to date.
|
||||
[INFO]
|
||||
[INFO] --- resources:3.3.1:testResources (default-testResources) @ child-a ---
|
||||
[INFO] skip non existing resourceDirectory /tmp/rtk-reactor/child-a/src/test/resources
|
||||
[INFO]
|
||||
[INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ child-a ---
|
||||
[INFO] No sources to compile
|
||||
[INFO]
|
||||
[INFO] --- surefire:2.17:test (default-test) @ child-a ---
|
||||
[INFO] No tests to run.
|
||||
[INFO]
|
||||
[INFO] --- jar:3.1.2:jar (default-jar) @ child-a ---
|
||||
[INFO]
|
||||
[INFO] --- install:3.1.2:install (default-install) @ child-a ---
|
||||
[INFO] Installing /tmp/rtk-reactor/child-a/pom.xml to /home/vcyber/.m2/repository/com/example/rtk/child-a/1.0.0-SNAPSHOT/child-a-1.0.0-SNAPSHOT.pom
|
||||
[INFO] Installing /tmp/rtk-reactor/child-a/target/child-a-1.0.0-SNAPSHOT.jar to /home/vcyber/.m2/repository/com/example/rtk/child-a/1.0.0-SNAPSHOT/child-a-1.0.0-SNAPSHOT.jar
|
||||
[INFO]
|
||||
[INFO] ----------------------< com.example.rtk:child-b >-----------------------
|
||||
[INFO] Building child-b 1.0.0-SNAPSHOT [3/3]
|
||||
[INFO] from child-b/pom.xml
|
||||
[INFO] --------------------------------[ jar ]---------------------------------
|
||||
[INFO]
|
||||
[INFO] --- resources:3.3.1:resources (default-resources) @ child-b ---
|
||||
[INFO] skip non existing resourceDirectory /tmp/rtk-reactor/child-b/src/main/resources
|
||||
[INFO]
|
||||
[INFO] --- compiler:3.13.0:compile (default-compile) @ child-b ---
|
||||
[INFO] Nothing to compile - all classes are up to date.
|
||||
[INFO]
|
||||
[INFO] --- resources:3.3.1:testResources (default-testResources) @ child-b ---
|
||||
[INFO] skip non existing resourceDirectory /tmp/rtk-reactor/child-b/src/test/resources
|
||||
[INFO]
|
||||
[INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ child-b ---
|
||||
[INFO] No sources to compile
|
||||
[INFO]
|
||||
[INFO] --- surefire:2.17:test (default-test) @ child-b ---
|
||||
[INFO] No tests to run.
|
||||
[INFO]
|
||||
[INFO] --- jar:3.1.2:jar (default-jar) @ child-b ---
|
||||
[INFO]
|
||||
[INFO] --- install:3.1.2:install (default-install) @ child-b ---
|
||||
[INFO] Installing /tmp/rtk-reactor/child-b/pom.xml to /home/vcyber/.m2/repository/com/example/rtk/child-b/1.0.0-SNAPSHOT/child-b-1.0.0-SNAPSHOT.pom
|
||||
[INFO] Installing /tmp/rtk-reactor/child-b/target/child-b-1.0.0-SNAPSHOT.jar to /home/vcyber/.m2/repository/com/example/rtk/child-b/1.0.0-SNAPSHOT/child-b-1.0.0-SNAPSHOT.jar
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] Reactor Summary for multi-module-skeleton 1.0.0-SNAPSHOT:
|
||||
[INFO]
|
||||
[INFO] multi-module-skeleton .............................. SUCCESS [ 0.353 s]
|
||||
[INFO] child-a ............................................ SUCCESS [ 1.676 s]
|
||||
[INFO] child-b ............................................ SUCCESS [ 0.069 s]
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] BUILD SUCCESS
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] Total time: 2.284 s
|
||||
[INFO] Finished at: 2026-05-25T12:11:31-03:00
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
@@ -0,0 +1,29 @@
|
||||
[INFO] Scanning for projects...
|
||||
[INFO]
|
||||
[INFO] ----------------------< commons-cli:commons-cli >-----------------------
|
||||
[INFO] Building Apache Commons CLI 1.11.1-SNAPSHOT
|
||||
[INFO] from pom.xml
|
||||
[INFO] --------------------------------[ jar ]---------------------------------
|
||||
[INFO]
|
||||
[INFO] --- compiler:3.15.0:compile (default-compile) @ commons-cli ---
|
||||
[INFO] Recompiling the module because of changed source code.
|
||||
[INFO] Compiling 37 source files with javac [debug release 8] to target/classes
|
||||
[INFO] -------------------------------------------------------------
|
||||
[ERROR] COMPILATION ERROR :
|
||||
[INFO] -------------------------------------------------------------
|
||||
[ERROR] src/main/java/org/apache/commons/cli/CompileBreaker.java:[21,16] cannot find symbol
|
||||
symbol: variable bar
|
||||
location: class org.apache.commons.cli.CompileBreaker
|
||||
[INFO] 1 error
|
||||
[INFO] -------------------------------------------------------------
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] BUILD FAILURE
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] Total time: 3.214 s
|
||||
[INFO] Finished at: 2026-05-21T15:02:31Z
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.15.0:compile (default-compile) on project commons-cli: Compilation failure
|
||||
[ERROR] /home/runner/commons-cli/src/main/java/org/apache/commons/cli/CompileBreaker.java:[21,16] cannot find symbol
|
||||
[ERROR] symbol: variable bar
|
||||
[ERROR] location: class org.apache.commons.cli.CompileBreaker
|
||||
[ERROR] -> [Help 1]
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
[INFO] Scanning for projects...
|
||||
[INFO]
|
||||
[INFO] ----------------------< commons-cli:commons-cli >-----------------------
|
||||
[INFO] Building Apache Commons CLI 1.11.1-SNAPSHOT
|
||||
[INFO] from pom.xml
|
||||
[INFO] --------------------------------[ jar ]---------------------------------
|
||||
[INFO]
|
||||
[INFO] --- surefire:3.5.5:test (default-test) @ commons-cli ---
|
||||
[INFO]
|
||||
[INFO] -------------------------------------------------------
|
||||
[INFO] T E S T S
|
||||
[INFO] -------------------------------------------------------
|
||||
[INFO] Running org.apache.commons.cli.SolrCliTest
|
||||
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.005 s -- in org.apache.commons.cli.SolrCliTest
|
||||
[INFO] Running org.apache.commons.cli.RtkInducedFailTest
|
||||
[ERROR] Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.033 s <<< FAILURE! -- in org.apache.commons.cli.RtkInducedFailTest
|
||||
[ERROR] org.apache.commons.cli.RtkInducedFailTest.rtkInducedFailure -- Time elapsed: 0.025 s <<< FAILURE!
|
||||
org.opentest4j.AssertionFailedError: expected: <expected> but was: <actual>
|
||||
at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
|
||||
at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
|
||||
at org.junit.jupiter.api.AssertEquals.failNotEqual(AssertEquals.java:197)
|
||||
at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:182)
|
||||
at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:177)
|
||||
at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:1145)
|
||||
at org.apache.commons.cli.RtkInducedFailTest.rtkInducedFailure(RtkInducedFailTest.java:25)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
|
||||
|
||||
[INFO] Running org.apache.commons.cli.PatternOptionBuilderTest
|
||||
[INFO] Tests run: 10, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.066 s -- in org.apache.commons.cli.PatternOptionBuilderTest
|
||||
[INFO]
|
||||
[INFO] Results:
|
||||
[INFO]
|
||||
[ERROR] Failures:
|
||||
[ERROR] RtkInducedFailTest.rtkInducedFailure:25 expected: <expected> but was: <actual>
|
||||
[INFO]
|
||||
[ERROR] Tests run: 978, Failures: 1, Errors: 0, Skipped: 61
|
||||
[INFO]
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] BUILD FAILURE
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] Total time: 01:05 min
|
||||
[INFO] Finished at: 2026-05-21T14:57:09Z
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:3.5.5:test (default-test) on project commons-cli: There are test failures.
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
[INFO] Scanning for projects...
|
||||
[INFO]
|
||||
[INFO] -----------------< com.example.rtk:multifail-skeleton >-----------------
|
||||
[INFO] Building multifail-skeleton 1.0.0-SNAPSHOT
|
||||
[INFO] from pom.xml
|
||||
[INFO] --------------------------------[ jar ]---------------------------------
|
||||
[INFO]
|
||||
[INFO] --- surefire:3.5.5:test (default-test) @ multifail-skeleton ---
|
||||
[INFO]
|
||||
[INFO] -------------------------------------------------------
|
||||
[INFO] T E S T S
|
||||
[INFO] -------------------------------------------------------
|
||||
[INFO] Running com.example.rtk.CalcTest
|
||||
[ERROR] Tests run: 3, Failures: 1, Errors: 1, Skipped: 0, Time elapsed: 0.108 s <<< FAILURE! -- in com.example.rtk.CalcTest
|
||||
[ERROR] com.example.rtk.CalcTest.failOne -- Time elapsed: 0.050 s <<< FAILURE!
|
||||
org.opentest4j.AssertionFailedError: failOne: addition should equal five ==> expected: <5> but was: <4>
|
||||
at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
|
||||
at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
|
||||
at org.junit.jupiter.api.AssertEquals.failNotEqual(AssertEquals.java:197)
|
||||
at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:150)
|
||||
at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:563)
|
||||
at com.example.rtk.CalcTest.failOne(CalcTest.java:12)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
|
||||
|
||||
[ERROR] com.example.rtk.CalcTest.failTwo -- Time elapsed: 0.006 s <<< ERROR!
|
||||
java.lang.IllegalStateException: failTwo: induced error for fixture capture
|
||||
at com.example.rtk.CalcTest.failTwo(CalcTest.java:17)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
|
||||
|
||||
[INFO] Running com.example.rtk.BoomTest
|
||||
[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.006 s <<< FAILURE! -- in com.example.rtk.BoomTest
|
||||
[ERROR] com.example.rtk.BoomTest.boom -- Time elapsed: 0.004 s <<< ERROR!
|
||||
java.lang.IllegalStateException: boom: errors-only class for fixture capture
|
||||
at com.example.rtk.BoomTest.boom(BoomTest.java:8)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
|
||||
|
||||
[INFO]
|
||||
[INFO] Results:
|
||||
[INFO]
|
||||
[ERROR] Failures:
|
||||
[ERROR] CalcTest.failOne:12 failOne: addition should equal five ==> expected: <5> but was: <4>
|
||||
[ERROR] Errors:
|
||||
[ERROR] BoomTest.boom:8 IllegalState boom: errors-only class for fixture capture
|
||||
[ERROR] CalcTest.failTwo:17 IllegalState failTwo: induced error for fixture capture
|
||||
[INFO]
|
||||
[ERROR] Tests run: 4, Failures: 1, Errors: 2, Skipped: 0
|
||||
[INFO]
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] BUILD FAILURE
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] Total time: 3.171 s
|
||||
[INFO] Finished at: 2026-06-06T10:53:18-03:00
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:3.5.5:test (default-test) on project multifail-skeleton: There are test failures.
|
||||
[ERROR]
|
||||
[ERROR] See /home/vcyber/projetos/rtk/tests/fixtures/multifail-skeleton/target/surefire-reports for the individual test results.
|
||||
[ERROR] See dump files (if any exist) [date].dump, [date]-jvmRun[N].dump and [date].dumpstream.
|
||||
[ERROR] -> [Help 1]
|
||||
[ERROR]
|
||||
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
|
||||
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
|
||||
[ERROR]
|
||||
[ERROR] For more information about the errors and possible solutions, please read the following articles:
|
||||
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
|
||||
BIN
Binary file not shown.
+33
@@ -0,0 +1,33 @@
|
||||
[INFO] Scanning for projects...
|
||||
[INFO]
|
||||
[INFO] ----------------------< commons-cli:commons-cli >-----------------------
|
||||
[INFO] Building Apache Commons CLI 1.11.1-SNAPSHOT
|
||||
[INFO] from pom.xml
|
||||
[INFO] --------------------------------[ jar ]---------------------------------
|
||||
[INFO]
|
||||
[INFO] --- surefire:3.5.5:test (default-test) @ commons-cli ---
|
||||
[INFO]
|
||||
[INFO] -------------------------------------------------------
|
||||
[INFO] T E S T S
|
||||
[INFO] -------------------------------------------------------
|
||||
[INFO] Running org.apache.commons.cli.help.UtilTest
|
||||
[INFO] Tests run: 34, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.023 s -- in org.apache.commons.cli.help.UtilTest
|
||||
[INFO] Running org.apache.commons.cli.help.TextStyleTest
|
||||
[INFO] Tests run: 13, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.240 s -- in org.apache.commons.cli.help.TextStyleTest
|
||||
[INFO] Running org.apache.commons.cli.DefaultParserTest
|
||||
[WARNING] Tests run: 87, Failures: 0, Errors: 0, Skipped: 2, Time elapsed: 1.023 s -- in org.apache.commons.cli.DefaultParserTest
|
||||
[INFO] Running org.apache.commons.cli.ConverterTests
|
||||
[INFO] Tests run: 14, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.204 s -- in org.apache.commons.cli.ConverterTests
|
||||
[INFO] Running org.apache.commons.cli.AlreadySelectedExceptionTest
|
||||
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.014 s -- in org.apache.commons.cli.AlreadySelectedExceptionTest
|
||||
[INFO]
|
||||
[INFO] Results:
|
||||
[INFO]
|
||||
[INFO] Tests run: 977, Failures: 0, Errors: 0, Skipped: 61
|
||||
[INFO]
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] BUILD SUCCESS
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] Total time: 01:14 min
|
||||
[INFO] Finished at: 2026-05-21T14:54:30Z
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
Vendored
+450
@@ -0,0 +1,450 @@
|
||||
{
|
||||
"apiVersion": "v1",
|
||||
"kind": "List",
|
||||
"metadata": {
|
||||
"resourceVersion": ""
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"metadata": {
|
||||
"name": "alertmanager-main-0",
|
||||
"namespace": "openshift-monitoring"
|
||||
},
|
||||
"status": {
|
||||
"phase": "Running",
|
||||
"containerStatuses": [
|
||||
{
|
||||
"name": "alertmanager",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "config-reloader",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "kube-rbac-proxy",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "kube-rbac-proxy-metric",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "kube-rbac-proxy-web",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "prom-label-proxy",
|
||||
"restartCount": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "alertmanager-main-1",
|
||||
"namespace": "openshift-monitoring"
|
||||
},
|
||||
"status": {
|
||||
"phase": "Running",
|
||||
"containerStatuses": [
|
||||
{
|
||||
"name": "alertmanager",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "config-reloader",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "kube-rbac-proxy",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "kube-rbac-proxy-metric",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "kube-rbac-proxy-web",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "prom-label-proxy",
|
||||
"restartCount": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "cluster-monitoring-operator-7fb9fd4c5d-wm2k6",
|
||||
"namespace": "openshift-monitoring"
|
||||
},
|
||||
"status": {
|
||||
"phase": "Running",
|
||||
"containerStatuses": [
|
||||
{
|
||||
"name": "cluster-monitoring-operator",
|
||||
"restartCount": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "kube-state-metrics-75586fdddb-5zw6b",
|
||||
"namespace": "openshift-monitoring"
|
||||
},
|
||||
"status": {
|
||||
"phase": "Running",
|
||||
"containerStatuses": [
|
||||
{
|
||||
"name": "kube-rbac-proxy-main",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "kube-rbac-proxy-self",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "kube-state-metrics",
|
||||
"restartCount": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "metrics-server-fdfb77995-jmqnm",
|
||||
"namespace": "openshift-monitoring"
|
||||
},
|
||||
"status": {
|
||||
"phase": "Running",
|
||||
"containerStatuses": [
|
||||
{
|
||||
"name": "metrics-server",
|
||||
"restartCount": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "metrics-server-fdfb77995-w4r8p",
|
||||
"namespace": "openshift-monitoring"
|
||||
},
|
||||
"status": {
|
||||
"phase": "Running",
|
||||
"containerStatuses": [
|
||||
{
|
||||
"name": "metrics-server",
|
||||
"restartCount": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "monitoring-plugin-85b45d978c-27rfm",
|
||||
"namespace": "openshift-monitoring"
|
||||
},
|
||||
"status": {
|
||||
"phase": "Running",
|
||||
"containerStatuses": [
|
||||
{
|
||||
"name": "monitoring-plugin",
|
||||
"restartCount": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "monitoring-plugin-85b45d978c-64g98",
|
||||
"namespace": "openshift-monitoring"
|
||||
},
|
||||
"status": {
|
||||
"phase": "Running",
|
||||
"containerStatuses": [
|
||||
{
|
||||
"name": "monitoring-plugin",
|
||||
"restartCount": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "node-exporter-5fw9f",
|
||||
"namespace": "openshift-monitoring"
|
||||
},
|
||||
"status": {
|
||||
"phase": "Running",
|
||||
"containerStatuses": [
|
||||
{
|
||||
"name": "kube-rbac-proxy",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "node-exporter",
|
||||
"restartCount": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "node-exporter-gbnrd",
|
||||
"namespace": "openshift-monitoring"
|
||||
},
|
||||
"status": {
|
||||
"phase": "Running",
|
||||
"containerStatuses": [
|
||||
{
|
||||
"name": "kube-rbac-proxy",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "node-exporter",
|
||||
"restartCount": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "openshift-state-metrics-856bc7fff5-p8s92",
|
||||
"namespace": "openshift-monitoring"
|
||||
},
|
||||
"status": {
|
||||
"phase": "Running",
|
||||
"containerStatuses": [
|
||||
{
|
||||
"name": "kube-rbac-proxy-main",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "kube-rbac-proxy-self",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "openshift-state-metrics",
|
||||
"restartCount": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "prometheus-k8s-0",
|
||||
"namespace": "openshift-monitoring"
|
||||
},
|
||||
"status": {
|
||||
"phase": "Running",
|
||||
"containerStatuses": [
|
||||
{
|
||||
"name": "config-reloader",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "kube-rbac-proxy",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "kube-rbac-proxy-thanos",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "kube-rbac-proxy-web",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "prometheus",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "thanos-sidecar",
|
||||
"restartCount": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "prometheus-k8s-1",
|
||||
"namespace": "openshift-monitoring"
|
||||
},
|
||||
"status": {
|
||||
"phase": "Running",
|
||||
"containerStatuses": [
|
||||
{
|
||||
"name": "config-reloader",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "kube-rbac-proxy",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "kube-rbac-proxy-thanos",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "kube-rbac-proxy-web",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "prometheus",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "thanos-sidecar",
|
||||
"restartCount": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "prometheus-operator-5978c4f47f-9zwdq",
|
||||
"namespace": "openshift-monitoring"
|
||||
},
|
||||
"status": {
|
||||
"phase": "Running",
|
||||
"containerStatuses": [
|
||||
{
|
||||
"name": "kube-rbac-proxy",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "prometheus-operator",
|
||||
"restartCount": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "prometheus-operator-admission-webhook-6485c485f4-8cfhf",
|
||||
"namespace": "openshift-monitoring"
|
||||
},
|
||||
"status": {
|
||||
"phase": "Running",
|
||||
"containerStatuses": [
|
||||
{
|
||||
"name": "prometheus-operator-admission-webhook",
|
||||
"restartCount": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "prometheus-operator-admission-webhook-6485c485f4-b655d",
|
||||
"namespace": "openshift-monitoring"
|
||||
},
|
||||
"status": {
|
||||
"phase": "Running",
|
||||
"containerStatuses": [
|
||||
{
|
||||
"name": "prometheus-operator-admission-webhook",
|
||||
"restartCount": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "telemeter-client-5d75f79f95-hr22b",
|
||||
"namespace": "openshift-monitoring"
|
||||
},
|
||||
"status": {
|
||||
"phase": "Running",
|
||||
"containerStatuses": [
|
||||
{
|
||||
"name": "kube-rbac-proxy",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "reload",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "telemeter-client",
|
||||
"restartCount": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "thanos-querier-5fcf655bd-4h2m2",
|
||||
"namespace": "openshift-monitoring"
|
||||
},
|
||||
"status": {
|
||||
"phase": "Running",
|
||||
"containerStatuses": [
|
||||
{
|
||||
"name": "kube-rbac-proxy",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "kube-rbac-proxy-metrics",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "kube-rbac-proxy-rules",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "kube-rbac-proxy-web",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "prom-label-proxy",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "thanos-query",
|
||||
"restartCount": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "thanos-querier-5fcf655bd-wd28r",
|
||||
"namespace": "openshift-monitoring"
|
||||
},
|
||||
"status": {
|
||||
"phase": "Running",
|
||||
"containerStatuses": [
|
||||
{
|
||||
"name": "kube-rbac-proxy",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "kube-rbac-proxy-metrics",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "kube-rbac-proxy-rules",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "kube-rbac-proxy-web",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "prom-label-proxy",
|
||||
"restartCount": 0
|
||||
},
|
||||
{
|
||||
"name": "thanos-query",
|
||||
"restartCount": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
+380
@@ -0,0 +1,380 @@
|
||||
{
|
||||
"totals": {
|
||||
"errors": 47,
|
||||
"file_errors": 47
|
||||
},
|
||||
"files": {
|
||||
"/var/www/project/app/Models/User.php": {
|
||||
"errors": 6,
|
||||
"messages": [
|
||||
{
|
||||
"message": "Property User::$id (int) does not accept null.",
|
||||
"line": 15,
|
||||
"ignorable": false,
|
||||
"identifier": "property.nonObject",
|
||||
"tip": "Use ?int if null is a valid value."
|
||||
},
|
||||
{
|
||||
"message": "Property User::$email (string) does not accept null.",
|
||||
"line": 18,
|
||||
"ignorable": false,
|
||||
"identifier": "property.nonObject",
|
||||
"tip": null
|
||||
},
|
||||
{
|
||||
"message": "Method User::find() has no return type specified.",
|
||||
"line": 45,
|
||||
"ignorable": true,
|
||||
"identifier": "missingType.return",
|
||||
"tip": "Add @return type annotation or declare the return type."
|
||||
},
|
||||
{
|
||||
"message": "Call to an undefined method Illuminate\\Database\\Eloquent\\Model::unknownMethod().",
|
||||
"line": 67,
|
||||
"ignorable": false,
|
||||
"identifier": "method.notFound",
|
||||
"tip": null
|
||||
},
|
||||
{
|
||||
"message": "Parameter #1 $id of method User::find() expects int, string given.",
|
||||
"line": 89,
|
||||
"ignorable": false,
|
||||
"identifier": "argument.type",
|
||||
"tip": null
|
||||
},
|
||||
{
|
||||
"message": "Dead catch - Exception is never thrown in the try block.",
|
||||
"line": 120,
|
||||
"ignorable": true,
|
||||
"identifier": "deadCode.catch",
|
||||
"tip": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"/var/www/project/app/Http/Controllers/UserController.php": {
|
||||
"errors": 5,
|
||||
"messages": [
|
||||
{
|
||||
"message": "Parameter $request of method UserController::store() has no type specified.",
|
||||
"line": 34,
|
||||
"ignorable": false,
|
||||
"identifier": "missingType.parameter",
|
||||
"tip": null
|
||||
},
|
||||
{
|
||||
"message": "Variable $user might not be defined.",
|
||||
"line": 56,
|
||||
"ignorable": false,
|
||||
"identifier": "variable.undefined",
|
||||
"tip": null
|
||||
},
|
||||
{
|
||||
"message": "Binary operation '+' between string and int results in an error.",
|
||||
"line": 78,
|
||||
"ignorable": true,
|
||||
"identifier": "binaryOp.invalid",
|
||||
"tip": null
|
||||
},
|
||||
{
|
||||
"message": "Unreachable statement - code above always terminates.",
|
||||
"line": 95,
|
||||
"ignorable": false,
|
||||
"identifier": "deadCode.unreachable",
|
||||
"tip": null
|
||||
},
|
||||
{
|
||||
"message": "Result of method UserRepository::create() (void) is used.",
|
||||
"line": 112,
|
||||
"ignorable": false,
|
||||
"identifier": "return.void",
|
||||
"tip": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"/var/www/project/app/Services/AuthService.php": {
|
||||
"errors": 4,
|
||||
"messages": [
|
||||
{
|
||||
"message": "Method AuthService::login() should return User but returns User|null.",
|
||||
"line": 23,
|
||||
"ignorable": false,
|
||||
"identifier": "return.type",
|
||||
"tip": null
|
||||
},
|
||||
{
|
||||
"message": "Comparison operation '>' between int<0, max> and 0 is always true.",
|
||||
"line": 45,
|
||||
"ignorable": true,
|
||||
"identifier": "comparison.alwaysTrue",
|
||||
"tip": null
|
||||
},
|
||||
{
|
||||
"message": "Parameter #2 $password of function password_verify expects string, int given.",
|
||||
"line": 67,
|
||||
"ignorable": false,
|
||||
"identifier": "argument.type",
|
||||
"tip": null
|
||||
},
|
||||
{
|
||||
"message": "Property AuthService::$logger is never read, only written.",
|
||||
"line": 89,
|
||||
"ignorable": true,
|
||||
"identifier": "deadCode.property",
|
||||
"tip": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"/var/www/project/app/Repositories/UserRepository.php": {
|
||||
"errors": 3,
|
||||
"messages": [
|
||||
{
|
||||
"message": "Access to an undefined property User::$unknownField.",
|
||||
"line": 28,
|
||||
"ignorable": false,
|
||||
"identifier": "property.notFound",
|
||||
"tip": null
|
||||
},
|
||||
{
|
||||
"message": "Method UserRepository::all() should return Collection<User> but returns Collection.",
|
||||
"line": 52,
|
||||
"ignorable": false,
|
||||
"identifier": "return.type",
|
||||
"tip": "Specify the collection type parameter."
|
||||
},
|
||||
{
|
||||
"message": "Instanceof between User and stdClass will always evaluate to false.",
|
||||
"line": 78,
|
||||
"ignorable": false,
|
||||
"identifier": "instanceof.alwaysFalse",
|
||||
"tip": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"/var/www/project/app/Http/Middleware/Authenticate.php": {
|
||||
"errors": 2,
|
||||
"messages": [
|
||||
{
|
||||
"message": "Method Authenticate::handle() has parameter $next with no type specified.",
|
||||
"line": 19,
|
||||
"ignorable": false,
|
||||
"identifier": "missingType.parameter",
|
||||
"tip": null
|
||||
},
|
||||
{
|
||||
"message": "Negated boolean expression is always false.",
|
||||
"line": 34,
|
||||
"ignorable": true,
|
||||
"identifier": "booleanNot.alwaysFalse",
|
||||
"tip": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"/var/www/project/app/Console/Commands/SyncUsers.php": {
|
||||
"errors": 3,
|
||||
"messages": [
|
||||
{
|
||||
"message": "Method SyncUsers::handle() has no return type specified.",
|
||||
"line": 22,
|
||||
"ignorable": false,
|
||||
"identifier": "missingType.return",
|
||||
"tip": null
|
||||
},
|
||||
{
|
||||
"message": "Variable $users might not be defined.",
|
||||
"line": 45,
|
||||
"ignorable": false,
|
||||
"identifier": "variable.undefined",
|
||||
"tip": null
|
||||
},
|
||||
{
|
||||
"message": "Call to function array_map() with Closure and array|null will result in an error.",
|
||||
"line": 67,
|
||||
"ignorable": false,
|
||||
"identifier": "argument.type",
|
||||
"tip": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"/var/www/project/app/Events/UserRegistered.php": {
|
||||
"errors": 2,
|
||||
"messages": [
|
||||
{
|
||||
"message": "Property UserRegistered::$user has no type specified.",
|
||||
"line": 12,
|
||||
"ignorable": false,
|
||||
"identifier": "missingType.property",
|
||||
"tip": null
|
||||
},
|
||||
{
|
||||
"message": "Call to an undefined method Illuminate\\Events\\Dispatcher::dispatch().",
|
||||
"line": 30,
|
||||
"ignorable": false,
|
||||
"identifier": "method.notFound",
|
||||
"tip": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"/var/www/project/app/Listeners/SendWelcomeEmail.php": {
|
||||
"errors": 2,
|
||||
"messages": [
|
||||
{
|
||||
"message": "Parameter $event of method SendWelcomeEmail::handle() has no type specified.",
|
||||
"line": 18,
|
||||
"ignorable": false,
|
||||
"identifier": "missingType.parameter",
|
||||
"tip": null
|
||||
},
|
||||
{
|
||||
"message": "Variable $mailer might not be defined.",
|
||||
"line": 35,
|
||||
"ignorable": false,
|
||||
"identifier": "variable.undefined",
|
||||
"tip": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"/var/www/project/app/Policies/UserPolicy.php": {
|
||||
"errors": 3,
|
||||
"messages": [
|
||||
{
|
||||
"message": "Method UserPolicy::view() has no return type specified.",
|
||||
"line": 25,
|
||||
"ignorable": false,
|
||||
"identifier": "missingType.return",
|
||||
"tip": null
|
||||
},
|
||||
{
|
||||
"message": "Method UserPolicy::create() has no return type specified.",
|
||||
"line": 35,
|
||||
"ignorable": false,
|
||||
"identifier": "missingType.return",
|
||||
"tip": null
|
||||
},
|
||||
{
|
||||
"message": "Method UserPolicy::update() has no return type specified.",
|
||||
"line": 45,
|
||||
"ignorable": false,
|
||||
"identifier": "missingType.return",
|
||||
"tip": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"/var/www/project/app/Observers/UserObserver.php": {
|
||||
"errors": 2,
|
||||
"messages": [
|
||||
{
|
||||
"message": "Method UserObserver::created() has parameter $user with no type specified.",
|
||||
"line": 14,
|
||||
"ignorable": false,
|
||||
"identifier": "missingType.parameter",
|
||||
"tip": null
|
||||
},
|
||||
{
|
||||
"message": "Method UserObserver::deleted() has parameter $user with no type specified.",
|
||||
"line": 24,
|
||||
"ignorable": false,
|
||||
"identifier": "missingType.parameter",
|
||||
"tip": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"/var/www/project/app/Providers/AuthServiceProvider.php": {
|
||||
"errors": 2,
|
||||
"messages": [
|
||||
{
|
||||
"message": "Method AuthServiceProvider::boot() has no return type specified.",
|
||||
"line": 30,
|
||||
"ignorable": false,
|
||||
"identifier": "missingType.return",
|
||||
"tip": null
|
||||
},
|
||||
{
|
||||
"message": "Variable $gate might not be defined.",
|
||||
"line": 45,
|
||||
"ignorable": false,
|
||||
"identifier": "variable.undefined",
|
||||
"tip": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"/var/www/project/app/Jobs/ProcessPayment.php": {
|
||||
"errors": 4,
|
||||
"messages": [
|
||||
{
|
||||
"message": "Method ProcessPayment::handle() has no return type specified.",
|
||||
"line": 35,
|
||||
"ignorable": false,
|
||||
"identifier": "missingType.return",
|
||||
"tip": null
|
||||
},
|
||||
{
|
||||
"message": "Property ProcessPayment::$amount has no type specified.",
|
||||
"line": 18,
|
||||
"ignorable": false,
|
||||
"identifier": "missingType.property",
|
||||
"tip": null
|
||||
},
|
||||
{
|
||||
"message": "Variable $payment might not be defined.",
|
||||
"line": 58,
|
||||
"ignorable": false,
|
||||
"identifier": "variable.undefined",
|
||||
"tip": null
|
||||
},
|
||||
{
|
||||
"message": "Call to an undefined method PaymentGateway::charge().",
|
||||
"line": 72,
|
||||
"ignorable": false,
|
||||
"identifier": "method.notFound",
|
||||
"tip": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"/var/www/project/app/Mail/WelcomeEmail.php": {
|
||||
"errors": 2,
|
||||
"messages": [
|
||||
{
|
||||
"message": "Method WelcomeEmail::build() has no return type specified.",
|
||||
"line": 28,
|
||||
"ignorable": false,
|
||||
"identifier": "missingType.return",
|
||||
"tip": null
|
||||
},
|
||||
{
|
||||
"message": "Property WelcomeEmail::$user has no type specified.",
|
||||
"line": 15,
|
||||
"ignorable": false,
|
||||
"identifier": "missingType.property",
|
||||
"tip": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"/var/www/project/app/Http/Requests/StoreUserRequest.php": {
|
||||
"errors": 3,
|
||||
"messages": [
|
||||
{
|
||||
"message": "Method StoreUserRequest::rules() has no return type specified.",
|
||||
"line": 18,
|
||||
"ignorable": false,
|
||||
"identifier": "missingType.return",
|
||||
"tip": null
|
||||
},
|
||||
{
|
||||
"message": "Method StoreUserRequest::authorize() has no return type specified.",
|
||||
"line": 12,
|
||||
"ignorable": false,
|
||||
"identifier": "missingType.return",
|
||||
"tip": null
|
||||
},
|
||||
{
|
||||
"message": "Strict comparison using === between string and int will always evaluate to false.",
|
||||
"line": 32,
|
||||
"ignorable": false,
|
||||
"identifier": "comparison.strict",
|
||||
"tip": null
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"errors": []
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
Downloading cpython-3.13.5-macos-aarch64-none (download) (14.9MiB)
|
||||
Downloading cpython-3.13.5-macos-aarch64-none (download)
|
||||
Using CPython 3.13.5
|
||||
Creating virtual environment at: .venv
|
||||
Downloading pygments (1.2MiB)
|
||||
Downloading pygments
|
||||
Installed 5 packages in 7ms
|
||||
============================= test session starts ==============================
|
||||
platform darwin -- Python 3.13.5, pytest-8.4.1, pluggy-1.6.0
|
||||
rootdir: /private/tmp/rtk-uv-fixture
|
||||
configfile: pyproject.toml
|
||||
collected 2 items
|
||||
|
||||
tests/test_users.py .F [100%]
|
||||
|
||||
=================================== FAILURES ===================================
|
||||
______________________ test_normalize_user_rejects_empty _______________________
|
||||
|
||||
def test_normalize_user_rejects_empty():
|
||||
> assert normalize_user(" ") == "anonymous"
|
||||
E AssertionError: assert '' == 'anonymous'
|
||||
E
|
||||
E - anonymous
|
||||
|
||||
tests/test_users.py:10: AssertionError
|
||||
=========================== short test summary info ============================
|
||||
FAILED tests/test_users.py::test_normalize_user_rejects_empty - AssertionErro...
|
||||
========================= 1 failed, 1 passed in 0.01s ==========================
|
||||
@@ -0,0 +1,171 @@
|
||||
#![cfg(unix)]
|
||||
//! Regressions from the #2333 grep overhaul: -A/-B/-C must keep context lines,
|
||||
//! -c/-o must not leak ripgrep's NUL separator.
|
||||
|
||||
use std::process::Command;
|
||||
|
||||
fn rtk() -> Command {
|
||||
Command::new(env!("CARGO_BIN_EXE_rtk"))
|
||||
}
|
||||
|
||||
fn rg_available() -> bool {
|
||||
Command::new("rg")
|
||||
.arg("--version")
|
||||
.output()
|
||||
.map(|o| o.status.success())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn after_context_lines_are_shown() {
|
||||
if !rg_available() {
|
||||
return;
|
||||
}
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let f = dir.path().join("ctx.txt");
|
||||
std::fs::write(&f, "before1\nbefore2\nMATCHME\nafter1\nafter2\nafter3\n").unwrap();
|
||||
let out = rtk()
|
||||
.args(["grep", "-A2", "MATCHME", f.to_str().unwrap()])
|
||||
.output()
|
||||
.unwrap();
|
||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||
assert!(
|
||||
stdout.contains("after1"),
|
||||
"missing after-context line 1:\n{stdout}"
|
||||
);
|
||||
assert!(
|
||||
stdout.contains("after2"),
|
||||
"missing after-context line 2:\n{stdout}"
|
||||
);
|
||||
assert!(!stdout.contains("after3"), "leaked beyond -A2:\n{stdout}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn before_context_lines_are_shown() {
|
||||
if !rg_available() {
|
||||
return;
|
||||
}
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let f = dir.path().join("ctx.txt");
|
||||
std::fs::write(&f, "before1\nbefore2\nMATCHME\nafter1\n").unwrap();
|
||||
let out = rtk()
|
||||
.args(["grep", "-B1", "MATCHME", f.to_str().unwrap()])
|
||||
.output()
|
||||
.unwrap();
|
||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||
assert!(
|
||||
stdout.contains("before2"),
|
||||
"missing before-context line:\n{stdout}"
|
||||
);
|
||||
assert!(!stdout.contains("before1"), "leaked beyond -B1:\n{stdout}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn count_output_has_no_nul_separator() {
|
||||
if !rg_available() {
|
||||
return;
|
||||
}
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let f = dir.path().join("nul.txt");
|
||||
std::fs::write(&f, "TODO one\nnope\nTODO two\n").unwrap();
|
||||
let out = rtk()
|
||||
.args(["grep", "-c", "TODO", f.to_str().unwrap()])
|
||||
.output()
|
||||
.unwrap();
|
||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||
assert!(
|
||||
!stdout.contains('\u{0}'),
|
||||
"NUL leaked into -c output: {stdout:?}"
|
||||
);
|
||||
assert!(
|
||||
stdout.contains('2'),
|
||||
"count missing from -c output: {stdout:?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn group_separator_between_non_adjacent_matches() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let f = dir.path().join("sep.txt");
|
||||
std::fs::write(
|
||||
&f,
|
||||
"alpha match here\nfiller 1\nfiller 2\nfiller 3\nfiller 4\nfiller 5\nbeta match here\n",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let out = rtk()
|
||||
.args(["grep", "-A1", "match", f.to_str().unwrap()])
|
||||
.output()
|
||||
.unwrap();
|
||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||
|
||||
assert!(
|
||||
stdout.contains("--"),
|
||||
"missing group separator between non-adjacent match blocks:\n{stdout}"
|
||||
);
|
||||
assert!(
|
||||
stdout.contains("alpha match here"),
|
||||
"first match must be present:\n{stdout}"
|
||||
);
|
||||
assert!(
|
||||
stdout.contains("beta match here"),
|
||||
"second match must be present:\n{stdout}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_separator_without_context_flag() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let f = dir.path().join("nosep.txt");
|
||||
std::fs::write(
|
||||
&f,
|
||||
"match line 1\nfiller\nfiller\nfiller\nmatch line 2\nfiller\nfiller\nmatch line 3\n",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let out = rtk()
|
||||
.args(["grep", "-n", "match", f.to_str().unwrap()])
|
||||
.output()
|
||||
.unwrap();
|
||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||
|
||||
assert!(
|
||||
!stdout.contains("--"),
|
||||
"plain grep without -A/-B/-C must not insert -- separators:\n{stdout}"
|
||||
);
|
||||
assert!(
|
||||
stdout.contains("match line 1"),
|
||||
"first match must be present:\n{stdout}"
|
||||
);
|
||||
assert!(
|
||||
stdout.contains("match line 3"),
|
||||
"third match must be present:\n{stdout}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn only_matching_output_has_no_nul_separator() {
|
||||
if !rg_available() {
|
||||
return;
|
||||
}
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let f = dir.path().join("nul.txt");
|
||||
std::fs::write(&f, "TODO one\nnope\nTODO two\n").unwrap();
|
||||
let out = rtk()
|
||||
.args(["grep", "-o", "TODO", f.to_str().unwrap()])
|
||||
.output()
|
||||
.unwrap();
|
||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||
assert!(
|
||||
!stdout.contains('\u{0}'),
|
||||
"NUL leaked into -o output: {stdout:?}"
|
||||
);
|
||||
assert!(
|
||||
stdout.contains("TODO"),
|
||||
"match missing from -o output: {stdout:?}"
|
||||
);
|
||||
assert!(
|
||||
!stdout.contains("1:TODO"),
|
||||
"line-number prefix leaked into -o output: {stdout:?}"
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
#![cfg(unix)]
|
||||
//! For un-capped searches `rtk grep X` must be byte-identical to `grep -n X`:
|
||||
//! line number always, filename only when grep itself prints one. Covers content
|
||||
//! and regex edge cases (colons, digits, shell metachars, unicode, colon-in-path)
|
||||
//! that must never be misparsed.
|
||||
|
||||
use std::io::Write;
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
fn rtk_grep(args: &[&str]) -> (String, Option<i32>) {
|
||||
let mut a = vec!["grep"];
|
||||
a.extend_from_slice(args);
|
||||
let out = Command::new(env!("CARGO_BIN_EXE_rtk"))
|
||||
.args(&a)
|
||||
.output()
|
||||
.expect("rtk");
|
||||
(
|
||||
String::from_utf8_lossy(&out.stdout).into_owned(),
|
||||
out.status.code(),
|
||||
)
|
||||
}
|
||||
|
||||
fn grep_n(args: &[&str]) -> (String, Option<i32>) {
|
||||
let mut a = vec!["-n"];
|
||||
a.extend_from_slice(args);
|
||||
let out = Command::new("grep").args(&a).output().expect("grep");
|
||||
(
|
||||
String::from_utf8_lossy(&out.stdout).into_owned(),
|
||||
out.status.code(),
|
||||
)
|
||||
}
|
||||
|
||||
fn assert_eq_grep_n(args: &[&str]) {
|
||||
let (rtk, rc) = rtk_grep(args);
|
||||
let (grep, gc) = grep_n(args);
|
||||
assert_eq!(rtk, grep, "stdout mismatch for {args:?}");
|
||||
assert_eq!(rc, gc, "exit code mismatch for {args:?}");
|
||||
}
|
||||
|
||||
fn write(dir: &std::path::Path, name: &str, body: &str) -> String {
|
||||
let p = dir.join(name);
|
||||
std::fs::write(&p, body).expect("write");
|
||||
p.to_str().unwrap().to_string()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_multi_recursive_and_h_match_grep_n() {
|
||||
let d = tempfile::tempdir().unwrap();
|
||||
let f1 = write(d.path(), "f1.txt", "apple\nzebra apple\nbanana\n");
|
||||
let f2 = write(d.path(), "f2.txt", "apricot\n");
|
||||
assert_eq_grep_n(&["apple", &f1]); // single: position only
|
||||
assert_eq_grep_n(&["a", &f1, &f2]); // multi: file + position
|
||||
assert_eq_grep_n(&["-H", "apple", &f1]); // -H forces filename on a single file
|
||||
assert_eq_grep_n(&["-r", "a", d.path().to_str().unwrap()]); // recursive
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_match_matches_grep_n() {
|
||||
let d = tempfile::tempdir().unwrap();
|
||||
let f = write(d.path(), "f.txt", "hello\n");
|
||||
assert_eq_grep_n(&["zzz_no_match_xyz", &f]); // empty stdout, exit 1
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nasty_content_is_not_misparsed() {
|
||||
let d = tempfile::tempdir().unwrap();
|
||||
let f = write(
|
||||
d.path(),
|
||||
"n.txt",
|
||||
"12:34 looks like a line number\na::b::c ClassRegistry::init('x')\nport :8080: here\n$(rm -rf /) `whoami` && echo\n中文 テスト مرحبا\n",
|
||||
);
|
||||
assert_eq_grep_n(&[":", &f]);
|
||||
assert_eq_grep_n(&["ClassRegistry", &f]);
|
||||
assert_eq_grep_n(&["中文", &f]);
|
||||
assert_eq_grep_n(&["whoami", &f]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn regex_metacharacters_match_grep_n() {
|
||||
let d = tempfile::tempdir().unwrap();
|
||||
let f = write(d.path(), "r.txt", "a.b\naxb\nfoo.bar\n[x]\n");
|
||||
assert_eq_grep_n(&["a.b", &f]); // . is any-char
|
||||
assert_eq_grep_n(&["-F", "a.b", &f]); // fixed-string
|
||||
assert_eq_grep_n(&["^foo", &f]); // anchor
|
||||
assert_eq_grep_n(&["-E", "ax?b", &f]); // ERE
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn context_flags_match_grep_n() {
|
||||
let d = tempfile::tempdir().unwrap();
|
||||
let f = write(d.path(), "c.txt", "x\nMATCH\ny\nz\n");
|
||||
assert_eq_grep_n(&["-A1", "MATCH", &f]);
|
||||
assert_eq_grep_n(&["-B1", "MATCH", &f]);
|
||||
assert_eq_grep_n(&["-C1", "MATCH", &f]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn context_group_separator_matches_grep_n() {
|
||||
let d = tempfile::tempdir().unwrap();
|
||||
let f = write(
|
||||
d.path(),
|
||||
"sep.txt",
|
||||
"match A\nfill1\nfill2\nfill3\nmatch B\n",
|
||||
);
|
||||
assert_eq_grep_n(&["-A1", "match", &f]);
|
||||
}
|
||||
|
||||
// #1436: a single-file `-n` search with `::` content and a BRE pattern with
|
||||
// literal `()` must equal grep exactly — no broadened matches, and no synthetic
|
||||
// `[file]` bucket from splitting on `::`.
|
||||
#[test]
|
||||
fn issue_1436_colons_and_literal_parens() {
|
||||
let d = tempfile::tempdir().unwrap();
|
||||
let f = write(
|
||||
d.path(),
|
||||
"shell.php",
|
||||
"use Util\\ClassRegistry;\nclass Foo {\n public function run() {\n $this->m = ClassRegistry::init('Collections.QueueProcess');\n try {\n deleteRow($id);\n $this->delete();\n } catch (\\Exception $e) {\n } finally {}\n }\n private function delete() {}\n}\n",
|
||||
);
|
||||
assert_eq_grep_n(&[
|
||||
"private function delete\\|try\\|catch\\|finally\\|delete()",
|
||||
&f,
|
||||
]);
|
||||
assert_eq_grep_n(&["init", &f]); // ClassRegistry::init must stay one intact line
|
||||
}
|
||||
|
||||
// #1436 (comments): a leading `^` anchor must stay scoped to the given file
|
||||
// (tenequm), and a line ending in `:` (Python `if x:`) must keep full content
|
||||
// (BTCAlchemist).
|
||||
#[test]
|
||||
fn issue_1436_anchor_scope_and_trailing_colon() {
|
||||
let d = tempfile::tempdir().unwrap();
|
||||
let f = write(d.path(), "code.rs", "pub fn a\nprivate b\npub fn c\n");
|
||||
let py = write(
|
||||
d.path(),
|
||||
"t.py",
|
||||
"x = 1\nif crypto >= MAX_CRYPTO:\nclass Foo:\n",
|
||||
);
|
||||
assert_eq_grep_n(&["^pub", &f]); // anchored pattern must not escape the path
|
||||
assert_eq_grep_n(&["MAX_CRYPTO", &py]); // trailing-colon line kept intact
|
||||
assert_eq_grep_n(&["class", &py]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn colon_in_filename_matches_grep_n() {
|
||||
let d = tempfile::tempdir().unwrap();
|
||||
let f1 = write(d.path(), "weird:name.txt", "hit\n");
|
||||
let f2 = write(d.path(), "other.txt", "hit\n");
|
||||
assert_eq_grep_n(&["hit", &f1, &f2]); // colon in a path must not fool the parser
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn case_insensitive_and_invert_match_grep_n() {
|
||||
let d = tempfile::tempdir().unwrap();
|
||||
let f = write(d.path(), "i.txt", "Apple\nbanana\nAPPLE\n");
|
||||
assert_eq_grep_n(&["-i", "apple", &f]);
|
||||
assert_eq_grep_n(&["-v", "apple", &f]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn piped_stdin_matches_grep_n() {
|
||||
let input = "apple\nzebra\napple pie\n";
|
||||
let feed = |cmd: &mut Command| {
|
||||
let mut c = cmd
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()
|
||||
.expect("spawn");
|
||||
c.stdin.take().unwrap().write_all(input.as_bytes()).unwrap();
|
||||
String::from_utf8_lossy(&c.wait_with_output().unwrap().stdout).into_owned()
|
||||
};
|
||||
let rtk = feed(Command::new(env!("CARGO_BIN_EXE_rtk")).args(["grep", "apple"]));
|
||||
let grep = feed(Command::new("grep").args(["-n", "apple"]));
|
||||
assert_eq!(rtk, grep, "piped stdin must equal grep -n");
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
//! End-to-end proof of the never-worse guard (src/core/guard.rs).
|
||||
|
||||
use std::io::Write;
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
fn rtk_stdin(args: &[&str], input: &str) -> String {
|
||||
let mut child = Command::new(env!("CARGO_BIN_EXE_rtk"))
|
||||
.args(args)
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::null())
|
||||
.spawn()
|
||||
.expect("spawn rtk");
|
||||
child
|
||||
.stdin
|
||||
.take()
|
||||
.expect("stdin")
|
||||
.write_all(input.as_bytes())
|
||||
.expect("write stdin");
|
||||
let out = child.wait_with_output().expect("wait rtk");
|
||||
String::from_utf8_lossy(&out.stdout).into_owned()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn guard_shows_raw_when_filter_would_bloat_tiny_input() {
|
||||
let input = "{\"a\":1,\"b\":2,\"c\":3,\"d\":4}";
|
||||
let out = rtk_stdin(&["json", "-"], input);
|
||||
|
||||
assert_eq!(
|
||||
out.trim(),
|
||||
input,
|
||||
"guard should emit the raw minified JSON, not a larger pretty-printed form"
|
||||
);
|
||||
assert!(
|
||||
out.trim().len() <= input.len(),
|
||||
"never-worse violated: {} chars emitted for a {}-char raw input",
|
||||
out.trim().len(),
|
||||
input.len()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn guard_does_not_block_real_compression() {
|
||||
let mut input = String::from("{");
|
||||
for i in 0..60 {
|
||||
input.push_str(&format!("\"key_{i}\":\"value_{i}\","));
|
||||
}
|
||||
input.push_str("\"last\":1}");
|
||||
|
||||
let out = rtk_stdin(&["json", "-"], &input);
|
||||
assert!(
|
||||
out.len() < input.len(),
|
||||
"filter should compress large input (guard must not over-trigger): {} vs {}",
|
||||
out.len(),
|
||||
input.len()
|
||||
);
|
||||
}
|
||||
|
||||
fn rtk_output_in_dir(dir: &std::path::Path, args: &[&str]) -> (String, String, Option<i32>) {
|
||||
let out = Command::new(env!("CARGO_BIN_EXE_rtk"))
|
||||
.args(args)
|
||||
.current_dir(dir)
|
||||
.output()
|
||||
.expect("spawn rtk");
|
||||
(
|
||||
String::from_utf8_lossy(&out.stdout).into_owned(),
|
||||
String::from_utf8_lossy(&out.stderr).into_owned(),
|
||||
out.status.code(),
|
||||
)
|
||||
}
|
||||
|
||||
fn rtk_in_dir(dir: &std::path::Path, args: &[&str]) -> (String, Option<i32>) {
|
||||
let (stdout, _, code) = rtk_output_in_dir(dir, args);
|
||||
(stdout, code)
|
||||
}
|
||||
|
||||
fn rg_available() -> bool {
|
||||
Command::new("rg")
|
||||
.arg("--version")
|
||||
.output()
|
||||
.map(|o| o.status.success())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn init_git_repo() -> tempfile::TempDir {
|
||||
let dir = tempfile::tempdir().expect("tempdir");
|
||||
for args in [
|
||||
&["init", "-q", "-b", "main"][..],
|
||||
&["config", "user.email", "t@t.t"][..],
|
||||
&["config", "user.name", "t"][..],
|
||||
&["commit", "-q", "--allow-empty", "-m", "init"][..],
|
||||
] {
|
||||
let ok = Command::new("git")
|
||||
.args(args)
|
||||
.current_dir(dir.path())
|
||||
.output()
|
||||
.map(|o| o.status.success())
|
||||
.unwrap_or(false);
|
||||
assert!(ok, "git setup failed: {args:?}");
|
||||
}
|
||||
dir
|
||||
}
|
||||
|
||||
fn git_in_dir(dir: &std::path::Path, args: &[&str]) {
|
||||
let out = Command::new("git")
|
||||
.args(args)
|
||||
.current_dir(dir)
|
||||
.output()
|
||||
.expect("spawn git");
|
||||
assert!(
|
||||
out.status.success(),
|
||||
"git command failed: {args:?}\nstdout: {}\nstderr: {}",
|
||||
String::from_utf8_lossy(&out.stdout),
|
||||
String::from_utf8_lossy(&out.stderr)
|
||||
);
|
||||
}
|
||||
|
||||
fn read_text_normalized(path: &std::path::Path) -> String {
|
||||
std::fs::read_to_string(path).unwrap().replace("\r\n", "\n")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn grep_no_match_emits_empty_not_a_message() {
|
||||
if !rg_available() {
|
||||
return;
|
||||
}
|
||||
let dir = tempfile::tempdir().expect("tempdir");
|
||||
std::fs::write(dir.path().join("a.txt"), "hello world\n").expect("write");
|
||||
// Faithful grep needs -r to descend a directory; we no longer force recursion
|
||||
// by routing through rg (the engine-faithful contract).
|
||||
let (out, code) = rtk_in_dir(dir.path(), &["grep", "-r", "zzz_no_match_xyz", "."]);
|
||||
assert!(
|
||||
out.trim().is_empty(),
|
||||
"no-match grep must emit empty, not a '0 matches' line: {out:?}"
|
||||
);
|
||||
assert_eq!(code, Some(1), "grep no-match must preserve exit 1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn find_no_results_emits_empty() {
|
||||
let dir = tempfile::tempdir().expect("tempdir");
|
||||
std::fs::write(dir.path().join("a.txt"), "x").expect("write");
|
||||
let (out, _) = rtk_in_dir(dir.path(), &["find", ".", "-name", "zzz_no_match_xyz"]);
|
||||
assert!(
|
||||
out.trim().is_empty(),
|
||||
"no-result find must emit empty, not a '0 for' line: {out:?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn git_stash_list_no_stashes_emits_empty() {
|
||||
let dir = init_git_repo();
|
||||
let (out, code) = rtk_in_dir(dir.path(), &["git", "stash", "list"]);
|
||||
assert!(
|
||||
out.trim().is_empty(),
|
||||
"no-stashes must emit empty, not 'No stashes': {out:?}"
|
||||
);
|
||||
assert_eq!(code, Some(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn git_stash_show_no_stash_emits_empty_and_propagates_failure() {
|
||||
// Regression: previously printed "Empty stash" and returned Ok(0), masking
|
||||
// the underlying `git stash show` failure.
|
||||
let dir = init_git_repo();
|
||||
let (out, code) = rtk_in_dir(dir.path(), &["git", "stash", "show"]);
|
||||
assert!(
|
||||
out.trim().is_empty(),
|
||||
"must emit empty, not 'Empty stash': {out:?}"
|
||||
);
|
||||
assert_ne!(
|
||||
code,
|
||||
Some(0),
|
||||
"a real git stash show failure must not be masked as exit 0"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn git_checkout_branch_switch_emits_compact_ok() {
|
||||
let dir = init_git_repo();
|
||||
git_in_dir(dir.path(), &["checkout", "-q", "-b", "feature/test"]);
|
||||
|
||||
let (out, code) = rtk_in_dir(dir.path(), &["git", "checkout", "main"]);
|
||||
|
||||
assert_eq!(code, Some(0));
|
||||
assert_eq!(out.trim(), "ok main");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn git_checkout_new_branch_emits_compact_ok() {
|
||||
let dir = init_git_repo();
|
||||
|
||||
let (out, code) = rtk_in_dir(dir.path(), &["git", "checkout", "-b", "feature/test"]);
|
||||
|
||||
assert_eq!(code, Some(0));
|
||||
assert_eq!(out.trim(), "ok feature/test (new)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn git_checkout_reset_branch_does_not_claim_new_branch() {
|
||||
let dir = init_git_repo();
|
||||
|
||||
let (out, code) = rtk_in_dir(dir.path(), &["git", "checkout", "-B", "feature/test"]);
|
||||
|
||||
assert_eq!(code, Some(0));
|
||||
assert_eq!(out.trim(), "ok feature/test");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn git_checkout_file_restore_emits_restored_count() {
|
||||
let dir = init_git_repo();
|
||||
std::fs::write(dir.path().join("a.txt"), "original\n").expect("write a");
|
||||
std::fs::write(dir.path().join("b.txt"), "original\n").expect("write b");
|
||||
git_in_dir(dir.path(), &["add", "a.txt", "b.txt"]);
|
||||
git_in_dir(dir.path(), &["commit", "-q", "-m", "add files"]);
|
||||
|
||||
std::fs::write(dir.path().join("a.txt"), "changed\n").expect("write a");
|
||||
std::fs::write(dir.path().join("b.txt"), "changed\n").expect("write b");
|
||||
|
||||
let (out, code) = rtk_in_dir(
|
||||
dir.path(),
|
||||
&["git", "checkout", "HEAD", "--", "a.txt", "b.txt"],
|
||||
);
|
||||
|
||||
assert_eq!(code, Some(0));
|
||||
assert!(
|
||||
out.trim().is_empty() || out.trim() == "ok 2 files restored",
|
||||
"guarded output may stay empty when native git emits no success text: {out:?}"
|
||||
);
|
||||
assert_eq!(
|
||||
read_text_normalized(&dir.path().join("a.txt")),
|
||||
"original\n"
|
||||
);
|
||||
assert_eq!(
|
||||
read_text_normalized(&dir.path().join("b.txt")),
|
||||
"original\n"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn git_checkout_dirty_tree_error_keeps_file_list() {
|
||||
let dir = init_git_repo();
|
||||
std::fs::write(dir.path().join("a.txt"), "main\n").expect("write a");
|
||||
git_in_dir(dir.path(), &["add", "a.txt"]);
|
||||
git_in_dir(dir.path(), &["commit", "-q", "-m", "add a"]);
|
||||
git_in_dir(dir.path(), &["checkout", "-q", "-b", "feature/test"]);
|
||||
std::fs::write(dir.path().join("a.txt"), "feature\n").expect("write feature");
|
||||
git_in_dir(dir.path(), &["commit", "-am", "feature change"]);
|
||||
git_in_dir(dir.path(), &["checkout", "-q", "main"]);
|
||||
std::fs::write(dir.path().join("a.txt"), "dirty\n").expect("write dirty");
|
||||
|
||||
let (stdout, stderr, code) =
|
||||
rtk_output_in_dir(dir.path(), &["git", "checkout", "feature/test"]);
|
||||
let combined = format!("{stdout}{stderr}");
|
||||
|
||||
assert_ne!(code, Some(0));
|
||||
assert!(
|
||||
combined.contains("error:"),
|
||||
"dirty checkout failure should keep error header: {combined:?}"
|
||||
);
|
||||
assert!(
|
||||
combined.contains("a.txt"),
|
||||
"dirty checkout failure should keep conflicting filename: {combined:?}"
|
||||
);
|
||||
assert!(
|
||||
combined.contains("Aborting"),
|
||||
"dirty checkout failure should keep abort line: {combined:?}"
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,378 @@
|
||||
#![cfg(unix)]
|
||||
//! Integration tests for the shared grep/rg compression filter: the GROUP path
|
||||
//! with context flags (-A/-B/-C) and the safety-net passthrough for flags (some
|
||||
//! grep-only like -I, some rg-only like --heading/-p) that break the NUL reparse.
|
||||
|
||||
use std::process::Command;
|
||||
|
||||
fn rtk() -> Command {
|
||||
Command::new(env!("CARGO_BIN_EXE_rtk"))
|
||||
}
|
||||
|
||||
fn rg_available() -> bool {
|
||||
Command::new("rg")
|
||||
.arg("--version")
|
||||
.output()
|
||||
.map(|o| o.status.success())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn write_temp(content: &str) -> (tempfile::TempDir, std::path::PathBuf) {
|
||||
let dir = tempfile::tempdir().expect("tempdir");
|
||||
let path = dir.path().join("test.txt");
|
||||
std::fs::write(&path, content).expect("write");
|
||||
(dir, path)
|
||||
}
|
||||
|
||||
// --- context compression (the gain win) ---
|
||||
|
||||
#[test]
|
||||
fn single_file_context_shown_without_header() {
|
||||
if !rg_available() {
|
||||
return;
|
||||
}
|
||||
let long = "x".repeat(120);
|
||||
let content =
|
||||
format!("before {long}\nMATCH {long}\nafter1 {long}\nafter2 {long}\nend {long}\n");
|
||||
let (_dir, path) = write_temp(&content);
|
||||
let out = rtk()
|
||||
.args(["grep", "-A2", "MATCH", path.to_str().unwrap()])
|
||||
.output()
|
||||
.expect("rtk grep");
|
||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||
|
||||
assert!(
|
||||
!stdout.contains("matches in"),
|
||||
"single-file search must not add a grouped header:\n{stdout}"
|
||||
);
|
||||
assert!(
|
||||
stdout.contains("after1") && stdout.contains("after2"),
|
||||
"after-context lines must be shown:\n{stdout}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn after_context_uses_dash_separator_for_context_lines() {
|
||||
if !rg_available() {
|
||||
return;
|
||||
}
|
||||
let (_dir, path) = write_temp("MATCH\nafter1\n");
|
||||
let out = rtk()
|
||||
.args(["grep", "-nA1", "MATCH", path.to_str().unwrap()])
|
||||
.output()
|
||||
.expect("rtk grep");
|
||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||
|
||||
let has_context_dash = stdout.lines().any(|l| l.contains("-after1"));
|
||||
assert!(
|
||||
has_context_dash,
|
||||
"context lines must use dash separator:\n{stdout}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn capped_single_file_shows_header() {
|
||||
if !rg_available() {
|
||||
return;
|
||||
}
|
||||
let filler: String = (0..40).map(|i| format!("w{i} ")).collect();
|
||||
let content: String = (0..60).map(|i| format!("foo {i} {filler}\n")).collect();
|
||||
let (_dir, path) = write_temp(&content);
|
||||
let out = rtk()
|
||||
.args(["grep", "foo", path.to_str().unwrap()])
|
||||
.output()
|
||||
.expect("rtk grep");
|
||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||
|
||||
assert!(
|
||||
stdout.contains("matches in"),
|
||||
"header must show once capping compresses:\n{stdout}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn true_no_match_exits_1() {
|
||||
if !rg_available() {
|
||||
return;
|
||||
}
|
||||
let (_dir, path) = write_temp("hello world\n");
|
||||
let out = rtk()
|
||||
.args(["grep", "zzzz_no_match_xyz", path.to_str().unwrap()])
|
||||
.output()
|
||||
.expect("rtk grep");
|
||||
|
||||
assert_eq!(
|
||||
out.status.code(),
|
||||
Some(1),
|
||||
"true no-match must exit 1, not 0"
|
||||
);
|
||||
}
|
||||
|
||||
// --- safety net: flags that break the NUL-based reparse ---
|
||||
|
||||
#[test]
|
||||
fn no_line_number_flag_produces_output_not_zero_matches() {
|
||||
if !rg_available() {
|
||||
return;
|
||||
}
|
||||
let (_dir, path) = write_temp("hello world\n");
|
||||
let out = rtk()
|
||||
.args(["rg", "-N", "hello", path.to_str().unwrap()])
|
||||
.output()
|
||||
.expect("rtk grep");
|
||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||
|
||||
assert!(
|
||||
!stdout.contains("0 matches"),
|
||||
"-N output must not be reported as '0 matches':\n{stdout}"
|
||||
);
|
||||
assert!(
|
||||
stdout.contains("hello"),
|
||||
"-N output must contain the matching line:\n{stdout}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_filename_flag_produces_output_not_zero_matches() {
|
||||
if !rg_available() {
|
||||
return;
|
||||
}
|
||||
let (_dir, path) = write_temp("hello world\n");
|
||||
let out = rtk()
|
||||
.args(["grep", "-I", "hello", path.to_str().unwrap()])
|
||||
.output()
|
||||
.expect("rtk grep");
|
||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||
|
||||
assert!(
|
||||
!stdout.contains("0 matches"),
|
||||
"-I output must not be reported as '0 matches':\n{stdout}"
|
||||
);
|
||||
assert!(
|
||||
stdout.contains("hello"),
|
||||
"-I output must contain the matching line:\n{stdout}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn heading_flag_produces_output_not_zero_matches() {
|
||||
if !rg_available() {
|
||||
return;
|
||||
}
|
||||
let (_dir, path) = write_temp("hello world\n");
|
||||
let out = rtk()
|
||||
.args(["rg", "--heading", "hello", path.to_str().unwrap()])
|
||||
.output()
|
||||
.expect("rtk grep");
|
||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||
|
||||
assert!(
|
||||
!stdout.contains("0 matches"),
|
||||
"--heading output must not be reported as '0 matches':\n{stdout}"
|
||||
);
|
||||
assert!(
|
||||
stdout.contains("hello"),
|
||||
"--heading output must contain the matching line:\n{stdout}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pretty_flag_produces_output_not_zero_matches() {
|
||||
if !rg_available() {
|
||||
return;
|
||||
}
|
||||
let (_dir, path) = write_temp("hello world\n");
|
||||
let out = rtk()
|
||||
.args(["rg", "-p", "hello", path.to_str().unwrap()])
|
||||
.output()
|
||||
.expect("rtk grep");
|
||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||
|
||||
assert!(
|
||||
!stdout.contains("0 matches"),
|
||||
"-p output must not be reported as '0 matches':\n{stdout}"
|
||||
);
|
||||
assert!(
|
||||
stdout.contains("hello"),
|
||||
"-p output must contain the matching line:\n{stdout}"
|
||||
);
|
||||
}
|
||||
|
||||
// --- shape flags: passthrough, no NUL leak ---
|
||||
|
||||
#[test]
|
||||
fn column_flag_output_has_no_nul() {
|
||||
if !rg_available() {
|
||||
return;
|
||||
}
|
||||
let (_dir, path) = write_temp("hello world\n");
|
||||
let out = rtk()
|
||||
.args(["rg", "--column", "hello", path.to_str().unwrap()])
|
||||
.output()
|
||||
.expect("rtk grep");
|
||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||
|
||||
assert!(
|
||||
!stdout.contains('\u{0}'),
|
||||
"--column output must not contain NUL:\n{stdout:?}"
|
||||
);
|
||||
assert!(
|
||||
stdout.contains("hello"),
|
||||
"--column output must contain the match:\n{stdout}"
|
||||
);
|
||||
}
|
||||
|
||||
// --- token savings (the compression gain) ---
|
||||
|
||||
fn count_tokens(s: &str) -> usize {
|
||||
s.split_whitespace().count()
|
||||
}
|
||||
|
||||
// Covers #545: grep savings are measured against the real grep output.
|
||||
#[test]
|
||||
fn bulky_grep_yields_token_savings() {
|
||||
if !rg_available() {
|
||||
return;
|
||||
}
|
||||
let filler: String = (0..50).map(|i| format!("word{i} ")).collect();
|
||||
let mut content = String::new();
|
||||
for i in 0..60 {
|
||||
content.push_str(&format!("MATCH line {i} {filler}\n"));
|
||||
}
|
||||
let (_dir, path) = write_temp(&content);
|
||||
|
||||
let raw = Command::new("rg")
|
||||
.args(["-nH", "MATCH", path.to_str().unwrap()])
|
||||
.output()
|
||||
.expect("rg");
|
||||
let raw_tokens = count_tokens(&String::from_utf8_lossy(&raw.stdout));
|
||||
|
||||
let out = rtk()
|
||||
.args(["grep", "MATCH", path.to_str().unwrap()])
|
||||
.output()
|
||||
.expect("rtk grep");
|
||||
let rtk_tokens = count_tokens(&String::from_utf8_lossy(&out.stdout));
|
||||
|
||||
let savings = 100.0 - (rtk_tokens as f64 / raw_tokens as f64 * 100.0);
|
||||
assert!(
|
||||
savings >= 50.0,
|
||||
"expected >=50% token savings, got {savings:.1}% (raw={raw_tokens}, rtk={rtk_tokens})"
|
||||
);
|
||||
}
|
||||
|
||||
// --- grep-only syntax falls back to system grep (#2543) ---
|
||||
|
||||
#[test]
|
||||
fn grep_only_flags_fall_back_to_system_grep() {
|
||||
if !rg_available() {
|
||||
return;
|
||||
}
|
||||
let dir = tempfile::tempdir().expect("tempdir");
|
||||
std::fs::write(dir.path().join("a.java"), "DRAFT in java\n").expect("write");
|
||||
std::fs::write(dir.path().join("b.txt"), "DRAFT in text\n").expect("write");
|
||||
let path = dir.path().to_str().unwrap();
|
||||
|
||||
let out = rtk()
|
||||
.args(["grep", "-rn", "DRAFT", "--include=*.java", path])
|
||||
.output()
|
||||
.expect("rtk grep");
|
||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||
|
||||
assert!(
|
||||
stdout.contains("a.java"),
|
||||
"--include=*.java should match the java file:\n{stdout}"
|
||||
);
|
||||
assert!(
|
||||
!stdout.contains("b.txt"),
|
||||
"--include=*.java should exclude the txt file:\n{stdout}"
|
||||
);
|
||||
assert!(
|
||||
!stdout.contains("grep failed") && !stdout.contains("unrecognized"),
|
||||
"rg-incompatible flag must fall back to grep, not error:\n{stdout}"
|
||||
);
|
||||
}
|
||||
|
||||
// --- never-worse guard: small greps must not cost more than plain grep ---
|
||||
|
||||
#[test]
|
||||
fn small_grep_not_worse_than_plain() {
|
||||
if !rg_available() {
|
||||
return;
|
||||
}
|
||||
let (_dir, path) = write_temp("foo\n");
|
||||
let out = rtk()
|
||||
.args(["grep", "foo", path.to_str().unwrap()])
|
||||
.output()
|
||||
.expect("rtk grep");
|
||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||
|
||||
assert!(
|
||||
stdout.trim() == "1:foo",
|
||||
"single-file grep must equal `grep -n` (position, no filename):\n{stdout}"
|
||||
);
|
||||
assert!(
|
||||
!stdout.contains("matches in"),
|
||||
"header that costs more than raw must be dropped:\n{stdout}"
|
||||
);
|
||||
}
|
||||
|
||||
// --- #2543: bundled files-with-matches cluster (-rln / -ln) lists files, not "0 matches" ---
|
||||
|
||||
#[test]
|
||||
fn bundled_files_with_matches_cluster_lists_files() {
|
||||
if !rg_available() {
|
||||
return;
|
||||
}
|
||||
let dir = tempfile::tempdir().expect("tempdir");
|
||||
std::fs::write(dir.path().join("a.txt"), "TODO alpha\n").expect("write");
|
||||
std::fs::write(dir.path().join("b.txt"), "TODO beta\n").expect("write");
|
||||
std::fs::write(dir.path().join("c.txt"), "nothing here\n").expect("write");
|
||||
let path = dir.path().to_str().unwrap();
|
||||
|
||||
let out = rtk()
|
||||
.args(["grep", "-rln", "TODO", path])
|
||||
.output()
|
||||
.expect("rtk grep");
|
||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||
|
||||
assert!(
|
||||
!stdout.contains("0 matches"),
|
||||
"-rln must list files, not report a false '0 matches' (#2543):\n{stdout}"
|
||||
);
|
||||
assert!(
|
||||
stdout.contains("a.txt") && stdout.contains("b.txt"),
|
||||
"-rln must list every matching file:\n{stdout}"
|
||||
);
|
||||
assert!(
|
||||
!stdout.contains("c.txt"),
|
||||
"-rln must not list non-matching files:\n{stdout}"
|
||||
);
|
||||
}
|
||||
|
||||
// A match inside a binary file is noise (grep prints only a "binary file matches"
|
||||
// notice); skip it by default, but `-a` lets the agent opt back into the content.
|
||||
#[test]
|
||||
fn binary_match_is_skipped_unless_text_requested() {
|
||||
let dir = tempfile::tempdir().expect("tempdir");
|
||||
let p = dir.path().join("blob.bin");
|
||||
std::fs::write(&p, b"SECRET\x00\x01binary\xff\xfe").expect("write");
|
||||
let path = p.to_str().unwrap();
|
||||
|
||||
let out = rtk().args(["grep", "SECRET", path]).output().expect("rtk");
|
||||
assert_eq!(
|
||||
out.status.code(),
|
||||
Some(1),
|
||||
"binary match must be skipped as noise by default"
|
||||
);
|
||||
assert!(out.stdout.is_empty(), "no binary content by default");
|
||||
|
||||
let out = rtk()
|
||||
.args(["grep", "-a", "SECRET", path])
|
||||
.output()
|
||||
.expect("rtk -a");
|
||||
assert_eq!(out.status.code(), Some(0), "-a must surface the match");
|
||||
assert!(
|
||||
String::from_utf8_lossy(&out.stdout).contains("SECRET"),
|
||||
"-a must show the binary content"
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
#![cfg(unix)]
|
||||
//! Error/exit faithfulness: rtk surfaces the engine's own stderr and propagates
|
||||
//! its exit code, adding nothing (no synthetic "search failed" line). An engine
|
||||
//! error (exit >=2) must never look like a silent no-match (#2465 / #1436).
|
||||
|
||||
use std::process::Command;
|
||||
|
||||
fn rtk(args: &[&str]) -> std::process::Output {
|
||||
Command::new(env!("CARGO_BIN_EXE_rtk"))
|
||||
.args(args)
|
||||
.output()
|
||||
.expect("rtk")
|
||||
}
|
||||
|
||||
fn grep_exit(args: &[&str]) -> Option<i32> {
|
||||
Command::new("grep")
|
||||
.args(args)
|
||||
.output()
|
||||
.expect("grep")
|
||||
.status
|
||||
.code()
|
||||
}
|
||||
|
||||
fn rg_available() -> bool {
|
||||
Command::new("rg")
|
||||
.arg("--version")
|
||||
.output()
|
||||
.map(|o| o.status.success())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn write_temp(content: &str) -> (tempfile::TempDir, String) {
|
||||
let d = tempfile::tempdir().expect("tempdir");
|
||||
let p = d.path().join("ok.txt");
|
||||
std::fs::write(&p, content).expect("write");
|
||||
let s = p.to_str().unwrap().to_string();
|
||||
(d, s)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn file_not_found_propagates_exit_and_surfaces_error() {
|
||||
let d = tempfile::tempdir().unwrap();
|
||||
let missing = d.path().join("nope.txt");
|
||||
let m = missing.to_str().unwrap();
|
||||
let out = rtk(&["grep", "fn", m]);
|
||||
assert_eq!(
|
||||
out.status.code(),
|
||||
grep_exit(&["fn", m]),
|
||||
"exit must match grep"
|
||||
);
|
||||
let stderr = String::from_utf8_lossy(&out.stderr);
|
||||
assert!(
|
||||
stderr.contains("No such file"),
|
||||
"the engine's error must be surfaced:\n{stderr}"
|
||||
);
|
||||
assert!(
|
||||
!stderr.contains("search failed"),
|
||||
"no synthetic line:\n{stderr}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bad_regex_surfaces_error_never_silent_no_match() {
|
||||
let (_d, f) = write_temp("fn alpha\n");
|
||||
let out = rtk(&["grep", "[", &f]);
|
||||
assert_eq!(
|
||||
out.status.code(),
|
||||
Some(2),
|
||||
"a bad regex must propagate exit 2, not a silent exit-1 no-match"
|
||||
);
|
||||
let stderr = String::from_utf8_lossy(&out.stderr);
|
||||
assert!(!stderr.is_empty(), "the engine error must surface");
|
||||
assert!(
|
||||
!stderr.contains("search failed"),
|
||||
"nothing added:\n{stderr}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_match_with_error_surfaces_both() {
|
||||
let (_d, f) = write_temp("fn alpha\nfn beta\n");
|
||||
let d2 = tempfile::tempdir().unwrap();
|
||||
let missing = d2.path().join("nope.txt");
|
||||
let out = rtk(&["grep", "fn", &f, missing.to_str().unwrap()]);
|
||||
assert_eq!(out.status.code(), Some(2), "the error exit must propagate");
|
||||
assert!(
|
||||
String::from_utf8_lossy(&out.stderr).contains("No such file"),
|
||||
"the file error must surface alongside the matches"
|
||||
);
|
||||
assert!(
|
||||
!out.stdout.is_empty(),
|
||||
"the matches from the readable file must still be shown"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_match_stays_exit_1_and_empty() {
|
||||
let (_d, f) = write_temp("fn alpha\n");
|
||||
let out = rtk(&["grep", "zzzz_no_match", &f]);
|
||||
assert_eq!(out.status.code(), Some(1), "no-match is exit 1");
|
||||
assert!(
|
||||
out.stdout.is_empty() && out.stderr.is_empty(),
|
||||
"no-match emits nothing"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rg_bad_regex_surfaces_error_exit_2() {
|
||||
if !rg_available() {
|
||||
return;
|
||||
}
|
||||
let (_d, f) = write_temp("GET /objects/{path}\n");
|
||||
let out = rtk(&["rg", "a|{path}", &f]);
|
||||
assert_eq!(
|
||||
out.status.code(),
|
||||
Some(2),
|
||||
"rg's regex parse error must propagate exit 2"
|
||||
);
|
||||
assert!(
|
||||
!String::from_utf8_lossy(&out.stderr).contains("search failed"),
|
||||
"nothing added"
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,348 @@
|
||||
#![cfg(unix)]
|
||||
//! Engine-faithfulness contract: `rtk grep` runs grep and `rtk rg` runs rg, each
|
||||
//! with its own regex dialect and ignore semantics. rtk filters output noise only;
|
||||
//! it never substitutes one engine for the other (the bug this PR removes).
|
||||
|
||||
use std::io::Write;
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
fn rtk() -> Command {
|
||||
Command::new(env!("CARGO_BIN_EXE_rtk"))
|
||||
}
|
||||
|
||||
/// Run rtk with `input` fed on stdin; returns (stdout, exit_code).
|
||||
fn rtk_stdin(input: &str, args: &[&str]) -> (String, Option<i32>) {
|
||||
let mut child = rtk()
|
||||
.args(args)
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()
|
||||
.expect("spawn rtk");
|
||||
child
|
||||
.stdin
|
||||
.take()
|
||||
.expect("stdin")
|
||||
.write_all(input.as_bytes())
|
||||
.expect("write stdin");
|
||||
let out = child.wait_with_output().expect("wait");
|
||||
(
|
||||
String::from_utf8_lossy(&out.stdout).into_owned(),
|
||||
out.status.code(),
|
||||
)
|
||||
}
|
||||
|
||||
fn rg_available() -> bool {
|
||||
Command::new("rg")
|
||||
.arg("--version")
|
||||
.output()
|
||||
.map(|o| o.status.success())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn write_temp(content: &str) -> (tempfile::TempDir, std::path::PathBuf) {
|
||||
let dir = tempfile::tempdir().expect("tempdir");
|
||||
let path = dir.path().join("test.txt");
|
||||
std::fs::write(&path, content).expect("write");
|
||||
(dir, path)
|
||||
}
|
||||
|
||||
fn count_tokens(s: &str) -> usize {
|
||||
s.split_whitespace().count()
|
||||
}
|
||||
|
||||
// --- regex dialect: the single most important regression guard ---
|
||||
|
||||
// Covers #2253 (matches silently rewritten when grep was routed through rg),
|
||||
// #2301 (rg routed to BSD grep, wrong dialect) and #545 (savings can't be faked
|
||||
// against a foreign engine's output).
|
||||
#[test]
|
||||
fn grep_and_rg_use_their_own_regex_dialect() {
|
||||
if !rg_available() {
|
||||
return;
|
||||
}
|
||||
// "alpha" holds "al" and "gamma" holds "ga", but neither line ever contains
|
||||
// the literal string "al|ga".
|
||||
let (_dir, path) = write_temp("alpha\ngamma\n");
|
||||
let p = path.to_str().unwrap();
|
||||
|
||||
// grep BRE: a bare `|` is a literal pipe, so "al|ga" matches nothing -> exit 1.
|
||||
let g = rtk().args(["grep", "al|ga", p]).output().expect("rtk grep");
|
||||
assert_eq!(
|
||||
g.status.code(),
|
||||
Some(1),
|
||||
"grep must treat | as a literal pipe (0 matches), proving no rg substitution:\n{}",
|
||||
String::from_utf8_lossy(&g.stdout)
|
||||
);
|
||||
|
||||
// rg: `|` is alternation, so "al|ga" matches both lines -> exit 0.
|
||||
let r = rtk().args(["rg", "al|ga", p]).output().expect("rtk rg");
|
||||
assert_eq!(
|
||||
r.status.code(),
|
||||
Some(0),
|
||||
"rg must treat | as alternation (matches), proving it runs rg, not grep"
|
||||
);
|
||||
let r_out = String::from_utf8_lossy(&r.stdout);
|
||||
assert!(
|
||||
r_out.contains("alpha") && r_out.contains("gamma"),
|
||||
"rg alternation must match both lines:\n{r_out}"
|
||||
);
|
||||
}
|
||||
|
||||
// --- ignore semantics: rg stays lean, grep -r descends (the node_modules flood fix) ---
|
||||
|
||||
// Covers #2606 (rg must keep .gitignore/binary skipping) and #2064 (forced
|
||||
// --no-ignore-vcs made rg read node_modules and dump minified files).
|
||||
#[test]
|
||||
fn rg_honors_ignore_files_grep_does_not() {
|
||||
if !rg_available() {
|
||||
return;
|
||||
}
|
||||
let dir = tempfile::tempdir().expect("tempdir");
|
||||
// `.ignore` is rg-native and applies without a surrounding git repo.
|
||||
std::fs::write(dir.path().join(".ignore"), "skip.txt\n").expect("write");
|
||||
std::fs::write(dir.path().join("skip.txt"), "NEEDLE here\n").expect("write");
|
||||
std::fs::write(dir.path().join("keep.txt"), "NEEDLE here\n").expect("write");
|
||||
let path = dir.path().to_str().unwrap();
|
||||
|
||||
// rg respects the ignore file: skip.txt must not appear (no forced --no-ignore-vcs).
|
||||
let r = rtk().args(["rg", "NEEDLE", path]).output().expect("rtk rg");
|
||||
let r_out = String::from_utf8_lossy(&r.stdout);
|
||||
assert!(
|
||||
r_out.contains("keep.txt"),
|
||||
"rg must match the non-ignored file:\n{r_out}"
|
||||
);
|
||||
assert!(
|
||||
!r_out.contains("skip.txt"),
|
||||
"rg must honor .ignore and skip skip.txt (no forced --no-ignore-vcs flood):\n{r_out}"
|
||||
);
|
||||
|
||||
// grep knows nothing of ignore files: -r descends and matches both.
|
||||
let g = rtk()
|
||||
.args(["grep", "-rn", "NEEDLE", path])
|
||||
.output()
|
||||
.expect("rtk grep");
|
||||
let g_out = String::from_utf8_lossy(&g.stdout);
|
||||
assert!(
|
||||
g_out.contains("keep.txt") && g_out.contains("skip.txt"),
|
||||
"grep -r must descend into every file, ignoring .ignore:\n{g_out}"
|
||||
);
|
||||
}
|
||||
|
||||
// --- token savings: rg path compresses as much as the grep path ---
|
||||
|
||||
// Covers #545: rg savings are measured against the real rg output, not a
|
||||
// substituted engine's inflated result.
|
||||
#[test]
|
||||
fn bulky_rg_yields_token_savings() {
|
||||
if !rg_available() {
|
||||
return;
|
||||
}
|
||||
let filler: String = (0..50).map(|i| format!("word{i} ")).collect();
|
||||
let mut content = String::new();
|
||||
for i in 0..60 {
|
||||
content.push_str(&format!("MATCH line {i} {filler}\n"));
|
||||
}
|
||||
let (_dir, path) = write_temp(&content);
|
||||
|
||||
let raw = Command::new("rg")
|
||||
.args(["-nH", "MATCH", path.to_str().unwrap()])
|
||||
.output()
|
||||
.expect("rg");
|
||||
let raw_tokens = count_tokens(&String::from_utf8_lossy(&raw.stdout));
|
||||
|
||||
let out = rtk()
|
||||
.args(["rg", "MATCH", path.to_str().unwrap()])
|
||||
.output()
|
||||
.expect("rtk rg");
|
||||
let rtk_tokens = count_tokens(&String::from_utf8_lossy(&out.stdout));
|
||||
|
||||
let savings = 100.0 - (rtk_tokens as f64 / raw_tokens as f64 * 100.0);
|
||||
assert!(
|
||||
savings >= 50.0,
|
||||
"expected >=50% rg token savings, got {savings:.1}% (raw={raw_tokens}, rtk={rtk_tokens})"
|
||||
);
|
||||
}
|
||||
|
||||
// --- engine-specific flags reach their own engine ---
|
||||
|
||||
// `-E` selects grep's extended regex; the flag must reach grep, never be swallowed
|
||||
// as ripgrep's `--encoding` (#2253) or routed to the wrong engine (#2167).
|
||||
#[test]
|
||||
fn grep_dash_e_selects_extended_regex() {
|
||||
if !rg_available() {
|
||||
return;
|
||||
}
|
||||
let (_dir, path) = write_temp("alpha\ngamma\n");
|
||||
let p = path.to_str().unwrap();
|
||||
|
||||
// Plain BRE: bare `|` is literal -> no match, exit 1.
|
||||
let bre = rtk().args(["grep", "al|ga", p]).output().expect("rtk grep");
|
||||
assert_eq!(bre.status.code(), Some(1), "BRE | must stay literal");
|
||||
|
||||
// -E (ERE): `|` is alternation -> both lines match, exit 0.
|
||||
let ere = rtk()
|
||||
.args(["grep", "-E", "al|ga", p])
|
||||
.output()
|
||||
.expect("rtk grep -E");
|
||||
assert_eq!(
|
||||
ere.status.code(),
|
||||
Some(0),
|
||||
"grep -E must enable ERE alternation, proving -E reaches grep and is not read as rg --encoding"
|
||||
);
|
||||
let out = String::from_utf8_lossy(&ere.stdout);
|
||||
assert!(
|
||||
out.contains("alpha") && out.contains("gamma"),
|
||||
"grep -E alternation must match both lines:\n{out}"
|
||||
);
|
||||
}
|
||||
|
||||
// rg's `-g/--glob` filters the file set; it must reach rg with correct ordering,
|
||||
// not be mangled by a grep that has no such flag (#1824, #2167).
|
||||
#[test]
|
||||
fn rg_glob_flag_filters_the_file_set() {
|
||||
if !rg_available() {
|
||||
return;
|
||||
}
|
||||
let dir = tempfile::tempdir().expect("tempdir");
|
||||
std::fs::write(dir.path().join("a.rs"), "NEEDLE in rust\n").expect("write");
|
||||
std::fs::write(dir.path().join("b.txt"), "NEEDLE in text\n").expect("write");
|
||||
let path = dir.path().to_str().unwrap();
|
||||
|
||||
let out = rtk()
|
||||
.args(["rg", "-g", "*.rs", "NEEDLE", path])
|
||||
.output()
|
||||
.expect("rtk rg -g");
|
||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||
assert!(
|
||||
stdout.contains("a.rs"),
|
||||
"rg -g '*.rs' must match the rust file:\n{stdout}"
|
||||
);
|
||||
assert!(
|
||||
!stdout.contains("b.txt"),
|
||||
"rg -g '*.rs' must exclude files outside the glob:\n{stdout}"
|
||||
);
|
||||
}
|
||||
|
||||
// --- piped stdin: read the pipe, never inject a path ---
|
||||
|
||||
#[test]
|
||||
fn grep_reads_piped_stdin() {
|
||||
let (out, code) = rtk_stdin("alpha\nmatch me here\nomega\n", &["grep", "match"]);
|
||||
assert_eq!(
|
||||
code,
|
||||
Some(0),
|
||||
"stdin match must exit 0, got {code:?}:\n{out}"
|
||||
);
|
||||
assert!(
|
||||
out.contains("match me here"),
|
||||
"grep must read stdin and emit the match:\n{out}"
|
||||
);
|
||||
assert!(
|
||||
!out.contains("Is a directory"),
|
||||
"RTK must not inject '.' and break a stdin pipe:\n{out}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rg_reads_piped_stdin_without_flooding_cwd() {
|
||||
if !rg_available() {
|
||||
return;
|
||||
}
|
||||
// `fn` matches thousands of repo lines; reading stdin must yield only the pipe.
|
||||
let (out, code) = rtk_stdin("fn stdin_only_line\n", &["rg", "fn"]);
|
||||
assert_eq!(
|
||||
code,
|
||||
Some(0),
|
||||
"stdin match must exit 0, got {code:?}:\n{out}"
|
||||
);
|
||||
assert!(
|
||||
out.contains("stdin_only_line"),
|
||||
"rg must read stdin and emit the match:\n{out}"
|
||||
);
|
||||
assert!(
|
||||
!out.contains(".rs:") && !out.contains("src/"),
|
||||
"rg must read stdin, not flood the working tree:\n{out}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn grep_counts_piped_stdin_via_passthrough() {
|
||||
// `-c` routes to the passthrough path; it must still read the pipe, not null stdin.
|
||||
let (out, code) = rtk_stdin("hit\nmiss\nhit\n", &["grep", "-c", "hit"]);
|
||||
assert_eq!(
|
||||
code,
|
||||
Some(0),
|
||||
"stdin count must exit 0, got {code:?}:\n{out}"
|
||||
);
|
||||
assert_eq!(
|
||||
out.trim(),
|
||||
"2",
|
||||
"grep -c must count matches from stdin:\n{out}"
|
||||
);
|
||||
}
|
||||
|
||||
// --- pattern-less commands run instead of being blocked ---
|
||||
|
||||
#[test]
|
||||
fn rg_type_list_passes_through() {
|
||||
if !rg_available() {
|
||||
return;
|
||||
}
|
||||
let out = rtk().args(["rg", "--type-list"]).output().expect("rtk rg");
|
||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||
let stderr = String::from_utf8_lossy(&out.stderr);
|
||||
assert_eq!(out.status.code(), Some(0), "--type-list must exit 0");
|
||||
assert!(
|
||||
stdout.lines().count() > 10,
|
||||
"--type-list must produce the real type list:\n{stdout}"
|
||||
);
|
||||
assert!(
|
||||
!stdout.contains("pattern required") && !stderr.contains("pattern required"),
|
||||
"valid pattern-less command must not be blocked:\n{stdout}{stderr}"
|
||||
);
|
||||
assert!(
|
||||
!stderr.contains("rtk grep:"),
|
||||
"an rg command must never be labelled 'rtk grep:':\n{stderr}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rg_files_lists_the_given_dir() {
|
||||
if !rg_available() {
|
||||
return;
|
||||
}
|
||||
let dir = tempfile::tempdir().expect("tempdir");
|
||||
std::fs::write(dir.path().join("only_here.txt"), "x\n").expect("write");
|
||||
let path = dir.path().to_str().unwrap();
|
||||
|
||||
let out = rtk()
|
||||
.args(["rg", "--files", path])
|
||||
.output()
|
||||
.expect("rtk rg");
|
||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||
assert_eq!(out.status.code(), Some(0), "--files must exit 0");
|
||||
assert!(
|
||||
stdout.contains("only_here.txt"),
|
||||
"--files must list the given dir, not the cwd:\n{stdout}"
|
||||
);
|
||||
}
|
||||
|
||||
// #1436 (jhagberg): a pattern rg rejects must surface rg's error (exit 2), never
|
||||
// be swallowed into a silent "0 matches" (exit 1) that reads as a clean no-match.
|
||||
#[test]
|
||||
fn rg_surfaces_regex_error_not_silent_zero() {
|
||||
if !rg_available() {
|
||||
return;
|
||||
}
|
||||
let (_dir, path) = write_temp("GET /objects/{path}\nfilePath: x\n");
|
||||
let out = rtk()
|
||||
.args(["rg", "objects|{path}", path.to_str().unwrap()])
|
||||
.output()
|
||||
.expect("rtk rg");
|
||||
assert_eq!(
|
||||
out.status.code(),
|
||||
Some(2),
|
||||
"an rg regex parse error must surface as exit 2, not a silent 0/1"
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user