diff --git a/cli/azd/internal/appdetect/appdetect_test.go b/cli/azd/internal/appdetect/appdetect_test.go
index 2182293a5ba..16faa53eda0 100644
--- a/cli/azd/internal/appdetect/appdetect_test.go
+++ b/cli/azd/internal/appdetect/appdetect_test.go
@@ -62,16 +62,10 @@ func TestDetect(t *testing.T) {
},
{
Language: Java,
- Path: "java-multimodules/module1",
+ Path: "java-multimodules/module",
RootPath: filepath.Join(dir, "java-multimodules"),
DetectionRule: "Inferred by presence of: pom.xml",
},
- {
- Language: Java,
- Path: "java-multimodules/module2/submodule1",
- RootPath: filepath.Join(dir, "java-multimodules"), // point to the root, not direct parent
- DetectionRule: "Inferred by presence of: pom.xml",
- },
{
Language: Java,
Path: "java-multimodules/notmodule",
diff --git a/cli/azd/internal/appdetect/java_test.go b/cli/azd/internal/appdetect/java_test.go
deleted file mode 100644
index c448a2bcfa4..00000000000
--- a/cli/azd/internal/appdetect/java_test.go
+++ /dev/null
@@ -1,454 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-
-package appdetect
-
-import (
- "context"
- "fmt"
- "log/slog"
- "os"
- osexec "os/exec"
- "path/filepath"
- "strings"
- "testing"
- "time"
-
- "github.com/azure/azure-dev/cli/azd/pkg/exec"
- "github.com/azure/azure-dev/cli/azd/pkg/tools/maven"
- "github.com/sethvargo/go-retry"
-)
-
-func TestToMavenProject(t *testing.T) {
- // Skip in short mode since this test requires network access to Maven Central
- if testing.Short() {
- t.Skip("Skipping Maven network-dependent test in short mode")
- }
-
- path, err := osexec.LookPath("java")
- if err != nil {
- t.Skip("Skip readMavenProject because java command doesn't exist.")
- } else {
- slog.Info("Java command found.", "path", path)
- }
- path, err = osexec.LookPath("mvn")
- if err != nil {
- t.Skip("Skip readMavenProject because mvn command doesn't exist.")
- } else {
- slog.Info("Java command found.", "path", path)
- }
- tests := []struct {
- name string
- testPoms []testPom
- expected []dependency
- }{
- {
- name: "Test with two dependencies",
- testPoms: []testPom{
- {
- pomFilePath: "pom.xml",
- pomContentString: `
-
- 4.0.0
- com.example
- example-project
- 1.0.0
-
-
- org.springframework
- spring-core
- 5.3.8
- compile
-
-
- junit
- junit
- 4.13.2
- test
-
-
-
- `,
- },
- },
- expected: []dependency{
- {
- GroupId: "org.springframework",
- ArtifactId: "spring-core",
- Version: "5.3.8",
- Scope: "compile",
- },
- {
- GroupId: "junit",
- ArtifactId: "junit",
- Version: "4.13.2",
- Scope: "test",
- },
- },
- },
- {
- name: "Test with no dependencies",
- testPoms: []testPom{
- {
- pomFilePath: "pom.xml",
- pomContentString: `
-
- 4.0.0
- com.example
- example-project
- 1.0.0
-
-
-
- `,
- },
- },
- expected: []dependency{},
- },
- {
- name: "Test with one dependency which version is decided by dependencyManagement",
- testPoms: []testPom{
- {
- pomFilePath: "pom.xml",
- pomContentString: `
-
- 4.0.0
- com.example
- example-project
- 1.0.0
-
-
- org.slf4j
- slf4j-api
-
-
-
-
-
- org.springframework.boot
- spring-boot-dependencies
- 3.0.0
- pom
- import
-
-
-
-
- `,
- },
- },
- expected: []dependency{
- {
- GroupId: "org.slf4j",
- ArtifactId: "slf4j-api",
- Version: "2.0.4",
- Scope: "compile",
- },
- },
- },
- {
- name: "Test with one dependency which version is decided by parent",
- testPoms: []testPom{
- {
- pomFilePath: "pom.xml",
- pomContentString: `
-
-
- org.springframework.boot
- spring-boot-starter-parent
- 3.0.0
-
-
- 4.0.0
- com.example
- example-project
- 1.0.0
-
-
- org.slf4j
- slf4j-api
-
-
-
- `,
- },
- },
- expected: []dependency{
- {
- GroupId: "org.slf4j",
- ArtifactId: "slf4j-api",
- Version: "2.0.4",
- Scope: "compile",
- },
- },
- },
- {
- name: "Test pom with multi modules: root pom build first when run help:effective-pom",
- testPoms: []testPom{
- {
- pomFilePath: "pom.xml",
- pomContentString: `
-
- 4.0.0
-
- org.springframework.boot
- spring-boot-starter-parent
- 3.2.7
-
- org.springframework
- gs-multi-module
- 0.1.0
- pom
-
- library
- application
-
-
- `,
- },
- {
- pomFilePath: filepath.Join("application", "pom.xml"),
- pomContentString: `
-
- 4.0.0
-
- org.springframework
- gs-multi-module
- 0.1.0
-
- com.example
- application
- 0.0.1-SNAPSHOT
- application
- Demo project for Spring Boot
-
-
- org.slf4j
- slf4j-api
-
-
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
-
-
- `,
- },
- {
- pomFilePath: filepath.Join("library", "pom.xml"),
- pomContentString: `
-
- 4.0.0
-
- org.springframework
- gs-multi-module
- 0.1.0
-
- com.example
- library
- 0.0.1-SNAPSHOT
- library
- Demo project for Spring Boot
-
-
- org.springframework.boot
- spring-boot
-
-
- org.springframework.boot
- spring-boot-starter-test
- test
-
-
-
- `,
- },
- },
- expected: []dependency{},
- },
- {
- name: "Test pom with multi modules: root pom build last when run help:effective-pom",
- testPoms: []testPom{
- {
- pomFilePath: "pom.xml",
- pomContentString: `
-
- 4.0.0
- org.springframework
- gs-multi-module
- 0.1.0
- pom
-
- library
- application
-
-
- `,
- },
- {
- pomFilePath: filepath.Join("application", "pom.xml"),
- pomContentString: `
-
- 4.0.0
-
- org.springframework.boot
- spring-boot-starter-parent
- 3.3.0
-
-
- com.example
- application
- 0.0.1-SNAPSHOT
- application
- Demo project for Spring Boot
-
-
- org.slf4j
- slf4j-api
-
-
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
-
-
- `,
- },
- {
- pomFilePath: filepath.Join("library", "pom.xml"),
- pomContentString: `
-
- 4.0.0
-
- org.springframework.boot
- spring-boot-starter-parent
- 3.2.2
-
-
- com.example
- library
- 0.0.1-SNAPSHOT
- library
- Demo project for Spring Boot
-
-
- org.springframework.boot
- spring-boot
-
-
- org.springframework.boot
- spring-boot-starter-test
- test
-
-
-
- `,
- },
- },
- expected: []dependency{},
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- t.Parallel()
- workingDir, err := prepareTestPomFiles(tt.testPoms)
- if err != nil {
- t.Fatalf("%v", err)
- }
- testPom := tt.testPoms[0]
- pomFilePath := filepath.Join(workingDir, testPom.pomFilePath)
-
- // Use a timeout context to prevent hanging on network issues
- ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
- defer cancel()
-
- // Use retry logic for Maven operations due to potential network issues
- mavenProject, err := readMavenProjectWithRetry(ctx, maven.NewCli(exec.NewCommandRunner(nil)),
- pomFilePath)
- if err != nil {
- t.Fatalf("readMavenProject failed: %v", err)
- }
-
- if len(mavenProject.Dependencies) != len(tt.expected) {
- t.Fatalf("Expected: %d\nActual: %d", len(tt.expected), len(mavenProject.Dependencies))
- }
-
- for i, dep := range mavenProject.Dependencies {
- if dep != tt.expected[i] {
- t.Errorf("\nExpected: %s\nActual: %s", tt.expected[i], dep)
- }
- }
- })
- }
-}
-
-// readMavenProjectWithRetry wraps readMavenProject with retry logic to handle network issues
-func readMavenProjectWithRetry(ctx context.Context, mvnCli *maven.Cli, filePath string) (*mavenProject, error) {
- var mavenProject *mavenProject
- var lastErr error
-
- err := retry.Do(
- ctx,
- retry.WithMaxRetries(3, retry.NewExponential(1*time.Second)),
- func(ctx context.Context) error {
- result, err := readMavenProject(ctx, mvnCli, filePath)
- if err != nil {
- // Check if error is likely network-related
- errStr := strings.ToLower(err.Error())
- if strings.Contains(errStr, "connection") ||
- strings.Contains(errStr, "timeout") ||
- strings.Contains(errStr, "network") ||
- strings.Contains(errStr, "unknown host") ||
- strings.Contains(errStr, "could not resolve") ||
- strings.Contains(errStr, "transfer failed") {
- lastErr = err
- return retry.RetryableError(err)
- }
- // For non-network errors (parsing, etc.), fail immediately
- return err
- }
- mavenProject = result
- return nil
- },
- )
-
- if err != nil && lastErr != nil {
- // If we retried but still failed, include context about retries
- return nil, fmt.Errorf("maven operation failed after retries due to network issues: %w", lastErr)
- }
-
- return mavenProject, err
-}
-
-type testPom struct {
- pomFilePath string
- pomContentString string
-}
-
-func prepareTestPomFiles(testPoms []testPom) (string, error) {
- tempDir, err := os.MkdirTemp("", "prepareTestPomFiles")
- if err != nil {
- return "", err
- }
- for _, testPom := range testPoms {
- pomPath := filepath.Join(tempDir, testPom.pomFilePath)
- err := os.MkdirAll(filepath.Dir(pomPath), 0755)
- if err != nil {
- return "", err
- }
- err = os.WriteFile(pomPath, []byte(testPom.pomContentString), 0600)
- if err != nil {
- return "", err
- }
- }
- return tempDir, nil
-}
diff --git a/cli/azd/internal/appdetect/testdata/java-multimodules/application/pom.xml b/cli/azd/internal/appdetect/testdata/java-multimodules/application/pom.xml
index 62df3be885d..6f5f7dd70c0 100644
--- a/cli/azd/internal/appdetect/testdata/java-multimodules/application/pom.xml
+++ b/cli/azd/internal/appdetect/testdata/java-multimodules/application/pom.xml
@@ -3,57 +3,27 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
- org.springframework.boot
- spring-boot-starter-parent
- 3.5.6
-
+ org.springframework
+ java-multimodules
+ 0.1.0
+ ..
com.example
application
0.0.1-SNAPSHOT
- application
- Demo project for Spring Boot
-
- org.springframework.boot
- spring-boot-starter-actuator
-
-
- org.springframework.boot
- spring-boot-starter-web
-
-
- com.example
- library
- ${project.version}
-
-
-
- org.springframework.boot
- spring-boot-starter-test
- test
-
-
com.mysql
mysql-connector-j
+ 8.0.33
org.postgresql
postgresql
- test
+ 42.6.0
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
-
-
diff --git a/cli/azd/internal/appdetect/testdata/java-multimodules/library/pom.xml b/cli/azd/internal/appdetect/testdata/java-multimodules/library/pom.xml
index e969a23417a..4633ca304ee 100644
--- a/cli/azd/internal/appdetect/testdata/java-multimodules/library/pom.xml
+++ b/cli/azd/internal/appdetect/testdata/java-multimodules/library/pom.xml
@@ -3,27 +3,15 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
- org.springframework.boot
- spring-boot-starter-parent
- 3.5.6
-
+ org.springframework
+ java-multimodules
+ 0.1.0
+ ..
com.example
library
0.0.1-SNAPSHOT
- library
- Demo project for Spring Boot
-
- org.springframework.boot
- spring-boot
-
-
-
- org.springframework.boot
- spring-boot-starter-test
- test
-
diff --git a/cli/azd/internal/appdetect/testdata/java-multimodules/module1/pom.xml b/cli/azd/internal/appdetect/testdata/java-multimodules/module/pom.xml
similarity index 93%
rename from cli/azd/internal/appdetect/testdata/java-multimodules/module1/pom.xml
rename to cli/azd/internal/appdetect/testdata/java-multimodules/module/pom.xml
index 64400716997..abb54dc5ae3 100644
--- a/cli/azd/internal/appdetect/testdata/java-multimodules/module1/pom.xml
+++ b/cli/azd/internal/appdetect/testdata/java-multimodules/module/pom.xml
@@ -9,9 +9,9 @@
com.example
- module1
+ module
0.0.1-SNAPSHOT
- module1
+ module
Demo project for Spring Boot
diff --git a/cli/azd/internal/appdetect/testdata/java-multimodules/module2/pom.xml b/cli/azd/internal/appdetect/testdata/java-multimodules/module2/pom.xml
deleted file mode 100644
index 3d06ae0d829..00000000000
--- a/cli/azd/internal/appdetect/testdata/java-multimodules/module2/pom.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
- 4.0.0
-
- org.springframework.boot
- spring-boot-starter-parent
- 3.5.6
-
-
-
- com.example
- module2
- 0.0.1-SNAPSHOT
- module2
- Demo project for Spring Boot
- pom
-
-
- submodule1
-
-
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
-
-
-
diff --git a/cli/azd/internal/appdetect/testdata/java-multimodules/module2/submodule1/pom.xml b/cli/azd/internal/appdetect/testdata/java-multimodules/module2/submodule1/pom.xml
deleted file mode 100644
index 88a9349047b..00000000000
--- a/cli/azd/internal/appdetect/testdata/java-multimodules/module2/submodule1/pom.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
- 4.0.0
-
- org.springframework.boot
- spring-boot-starter-parent
- 3.5.6
-
-
-
- com.example
- submodule1
- 0.0.1-SNAPSHOT
- submodule1
- Demo project for Spring Boot
-
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
-
-
-
\ No newline at end of file
diff --git a/cli/azd/internal/appdetect/testdata/java-multimodules/notmodule/pom.xml b/cli/azd/internal/appdetect/testdata/java-multimodules/notmodule/pom.xml
index 9ef2a6f0ba7..3fdaf812d38 100644
--- a/cli/azd/internal/appdetect/testdata/java-multimodules/notmodule/pom.xml
+++ b/cli/azd/internal/appdetect/testdata/java-multimodules/notmodule/pom.xml
@@ -3,26 +3,9 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
-
- org.springframework.boot
- spring-boot-starter-parent
- 3.4.5
-
-
com.example
notmodule
0.0.1-SNAPSHOT
- notmodule
- Demo project for Spring Boot
-
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
-
\ No newline at end of file
diff --git a/cli/azd/internal/appdetect/testdata/java-multimodules/pom.xml b/cli/azd/internal/appdetect/testdata/java-multimodules/pom.xml
index e0cff252eff..a84c82e8bbe 100644
--- a/cli/azd/internal/appdetect/testdata/java-multimodules/pom.xml
+++ b/cli/azd/internal/appdetect/testdata/java-multimodules/pom.xml
@@ -11,8 +11,7 @@
library
application
- module1
- module2
+ module
diff --git a/cli/azd/test/mocks/mockgraphsdk/mocks.go b/cli/azd/test/mocks/mockgraphsdk/mocks.go
index bbfd1f24583..2f4c34d40aa 100644
--- a/cli/azd/test/mocks/mockgraphsdk/mocks.go
+++ b/cli/azd/test/mocks/mockgraphsdk/mocks.go
@@ -19,7 +19,11 @@ import (
func CreateGraphClient(mockContext *mocks.MockContext) (*graphsdk.GraphClient, error) {
clientOptions := &azcore.ClientOptions{
Transport: mockContext.HttpClient,
- Retry: policy.RetryOptions{RetryDelay: -1},
+ Retry: policy.RetryOptions{
+ MaxRetries: -1,
+ MaxRetryDelay: -1,
+ RetryDelay: -1,
+ },
}
return graphsdk.NewGraphClient(mockContext.Credentials, clientOptions)
}
diff --git a/eng/scripts/Set-CliBuildVariables.ps1 b/eng/scripts/Set-CliBuildVariables.ps1
index 5959de05a4f..463946d2ddc 100644
--- a/eng/scripts/Set-CliBuildVariables.ps1
+++ b/eng/scripts/Set-CliBuildVariables.ps1
@@ -26,7 +26,7 @@
# AZURE_RECORD_MODE is used for running tests in a specific recording mode.
if (-not $env:AZURE_RECORD_MODE) {
- $recordMode = "live"
+ $recordMode = "playback"
if ($BuildReason -eq "PullRequest") {
$recordMode = "playback"