fix(cso): a Maven or Gradle repository is Java, not Python (#3028)

With no supported stack metadata, preparation defaulted to Python and asked
a Java repository for requirements.txt. A root pom.xml, build.gradle or
build.gradle.kts now names the stack as Java (unsupported for runtime
preparation, so the prerequisite says so), and Python helper scripts or a
root requirements.txt beside it no longer make it Python.
This commit is contained in:
garrytan committed 2026-10-06 20:42:38 +00:00
1 parent 2ff3b6a854
commit d8e934af5e
4 files changed
+86 -10

No files matched your search

+1 -1
View File
@@ -50,7 +50,7 @@ function snapshot(stack: CsoStack): string {
return base;
}
function runtime(stack: CsoStack | 'postgresql') { return qualifiedRuntimeFixture(stack); }
function runtime(stack: Parameters<typeof qualifiedRuntimeFixture>[0]) { return qualifiedRuntimeFixture(stack); }
function catalog(..._stacks: Array<CsoStack | 'postgresql'>) { return completeRuntimeCatalogFixture('executor-test-v1'); }
function cacheFixture() {
const base = root('cso-executor-cache-'), staging = path.join(base, 'staging'); fs.mkdirSync(staging, { mode: 0o700 });
+62
View File
@@ -0,0 +1,62 @@
/**
* A Java/Maven repository was reported as `stack: python` and asked for a
* requirements.txt, because no supported stack matched and preparation
* defaulted to Python. A root Maven or Gradle build now names the stack as
* Java (unsupported for runtime preparation, so static assessment only), and
* Python helper scripts or metadata beside it do not turn it into Python.
*/
import { afterEach, describe, expect, test } from 'bun:test';
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { inspectPreparation } from '../lib/cso/preparation';
const roots: string[] = [];
afterEach(() => { for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true }); });
function fixture(files: Record<string, string>): string {
const root = mkdtempSync(join(tmpdir(), 'cso-preparation-java-'));
roots.push(root);
for (const [path, contents] of Object.entries(files)) {
mkdirSync(join(root, path, '..'), { recursive: true });
writeFileSync(join(root, path), contents);
}
return root;
}
const maven = {
'pom.xml': '<project><modelVersion>4.0.0</modelVersion><groupId>a</groupId><artifactId>app</artifactId><version>1</version></project>\n',
'src/main/java/app/App.java': 'package app;\npublic class App { public static void main(String[] a) {} }\n',
'scripts/release.py': 'print("helper")\n',
'tools/lint_check.py': 'import sys\n',
};
describe('/cso preparation: a Maven repository with helper Python scripts is Java', () => {
test('helper .py scripts only', () => {
const plan = inspectPreparation(fixture(maven));
expect(plan.stack).toBe('java');
expect(plan.status).toBe('prerequisites');
expect(plan.prerequisites).toEqual([{
code: 'UNSUPPORTED_STACK',
message: 'Java (pom.xml) is not a supported runtime stack yet; supported runtime stacks are Node, Bun, Python, and Rails.',
path: 'pom.xml',
}]);
expect(JSON.stringify(plan)).not.toContain('requirements.txt');
});
test('helper scripts with a root requirements.txt stay Java', () => {
const plan = inspectPreparation(fixture({ ...maven, 'requirements.txt': 'requests==2.32.3\n' }));
expect(plan.stack).toBe('java');
expect(plan.prerequisites[0]?.code).toBe('UNSUPPORTED_STACK');
});
test('Gradle builds are Java too', () => {
const plan = inspectPreparation(fixture({ 'build.gradle.kts': 'plugins { java }\n', 'scripts/x.py': '' }));
expect(plan.stack).toBe('java');
expect(plan.prerequisites[0]?.message).toContain('Java (build.gradle.kts)');
});
test('a Python project without a JVM build is still Python (control)', () => {
expect(inspectPreparation(fixture({ 'requirements.txt': 'requests==2.32.3\n', 'app.py': '' })).stack).toBe('python');
});
});
+5 -3
View File
@@ -1,4 +1,6 @@
import type { CsoStack } from '../../lib/cso/preparation';
type RuntimeStack = Exclude<CsoStack, 'java'>;
import { canonical, sha256 } from '../../lib/cso/contracts';
import { ISOLATION_POLICY_HASH } from '../../lib/cso/docker';
import {
@@ -14,7 +16,7 @@ const SOURCE_COMMIT = 'b'.repeat(40);
const WORKFLOW = 'https://github.com/garrytan/gstack/actions/runs/1';
const DIGEST = `sha256:${'a'.repeat(64)}`;
const VERSIONS: Record<CsoStack | 'postgresql', Record<string, string>> = {
const VERSIONS: Record<RuntimeStack | 'postgresql', Record<string, string>> = {
node: { node: '24.1.0', npm: '11.3.0', 'cso-preparation': '1.0.0' },
bun: { bun: '1.3.10', 'cso-preparation': '1.0.0' },
python: { python: '3.12.9', uv: '0.8.0', 'cso-preparation': '1.0.0' },
@@ -22,12 +24,12 @@ const VERSIONS: Record<CsoStack | 'postgresql', Record<string, string>> = {
postgresql: { postgresql: '17.2' },
};
function runtimeId(stack: CsoStack | 'postgresql', platform: RuntimePlatform): string {
function runtimeId(stack: RuntimeStack | 'postgresql', platform: RuntimePlatform): string {
return `${stack}-qualified-test-${platform === 'linux/amd64' ? 'amd64' : 'arm64'}`;
}
export function qualifiedRuntimeFixture(
stack: CsoStack | 'postgresql',
stack: RuntimeStack | 'postgresql',
platform: RuntimePlatform = 'linux/amd64',
): QualifiedRuntime {
const arch = platform === 'linux/amd64' ? 'amd64' : 'arm64';