Skip to content

track: build-file-detect-20260428 #4

@amondnet

Description

@amondnet

product_spec_domain: install/detect

Build-File Detection

Track: build-file-detect-20260428
Type: feature

Overview

Implement scripts/detect.ts, the first domain function in the Spring install pipeline. Given a project root, it inspects the relevant build file(s) and returns a structured result describing which Spring Boot version (if any) the project declares. It is the single source of truth that downstream stages (resolve.ts, install.ts) consume — no other component is permitted to parse build files.

This function is architecture-agnostic with respect to the athens-v2 dynamic-loading direction: detect.ts contracts (input: project dir → output: structured result) are identical whether the eventual install writes static Markdown or a thin skill that delegates to @pleaseai/ask at runtime.

The function lives in the Domain Layer per ARCHITECTURE.md: it may read files but performs no network I/O and exposes a CLI for direct invocation (bun run scripts/detect.ts <project-dir>).

Requirements

Functional Requirements

  • FR-1: Detect Spring Boot version from pom.xml when declared via spring-boot-starter-parent (<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.x.y</version></parent>).

  • FR-2: Detect Spring Boot version from pom.xml when declared via spring-boot-dependencies BOM in <dependencyManagement> (no <parent>).

  • FR-3: Detect Spring Boot version from build.gradle (Groovy DSL) when declared via the Spring Boot plugin: id 'org.springframework.boot' version '3.x.y' (also plugins { id ... }, apply plugin:, and buildscript { ext['spring-boot.version'] = '...' } patterns).

  • FR-4: Detect Spring Boot version from build.gradle.kts (Kotlin DSL) for the equivalent patterns: id("org.springframework.boot") version "3.x.y", plugins { id(...) }, etc.

  • FR-5: Resolve Maven parent POM inheritance when the immediate pom.xml declares <parent> pointing at a sibling project file (<relativePath>...</relativePath>); read the parent file from disk and continue the search there. Maximum 5 levels of parent traversal to bound the search.

  • FR-6: Detect Spring Boot version in Maven multi-module projects: when invoked at a directory that contains a parent POM and child modules, search the parent POM first; if not found, scan declared <modules> for the first child whose POM declares a Boot version.

  • FR-7: Detect Spring Boot version in Gradle multi-module projects: when invoked at a settings.gradle(.kts) root, search the root build file first; if not found, walk include(...) subprojects (one level deep) and scan each subproject's build.gradle(.kts) for the Boot plugin declaration.

  • FR-8: Return a structured result object with the following shape (TypeScript types defined in scripts/lib/detect-types.ts):

    type DetectResult =
      | { kind: 'detected'; version: string; source: DetectSource }
      | { kind: 'unsupported'; reason: string; suggestion: string; source?: DetectSource }
      | { kind: 'not-found'; reason: string; suggestion: string }
    
    type DetectSource = {
      file: string         // relative path from project root
      locator: string      // human-readable hint (e.g., "spring-boot-starter-parent in <parent>")
      line?: number        // best-effort line number for diagnostics
    }
  • FR-9: When detection fails on a recognized-but-unsupported pattern (e.g., version catalog reference id 'org.springframework.boot' version libs.versions.spring.boot.get()), return { kind: 'unsupported', reason, suggestion: "Use --boot <version> to override" }. Do NOT throw.

  • FR-10: When no build file is found at the project root (no pom.xml, build.gradle, build.gradle.kts), return { kind: 'not-found', reason: 'No supported build file at <path>', suggestion: 'Run from a Spring project root, or pass --boot <version>' }. Do NOT throw.

  • FR-11: Expose a CLI: bun run scripts/detect.ts <project-dir> prints the result as JSON to stdout. Exit code: 0 for kind: 'detected', 1 for kind: 'unsupported' or kind: 'not-found', 2 for unexpected internal errors (only — never thrown for recognized failure modes).

Non-functional Requirements

  • NFR-1: All parsing logic is in scripts/lib/ (Library Layer) — pure functions accepting strings or already-read file contents and returning typed results. No fs, fetch, or process.env access in scripts/lib/.

Track: build-file-detect-20260428
Type: feature
Phase: planning (PR for team review)
Depends on track: plugin-scaffold-20260428 (provides scripts/lib layout, ESLint config, test runner)
See full spec: .please/docs/tracks/active/build-file-detect-20260428/spec.md
See plan: .please/docs/tracks/active/build-file-detect-20260428/plan.md

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions