mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-05 08:23:59 +01:00
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:
1 parent
2ff3b6a854
commit
d8e934af5e
4 files changed
+86
-10
No files matched your search
+18
-6
@@ -5,7 +5,8 @@ import { createHash } from 'node:crypto';
|
||||
import { lstatSync, readFileSync, realpathSync } from 'node:fs';
|
||||
import { isAbsolute, relative, resolve, sep } from 'node:path';
|
||||
|
||||
export type CsoStack = 'node' | 'bun' | 'python' | 'rails';
|
||||
/** 'java' (Maven or Gradle) is detected so it is reported as itself; no runtime prepares it. */
|
||||
export type CsoStack = 'node' | 'bun' | 'python' | 'rails' | 'java';
|
||||
export interface PreparationPrerequisite {
|
||||
code: string;
|
||||
message: string;
|
||||
@@ -1196,7 +1197,13 @@ export function inspectPreparation(snapshotPath: string, stack?: CsoStack): Prep
|
||||
detectedStacks.push('node');
|
||||
if (read(root, 'Gemfile.lock', true) !== undefined || read(root, 'Gemfile', true) !== undefined)
|
||||
detectedStacks.push('rails');
|
||||
if (
|
||||
// A root Maven or Gradle build names the repository's language; Python
|
||||
// metadata beside it is helper tooling, not a second application stack.
|
||||
const jvmBuild = ['pom.xml', 'build.gradle', 'build.gradle.kts'].find(
|
||||
(file) => read(root, file, true) !== undefined,
|
||||
);
|
||||
if (jvmBuild) detectedStacks.push('java');
|
||||
else if (
|
||||
read(root, 'uv.lock', true) !== undefined ||
|
||||
read(root, 'requirements.txt', true) !== undefined ||
|
||||
read(root, 'pyproject.toml', true) !== undefined
|
||||
@@ -1210,12 +1217,17 @@ export function inspectPreparation(snapshotPath: string, stack?: CsoStack): Prep
|
||||
const detected = stack ?? detectedStacks[0] ?? 'python';
|
||||
plan.stack = detected;
|
||||
plan.runtimeProfile = detected;
|
||||
if (detected === 'java')
|
||||
fail(
|
||||
'UNSUPPORTED_STACK',
|
||||
`Java (${jvmBuild ?? 'Maven or Gradle'}) is not a supported runtime stack yet; supported runtime stacks are Node, Bun, Python, and Rails.`,
|
||||
jvmBuild,
|
||||
);
|
||||
if (!['node', 'bun', 'python', 'rails'].includes(detected))
|
||||
fail('UNSUPPORTED_STACK', 'Supported runtime stacks are Node, Bun, Python, and Rails.');
|
||||
({ node: inspectNode, bun: inspectBun, python: inspectPython, rails: inspectRails })[detected](
|
||||
root,
|
||||
plan,
|
||||
);
|
||||
({ node: inspectNode, bun: inspectBun, python: inspectPython, rails: inspectRails })[
|
||||
detected as Exclude<CsoStack, 'java'>
|
||||
](root, plan);
|
||||
} catch (error) {
|
||||
plan.status = 'prerequisites';
|
||||
plan.prerequisites.push(
|
||||
|
||||
@@ -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 });
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
@@ -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';
|
||||
|
||||
Reference in new issue
Block a user