Skip to content

Commit

Permalink
Merge pull request #13 from rujche/rujche/java-analyzer
Browse files Browse the repository at this point in the history
Support all kinds of properties file like application(-profile).yaml(or yaml, properties)
  • Loading branch information
rujche authored Oct 16, 2024
2 parents 671902a + 9c53e73 commit 6e14a1b
Show file tree
Hide file tree
Showing 9 changed files with 170 additions and 13 deletions.
60 changes: 48 additions & 12 deletions cli/azd/internal/appdetect/javaanalyze/project_analyzer_spring.go
Original file line number Diff line number Diff line change
@@ -1,28 +1,44 @@
package javaanalyze

import (
"bufio"
"fmt"
"gopkg.in/yaml.v3"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
)

type springProject struct {
applicationProperties map[string]interface{}
applicationProperties map[string]string
}

func analyzeSpringProject(projectPath string) springProject {
return springProject{
applicationProperties: findSpringApplicationProperties(projectPath),
applicationProperties: getProperties(projectPath),
}
}

func findSpringApplicationProperties(projectPath string) map[string]interface{} {
yamlFilePath := projectPath + "/src/main/resources/application.yml"
data, err := ioutil.ReadFile(yamlFilePath)
func getProperties(projectPath string) map[string]string {
result := make(map[string]string)
getPropertiesInPropertiesFile(filepath.Join(projectPath, "/src/main/resources/application.properties"), result)
getPropertiesInYamlFile(filepath.Join(projectPath, "/src/main/resources/application.yml"), result)
getPropertiesInYamlFile(filepath.Join(projectPath, "/src/main/resources/application.yaml"), result)
profile, profileSet := result["spring.profiles.active"]
if profileSet {
getPropertiesInPropertiesFile(filepath.Join(projectPath, "/src/main/resources/application-"+profile+".properties"), result)

Check failure on line 30 in cli/azd/internal/appdetect/javaanalyze/project_analyzer_spring.go

View workflow job for this annotation

GitHub Actions / azd-lint (ubuntu-latest)

the line is 131 characters long, which exceeds the maximum of 125 characters. (lll)
getPropertiesInYamlFile(filepath.Join(projectPath, "/src/main/resources/application-"+profile+".yml"), result)
getPropertiesInYamlFile(filepath.Join(projectPath, "/src/main/resources/application-"+profile+".yaml"), result)
}
return result
}

func getPropertiesInYamlFile(yamlFilePath string, result map[string]string) {
data, err := os.ReadFile(yamlFilePath)
if err != nil {
log.Printf("failed to read spring application properties: %s", yamlFilePath)
return nil
// Ignore the error if file not exist.
return
}

// Parse the YAML into a yaml.Node
Expand All @@ -32,14 +48,11 @@ func findSpringApplicationProperties(projectPath string) map[string]interface{}
log.Fatalf("error unmarshalling YAML: %v", err)
}

result := make(map[string]interface{})
parseYAML("", &root, result)

return result
}

// Recursively parse the YAML and build dot-separated keys into a map
func parseYAML(prefix string, node *yaml.Node, result map[string]interface{}) {
func parseYAML(prefix string, node *yaml.Node, result map[string]string) {
switch node.Kind {
case yaml.DocumentNode:
// Process each document's content
Expand Down Expand Up @@ -77,3 +90,26 @@ func parseYAML(prefix string, node *yaml.Node, result map[string]interface{}) {
// Handle other node types if necessary
}
}

func getPropertiesInPropertiesFile(propertiesFilePath string, result map[string]string) {
file, err := os.Open(propertiesFilePath)
if err != nil {
// Ignore the error if file not exist.
return
}
defer file.Close()

scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
if strings.TrimSpace(line) == "" || strings.HasPrefix(line, "#") {
continue
}
parts := strings.SplitN(line, "=", 2)
if len(parts) == 2 {
key := strings.TrimSpace(parts[0])
value := strings.TrimSpace(parts[1])
result[key] = value
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package javaanalyze

import (
"path/filepath"
"testing"

"github.com/stretchr/testify/require"
)

func TestAnalyzeSpringProject(t *testing.T) {
var project = analyzeSpringProject(filepath.Join("testdata", "project-one"))
require.Equal(t, "", project.applicationProperties["not.exist"])
require.Equal(t, "jdbc:h2:mem:testdb", project.applicationProperties["spring.datasource.url"])

project = analyzeSpringProject(filepath.Join("testdata", "project-two"))
require.Equal(t, "", project.applicationProperties["not.exist"])
require.Equal(t, "jdbc:h2:mem:testdb", project.applicationProperties["spring.datasource.url"])

project = analyzeSpringProject(filepath.Join("testdata", "project-three"))
require.Equal(t, "", project.applicationProperties["not.exist"])
require.Equal(t, "HTML", project.applicationProperties["spring.thymeleaf.mode"])

project = analyzeSpringProject(filepath.Join("testdata", "project-four"))
require.Equal(t, "", project.applicationProperties["not.exist"])
require.Equal(t, "mysql", project.applicationProperties["database"])
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func (r *ruleServiceBusScsb) match(javaProject *javaProject) bool {
}

// Function to find all properties that match the pattern `spring.cloud.stream.bindings.<binding-name>.destination`
func findBindingDestinations(properties map[string]interface{}) map[string]string {
func findBindingDestinations(properties map[string]string) map[string]string {
result := make(map[string]string)

// Iterate through the properties map and look for matching keys
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# database init, supports mysql too
database=mysql
spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:${MYSQL_PORT:3306}/${MYSQL_DATABASE:petclinic}
spring.datasource.username=${MYSQL_USERNAME:petclinic}
spring.datasource.password=${MYSQL_PASSWORD:}
# SQL is written to be idempotent so this is safe
spring.sql.init.mode=always
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
database=postgres
spring.datasource.url=jdbc:postgresql://${POSTGRES_HOST:localhost}:${POSTGRES_HOST:5432}/${POSTGRES_DATABASE:petclinic}
spring.datasource.username=${POSTGRES_USERNAME:petclinic}
spring.datasource.password=${POSTGRES_PASSWORD:}
# SQL is written to be idempotent so this is safe
spring.sql.init.mode=always
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# database init, supports mysql too
database=h2
spring.sql.init.schema-locations=classpath*:db/${database}/schema.sql
spring.sql.init.data-locations=classpath*:db/${database}/data.sql

# Web
spring.thymeleaf.mode=HTML

# JPA
spring.jpa.hibernate.ddl-auto=none
spring.jpa.open-in-view=true

# Internationalization
spring.messages.basename=messages/messages

spring.profiles.active=mysql

# Actuator
management.endpoints.web.exposure.include=*

# Logging
logging.level.org.springframework=INFO
# logging.level.org.springframework.web=DEBUG
# logging.level.org.springframework.context.annotation=TRACE

# Maximum time static resources should be cached
spring.web.resources.cache.cachecontrol.max-age=12h

server.port=8081
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
spring:
datasource:
url: jdbc:h2:mem:testdb
jackson:
date-format: com.microsoft.azure.simpletodo.configuration.RFC3339DateFormat
serialization:
write-dates-as-timestamps: false
jpa:
hibernate:
ddl-auto: update
show-sql: true

Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# database init, supports mysql too
database=h2
spring.sql.init.schema-locations=classpath*:db/${database}/schema.sql
spring.sql.init.data-locations=classpath*:db/${database}/data.sql

# Web
spring.thymeleaf.mode=HTML

# JPA
spring.jpa.hibernate.ddl-auto=none
spring.jpa.open-in-view=true

# Internationalization
spring.messages.basename=messages/messages

spring.profiles.active=mysql

# Actuator
management.endpoints.web.exposure.include=*

# Logging
logging.level.org.springframework=INFO
# logging.level.org.springframework.web=DEBUG
# logging.level.org.springframework.context.annotation=TRACE

# Maximum time static resources should be cached
spring.web.resources.cache.cachecontrol.max-age=12h

server.port=8081
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
spring:
datasource:
url: jdbc:h2:mem:testdb
jackson:
date-format: com.microsoft.azure.simpletodo.configuration.RFC3339DateFormat
serialization:
write-dates-as-timestamps: false
jpa:
hibernate:
ddl-auto: update
show-sql: true

0 comments on commit 6e14a1b

Please sign in to comment.