Skip to content

Commit 18a8947

Browse files
ruromeroclaude
andcommitted
test(pip): call pip directly instead of using env var overrides
Remove TRUSTIFY_DA_PIP_REPORT setup/teardown from pip tests and let them invoke pip directly. Pin fixture pyproject.toml versions to get deterministic output, add --quiet flag to suppress non-JSON stdout, and update expected SBOMs with real resolved versions. Add testing convention to CONVENTIONS.md and ignore *.egg-info build artifacts. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent d3525b1 commit 18a8947

10 files changed

Lines changed: 118 additions & 166 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ build
1010
target
1111
.npmrc
1212
src/providers/*.wasm
13+
*.egg-info

CONVENTIONS.md

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# Coding Conventions
2+
3+
<!-- This file documents project-specific coding standards for exhort-javascript-api. -->
4+
5+
## Language and Framework
6+
7+
- **Primary Language**: JavaScript (ES modules, `"type": "module"` in package.json)
8+
- **TypeScript**: Configuration present but code is primarily JavaScript with JSDoc
9+
- **Node.js**: Requires Node >= 20.0.0, npm >= 11.5.1
10+
- **CLI**: `yargs` for command-line argument parsing
11+
- **Parsing Libraries**: `fast-xml-parser`, `fast-toml`, `smol-toml`, `tree-sitter-requirements`
12+
13+
## Code Style
14+
15+
- **Linter**: ESLint with recommended config + editorconfig + import plugins
16+
- **Indentation**: Tabs (4 spaces for YAML/Markdown)
17+
- **Line endings**: LF
18+
- **Max line length**: 100 (120 for Markdown)
19+
- **Charset**: UTF-8, final newline, trim trailing whitespace
20+
- **Import ordering** (ESLint enforced): builtin, external, internal, parent, sibling, index — alphabetical within groups
21+
- **Strict equality**: `eqeqeq: ["warn", "always", {"null": "never"}]`
22+
- **Curly braces**: Required (`curly: "warn"`)
23+
- **No throw literals**: `no-throw-literal: "warn"`
24+
- **No Prettier** — ESLint + EditorConfig handle formatting
25+
26+
## Naming Conventions
27+
28+
- **Classes**: PascalCase with underscore-separated language names (`Java_maven`, `Base_java`, `Javascript_npm`)
29+
- **Files**: snake_case for providers (`base_java.js`, `javascript_npm.js`, `python_pip.js`)
30+
- **Test files**: `*.test.js` suffix (`analysis.test.js`, `provider.test.js`)
31+
- **Functions/Methods**: camelCase (`provideComponent()`, `provideStack()`, `validateLockFile()`)
32+
- **Variables**: camelCase (`manifestPath`, `backendUrl`)
33+
- **Constants**: UPPER_SNAKE_CASE (`ecosystem_maven`, `DEFAULT_WORKSPACE_DISCOVERY_IGNORE`)
34+
- **Private class fields**: `#` prefix (`#manifest`, `#cmd`, `#ecosystem`)
35+
- **Protected methods**: `_` prefix (`_lockFileName()`, `_cmdName()`, `_listCmdArgs()`)
36+
37+
## File Organization
38+
39+
```
40+
src/
41+
├── index.js # Main export
42+
├── cli.js # CLI entry point
43+
├── analysis.js # API request handling
44+
├── provider.js # Provider matching logic
45+
├── workspace.js # Workspace discovery
46+
├── tools.js # Utilities
47+
├── sbom.js # SBOM handling
48+
├── cyclone_dx_sbom.js # CycloneDX SBOM generation
49+
├── providers/ # Ecosystem providers
50+
│ ├── base_java.js
51+
│ ├── base_javascript.js
52+
│ ├── java_maven.js
53+
│ ├── javascript_npm.js
54+
│ ├── python_pip.js
55+
│ ├── rust_cargo.js
56+
│ └── processors/ # Specialized processors
57+
├── license/ # License detection
58+
└── oci_image/ # OCI image analysis
59+
60+
test/
61+
├── analysis.test.js
62+
├── provider.test.js
63+
├── tools.test.js
64+
└── providers/ # Provider-specific tests
65+
```
66+
67+
## Error Handling
68+
69+
- **Throw Error objects**: `throw new Error("message")`, `throw new TypeError("message")`
70+
- **No custom error classes** — uses built-in `Error` and `TypeError`
71+
- **HTTP errors**: Check `resp.status`, throw with status code and response text
72+
- **Async errors**: Bubble up naturally via async/await (no blanket try-catch)
73+
- **Validation errors**: Thrown early with descriptive context (manifest type, lock file)
74+
75+
## Testing Conventions
76+
77+
- **Framework**: Mocha with TDD UI (`suite()` / `test()`)
78+
- **Assertions**: Chai with `expect()` syntax
79+
- **Mocking**: Sinon for stubs; MSW (Mock Service Worker) for HTTP mocking
80+
- **Module mocking**: `esmock` with experimental loader
81+
- **Coverage**: C8 with 82% line coverage requirement
82+
- **Test patterns**: `expect(res).to.deep.equal(...)`, `expect(() => ...).to.throw('message')`
83+
- **Higher-order setup**: Functions like `interceptAndRun()` for test setup/teardown
84+
- **Prefer real tool invocations over env var overrides**: Tests should call the actual ecosystem tools (pip, uv, poetry, mvn, npm, etc.) rather than injecting pre-recorded output via `TRUSTIFY_DA_*` environment variables. The CI environment has these tools available. Env var overrides (`TRUSTIFY_DA_PIP_REPORT`, `TRUSTIFY_DA_UV_EXPORT`, etc.) exist for users who lack the tool locally, but tests should exercise the real tool path to catch integration issues.
85+
86+
## Commit Messages
87+
88+
- Likely Conventional Commits format
89+
- DCO (Developer Certificate of Origin) required
90+
- Semantic versioning (`0.3.0` in package.json)
91+
92+
## Dependencies
93+
94+
- **Package manager**: npm with `package-lock.json`
95+
- **Module system**: ES modules with explicit `.js` extensions in relative imports
96+
- **Import convention**: `import fs from 'node:fs'` (node: protocol for built-ins)
97+
- **Environment variables**: Prefixed with `TRUSTIFY_DA_` (e.g., `TRUSTIFY_DA_MVN_PATH`, `TRUSTIFY_DA_TOKEN`, `TRUSTIFY_DA_DEBUG`)
98+
- **Multi-ecosystem support**: npm, pnpm, yarn, Maven, Gradle, pip, cargo, Go modules, Docker/Podman

src/providers/python_pip_pyproject.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export default class Python_pip_pyproject extends Base_pyproject {
4747
pipBin = getCustomPath('pip', opts)
4848
}
4949
return invokeCommand(pipBin, [
50-
'install', '--dry-run', '--ignore-installed', '--report', '-', '.'
50+
'install', '--dry-run', '--ignore-installed', '--quiet', '--report', '-', '.'
5151
], { cwd: manifestDir }).toString()
5252
}
5353

test/providers/python_pyproject.test.js

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import Python_uv from '../../src/providers/python_uv.js'
1010

1111
let clock
1212

13-
const TIMEOUT = process.env.GITHUB_ACTIONS ? 30000 : 10000
13+
const TIMEOUT = process.env.GITHUB_ACTIONS ? 30000 : 15000
1414

1515
const uvProvider = new Python_uv()
1616
const poetryProvider = new Python_poetry()
@@ -180,21 +180,6 @@ suite('testing the python-pyproject data provider', () => {
180180
suite('pip projects (via pip --dry-run --report)', () => {
181181
const pipFixtureDir = `${MANIFESTS}/pip_pep621`
182182
const pipIgnoreDir = `${MANIFESTS}/pip_pep621_ignore`
183-
let savedEnv
184-
185-
setup(() => {
186-
savedEnv = process.env.TRUSTIFY_DA_PIP_REPORT
187-
let report = fs.readFileSync(path.join(pipFixtureDir, 'pip_report.json'), 'utf-8')
188-
process.env.TRUSTIFY_DA_PIP_REPORT = Buffer.from(report).toString('base64')
189-
})
190-
191-
teardown(() => {
192-
if (savedEnv === undefined) {
193-
delete process.env.TRUSTIFY_DA_PIP_REPORT
194-
} else {
195-
process.env.TRUSTIFY_DA_PIP_REPORT = savedEnv
196-
}
197-
})
198183

199184
/** Verifies stack and component SBOM output matches expected pip fixtures. */
200185
SBOM_CASES.forEach(({type, method, fixture}) => {

test/providers/tst_manifests/pyproject/pip_pep621/expected_component_sbom.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,21 @@
1515
"components": [
1616
{
1717
"name": "requests",
18-
"version": "2.33.1",
19-
"purl": "pkg:pypi/requests@2.33.1",
18+
"version": "2.32.3",
19+
"purl": "pkg:pypi/requests@2.32.3",
2020
"type": "library",
21-
"bom-ref": "pkg:pypi/requests@2.33.1"
21+
"bom-ref": "pkg:pypi/requests@2.32.3"
2222
}
2323
],
2424
"dependencies": [
2525
{
2626
"ref": "pkg:pypi/test-project@1.0.0",
2727
"dependsOn": [
28-
"pkg:pypi/requests@2.33.1"
28+
"pkg:pypi/requests@2.32.3"
2929
]
3030
},
3131
{
32-
"ref": "pkg:pypi/requests@2.33.1",
32+
"ref": "pkg:pypi/requests@2.32.3",
3333
"dependsOn": []
3434
}
3535
]

test/providers/tst_manifests/pyproject/pip_pep621/expected_stack_sbom.json

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,17 @@
1515
"components": [
1616
{
1717
"name": "requests",
18-
"version": "2.33.1",
19-
"purl": "pkg:pypi/requests@2.33.1",
18+
"version": "2.32.3",
19+
"purl": "pkg:pypi/requests@2.32.3",
2020
"type": "library",
21-
"bom-ref": "pkg:pypi/requests@2.33.1"
21+
"bom-ref": "pkg:pypi/requests@2.32.3"
2222
},
2323
{
2424
"name": "certifi",
25-
"version": "2026.2.2",
26-
"purl": "pkg:pypi/certifi@2026.2.2",
25+
"version": "2026.2.25",
26+
"purl": "pkg:pypi/certifi@2026.2.25",
2727
"type": "library",
28-
"bom-ref": "pkg:pypi/certifi@2026.2.2"
28+
"bom-ref": "pkg:pypi/certifi@2026.2.25"
2929
},
3030
{
3131
"name": "charset-normalizer",
@@ -53,20 +53,20 @@
5353
{
5454
"ref": "pkg:pypi/test-project@1.0.0",
5555
"dependsOn": [
56-
"pkg:pypi/requests@2.33.1"
56+
"pkg:pypi/requests@2.32.3"
5757
]
5858
},
5959
{
60-
"ref": "pkg:pypi/requests@2.33.1",
60+
"ref": "pkg:pypi/requests@2.32.3",
6161
"dependsOn": [
62-
"pkg:pypi/certifi@2026.2.2",
62+
"pkg:pypi/certifi@2026.2.25",
6363
"pkg:pypi/charset-normalizer@3.4.7",
6464
"pkg:pypi/idna@3.11",
6565
"pkg:pypi/urllib3@2.6.3"
6666
]
6767
},
6868
{
69-
"ref": "pkg:pypi/certifi@2026.2.2",
69+
"ref": "pkg:pypi/certifi@2026.2.25",
7070
"dependsOn": []
7171
},
7272
{

test/providers/tst_manifests/pyproject/pip_pep621/pip_report.json

Lines changed: 0 additions & 70 deletions
This file was deleted.

test/providers/tst_manifests/pyproject/pip_pep621/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@ name = "test-project"
33
version = "1.0.0"
44
requires-python = ">=3.12"
55
dependencies = [
6-
"requests[socks]>=2.32",
6+
"requests[socks]==2.32.3",
77
]

test/providers/tst_manifests/pyproject/pip_pep621_ignore/pip_report.json

Lines changed: 0 additions & 62 deletions
This file was deleted.

test/providers/tst_manifests/pyproject/pip_pep621_ignore/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@ name = "test-project"
33
version = "1.0.0"
44
requires-python = ">=3.12"
55
dependencies = [
6-
"requests>=2.32", #exhortignore
6+
"requests==2.32.3", #exhortignore
77
]

0 commit comments

Comments
 (0)