diff --git a/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/command/GenerateCommand.java b/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/command/GenerateCommand.java index 576f739..7d04f9c 100644 --- a/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/command/GenerateCommand.java +++ b/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/command/GenerateCommand.java @@ -44,15 +44,16 @@ public void execute(String commandText) { migrationContext.setTemplateContext(MigrationContext.DEFAULT_TEMPLATE_CONTEXT); } - terminal.println(ask("\nCopilot: Please tell me the environment name you want to use?")); - String envName = textIO.newStringInputReader().withDefaultValue("demoEnv").read("/generate/bicep>"); + String envName = askForEnvName(migrationContext); TemplateContext templateContext = migrationContext.getTemplateContext(); if (!StringUtils.hasText(templateContext.getAppName())) { - terminal.println(ask("Copilot: Please tell me the application name you want to use?")); - String defaultAppName = StringUtils.hasText(migrationContext.getAppName())? migrationContext.getAppName() : "demoApp"; - String appName = textIO.newStringInputReader().withDefaultValue(defaultAppName).read("/generate/bicep>"); - templateContext.setAppName(appName); + templateContext.setAppName(askForAppName(migrationContext)); + } + + if (templateContext.getDbServiceConnectTemplateContext().isRequired()) { + templateContext.getDbServiceConnectTemplateContext().setSubscriptionId(askForSub(migrationContext)); + templateContext.getDbServiceConnectTemplateContext().setResourceGroup(askForRg(migrationContext)); } azdConfigFilesGenerator.generateBicepFiles(envName, migrationContext); @@ -66,4 +67,37 @@ public void execute(String commandText) { } } + + private String askForEnvName(MigrationContext migrationContext) { + terminal.println(ask("\nCopilot: Please tell me the environment name you want to use?")); + return textIO.newStringInputReader().withDefaultValue("demoEnv").read("/generate/bicep>"); + } + + private String askForAppName(MigrationContext migrationContext) { + terminal.println(ask("Copilot: Please tell me the application name you want to use?")); + String defaultAppName = StringUtils.hasText(migrationContext.getAppName())? migrationContext.getAppName() : "demoApp"; + return textIO.newStringInputReader().withDefaultValue(defaultAppName).read("/generate/bicep>"); + } + + private String askForSub(MigrationContext migrationContext) { + if (!StringUtils.hasText(migrationContext.getTemplateContext().getDbServiceConnectTemplateContext().getSubscriptionId())) { + terminal.println(ask("Copilot: Please tell me the subscription Id you want to use for the database service connect?")); + String defaultSub = StringUtils.hasText(migrationContext.getTemplateContext().getDbServiceConnectTemplateContext().getSubscriptionId()) ? + migrationContext.getTemplateContext().getDbServiceConnectTemplateContext().getSubscriptionId() : "00000000-0000-0000-0000-000000000000"; + return textIO.newStringInputReader().withDefaultValue(defaultSub).read("/generate/bicep>"); + } + + return migrationContext.getTemplateContext().getDbServiceConnectTemplateContext().getSubscriptionId(); + } + + private String askForRg(MigrationContext migrationContext) { + if (!StringUtils.hasText(migrationContext.getTemplateContext().getDbServiceConnectTemplateContext().getResourceGroup())) { + terminal.println(ask("Copilot: Please tell me the resource group name you want to use for the database service connect?")); + String defaultRg = StringUtils.hasText(migrationContext.getTemplateContext().getDbServiceConnectTemplateContext().getResourceGroup()) ? + migrationContext.getTemplateContext().getDbServiceConnectTemplateContext().getResourceGroup() : "resourceGroup"; + return textIO.newStringInputReader().withDefaultValue(defaultRg).read("/generate/bicep>"); + } + + return migrationContext.getTemplateContext().getDbServiceConnectTemplateContext().getResourceGroup(); + } } diff --git a/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/command/ReportCommand.java b/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/command/ReportCommand.java index 322349c..f45ad37 100644 --- a/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/command/ReportCommand.java +++ b/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/command/ReportCommand.java @@ -6,8 +6,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import static com.azure.migration.java.copilot.service.ConsoleContext.answer; -import static com.azure.migration.java.copilot.service.ConsoleContext.error; +import static com.azure.migration.java.copilot.service.ConsoleContext.*; @Component public class ReportCommand implements MigrationCommand { @@ -25,6 +24,7 @@ public class ReportCommand implements MigrationCommand { public void execute(String commandText) { try { terminal.println(answer(serviceFacade.showReport())); + terminal.println("AppCat Report: " + "file://" + migrationContext.getWindupReportPath()); } catch (Exception e) { terminal.println(error(e.getMessage())); } diff --git a/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/command/ResourceCommand.java b/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/command/ResourceCommand.java index d356cfd..19c04b8 100644 --- a/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/command/ResourceCommand.java +++ b/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/command/ResourceCommand.java @@ -36,13 +36,8 @@ public void execute(String commandText) { try { final String[] json = new String[1]; json[0] = resourceFacade.resourceConfigAbstract(); - Resources resources; - try { - resources = JsonUtil.fromJson(json[0], Resources.class); - migrationContext.setTemplateContext(resources.toContext()); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } + Resources resources = JsonUtil.fromJson(json[0], Resources.class);; + migrationContext.setTemplateContext(resources.toContext()); String hint = resourceFacade.resourceConfigTable(resources); hint += "\n" + comment; MigrationCommand.loop( @@ -64,6 +59,7 @@ public void execute(String commandText) { } ); } catch (Exception e) { + e.printStackTrace(); terminal.println(error("Error: " + e.getMessage())); } } diff --git a/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/MigrationContext.java b/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/MigrationContext.java index 55aa976..3dc9639 100644 --- a/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/MigrationContext.java +++ b/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/MigrationContext.java @@ -15,6 +15,7 @@ import java.io.File; import java.io.IOException; import java.math.BigInteger; +import java.nio.file.Files; import java.nio.file.Path; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -24,6 +25,7 @@ import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; +import static com.azure.migration.java.copilot.service.ConsoleContext.*; import static java.lang.System.getProperty; @Component @@ -82,7 +84,7 @@ public void init(ApplicationArguments args) throws IOException { AtomicBoolean initSuccess = new AtomicBoolean(false); while (!initSuccess.get()) { if (sourcePathString == null) { - terminal.println(Ansi.ansi().bold().a("\nCopilot: I‘m your migration assistant. Could you please provide me with the location of your source code?").reset().toString()); + terminal.println(ask("Copilot: I‘m your migration assistant. Could you please provide me with the location of your source code?")); sourcePathString = textIO. newStringInputReader(). withDefaultValue(getProperty("user.dir")). @@ -90,8 +92,7 @@ public void init(ApplicationArguments args) throws IOException { } File file = new File(sourcePathString); if (!file.exists()) { - terminal.println("The path does not exist, please check and try again."); - continue; + throw new IOException(error("The path does not exist, please check and try again. " + sourcePathString)); } this.sourceCodePath = file.getCanonicalPath(); String tempDir = getProperty("java.io.tmpdir"); @@ -101,12 +102,12 @@ public void init(ApplicationArguments args) throws IOException { boolean needScan = false; findReport(); if (!Optional.ofNullable(baseFile.list()).map(arr -> arr.length == 0).orElse(true) && !force) { - terminal.println("Skip rebuild the report because find report and manifest.yml under: " + basePath); + terminal.println(warn("Skip rebuild the report because find report under: " + basePath)); } else { if (baseFile.exists()) { terminal.print("The report already exists, do you want to delete it and rebuild the report?:"); - String text = textIO.newStringInputReader().withDefaultValue("N").read("/> "); - if(text.equalsIgnoreCase("Y")) { + boolean confirm = textIO.newBooleanInputReader().withDefaultValue(false).read("/> "); + if(confirm) { baseFile.delete(); needScan=true; }else { @@ -118,9 +119,9 @@ public void init(ApplicationArguments args) throws IOException { } if(needScan) { - terminal.print("Start to scan the source code with AppCat and Cloud Foundary manifest.yml, it will take some time, continue?"); - String text = textIO.newStringInputReader().withDefaultValue("N").read("/>"); - if(text.equalsIgnoreCase("Y")) { + terminal.print(ask("Start to scan the source code with AppCat and Cloud Foundry manifest.yml, it will take some time, continue?")); + boolean confirm = textIO.newBooleanInputReader().withDefaultValue(false).read("/> "); + if(confirm) { scanCodeWithAppCat(); scanCFManifest(); }else{ @@ -132,15 +133,15 @@ public void init(ApplicationArguments args) throws IOException { } public void findReport(){ - File fromFile = new File(sourceCodePath, "manifest.yml"); - cfManifestPath = fromFile.getAbsolutePath(); - if (fromFile.exists()) { - terminal.println("Found the Cloud Foundary manifest.yml under: " + fromFile.getAbsolutePath()); + Path fromFile = Path.of(sourceCodePath, "manifest.yml"); + cfManifestPath = fromFile.toAbsolutePath().toString(); + if (Files.exists(fromFile)) { + terminal.println("Found the Cloud Foundry manifest.yml under: " + fromFile); } - fromFile = new File(basePath, "appcat-report"); - if (fromFile.exists()) { - terminal.println("Found the AppCat Report under: " + fromFile.getAbsolutePath()); - windupReportPath = fromFile.getAbsolutePath(); + fromFile = Path.of(basePath, "appcat-report"); + if (Files.exists(fromFile)) { + terminal.println("Found the AppCat Report under: " + fromFile); + windupReportPath = fromFile.toAbsolutePath().toString(); } } diff --git a/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/generate/AzdConfigFilesGenerator.java b/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/generate/AzdConfigFilesGenerator.java index 3ceed39..4977127 100644 --- a/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/generate/AzdConfigFilesGenerator.java +++ b/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/generate/AzdConfigFilesGenerator.java @@ -93,7 +93,8 @@ private CommonItem assembleMetadata(TemplateContext templateContext) { DbItem db = new DbItem(); resourceItem.setDb(db); - db.setName(templateContext.getDbTemplateContext().getName()); + // TODO: should consider what to set here +// db.setName(templateContext.getDbTemplateContext().getHost()); PersistentStorageItem persistent = new PersistentStorageItem(); resourceItem.setPersistent(persistent); @@ -114,14 +115,9 @@ private void assembleEnvParams(List settingItems, List assembleDbEnvParams(List settingItems, DbTemplateContext dbTemplateContext) { - String dbUrl = Constants.JDBC + Constants.COLON - + dbTemplateContext.getType() + Constants.COLON + Constants.DOUBLE_SLASH - + dbTemplateContext.getName() + Constants.Azure_MYSQL_DOMAIN_SUFFIX + Constants.COLON - + dbTemplateContext.getPort() + Constants.SLASH - + dbTemplateContext.getSchema() + Constants.Azure_MYSQL_CONN_STRING_SUFFIX; - settingItems.add(new SettingItem(Constants.SPRING_DATASOURCE_URL, dbUrl, null, defaultCommentName, defaultCommentValue)); - settingItems.add(new SettingItem(Constants.SPRING_DATASOURCE_USERNAME, dbTemplateContext.getUser(), true, defaultCommentName, defaultCommentValue)); - settingItems.add(new SettingItem(Constants.SPRING_DATASOURCE_PASSWORD, dbTemplateContext.getPwd(), true, defaultCommentName, defaultCommentValue)); + settingItems.add(new SettingItem(Constants.SPRING_DATASOURCE_URL, dbTemplateContext.getConnectionString(), null, defaultCommentName, defaultCommentValue)); + settingItems.add(new SettingItem(Constants.SPRING_DATASOURCE_USERNAME, dbTemplateContext.getUsername(), true, defaultCommentName, defaultCommentValue)); + settingItems.add(new SettingItem(Constants.SPRING_DATASOURCE_PASSWORD, dbTemplateContext.getPassword(), true, defaultCommentName, defaultCommentValue)); return settingItems; } diff --git a/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/model/resource/ResourceCategory.java b/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/model/resource/ResourceCategory.java index 717e999..c17c34d 100644 --- a/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/model/resource/ResourceCategory.java +++ b/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/model/resource/ResourceCategory.java @@ -51,7 +51,7 @@ public void apply(Object object) { field.set(object, p.getValue()); } } catch (NoSuchFieldException | IllegalAccessException e) { - throw new RuntimeException(e); + // just silently catch } }); } diff --git a/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/model/resource/Resources.java b/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/model/resource/Resources.java index 6f46e6a..12deac0 100644 --- a/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/model/resource/Resources.java +++ b/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/model/resource/Resources.java @@ -91,13 +91,16 @@ public TemplateContext toContext() { TemplateContext templateContext = new TemplateContext(); for (ResourceCategory resourceCategory : this.categories) { - switch (resourceCategory.getName()) { - case "Basic Information": + switch (resourceCategory.getName().toLowerCase()) { + case "basic information": resourceCategory.apply(templateContext); break; case "database": resourceCategory.apply(templateContext.getDbTemplateContext()); break; + case "databaseconnect": + resourceCategory.apply(templateContext.getDbServiceConnectTemplateContext()); + break; case "persistent": resourceCategory.apply(templateContext.getPersistentStorageTemplateContext()); break; diff --git a/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/model/template/DbServiceConnectTemplateContext.java b/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/model/template/DbServiceConnectTemplateContext.java new file mode 100644 index 0000000..0abc8d3 --- /dev/null +++ b/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/model/template/DbServiceConnectTemplateContext.java @@ -0,0 +1,38 @@ +package com.azure.migration.java.copilot.service.model.template; + +import com.fasterxml.jackson.annotation.JsonPropertyDescription; +import lombok.Getter; +import lombok.Setter; + +public class DbServiceConnectTemplateContext { + + @Getter + @Setter + @JsonPropertyDescription("whether use Azure Service Connector for connecting database, default to false") + private boolean required; + + @Getter + @Setter + @JsonPropertyDescription("the Azure Database type for the service connector, should be extracted from connection string, default to mysql") + private String type; + + @Getter + @Setter + @JsonPropertyDescription("the Azure Database resource name, should be extracted from the first part of host from connection string, default to application name") + private String resourceName; + + @Getter + @Setter + @JsonPropertyDescription("the Azure Database schema name, should be extracted from connection string, default to test") + private String database; + + @Getter + @Setter + @JsonPropertyDescription("the Azure Subscription ID for service connect, default to empty") + private String subscriptionId; + + @Getter + @Setter + @JsonPropertyDescription("the Azure Resource Group name for service connect, default to empty") + private String resourceGroup; +} diff --git a/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/model/template/DbTemplateContext.java b/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/model/template/DbTemplateContext.java index 7ac7af5..0578366 100644 --- a/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/model/template/DbTemplateContext.java +++ b/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/model/template/DbTemplateContext.java @@ -12,31 +12,16 @@ public class DbTemplateContext { @Getter @Setter - @JsonPropertyDescription("the database type, default to mysql") - private String type; - - @Getter - @Setter - @JsonPropertyDescription("the database name, default to application name") - private String name; - - @Getter - @Setter - @JsonPropertyDescription("the database port, default to 3306") - private int port; - - @Getter - @Setter - @JsonPropertyDescription("the database schema name, default to schema") - private String schema; + @JsonPropertyDescription("the database connection string, default to jdbc:mysql://localhost/test") + private String connectionString; @Getter @Setter @JsonPropertyDescription("the username used to connect to database, default to username") - private String user; + private String username; @Getter @Setter @JsonPropertyDescription("the password used to connect to database, default to password") - private String pwd; + private String password; } diff --git a/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/model/template/TemplateContext.java b/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/model/template/TemplateContext.java index 323ed1f..93f8a1b 100644 --- a/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/model/template/TemplateContext.java +++ b/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/model/template/TemplateContext.java @@ -36,6 +36,11 @@ public class TemplateContext { @JsonProperty("database") private final DbTemplateContext dbTemplateContext = new DbTemplateContext(); + @Getter + @JsonPropertyDescription(value = "service connect info for Azure Database") + @JsonProperty("databaseConnect") + private final DbServiceConnectTemplateContext dbServiceConnectTemplateContext = new DbServiceConnectTemplateContext(); + @Getter @JsonPropertyDescription(value = "persistent storage configuration if local storage usage is detected from report, also known as volume-mount setting") @JsonProperty("persistent") diff --git a/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/util/JsonUtil.java b/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/util/JsonUtil.java index 4353aa9..20fd55c 100644 --- a/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/util/JsonUtil.java +++ b/azure-java-migration-copilot-client/src/main/java/com/azure/migration/java/copilot/service/util/JsonUtil.java @@ -1,6 +1,7 @@ package com.azure.migration.java.copilot.service.util; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.StreamReadFeature; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; diff --git a/azure-java-migration-copilot-client/src/main/resources/application.properties.sample b/azure-java-migration-copilot-client/src/main/resources/application.properties.sample index 4053305..1496be8 100644 --- a/azure-java-migration-copilot-client/src/main/resources/application.properties.sample +++ b/azure-java-migration-copilot-client/src/main/resources/application.properties.sample @@ -6,7 +6,7 @@ langchain4j.azure.ai-search.content-retriever.query-type=VECTOR langchain4j.azure-open-ai.chat-model.endpoint=* langchain4j.azure-open-ai.chat-model.api-key=* langchain4j.azure-open-ai.chat-model.deployment-name=gpt-4 -logging.level.root=OFF +logging.level.root=ERROR logging.level.dev.langchain4j=INFO logging.level.dev.ai4j.openai4j=INFO spring.main.banner-mode=off