@skyramp/mcp 0.3.2-rc.pom-3 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/commands/commandLibrary.d.ts +1 -0
- package/build/commands/commandLibrary.js +19 -13
- package/build/commands/localDevTestChangesCommand.d.ts +15 -0
- package/build/commands/localDevTestChangesCommand.js +201 -0
- package/build/index.js +80 -6
- package/build/prompts/code-reuse.js +3 -0
- package/build/prompts/enhance-assertions/sharedAssertionRules.d.ts +1 -0
- package/build/prompts/enhance-assertions/sharedAssertionRules.js +17 -0
- package/build/prompts/initialize-workspace/initializeWorkspacePrompt.js +11 -9
- package/build/prompts/local-dev/local-dev-plan.d.ts +35 -0
- package/build/prompts/local-dev/local-dev-plan.js +429 -0
- package/build/prompts/local-dev/local-dev-prompts.d.ts +4 -0
- package/build/prompts/local-dev/local-dev-prompts.js +190 -0
- package/build/prompts/pom-aware-code-reuse.js +12 -0
- package/build/prompts/prompt-utils.d.ts +8 -0
- package/build/prompts/prompt-utils.js +33 -0
- package/build/prompts/sut-setup/modes/adaptWorkflowPrompt.js +37 -14
- package/build/prompts/sut-setup/shared.js +16 -12
- package/build/prompts/test-recommendation/analysisOutputPrompt.js +21 -29
- package/build/prompts/test-recommendation/scopeAssessment.d.ts +24 -7
- package/build/prompts/test-recommendation/scopeAssessment.js +111 -12
- package/build/prompts/test-recommendation/test-recommendation-prompt.js +41 -4
- package/build/prompts/testbot/testbot-prompts.d.ts +0 -5
- package/build/prompts/testbot/testbot-prompts.js +32 -52
- package/build/recommendation/planRanker.d.ts +15 -2
- package/build/recommendation/planRanker.js +76 -5
- package/build/resources/testbotResource.js +2 -1
- package/build/services/AnalyticsService.d.ts +1 -1
- package/build/services/TestExecutionService.d.ts +2 -1
- package/build/services/TestExecutionService.js +8 -3
- package/build/services/TestGenerationService.d.ts +2 -2
- package/build/services/TestGenerationService.js +39 -21
- package/build/services/containerEnv.js +3 -1
- package/build/tool-phases.js +6 -0
- package/build/tools/code-refactor/codeReuseTool.js +43 -4
- package/build/tools/code-refactor/enhanceAssertionsTool.js +68 -18
- package/build/tools/code-refactor/reuse-outcome.d.ts +109 -0
- package/build/tools/code-refactor/reuse-outcome.js +158 -0
- package/build/tools/code-refactor/reuse-state.d.ts +45 -0
- package/build/tools/code-refactor/reuse-state.js +140 -0
- package/build/tools/enrichTestWithMocksTool.d.ts +28 -0
- package/build/tools/enrichTestWithMocksTool.js +726 -0
- package/build/tools/executeSkyrampTestTool.d.ts +11 -0
- package/build/tools/executeSkyrampTestTool.js +62 -21
- package/build/tools/generate-tests/batchMockGenerationTool.d.ts +106 -0
- package/build/tools/generate-tests/batchMockGenerationTool.js +545 -0
- package/build/tools/generate-tests/generateBatchScenarioRestTool.js +25 -23
- package/build/tools/generate-tests/generateContractRestTool.js +2 -2
- package/build/tools/generate-tests/generateE2ERestTool.d.ts +1 -1
- package/build/tools/generate-tests/generateE2ERestTool.js +1 -1
- package/build/tools/generate-tests/generateLoadRestTool.d.ts +1 -1
- package/build/tools/generate-tests/generateLoadRestTool.js +1 -1
- package/build/tools/generate-tests/generateMockRestTool.d.ts +179 -6
- package/build/tools/generate-tests/generateMockRestTool.js +391 -22
- package/build/tools/generate-tests/loadTestSchema.d.ts +1 -1
- package/build/tools/generate-tests/planGuard.js +2 -22
- package/build/tools/generateEnrichedIntegrationTestTool.d.ts +25 -0
- package/build/tools/generateEnrichedIntegrationTestTool.js +235 -0
- package/build/tools/localDevWorkerComposeTool.d.ts +24 -0
- package/build/tools/localDevWorkerComposeTool.js +264 -0
- package/build/tools/one-click/oneClickTool.d.ts +13 -0
- package/build/tools/one-click/oneClickTool.js +195 -24
- package/build/tools/preflightMockCheckTool.d.ts +2 -0
- package/build/tools/preflightMockCheckTool.js +96 -0
- package/build/tools/queryProxyMocksTool.d.ts +70 -0
- package/build/tools/queryProxyMocksTool.js +522 -0
- package/build/tools/runExistingTestsTool.d.ts +31 -0
- package/build/tools/runExistingTestsTool.js +214 -13
- package/build/tools/submitReportTool.js +38 -3
- package/build/tools/test-management/analyzeChangesTool.d.ts +2 -1
- package/build/tools/test-management/analyzeChangesTool.js +63 -40
- package/build/tools/test-management/registerTestPlanTool.js +55 -7
- package/build/tools/trace/startTraceCollectionTool.js +3 -3
- package/build/types/FrontendIntegration.d.ts +3 -0
- package/build/types/FrontendIntegration.js +3 -0
- package/build/types/OneClickCommands.d.ts +1 -1
- package/build/types/Recommendation.d.ts +20 -0
- package/build/types/Recommendation.js +32 -6
- package/build/types/RepositoryAnalysis.d.ts +131 -14
- package/build/types/RepositoryAnalysis.js +16 -2
- package/build/types/ReuseOutcome.d.ts +63 -0
- package/build/types/ReuseOutcome.js +33 -0
- package/build/types/TestExecution.d.ts +1 -0
- package/build/types/TestTypes.d.ts +25 -7
- package/build/types/TestTypes.js +22 -6
- package/build/types/TestbotReport.d.ts +7 -0
- package/build/types/index.d.ts +2 -0
- package/build/types/index.js +1 -0
- package/build/utils/AnalysisStateManager.d.ts +26 -0
- package/build/utils/AnalysisStateManager.js +31 -1
- package/build/utils/analyze-openapi.js +18 -1
- package/build/utils/branchDiff.d.ts +17 -1
- package/build/utils/branchDiff.js +99 -14
- package/build/utils/featureFlags.d.ts +31 -0
- package/build/utils/featureFlags.js +37 -0
- package/build/utils/frontendIntegration.js +8 -1
- package/build/utils/grpcMockValidation.d.ts +1 -0
- package/build/utils/grpcMockValidation.js +49 -0
- package/build/utils/httpMethodValidation.d.ts +4 -0
- package/build/utils/httpMethodValidation.js +15 -0
- package/build/utils/logger.js +1 -1
- package/build/utils/mockCompatibility.d.ts +49 -0
- package/build/utils/mockCompatibility.js +82 -0
- package/build/utils/pom-scope/pom-files.js +7 -0
- package/build/utils/pom-verify/bindings.js +11 -1
- package/build/utils/pom-verify/re-exports.d.ts +10 -0
- package/build/utils/pom-verify/re-exports.js +61 -0
- package/build/utils/pom-verify/resolve.d.ts +4 -1
- package/build/utils/pom-verify/resolve.js +7 -4
- package/build/utils/pom-verify/verify.d.ts +5 -0
- package/build/utils/pom-verify/verify.js +25 -3
- package/build/utils/progress.js +10 -5
- package/build/utils/proxy-terminal.js +3 -3
- package/build/utils/routeParsers.d.ts +3 -9
- package/build/utils/routeParsers.js +79 -4
- package/build/utils/utils.js +2 -2
- package/build/utils/versions.d.ts +4 -3
- package/build/utils/versions.js +3 -1
- package/build/utils/workspaceAuth.d.ts +46 -0
- package/build/utils/workspaceAuth.js +156 -1
- package/build/workspace/testSuites.d.ts +2 -1
- package/build/workspace/testSuites.js +1 -1
- package/build/workspace/workspace.d.ts +108 -32
- package/build/workspace/workspace.js +32 -4
- package/package.json +5 -2
- package/build/adapters/jestAdapter.test.d.ts +0 -1
- package/build/adapters/jestAdapter.test.js +0 -93
- package/build/adapters/mochaAdapter.test.d.ts +0 -1
- package/build/adapters/mochaAdapter.test.js +0 -63
- package/build/adapters/playwrightAdapter.test.d.ts +0 -1
- package/build/adapters/playwrightAdapter.test.js +0 -169
- package/build/adapters/pytestAdapter.test.d.ts +0 -1
- package/build/adapters/pytestAdapter.test.js +0 -90
- package/build/prompts/code-reuse.test.d.ts +0 -1
- package/build/prompts/code-reuse.test.js +0 -62
- package/build/prompts/pom-aware-code-reuse.test.d.ts +0 -1
- package/build/prompts/pom-aware-code-reuse.test.js +0 -11
- package/build/prompts/test-maintenance/drift-analysis-prompt.test.d.ts +0 -1
- package/build/prompts/test-maintenance/drift-analysis-prompt.test.js +0 -51
- package/build/prompts/test-recommendation/analysisOutputPrompt.test.d.ts +0 -1
- package/build/prompts/test-recommendation/analysisOutputPrompt.test.js +0 -264
- package/build/prompts/test-recommendation/mergeEnrichedScenarios.test.d.ts +0 -1
- package/build/prompts/test-recommendation/mergeEnrichedScenarios.test.js +0 -126
- package/build/prompts/test-recommendation/promptPlan.test.d.ts +0 -1
- package/build/prompts/test-recommendation/promptPlan.test.js +0 -336
- package/build/prompts/test-recommendation/scopeAssessment.test.d.ts +0 -1
- package/build/prompts/test-recommendation/scopeAssessment.test.js +0 -371
- package/build/prompts/test-recommendation/test-recommendation-prompt.test.d.ts +0 -1
- package/build/prompts/test-recommendation/test-recommendation-prompt.test.js +0 -1925
- package/build/prompts/testbot/testbot-prompts.test.d.ts +0 -1
- package/build/prompts/testbot/testbot-prompts.test.js +0 -451
- package/build/recommendation/budgeters/diversityBalancedBudgeter.test.d.ts +0 -1
- package/build/recommendation/budgeters/diversityBalancedBudgeter.test.js +0 -138
- package/build/recommendation/budgeters/fixedNBudgeter.test.d.ts +0 -1
- package/build/recommendation/budgeters/fixedNBudgeter.test.js +0 -66
- package/build/recommendation/discriminators.test.d.ts +0 -1
- package/build/recommendation/discriminators.test.js +0 -324
- package/build/recommendation/diversity.test.d.ts +0 -1
- package/build/recommendation/diversity.test.js +0 -77
- package/build/recommendation/planRanker.test.d.ts +0 -1
- package/build/recommendation/planRanker.test.js +0 -110
- package/build/resources/testbotResource.test.d.ts +0 -1
- package/build/resources/testbotResource.test.js +0 -44
- package/build/services/AnalyticsService.test.d.ts +0 -1
- package/build/services/AnalyticsService.test.js +0 -86
- package/build/services/ScenarioGenerationService.integration.test.d.ts +0 -1
- package/build/services/ScenarioGenerationService.integration.test.js +0 -162
- package/build/services/ScenarioGenerationService.test.d.ts +0 -1
- package/build/services/ScenarioGenerationService.test.js +0 -414
- package/build/services/TestDiscoveryService.test.d.ts +0 -1
- package/build/services/TestDiscoveryService.test.js +0 -983
- package/build/services/TestExecutionService.test.d.ts +0 -1
- package/build/services/TestExecutionService.test.js +0 -1032
- package/build/services/TestGenerationService.test.d.ts +0 -1
- package/build/services/TestGenerationService.test.js +0 -578
- package/build/tool-phase-coverage.test.d.ts +0 -1
- package/build/tool-phase-coverage.test.js +0 -49
- package/build/tools/code-refactor/codeReuseTool.test.d.ts +0 -1
- package/build/tools/code-refactor/codeReuseTool.test.js +0 -572
- package/build/tools/generate-tests/generateBatchScenarioRestTool.test.d.ts +0 -1
- package/build/tools/generate-tests/generateBatchScenarioRestTool.test.js +0 -433
- package/build/tools/generate-tests/generateContractRestTool.test.d.ts +0 -1
- package/build/tools/generate-tests/generateContractRestTool.test.js +0 -142
- package/build/tools/generate-tests/generateIntegrationRestTool.test.d.ts +0 -1
- package/build/tools/generate-tests/generateIntegrationRestTool.test.js +0 -159
- package/build/tools/generate-tests/generateLoadRestTool.test.d.ts +0 -1
- package/build/tools/generate-tests/generateLoadRestTool.test.js +0 -169
- package/build/tools/generate-tests/generateUIRestTool.test.d.ts +0 -1
- package/build/tools/generate-tests/generateUIRestTool.test.js +0 -32
- package/build/tools/generate-tests/planGuard.test.d.ts +0 -1
- package/build/tools/generate-tests/planGuard.test.js +0 -185
- package/build/tools/generate-tests/scenarioLint.test.d.ts +0 -1
- package/build/tools/generate-tests/scenarioLint.test.js +0 -100
- package/build/tools/runExistingTestsTool.test.d.ts +0 -1
- package/build/tools/runExistingTestsTool.test.js +0 -379
- package/build/tools/submitReportTool.test.d.ts +0 -1
- package/build/tools/submitReportTool.test.js +0 -1428
- package/build/tools/test-management/actionsTool.test.d.ts +0 -1
- package/build/tools/test-management/actionsTool.test.js +0 -436
- package/build/tools/test-management/analyzeChangesTool.test.d.ts +0 -1
- package/build/tools/test-management/analyzeChangesTool.test.js +0 -522
- package/build/tools/test-management/analyzeTestHealthTool.test.d.ts +0 -1
- package/build/tools/test-management/analyzeTestHealthTool.test.js +0 -385
- package/build/tools/test-management/registerTestPlanTool.test.d.ts +0 -1
- package/build/tools/test-management/registerTestPlanTool.test.js +0 -296
- package/build/tools/trace/resolveSaveStoragePath.test.d.ts +0 -1
- package/build/tools/trace/resolveSaveStoragePath.test.js +0 -17
- package/build/tools/trace/resolveSessionPaths.test.d.ts +0 -1
- package/build/tools/trace/resolveSessionPaths.test.js +0 -104
- package/build/tools/trace/sessionState.test.d.ts +0 -1
- package/build/tools/trace/sessionState.test.js +0 -17
- package/build/tools/workspace/initializeWorkspaceTool.test.d.ts +0 -1
- package/build/tools/workspace/initializeWorkspaceTool.test.js +0 -139
- package/build/tools/workspace/serviceUpsert.test.d.ts +0 -1
- package/build/tools/workspace/serviceUpsert.test.js +0 -50
- package/build/utils/AnalysisStateManager.test.d.ts +0 -1
- package/build/utils/AnalysisStateManager.test.js +0 -134
- package/build/utils/dartRouteExtractor.test.d.ts +0 -1
- package/build/utils/dartRouteExtractor.test.js +0 -307
- package/build/utils/docker.test.d.ts +0 -1
- package/build/utils/docker.test.js +0 -114
- package/build/utils/featureFlags.test.d.ts +0 -1
- package/build/utils/featureFlags.test.js +0 -81
- package/build/utils/fileWalk.test.d.ts +0 -1
- package/build/utils/fileWalk.test.js +0 -252
- package/build/utils/frontendIntegration.test.d.ts +0 -1
- package/build/utils/frontendIntegration.test.js +0 -229
- package/build/utils/frontendSelectors.test.d.ts +0 -1
- package/build/utils/frontendSelectors.test.js +0 -118
- package/build/utils/gitStaging.test.d.ts +0 -1
- package/build/utils/gitStaging.test.js +0 -111
- package/build/utils/httpDefaults.test.d.ts +0 -1
- package/build/utils/httpDefaults.test.js +0 -21
- package/build/utils/importerHop.test.d.ts +0 -1
- package/build/utils/importerHop.test.js +0 -469
- package/build/utils/pathAffinityClassification.test.d.ts +0 -1
- package/build/utils/pathAffinityClassification.test.js +0 -208
- package/build/utils/planMatchKeys.test.d.ts +0 -1
- package/build/utils/planMatchKeys.test.js +0 -123
- package/build/utils/pom-scope/index.test.d.ts +0 -1
- package/build/utils/pom-scope/index.test.js +0 -278
- package/build/utils/pom-scope/pom-files.test.d.ts +0 -1
- package/build/utils/pom-scope/pom-files.test.js +0 -29
- package/build/utils/pom-scope/scoring.test.d.ts +0 -1
- package/build/utils/pom-scope/scoring.test.js +0 -39
- package/build/utils/pom-scope/selector-extractor.test.d.ts +0 -1
- package/build/utils/pom-scope/selector-extractor.test.js +0 -67
- package/build/utils/pom-verify/bindings.test.d.ts +0 -1
- package/build/utils/pom-verify/bindings.test.js +0 -164
- package/build/utils/pom-verify/calls.test.d.ts +0 -1
- package/build/utils/pom-verify/calls.test.js +0 -61
- package/build/utils/pom-verify/resolve.test.d.ts +0 -1
- package/build/utils/pom-verify/resolve.test.js +0 -114
- package/build/utils/pom-verify/verify.test.d.ts +0 -1
- package/build/utils/pom-verify/verify.test.js +0 -374
- package/build/utils/pr-comment-parser.test.d.ts +0 -1
- package/build/utils/pr-comment-parser.test.js +0 -428
- package/build/utils/progress.test.d.ts +0 -1
- package/build/utils/progress.test.js +0 -37
- package/build/utils/projectMetadata.test.d.ts +0 -1
- package/build/utils/projectMetadata.test.js +0 -172
- package/build/utils/pythonMountPrefixes.test.d.ts +0 -1
- package/build/utils/pythonMountPrefixes.test.js +0 -113
- package/build/utils/repoScanner.test.d.ts +0 -1
- package/build/utils/repoScanner.test.js +0 -190
- package/build/utils/reportVerification.test.d.ts +0 -1
- package/build/utils/reportVerification.test.js +0 -185
- package/build/utils/routeParsers.test.d.ts +0 -1
- package/build/utils/routeParsers.test.js +0 -1011
- package/build/utils/scenarioDrafting.test.d.ts +0 -1
- package/build/utils/scenarioDrafting.test.js +0 -876
- package/build/utils/sourceRouteExtractor.test.d.ts +0 -1
- package/build/utils/sourceRouteExtractor.test.js +0 -738
- package/build/utils/telemetry.test.d.ts +0 -1
- package/build/utils/telemetry.test.js +0 -70
- package/build/utils/trace-parser.test.d.ts +0 -6
- package/build/utils/trace-parser.test.js +0 -140
- package/build/utils/uiPageEnumerator.test.d.ts +0 -1
- package/build/utils/uiPageEnumerator.test.js +0 -824
- package/build/utils/utils.test.d.ts +0 -1
- package/build/utils/utils.test.js +0 -103
- package/build/utils/walkerCharacterization.test.d.ts +0 -1
- package/build/utils/walkerCharacterization.test.js +0 -233
- package/build/utils/workspaceAuth.test.d.ts +0 -1
- package/build/utils/workspaceAuth.test.js +0 -260
- package/build/workspace/testSuites.test.d.ts +0 -1
- package/build/workspace/testSuites.test.js +0 -23
- package/build/workspace/workspace.test.d.ts +0 -1
- package/build/workspace/workspace.test.js +0 -264
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import * as fs from "fs";
|
|
2
|
-
import * as os from "os";
|
|
3
|
-
import * as path from "path";
|
|
4
|
-
import { joinRoutePrefix, resolvePythonMountPrefixes } from "./pythonMountPrefixes.js";
|
|
5
|
-
describe("joinRoutePrefix", () => {
|
|
6
|
-
it("composes with exactly one slash regardless of surrounding slashes", () => {
|
|
7
|
-
expect(joinRoutePrefix("/api", "/recipes")).toBe("/api/recipes");
|
|
8
|
-
expect(joinRoutePrefix("/api/", "recipes")).toBe("/api/recipes");
|
|
9
|
-
expect(joinRoutePrefix("/api", "recipes/")).toBe("/api/recipes/");
|
|
10
|
-
});
|
|
11
|
-
it("returns the prefix unchanged for an empty child", () => {
|
|
12
|
-
expect(joinRoutePrefix("/api", "")).toBe("/api");
|
|
13
|
-
});
|
|
14
|
-
it("makes the child absolute for an empty prefix", () => {
|
|
15
|
-
expect(joinRoutePrefix("", "/recipes")).toBe("/recipes");
|
|
16
|
-
expect(joinRoutePrefix("", "recipes")).toBe("/recipes");
|
|
17
|
-
});
|
|
18
|
-
});
|
|
19
|
-
describe("resolvePythonMountPrefixes", () => {
|
|
20
|
-
const tempRepos = [];
|
|
21
|
-
afterEach(() => {
|
|
22
|
-
for (const repo of tempRepos.splice(0)) {
|
|
23
|
-
fs.rmSync(repo, { recursive: true, force: true });
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
function makeRepo(files) {
|
|
27
|
-
const repo = fs.mkdtempSync(path.join(os.tmpdir(), "py-mount-"));
|
|
28
|
-
tempRepos.push(repo);
|
|
29
|
-
for (const [rel, content] of Object.entries(files)) {
|
|
30
|
-
const full = path.join(repo, rel);
|
|
31
|
-
fs.mkdirSync(path.dirname(full), { recursive: true });
|
|
32
|
-
fs.writeFileSync(full, content);
|
|
33
|
-
}
|
|
34
|
-
return repo;
|
|
35
|
-
}
|
|
36
|
-
it("resolves a relative-import mount chain to the ancestor prefix", () => {
|
|
37
|
-
const repo = makeRepo({
|
|
38
|
-
"app/__init__.py": `
|
|
39
|
-
from fastapi import APIRouter
|
|
40
|
-
from . import users
|
|
41
|
-
|
|
42
|
-
router = APIRouter(prefix="/api")
|
|
43
|
-
router.include_router(users.router)
|
|
44
|
-
`,
|
|
45
|
-
"app/users.py": `
|
|
46
|
-
from fastapi import APIRouter
|
|
47
|
-
router = APIRouter(prefix="/users")
|
|
48
|
-
@router.get("")
|
|
49
|
-
def list_users(): pass
|
|
50
|
-
`,
|
|
51
|
-
});
|
|
52
|
-
const result = resolvePythonMountPrefixes(repo);
|
|
53
|
-
// users.router inherits "/api" (aggregator own prefix); its own "/users" is
|
|
54
|
-
// applied later by parseFileEndpoints, so it is NOT part of the ancestor.
|
|
55
|
-
expect(result.get("app/users.py")?.get("router")).toBe("/api");
|
|
56
|
-
// The root aggregator has no ancestor prefix, so it's omitted entirely.
|
|
57
|
-
expect(result.get("app/__init__.py")).toBeUndefined();
|
|
58
|
-
});
|
|
59
|
-
it("resolves a mount prefix given as a module-level string constant", () => {
|
|
60
|
-
const repo = makeRepo({
|
|
61
|
-
"svc/__init__.py": `
|
|
62
|
-
from fastapi import APIRouter
|
|
63
|
-
from . import billing
|
|
64
|
-
|
|
65
|
-
BILLING = "/billing"
|
|
66
|
-
router = APIRouter()
|
|
67
|
-
router.include_router(billing.router, prefix=BILLING)
|
|
68
|
-
`,
|
|
69
|
-
"svc/billing.py": `
|
|
70
|
-
from fastapi import APIRouter
|
|
71
|
-
router = APIRouter()
|
|
72
|
-
@router.get("/invoices")
|
|
73
|
-
def invoices(): pass
|
|
74
|
-
`,
|
|
75
|
-
});
|
|
76
|
-
const result = resolvePythonMountPrefixes(repo);
|
|
77
|
-
expect(result.get("svc/billing.py")?.get("router")).toBe("/billing");
|
|
78
|
-
});
|
|
79
|
-
it("fails safe (no ancestor prefix) when the mounted module can't be resolved", () => {
|
|
80
|
-
const repo = makeRepo({
|
|
81
|
-
"app/main.py": `
|
|
82
|
-
from fastapi import FastAPI
|
|
83
|
-
from some_external_pkg import router as ext_router
|
|
84
|
-
|
|
85
|
-
app = FastAPI()
|
|
86
|
-
app.include_router(ext_router, prefix="/api")
|
|
87
|
-
`,
|
|
88
|
-
});
|
|
89
|
-
// The external module isn't in the repo, so the edge is dropped and nothing
|
|
90
|
-
// is returned — the scanner then behaves exactly as it does today.
|
|
91
|
-
const result = resolvePythonMountPrefixes(repo);
|
|
92
|
-
expect(result.size).toBe(0);
|
|
93
|
-
});
|
|
94
|
-
it("does not loop forever on a mutually-recursive mount cycle", () => {
|
|
95
|
-
const repo = makeRepo({
|
|
96
|
-
"a.py": `
|
|
97
|
-
from fastapi import APIRouter
|
|
98
|
-
from b import router as b_router
|
|
99
|
-
router = APIRouter(prefix="/a")
|
|
100
|
-
router.include_router(b_router)
|
|
101
|
-
`,
|
|
102
|
-
"b.py": `
|
|
103
|
-
from fastapi import APIRouter
|
|
104
|
-
from a import router as a_router
|
|
105
|
-
router = APIRouter(prefix="/b")
|
|
106
|
-
router.include_router(a_router)
|
|
107
|
-
`,
|
|
108
|
-
});
|
|
109
|
-
// Should terminate; the exact prefixes are unimportant, only that it returns.
|
|
110
|
-
const result = resolvePythonMountPrefixes(repo);
|
|
111
|
-
expect(result).toBeInstanceOf(Map);
|
|
112
|
-
});
|
|
113
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
import * as fs from "fs";
|
|
2
|
-
import * as os from "os";
|
|
3
|
-
import * as path from "path";
|
|
4
|
-
import { scanAllRepoEndpoints, scanRelatedEndpoints } from "./repoScanner.js";
|
|
5
|
-
import { classifyEndpointsByChangedFiles } from "./routeParsers.js";
|
|
6
|
-
describe("scanAllRepoEndpoints", () => {
|
|
7
|
-
const tempRepos = [];
|
|
8
|
-
afterEach(() => {
|
|
9
|
-
for (const repo of tempRepos.splice(0)) {
|
|
10
|
-
fs.rmSync(repo, { recursive: true, force: true });
|
|
11
|
-
}
|
|
12
|
-
});
|
|
13
|
-
function makeTempRepo() {
|
|
14
|
-
const repo = fs.mkdtempSync(path.join(os.tmpdir(), "repo-scanner-"));
|
|
15
|
-
tempRepos.push(repo);
|
|
16
|
-
return repo;
|
|
17
|
-
}
|
|
18
|
-
it("preserves same router-relative paths from different source files", () => {
|
|
19
|
-
const repo = makeTempRepo();
|
|
20
|
-
const apiDir = path.join(repo, "src/prefect/server/api");
|
|
21
|
-
fs.mkdirSync(apiDir, { recursive: true });
|
|
22
|
-
fs.writeFileSync(path.join(apiDir, "flows.py"), `
|
|
23
|
-
@router.delete(
|
|
24
|
-
"/{id:uuid}",
|
|
25
|
-
status_code=204,
|
|
26
|
-
)
|
|
27
|
-
async def delete_flow(): pass
|
|
28
|
-
|
|
29
|
-
@router.post("/bulk_delete")
|
|
30
|
-
async def bulk_delete_flows(): pass
|
|
31
|
-
`);
|
|
32
|
-
fs.writeFileSync(path.join(apiDir, "deployments.py"), `
|
|
33
|
-
@router.delete(
|
|
34
|
-
"/{id:uuid}",
|
|
35
|
-
status_code=204,
|
|
36
|
-
)
|
|
37
|
-
async def delete_deployment(): pass
|
|
38
|
-
|
|
39
|
-
@router.post("/bulk_delete")
|
|
40
|
-
async def bulk_delete_deployments(): pass
|
|
41
|
-
`);
|
|
42
|
-
const endpoints = scanAllRepoEndpoints(repo);
|
|
43
|
-
const relatedEndpoints = scanRelatedEndpoints(repo, ["src/prefect/server/api/flows.py"]);
|
|
44
|
-
expect(endpoints).toEqual(expect.arrayContaining([
|
|
45
|
-
expect.objectContaining({ path: "/{id:uuid}", methods: ["DELETE"], sourceFile: "src/prefect/server/api/flows.py" }),
|
|
46
|
-
expect.objectContaining({ path: "/bulk_delete", methods: ["POST"], sourceFile: "src/prefect/server/api/flows.py" }),
|
|
47
|
-
expect.objectContaining({ path: "/{id:uuid}", methods: ["DELETE"], sourceFile: "src/prefect/server/api/deployments.py" }),
|
|
48
|
-
expect.objectContaining({ path: "/bulk_delete", methods: ["POST"], sourceFile: "src/prefect/server/api/deployments.py" }),
|
|
49
|
-
]));
|
|
50
|
-
expect(relatedEndpoints).toEqual(expect.arrayContaining([
|
|
51
|
-
expect.objectContaining({ path: "/{id:uuid}", methods: ["DELETE"], sourceFile: "src/prefect/server/api/flows.py" }),
|
|
52
|
-
expect.objectContaining({ path: "/bulk_delete", methods: ["POST"], sourceFile: "src/prefect/server/api/flows.py" }),
|
|
53
|
-
]));
|
|
54
|
-
const classified = classifyEndpointsByChangedFiles({
|
|
55
|
-
currentBranch: "feature/admin-key",
|
|
56
|
-
baseBranch: "origin/main",
|
|
57
|
-
changedFiles: ["src/prefect/server/api/flows.py"],
|
|
58
|
-
diffContent: "",
|
|
59
|
-
diffStat: "",
|
|
60
|
-
newFiles: [],
|
|
61
|
-
deletedFiles: [],
|
|
62
|
-
}, endpoints);
|
|
63
|
-
expect(classified.changedEndpoints).toEqual(expect.arrayContaining([
|
|
64
|
-
expect.objectContaining({ path: "/{id:uuid}", methods: ["DELETE"], sourceFile: "src/prefect/server/api/flows.py" }),
|
|
65
|
-
expect.objectContaining({ path: "/bulk_delete", methods: ["POST"], sourceFile: "src/prefect/server/api/flows.py" }),
|
|
66
|
-
]));
|
|
67
|
-
expect(classified.changedEndpoints).not.toEqual(expect.arrayContaining([
|
|
68
|
-
expect.objectContaining({ path: "/{id:uuid}", methods: ["DELETE"], sourceFile: "src/prefect/server/api/deployments.py" }),
|
|
69
|
-
]));
|
|
70
|
-
});
|
|
71
|
-
it("does not suppress removed router-relative endpoints with same-path siblings", () => {
|
|
72
|
-
const classified = classifyEndpointsByChangedFiles({
|
|
73
|
-
currentBranch: "feature/remove-flows",
|
|
74
|
-
baseBranch: "origin/main",
|
|
75
|
-
changedFiles: ["src/prefect/server/api/flows.py"],
|
|
76
|
-
diffContent: "",
|
|
77
|
-
diffStat: "",
|
|
78
|
-
newFiles: [],
|
|
79
|
-
deletedFiles: ["src/prefect/server/api/flows.py"],
|
|
80
|
-
}, [
|
|
81
|
-
{ path: "/{id:uuid}", methods: ["DELETE"], sourceFile: "src/prefect/server/api/deployments.py" },
|
|
82
|
-
{ path: "/bulk_delete", methods: ["POST"], sourceFile: "src/prefect/server/api/deployments.py" },
|
|
83
|
-
], [
|
|
84
|
-
{ path: "/{id:uuid}", methods: ["DELETE"], sourceFile: "src/prefect/server/api/flows.py" },
|
|
85
|
-
{ path: "/bulk_delete", methods: ["POST"], sourceFile: "src/prefect/server/api/flows.py" },
|
|
86
|
-
]);
|
|
87
|
-
expect(classified.removedEndpoints).toEqual(expect.arrayContaining([
|
|
88
|
-
{ path: "/{id:uuid}", methods: ["DELETE"], sourceFile: "src/prefect/server/api/flows.py" },
|
|
89
|
-
{ path: "/bulk_delete", methods: ["POST"], sourceFile: "src/prefect/server/api/flows.py" },
|
|
90
|
-
]));
|
|
91
|
-
});
|
|
92
|
-
// FastAPI composes a route's full URL from prefixes applied at include_router()
|
|
93
|
-
// mount points that live in *other* files — the single-file parser can't see
|
|
94
|
-
// them. Mealie mounts its whole API under a top-level APIRouter(prefix="/api"),
|
|
95
|
-
// so a leaf router's own prefix ("/recipes") must be composed with the ancestor
|
|
96
|
-
// "/api" or generated tests hit the un-prefixed URL and 405.
|
|
97
|
-
it("composes cross-file include_router mount prefixes into FastAPI route paths", () => {
|
|
98
|
-
const repo = makeTempRepo();
|
|
99
|
-
const routesDir = path.join(repo, "mealie/routes");
|
|
100
|
-
const recipeDir = path.join(routesDir, "recipe");
|
|
101
|
-
fs.mkdirSync(recipeDir, { recursive: true });
|
|
102
|
-
// Top-level app: mounts the API router with no extra prefix.
|
|
103
|
-
fs.writeFileSync(path.join(repo, "mealie/app.py"), `
|
|
104
|
-
from fastapi import FastAPI
|
|
105
|
-
from mealie.routes import router
|
|
106
|
-
|
|
107
|
-
app = FastAPI()
|
|
108
|
-
app.include_router(router)
|
|
109
|
-
`);
|
|
110
|
-
// API aggregator: APIRouter(prefix="/api") includes each resource router.
|
|
111
|
-
fs.writeFileSync(path.join(routesDir, "__init__.py"), `
|
|
112
|
-
from fastapi import APIRouter
|
|
113
|
-
from . import recipe
|
|
114
|
-
|
|
115
|
-
router = APIRouter(prefix="/api")
|
|
116
|
-
router.include_router(recipe.router)
|
|
117
|
-
`);
|
|
118
|
-
// Recipe aggregator: no own prefix; mounts the CRUD router directly and the
|
|
119
|
-
// comments router under a "/recipes" mount prefix drawn from a local const.
|
|
120
|
-
fs.writeFileSync(path.join(recipeDir, "__init__.py"), `
|
|
121
|
-
from fastapi import APIRouter
|
|
122
|
-
from . import recipe_crud_routes, comments
|
|
123
|
-
|
|
124
|
-
prefix = "/recipes"
|
|
125
|
-
|
|
126
|
-
router = APIRouter()
|
|
127
|
-
router.include_router(recipe_crud_routes.router, tags=["Recipe: CRUD"])
|
|
128
|
-
router.include_router(comments.router, prefix=prefix, tags=["Recipe: Comments"])
|
|
129
|
-
`);
|
|
130
|
-
// Leaf CRUD router declared via a custom APIRouter *subclass* with its own
|
|
131
|
-
// "/recipes" prefix.
|
|
132
|
-
fs.writeFileSync(path.join(recipeDir, "recipe_crud_routes.py"), `
|
|
133
|
-
from mealie.routes._base.routers import UserAPIRouter
|
|
134
|
-
|
|
135
|
-
router = UserAPIRouter(prefix="/recipes")
|
|
136
|
-
|
|
137
|
-
@router.get("")
|
|
138
|
-
async def get_all(): pass
|
|
139
|
-
|
|
140
|
-
@router.get("/{slug}")
|
|
141
|
-
async def get_one(): pass
|
|
142
|
-
`);
|
|
143
|
-
// Comments router: no own prefix — its "/recipes" comes only from the mount.
|
|
144
|
-
fs.writeFileSync(path.join(recipeDir, "comments.py"), `
|
|
145
|
-
from fastapi import APIRouter
|
|
146
|
-
|
|
147
|
-
router = APIRouter()
|
|
148
|
-
|
|
149
|
-
@router.get("/{slug}/comments")
|
|
150
|
-
async def get_comments(): pass
|
|
151
|
-
`);
|
|
152
|
-
const endpoints = scanAllRepoEndpoints(repo);
|
|
153
|
-
// CRUD: /api (aggregator) + /recipes (leaf subclass own prefix)
|
|
154
|
-
expect(endpoints).toEqual(expect.arrayContaining([
|
|
155
|
-
expect.objectContaining({ path: "/api/recipes", methods: ["GET"], sourceFile: "mealie/routes/recipe/recipe_crud_routes.py" }),
|
|
156
|
-
expect.objectContaining({ path: "/api/recipes/{slug}", methods: ["GET"], sourceFile: "mealie/routes/recipe/recipe_crud_routes.py" }),
|
|
157
|
-
]));
|
|
158
|
-
// Comments: /api (aggregator) + /recipes (mount prefix from a local const) + own path
|
|
159
|
-
expect(endpoints).toEqual(expect.arrayContaining([
|
|
160
|
-
expect.objectContaining({ path: "/api/recipes/{slug}/comments", methods: ["GET"], sourceFile: "mealie/routes/recipe/comments.py" }),
|
|
161
|
-
]));
|
|
162
|
-
// The un-prefixed path must NOT appear (the 405 bug).
|
|
163
|
-
expect(endpoints).not.toContainEqual(expect.objectContaining({ path: "/recipes" }));
|
|
164
|
-
});
|
|
165
|
-
it("composes an app-level include_router(prefix=...) mount", () => {
|
|
166
|
-
const repo = makeTempRepo();
|
|
167
|
-
const apiDir = path.join(repo, "src/api");
|
|
168
|
-
fs.mkdirSync(apiDir, { recursive: true });
|
|
169
|
-
// Prefix applied at the app mount point rather than on the APIRouter itself.
|
|
170
|
-
fs.writeFileSync(path.join(repo, "src/main.py"), `
|
|
171
|
-
from fastapi import FastAPI
|
|
172
|
-
from src.api.users import router as users_router
|
|
173
|
-
|
|
174
|
-
app = FastAPI()
|
|
175
|
-
app.include_router(users_router, prefix="/api/v1")
|
|
176
|
-
`);
|
|
177
|
-
fs.writeFileSync(path.join(apiDir, "users.py"), `
|
|
178
|
-
from fastapi import APIRouter
|
|
179
|
-
|
|
180
|
-
router = APIRouter(prefix="/users")
|
|
181
|
-
|
|
182
|
-
@router.get("/{id}")
|
|
183
|
-
async def get_user(): pass
|
|
184
|
-
`);
|
|
185
|
-
const endpoints = scanAllRepoEndpoints(repo);
|
|
186
|
-
expect(endpoints).toEqual(expect.arrayContaining([
|
|
187
|
-
expect.objectContaining({ path: "/api/v1/users/{id}", methods: ["GET"], sourceFile: "src/api/users.py" }),
|
|
188
|
-
]));
|
|
189
|
-
});
|
|
190
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "@jest/globals";
|
|
2
|
-
import { execFileSync } from "child_process";
|
|
3
|
-
import * as fs from "fs";
|
|
4
|
-
import * as os from "os";
|
|
5
|
-
import * as path from "path";
|
|
6
|
-
import { DriftAction } from "../types/TestAnalysis.js";
|
|
7
|
-
import { findUnbackedClaims, listChangedFiles } from "./reportVerification.js";
|
|
8
|
-
const REPO = "/repo";
|
|
9
|
-
describe("findUnbackedClaims", () => {
|
|
10
|
-
it("returns [] when every claim is backed by a working-tree change", () => {
|
|
11
|
-
const unbacked = findUnbackedClaims({
|
|
12
|
-
repoRoot: REPO,
|
|
13
|
-
changedFiles: [
|
|
14
|
-
"tests/skyramp/products_contract_test.py",
|
|
15
|
-
"dcim/tests/test_filtersets.py",
|
|
16
|
-
],
|
|
17
|
-
newTests: [
|
|
18
|
-
{
|
|
19
|
-
testId: "contract-get-products",
|
|
20
|
-
fileName: "products_contract_test.py",
|
|
21
|
-
},
|
|
22
|
-
],
|
|
23
|
-
verdicts: [
|
|
24
|
-
{
|
|
25
|
-
action: DriftAction.Update,
|
|
26
|
-
testFilePath: "/repo/dcim/tests/test_filtersets.py",
|
|
27
|
-
},
|
|
28
|
-
],
|
|
29
|
-
});
|
|
30
|
-
expect(unbacked).toEqual([]);
|
|
31
|
-
});
|
|
32
|
-
it("flags a newTestsCreated claim whose file was never created (hallucination)", () => {
|
|
33
|
-
const unbacked = findUnbackedClaims({
|
|
34
|
-
repoRoot: REPO,
|
|
35
|
-
changedFiles: ["tests/skyramp/products_contract_test.py"],
|
|
36
|
-
newTests: [
|
|
37
|
-
{
|
|
38
|
-
testId: "integration-phantom",
|
|
39
|
-
fileName: "phantom_integration_test.py",
|
|
40
|
-
},
|
|
41
|
-
],
|
|
42
|
-
verdicts: [],
|
|
43
|
-
});
|
|
44
|
-
expect(unbacked).toHaveLength(1);
|
|
45
|
-
expect(unbacked[0]).toContain("phantom_integration_test.py");
|
|
46
|
-
});
|
|
47
|
-
it("flags an UPDATE verdict whose file has no working-tree change (the SKYR-3883 case)", () => {
|
|
48
|
-
const unbacked = findUnbackedClaims({
|
|
49
|
-
repoRoot: REPO,
|
|
50
|
-
changedFiles: ["tests/skyramp/site_filter_integration_test.py"],
|
|
51
|
-
newTests: [],
|
|
52
|
-
verdicts: [
|
|
53
|
-
{
|
|
54
|
-
action: DriftAction.Update,
|
|
55
|
-
testFilePath: "/repo/dcim/tests/test_filtersets.py",
|
|
56
|
-
},
|
|
57
|
-
],
|
|
58
|
-
});
|
|
59
|
-
expect(unbacked).toHaveLength(1);
|
|
60
|
-
expect(unbacked[0]).toContain("test_filtersets.py");
|
|
61
|
-
});
|
|
62
|
-
it("never flags REGENERATE/DELETE/IGNORE/VERIFY verdicts even when absent from the tree", () => {
|
|
63
|
-
// REGENERATE is exempt: external (user-authored) regenerations are report-only
|
|
64
|
-
// with no working-tree change, and internal ones may regenerate identically.
|
|
65
|
-
const unbacked = findUnbackedClaims({
|
|
66
|
-
repoRoot: REPO,
|
|
67
|
-
changedFiles: [],
|
|
68
|
-
newTests: [],
|
|
69
|
-
verdicts: [
|
|
70
|
-
{
|
|
71
|
-
action: DriftAction.Regenerate,
|
|
72
|
-
testFilePath: "/repo/frontend/tests/cart_pom.spec.ts",
|
|
73
|
-
},
|
|
74
|
-
{ action: DriftAction.Delete, testFilePath: "/repo/tests/gone.py" },
|
|
75
|
-
{ action: DriftAction.Ignore, testFilePath: "/repo/tests/kept.py" },
|
|
76
|
-
{ action: DriftAction.Verify, testFilePath: "/repo/tests/checked.py" },
|
|
77
|
-
],
|
|
78
|
-
});
|
|
79
|
-
expect(unbacked).toEqual([]);
|
|
80
|
-
});
|
|
81
|
-
it("exempts a cross-repo newTest claim (repository differs from the primary)", () => {
|
|
82
|
-
const unbacked = findUnbackedClaims({
|
|
83
|
-
repoRoot: REPO,
|
|
84
|
-
changedFiles: [],
|
|
85
|
-
newTests: [
|
|
86
|
-
{
|
|
87
|
-
testId: "contract-related",
|
|
88
|
-
fileName: "related_contract_test.py",
|
|
89
|
-
repository: "acme/related-repo",
|
|
90
|
-
},
|
|
91
|
-
],
|
|
92
|
-
verdicts: [],
|
|
93
|
-
primaryRepository: "acme/primary-repo",
|
|
94
|
-
});
|
|
95
|
-
expect(unbacked).toEqual([]);
|
|
96
|
-
});
|
|
97
|
-
it("exempts a cross-repo newTest claim even when the primary repo is unknown", () => {
|
|
98
|
-
// primaryRepository omitted: we can't confirm the file belongs to this
|
|
99
|
-
// checkout, so an explicitly-attributed claim must not be validated here.
|
|
100
|
-
const unbacked = findUnbackedClaims({
|
|
101
|
-
repoRoot: REPO,
|
|
102
|
-
changedFiles: [],
|
|
103
|
-
newTests: [
|
|
104
|
-
{
|
|
105
|
-
testId: "contract-related",
|
|
106
|
-
fileName: "related_contract_test.py",
|
|
107
|
-
repository: "acme/related-repo",
|
|
108
|
-
},
|
|
109
|
-
],
|
|
110
|
-
verdicts: [],
|
|
111
|
-
});
|
|
112
|
-
expect(unbacked).toEqual([]);
|
|
113
|
-
});
|
|
114
|
-
it("exempts a verdict whose absolute path resolves outside the checkout", () => {
|
|
115
|
-
const unbacked = findUnbackedClaims({
|
|
116
|
-
repoRoot: REPO,
|
|
117
|
-
changedFiles: [],
|
|
118
|
-
newTests: [],
|
|
119
|
-
verdicts: [
|
|
120
|
-
{
|
|
121
|
-
action: DriftAction.Update,
|
|
122
|
-
testFilePath: "/somewhere/else/outside_test.py",
|
|
123
|
-
},
|
|
124
|
-
],
|
|
125
|
-
});
|
|
126
|
-
expect(unbacked).toEqual([]);
|
|
127
|
-
});
|
|
128
|
-
it("matches a nested newTest fileName by basename against the changed path", () => {
|
|
129
|
-
const backed = findUnbackedClaims({
|
|
130
|
-
repoRoot: REPO,
|
|
131
|
-
changedFiles: ["tests/skyramp/deep/nested_contract_test.py"],
|
|
132
|
-
newTests: [{ testId: "c", fileName: "nested_contract_test.py" }],
|
|
133
|
-
verdicts: [],
|
|
134
|
-
});
|
|
135
|
-
expect(backed).toEqual([]);
|
|
136
|
-
});
|
|
137
|
-
});
|
|
138
|
-
describe("listChangedFiles", () => {
|
|
139
|
-
it("lists staged, unstaged, and untracked paths as repo-relative strings", async () => {
|
|
140
|
-
const repo = fs.mkdtempSync(path.join(os.tmpdir(), "rv-repo-"));
|
|
141
|
-
const git = (args) => execFileSync("git", args, { cwd: repo, stdio: "pipe" });
|
|
142
|
-
git(["init", "-q"]);
|
|
143
|
-
git(["config", "user.email", "t@t.dev"]);
|
|
144
|
-
git(["config", "user.name", "t"]);
|
|
145
|
-
// committed baseline
|
|
146
|
-
fs.mkdirSync(path.join(repo, "dcim/tests"), { recursive: true });
|
|
147
|
-
fs.writeFileSync(path.join(repo, "dcim/tests/test_filtersets.py"), "orig\n");
|
|
148
|
-
git(["add", "-A"]);
|
|
149
|
-
git(["commit", "-q", "-m", "base"]);
|
|
150
|
-
// modify a tracked file (unstaged) + add an untracked file
|
|
151
|
-
fs.writeFileSync(path.join(repo, "dcim/tests/test_filtersets.py"), "edited\n");
|
|
152
|
-
fs.mkdirSync(path.join(repo, "tests/skyramp"), { recursive: true });
|
|
153
|
-
fs.writeFileSync(path.join(repo, "tests/skyramp/new_contract_test.py"), "new\n");
|
|
154
|
-
const changed = await listChangedFiles(repo);
|
|
155
|
-
expect(changed).toContain("dcim/tests/test_filtersets.py");
|
|
156
|
-
expect(changed).toContain("tests/skyramp/new_contract_test.py");
|
|
157
|
-
});
|
|
158
|
-
it("attributes a renamed file to its destination path and skips the original", async () => {
|
|
159
|
-
const repo = fs.mkdtempSync(path.join(os.tmpdir(), "rv-repo-"));
|
|
160
|
-
const git = (args) => execFileSync("git", args, { cwd: repo, stdio: "pipe" });
|
|
161
|
-
git(["init", "-q"]);
|
|
162
|
-
git(["config", "user.email", "t@t.dev"]);
|
|
163
|
-
git(["config", "user.name", "t"]);
|
|
164
|
-
fs.mkdirSync(path.join(repo, "dcim/tests"), { recursive: true });
|
|
165
|
-
fs.writeFileSync(path.join(repo, "dcim/tests/old_test.py"), "def test_x(): pass\n");
|
|
166
|
-
git(["add", "-A"]);
|
|
167
|
-
git(["commit", "-q", "-m", "base"]);
|
|
168
|
-
// Staged rename (identical content → git detects it as R100).
|
|
169
|
-
git(["mv", "dcim/tests/old_test.py", "dcim/tests/new_test.py"]);
|
|
170
|
-
const changed = await listChangedFiles(repo);
|
|
171
|
-
expect(changed).toContain("dcim/tests/new_test.py");
|
|
172
|
-
expect(changed).not.toContain("dcim/tests/old_test.py");
|
|
173
|
-
});
|
|
174
|
-
it("preserves a path containing spaces (NUL-delimited, no quoting)", async () => {
|
|
175
|
-
const repo = fs.mkdtempSync(path.join(os.tmpdir(), "rv-repo-"));
|
|
176
|
-
const git = (args) => execFileSync("git", args, { cwd: repo, stdio: "pipe" });
|
|
177
|
-
git(["init", "-q"]);
|
|
178
|
-
git(["config", "user.email", "t@t.dev"]);
|
|
179
|
-
git(["config", "user.name", "t"]);
|
|
180
|
-
fs.mkdirSync(path.join(repo, "tests/skyramp"), { recursive: true });
|
|
181
|
-
fs.writeFileSync(path.join(repo, "tests/skyramp/my new test.py"), "new\n");
|
|
182
|
-
const changed = await listChangedFiles(repo);
|
|
183
|
-
expect(changed).toContain("tests/skyramp/my new test.py");
|
|
184
|
-
});
|
|
185
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|