Skip to content

Commit 7937d27

Browse files
cuixqcopybara-github
authored andcommitted
Support non-standard Maven POM file names
PiperOrigin-RevId: 963202719
1 parent f0eb363 commit 7937d27

2 files changed

Lines changed: 174 additions & 7 deletions

File tree

guidedremediation/internal/manifest/maven/pomxml.go

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -199,12 +199,6 @@ func GetReadWriter(client *datasource.MavenRegistryAPIClient, projectRoot string
199199
if err != nil {
200200
return nil, fmt.Errorf("failed to get absolute path for project root %q: %w", projectRoot, err)
201201
}
202-
stat, err := os.Stat(absProjectRoot)
203-
if err == nil && stat.IsDir() {
204-
// Assume the root manifest file is named pom.xml.
205-
// Downstream DiscoverModules expects a file path.
206-
absProjectRoot = filepath.Join(absProjectRoot, "pom.xml")
207-
}
208202
vol := filepath.VolumeName(absProjectRoot) + "/"
209203
projectRoot, err = filepath.Rel(vol, absProjectRoot)
210204
if err != nil {
@@ -224,13 +218,44 @@ func (r readWriter) SupportedStrategies() []strategy.Strategy {
224218
return []strategy.Strategy{strategy.StrategyOverride}
225219
}
226220

221+
// isPOMFile returns true if the given path is a Maven POM file.
222+
// It matches "pom.xml", "pom-*.xml", and "*-pom.xml".
223+
func isPOMFile(path string) bool {
224+
base := strings.ToLower(filepath.Base(path))
225+
if base == "pom.xml" {
226+
return true
227+
}
228+
if !strings.HasSuffix(base, ".xml") {
229+
return false
230+
}
231+
name := strings.TrimSuffix(base, ".xml")
232+
return strings.HasPrefix(name, "pom-") || strings.HasSuffix(name, "-pom")
233+
}
234+
227235
// Read parses the manifest from the given file.
228236
func (r readWriter) Read(path string, fsys scalibrfs.FS) (manifest.Manifest, error) {
229237
ctx := context.Background()
230238
path = filepath.ToSlash(path)
231239
scanPaths := []string{path}
232240
if r.projectRoot != "" {
233-
scanPaths = append(scanPaths, filepath.ToSlash(r.projectRoot))
241+
resolvedProjectRoot := filepath.ToSlash(r.projectRoot)
242+
stat, err := fsys.Stat(resolvedProjectRoot)
243+
if err != nil {
244+
return nil, fmt.Errorf("failed to stat project root %q: %w", resolvedProjectRoot, err)
245+
}
246+
if !stat.IsDir() {
247+
return nil, fmt.Errorf("project root %q is not a directory", resolvedProjectRoot)
248+
}
249+
entries, err := fsys.ReadDir(resolvedProjectRoot)
250+
if err != nil {
251+
return nil, fmt.Errorf("failed to read project root directory %q: %w", resolvedProjectRoot, err)
252+
}
253+
for _, entry := range entries {
254+
if !entry.IsDir() && isPOMFile(entry.Name()) {
255+
// Add all found POM files to the scan paths.
256+
scanPaths = append(scanPaths, filepath.ToSlash(filepath.Join(resolvedProjectRoot, entry.Name())))
257+
}
258+
}
234259
}
235260
mavenutil.DiscoverModules(&scalibrfs.ScanRoot{FS: fsys, Path: ""}, scanPaths, r.MavenRegistryAPIClient)
236261
f, err := fsys.Open(path)

guidedremediation/internal/manifest/maven/pomxml_test.go

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,3 +1172,145 @@ func Test_generatePropertyPatches(t *testing.T) {
11721172
}
11731173
}
11741174
}
1175+
1176+
func TestRead_MultiModuleDiscovery_NonStandardPOM(t *testing.T) {
1177+
dir := t.TempDir()
1178+
1179+
// Create root/pom-conventions.xml
1180+
rootPOM := `
1181+
<project>
1182+
<modelVersion>4.0.0</modelVersion>
1183+
<groupId>com.example</groupId>
1184+
<artifactId>root</artifactId>
1185+
<version>1.0.0</version>
1186+
<packaging>pom</packaging>
1187+
<modules>
1188+
<module>module-a</module>
1189+
<module>module-b</module>
1190+
</modules>
1191+
</project>`
1192+
if err := os.WriteFile(filepath.Join(dir, "pom-conventions.xml"), []byte(rootPOM), 0644); err != nil {
1193+
t.Fatalf("failed to write root pom-conventions.xml: %v", err)
1194+
}
1195+
1196+
if err := os.MkdirAll(filepath.Join(dir, "module-a"), 0755); err != nil {
1197+
t.Fatalf("failed to create module-a dir: %v", err)
1198+
}
1199+
if err := os.MkdirAll(filepath.Join(dir, "module-b"), 0755); err != nil {
1200+
t.Fatalf("failed to create module-b dir: %v", err)
1201+
}
1202+
1203+
// Create module-b/pom.xml
1204+
moduleBPOM := `
1205+
<project>
1206+
<modelVersion>4.0.0</modelVersion>
1207+
<groupId>com.example</groupId>
1208+
<artifactId>module-b</artifactId>
1209+
<version>1.0.0</version>
1210+
<dependencyManagement>
1211+
<dependencies>
1212+
<dependency>
1213+
<groupId>junit</groupId>
1214+
<artifactId>junit</artifactId>
1215+
<version>4.12</version>
1216+
</dependency>
1217+
</dependencies>
1218+
</dependencyManagement>
1219+
</project>`
1220+
if err := os.WriteFile(filepath.Join(dir, "module-b", "pom.xml"), []byte(moduleBPOM), 0644); err != nil {
1221+
t.Fatalf("failed to write module-b pom.xml: %v", err)
1222+
}
1223+
1224+
// Create module-a/pom.xml
1225+
moduleAPOM := `
1226+
<project>
1227+
<modelVersion>4.0.0</modelVersion>
1228+
<groupId>com.example</groupId>
1229+
<artifactId>module-a</artifactId>
1230+
<version>1.0.0</version>
1231+
<dependencyManagement>
1232+
<dependencies>
1233+
<dependency>
1234+
<groupId>com.example</groupId>
1235+
<artifactId>module-b</artifactId>
1236+
<version>1.0.0</version>
1237+
<type>pom</type>
1238+
<scope>import</scope>
1239+
</dependency>
1240+
</dependencies>
1241+
</dependencyManagement>
1242+
<dependencies>
1243+
<dependency>
1244+
<groupId>junit</groupId>
1245+
<artifactId>junit</artifactId>
1246+
</dependency>
1247+
</dependencies>
1248+
</project>`
1249+
if err := os.WriteFile(filepath.Join(dir, "module-a", "pom.xml"), []byte(moduleAPOM), 0644); err != nil {
1250+
t.Fatalf("failed to write module-a pom.xml: %v", err)
1251+
}
1252+
1253+
client, _ := datasource.NewDefaultMavenRegistryAPIClient(t.Context(), "")
1254+
1255+
// Test WITH projectRoot (which is dir, containing pom-conventions.xml)
1256+
mavenRW, err := GetReadWriter(client, dir)
1257+
if err != nil {
1258+
t.Fatalf("error creating ReadWriter: %v", err)
1259+
}
1260+
1261+
vol := filepath.VolumeName(dir) + "/"
1262+
fsys := scalibrfs.DirFS(vol)
1263+
relPOM, err := filepath.Rel(vol, filepath.Join(dir, "module-a", "pom.xml"))
1264+
if err != nil {
1265+
t.Fatalf("error getting relative path: %v", err)
1266+
}
1267+
got, err := mavenRW.Read(filepath.ToSlash(relPOM), fsys)
1268+
if err != nil {
1269+
t.Fatalf("error reading manifest: %v", err)
1270+
}
1271+
1272+
// Verify that junit has version 4.12 (imported from module-b)
1273+
found := false
1274+
for _, req := range got.Requirements() {
1275+
if req.Name == "junit:junit" {
1276+
if req.Version == "4.12" {
1277+
found = true
1278+
break
1279+
}
1280+
}
1281+
}
1282+
if !found {
1283+
t.Errorf("expected to find junit:junit with version 4.12, got requirements: %v", got.Requirements())
1284+
}
1285+
}
1286+
1287+
func Test_isPOMFile(t *testing.T) {
1288+
tests := []struct {
1289+
path string
1290+
want bool
1291+
}{
1292+
{"pom.xml", true},
1293+
{"POM.XML", true},
1294+
{"pom-conventions.xml", true},
1295+
{"pom-conventions.XML", true},
1296+
{"pom-.xml", true},
1297+
{"pom-abc.xml", true},
1298+
{"parent-pom.xml", true},
1299+
{"common-pom.xml", true},
1300+
{"pom-conventions-pom.xml", true},
1301+
{"not-pom.xml", true}, // Matches *-pom.xml
1302+
{"my-app.pom", false},
1303+
{"not-a-pom-file.xml", false},
1304+
{"pom.xml.bak", false},
1305+
{"apom.xml", false},
1306+
{"pom", false},
1307+
}
1308+
for _, tt := range tests {
1309+
t.Run(tt.path, func(t *testing.T) {
1310+
got := isPOMFile(tt.path)
1311+
if got != tt.want {
1312+
t.Errorf("isPOMFile(%q) = %v, want %v", tt.path, got, tt.want)
1313+
}
1314+
})
1315+
}
1316+
}

0 commit comments

Comments
 (0)