diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 5932a42dce..5e024a053c 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -115,6 +115,7 @@ Release with new features and bugfixes: * https://github.com/devonfw/IDEasy/issues/1788[#1788]: Add Commandlet to create links * https://github.com/devonfw/IDEasy/issues/797[#797]: Use system unzip on macOS to preserve symlinks in ZIP extraction * https://github.com/devonfw/IDEasy/issues/1723[#1723]: Add commandlet for GitHub Copilot CLI +* https://github.com/devonfw/IDEasy/issues/1695[#1695]: Clone settings to temporary directory, analyse, and then move * https://github.com/devonfw/IDEasy/issues/1880[#1880]: Reinstall all plugins for IDE in force mode * https://github.com/devonfw/IDEasy/issues/861[#861]: Fix install of pgadmin throws IllegalStateException when the install wizard starts * https://github.com/devonfw/IDEasy/issues/1844[#1844]: VSCode plugin installation progress freezing diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/AbstractUpdateCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/AbstractUpdateCommandlet.java index 2874a0ef04..c8e1b0cc9a 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/AbstractUpdateCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/AbstractUpdateCommandlet.java @@ -12,7 +12,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.devonfw.tools.ide.cli.CliException; import com.devonfw.tools.ide.context.AbstractIdeContext; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.context.IdeStartContextImpl; @@ -192,7 +191,6 @@ private void updateSettingsInStep(boolean codeRepository) { this.context.getFileAccess().backup(settingsPath); } GitUrl gitUrl = getOrAskSettingsUrl(); - checkProjectNameConvention(gitUrl.getProjectName()); initializeRepository(gitUrl); return; } @@ -210,17 +208,10 @@ private GitUrl getOrAskSettingsUrl() { String repository = this.settingsRepo.getValue(); repository = handleDefaultRepository(repository); - String userPromt; - String defaultUrl; - if (isCodeRepository()) { - userPromt = "Code repository URL:"; - defaultUrl = null; - LOG.info(MESSAGE_CODE_REPO_URL); - } else { - userPromt = "Settings URL [" + IdeContext.DEFAULT_SETTINGS_REPO_URL + "]:"; - defaultUrl = IdeContext.DEFAULT_SETTINGS_REPO_URL; - LOG.info(MESSAGE_SETTINGS_REPO_URL, this.context.getSettingsPath()); - } + String userPromt = "Repository URL [" + IdeContext.DEFAULT_SETTINGS_REPO_URL + "]:"; + String defaultUrl = IdeContext.DEFAULT_SETTINGS_REPO_URL; + LOG.info(MESSAGE_SETTINGS_REPO_URL, this.context.getSettingsPath()); + GitUrl gitUrl = null; if (repository != null) { gitUrl = GitUrl.of(repository); @@ -238,57 +229,18 @@ private GitUrl getOrAskSettingsUrl() { private String handleDefaultRepository(String repository) { if ("-".equals(repository)) { - if (isCodeRepository()) { - LOG.warn("'-' is found after '--code'. This is invalid."); - repository = null; - } else { - LOG.info("'-' was found for settings repository, the default settings repository '{}' will be used.", IdeContext.DEFAULT_SETTINGS_REPO_URL); - repository = IdeContext.DEFAULT_SETTINGS_REPO_URL; - } + LOG.info("'-' was found for the repository, the default settings repository '{}' will be used.", IdeContext.DEFAULT_SETTINGS_REPO_URL); + repository = IdeContext.DEFAULT_SETTINGS_REPO_URL; } return repository; } - private void checkProjectNameConvention(String projectName) { - boolean isSettingsRepo = projectName.contains(IdeContext.SETTINGS_REPOSITORY_KEYWORD); - boolean codeRepository = isCodeRepository(); - if (isSettingsRepo == codeRepository) { - String warningTemplate; - if (codeRepository) { - warningTemplate = """ - Your git URL is pointing to the project name {} that contains the keyword '{}'. - Therefore we assume that you did a mistake by adding the '--code' option to the ide project creation. - Do you really want to create the project?"""; - } else { - warningTemplate = """ - Your git URL is pointing to the project name {} that does not contain the keyword ''{}''. - Therefore we assume that you forgot to add the '--code' option to the ide project creation. - Do you really want to create the project?"""; - } - this.context.askToContinue(warningTemplate, projectName, IdeContext.SETTINGS_REPOSITORY_KEYWORD); - } - } - private void initializeRepository(GitUrl gitUrl) { GitContext gitContext = this.context.getGitContext(); Path settingsPath = this.context.getSettingsPath(); Path repoPath = settingsPath; - boolean codeRepository = isCodeRepository(); - if (codeRepository) { - // clone the given code repository into IDE_HOME/workspaces/main - repoPath = context.getWorkspacePath().resolve(gitUrl.getProjectName()); - } gitContext.pullOrClone(gitUrl, repoPath); - if (codeRepository) { - // check for settings folder and create symlink to IDE_HOME/settings - Path settingsFolder = repoPath.resolve(IdeContext.FOLDER_SETTINGS); - if (Files.exists(settingsFolder)) { - context.getFileAccess().symlink(settingsFolder, settingsPath); - } else { - throw new CliException("Invalid code repository " + gitUrl + ": missing a settings folder at " + settingsFolder); - } - } this.context.getGitContext().saveCurrentCommitId(settingsPath, this.context.getSettingsCommitIdPath()); } @@ -446,14 +398,4 @@ private void createStartScript(String ide, String workspace) { fileAccess.writeFileContent(scriptContent, scriptPath); fileAccess.makeExecutable(scriptPath); } - - /** - * Judge if the repository is a code repository. - * - * @return true when the repository is a code repository, otherwise false. - */ - protected boolean isCodeRepository() { - return false; - } - } diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/CreateCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/CreateCommandlet.java index a68d6768c5..119fbfffd7 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/CreateCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/CreateCommandlet.java @@ -2,15 +2,18 @@ import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardCopyOption; import java.util.function.Predicate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.devonfw.tools.ide.cli.CliException; import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.environment.EnvironmentVariables; +import com.devonfw.tools.ide.git.GitUrl; import com.devonfw.tools.ide.io.FileAccess; import com.devonfw.tools.ide.log.IdeLogLevel; -import com.devonfw.tools.ide.property.FlagProperty; import com.devonfw.tools.ide.property.StringProperty; import com.devonfw.tools.ide.version.IdeVersion; @@ -24,9 +27,6 @@ public class CreateCommandlet extends AbstractUpdateCommandlet { /** {@link StringProperty} for the name of the new project */ public final StringProperty newProject; - /** {@link FlagProperty} for creating a project with settings inside a code repository */ - public final FlagProperty codeRepositoryFlag; - /** * The constructor. * @@ -36,7 +36,6 @@ public CreateCommandlet(IdeContext context) { super(context); this.newProject = add(new StringProperty("", true, "project")); - this.codeRepositoryFlag = add(new FlagProperty("--code")); add(this.settingsRepo); } @@ -57,16 +56,24 @@ protected void doRun() { String newProjectName = this.newProject.getValue(); Path newProjectPath = this.context.getIdeRoot().resolve(newProjectName); + Path tempProjectPath = this.context.getTempPath().resolve(IdeContext.FOLDER_PROJECTS).resolve(newProjectName); + + if (Files.exists(tempProjectPath)) { + throw new CliException( + String.format("Temporary project directory already exists in: %s. Please delete it and try again.", tempProjectPath)); + } else if (Files.exists(newProjectPath)) { + throw new CliException( + String.format("Project directory already exists in: %s. As the project already exists, try calling 'ide update'.", + newProjectPath)); + } LOG.info("Creating new IDEasy project in {}", newProjectPath); if (!this.context.getFileAccess().isEmptyDir(newProjectPath)) { this.context.askToContinue("Directory {} already exists. Do you want to continue?", newProjectPath); - } else { - this.context.getFileAccess().mkdirs(newProjectPath); } - initializeProject(newProjectPath); - this.context.setIdeHome(newProjectPath); + initializeProject(tempProjectPath); + this.context.setIdeHome(tempProjectPath); super.doRun(); this.context.getFileAccess().writeFileContent(IdeVersion.getVersionString(), newProjectPath.resolve(IdeContext.FILE_SOFTWARE_VERSION)); IdeLogLevel.SUCCESS.log(LOG, "Successfully created new project '{}'.", newProjectName); @@ -83,14 +90,99 @@ private void initializeProject(Path newInstancePath) { } @Override - protected boolean isCodeRepository() { - return this.codeRepositoryFlag.isTrue(); + protected void updateSettings() { + super.updateSettings(); + analyzeProject(); + } + + /** + * This method is invoked when a new porject is created. It analyzes the cloned repository to check if it is a valid IDEasy repository. The repository can + * either be a settings repository (with ide.properties or devon.properties on the top level) or a code repository (with a settings folder on the top level + * containing such a file). Otherwise, the project creation fails and an error message is logged. + */ + private void analyzeProject() { + // Settings repository: ide.properties on top levels (or devon.properties for legacy users) + // Code repository: settings folder on top level with ide.properties inside (or devon.properties for legacy users) + String projectName = this.context.getProjectName(); + Path actualProjectPath = this.context.getIdeRoot().resolve(projectName); + FileAccess fileAccess = this.context.getFileAccess(); + Path settingsPath = this.context.getSettingsPath(); + + // Check whether the repository is a valid settings repository, code repository, or neither + if (isSettingsRepository(settingsPath)) { + LOG.info("The repository seems to be a settings repository based on the presence of " + EnvironmentVariables.DEFAULT_PROPERTIES + " or " + + EnvironmentVariables.LEGACY_PROPERTIES + " on the top level."); + moveProject(this.context.getIdeHome(), actualProjectPath); + + } else if (isCodeRepository(settingsPath)) { + LOG.info(EnvironmentVariables.DEFAULT_PROPERTIES + " or " + EnvironmentVariables.LEGACY_PROPERTIES + + " found in settings subfolder. This indicates a code repository with a settings folder on the top level."); + + String gitProjectName = GitUrl.of(this.settingsRepo.getValue(0)).getProjectName(); + Path codeFolderPath = actualProjectPath.resolve(IdeContext.FOLDER_WORKSPACES).resolve(IdeContext.WORKSPACE_MAIN).resolve(gitProjectName); + // Move temp project to actual project location $IDE_ROOT/ + moveProject(this.context.getIdeHome(), actualProjectPath); + + // Move settings fodler containing code to $IDE_ROOT//workspaces/main/ + moveProject(actualProjectPath.resolve(IdeContext.FOLDER_SETTINGS), codeFolderPath); + + // Set IDE_HOME to new (and actual) project location + this.context.setIdeHome(actualProjectPath); + + // Link settings folder in IDE_HOME to settings folder in code repository + fileAccess.symlink(codeFolderPath.resolve(IdeContext.FOLDER_SETTINGS), actualProjectPath.resolve(IdeContext.FOLDER_SETTINGS)); + + } else { + // Repository seems to be invalid. Clean up temporary location and return error + fileAccess.delete(this.context.getIdeHome()); + throw new CliException("This repository does not include an " + EnvironmentVariables.DEFAULT_PROPERTIES + " or " + EnvironmentVariables.LEGACY_PROPERTIES + + " file at the top level or a settings folder with such a file. " + + "The repository does not seem to be a valid IDEasy repository. Please verify the repository and try again."); + } + // Set IDE_HOME to new (and actual) project location + this.context.setIdeHome(actualProjectPath); + } + + /** + * Moves files of a new projectfrom the temporary location to the final project location. + * + * @param oldPath - The path of the file or directory to be moved. + * @param newPath - The path of the destination. + */ + private void moveProject(Path oldPath, Path newPath) { + FileAccess fileAccess = this.context.getFileAccess(); + try { + fileAccess.mkdirs(newPath); + fileAccess.move(oldPath, newPath, StandardCopyOption.REPLACE_EXISTING); + } catch (Exception e) { + LOG.error("Failed to move project from {} to {}. Please move it manually.", oldPath, newPath, e); + } + } + + /** + * Checks whether te given repository is a settings repository by checking for the presence of ide.properties or devon.properties on the top level. + * + * @param repositoryPath - The path of the repository to be checked. + */ + private boolean isSettingsRepository(Path repositoryPath) { + return Files.exists(repositoryPath.resolve(EnvironmentVariables.DEFAULT_PROPERTIES)) || Files.exists( + repositoryPath.resolve(EnvironmentVariables.LEGACY_PROPERTIES)); + } + + /** + * Checks whether te given repository is a code repository by checking for the presence of ide.properties or devon.properties within a settings folder on the + * top level. + * + * @param repositoryPath - The path of the repository to be checked. + */ + private boolean isCodeRepository(Path repositoryPath) { + return isSettingsRepository(repositoryPath.resolve(IdeContext.FOLDER_SETTINGS)); } @Override protected String getStepMessage() { - return "Create (clone) " + (isCodeRepository() ? "code" : "settings") + " repository"; + return "Create (Clone) repository"; } private void logWelcomeMessage() { diff --git a/cli/src/main/resources/nls/Help.properties b/cli/src/main/resources/nls/Help.properties index aacdefef89..7e934f18f1 100644 --- a/cli/src/main/resources/nls/Help.properties +++ b/cli/src/main/resources/nls/Help.properties @@ -176,7 +176,6 @@ cmd.yarn.detail=Yarn is a package manager and build tool for JavaScript. Detaile commandlets=Available commandlets: icd-hint=Hint: Use 'icd' command to easily navigate between your IDE home, projects, and workspaces. Type 'icd --help' for more details. opt.--batch=enable batch mode (non-interactive). -opt.--code=clone given code repository containing a settings folder into workspaces so that settings can be committed alongside code changes. opt.--debug=enable debug logging. opt.--force=enable force mode. opt.--force-plugin-reinstall=resets installed plugins to the project configuration diff --git a/cli/src/main/resources/nls/Help_de.properties b/cli/src/main/resources/nls/Help_de.properties index 83bd160e63..5e56da2c14 100644 --- a/cli/src/main/resources/nls/Help_de.properties +++ b/cli/src/main/resources/nls/Help_de.properties @@ -176,7 +176,6 @@ cmd.yarn.detail=Yarn ist ein Package Manager und Build-Werkzeug für JavaScript. commandlets=Verfügbare Kommandos: icd-hint=Hinweis: Verwenden Sie den Befehl 'icd' um einfach zwischen Ihrem IDE-Hauptverzeichnis, Projekten und Workspaces zu navigieren. Geben Sie 'icd --help' für weitere Details ein. opt.--batch=Aktiviert den Batch-Modus (nicht-interaktive Stapelverarbeitung). -opt.--code=Git-Repository sowohl als Code- als auch als Settings-Repository verwenden. opt.--debug=Aktiviert Debug-Ausgaben (Fehleranalyse). opt.--force=Aktiviert den Force-Modus (Erzwingen). opt.--force-plugin-reinstall=Setzt installierte Plugins zurück auf die Projektkonfiguration. diff --git a/cli/src/test/java/com/devonfw/tools/ide/commandlet/CreateCommandletTest.java b/cli/src/test/java/com/devonfw/tools/ide/commandlet/CreateCommandletTest.java index 98534e72a9..cc393b7ff5 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/commandlet/CreateCommandletTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/commandlet/CreateCommandletTest.java @@ -7,15 +7,12 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; import com.devonfw.tools.ide.cli.CliArguments; import com.devonfw.tools.ide.cli.CliException; import com.devonfw.tools.ide.context.AbstractIdeContextTest; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.context.IdeTestContext; -import com.devonfw.tools.ide.context.ProcessContextGitMock; import com.devonfw.tools.ide.environment.EnvironmentVariables; import com.devonfw.tools.ide.environment.EnvironmentVariablesType; import com.devonfw.tools.ide.git.GitContextImplMock; @@ -39,6 +36,10 @@ void setup() { if (Files.exists(newProjectPath)) { context.getFileAccess().delete(newProjectPath); } + Path tempProjectPath = context.getTempPath().resolve(IdeContext.FOLDER_PROJECTS).resolve(NEW_PROJECT_NAME); + if (Files.exists(tempProjectPath)) { + context.getFileAccess().delete(tempProjectPath); + } this.context = context; } @@ -58,63 +59,18 @@ void testCreateCommandletRun() { cc.newProject.setValueAsString(NEW_PROJECT_NAME, context); cc.settingsRepo.setValue(IdeContext.DEFAULT_SETTINGS_REPO_URL); cc.skipTools.setValue(true); - // act - cc.run(); - // assert - Path newProjectPath = context.getIdeRoot().resolve(NEW_PROJECT_NAME); - assertThat(newProjectPath).exists(); - assertThat(context.getIdeHome()).isEqualTo(newProjectPath); - assertThat(newProjectPath.resolve(IdeContext.FOLDER_PLUGINS)).exists(); - assertThat(newProjectPath.resolve(IdeContext.FOLDER_SOFTWARE)).exists(); - assertThat(newProjectPath.resolve(IdeContext.FOLDER_WORKSPACES).resolve(IdeContext.WORKSPACE_MAIN)).exists(); - } - @ParameterizedTest - @ValueSource(strings = { "https://some-code-repository", "ssh://some-settings-repository" }) - void testWarningWhenRepoDoesNotMeetNamingConvention(String invalidRepo, @TempDir Path tempDir) { - // arrange - ProcessContextGitMock gitMock = new ProcessContextGitMock(context, tempDir); - context.setProcessContext(gitMock); - CreateCommandlet cc = context.getCommandletManager().getCommandlet(CreateCommandlet.class); - cc.newProject.setValueAsString(NEW_PROJECT_NAME, context); - cc.codeRepositoryFlag.setValue(!invalidRepo.contains("code")); // raise conflict - cc.settingsRepo.setValue(invalidRepo); - cc.skipTools.setValue(true); - context.setAnswers("yes"); // act cc.run(); - // assert - assertThat(context).logAtInteraction().hasMessageContaining("Do you really want to create the project?"); - Path newProjectPath = context.getIdeRoot().resolve(NEW_PROJECT_NAME); - assertThat(newProjectPath).exists(); - assertThat(context.getIdeHome()).isEqualTo(newProjectPath); - assertThat(newProjectPath.resolve(IdeContext.FOLDER_PLUGINS)).exists(); - assertThat(newProjectPath.resolve(IdeContext.FOLDER_SOFTWARE)).exists(); - assertThat(newProjectPath.resolve(IdeContext.FOLDER_WORKSPACES).resolve(IdeContext.WORKSPACE_MAIN)).exists(); - } - @Test - void testWarningWhenCodeRepoUsingDefaultMark(@TempDir Path tempDir) { - String invalidCodeRepo = "-"; - // arrange - ProcessContextGitMock gitMock = new ProcessContextGitMock(context, tempDir); - context.setProcessContext(gitMock); - CreateCommandlet cc = context.getCommandletManager().getCommandlet(CreateCommandlet.class); - cc.newProject.setValueAsString(NEW_PROJECT_NAME, context); - cc.settingsRepo.setValue(invalidCodeRepo); - cc.codeRepositoryFlag.setValue(true); - cc.skipTools.setValue(true); - context.setAnswers("https://some-code-repository"); - // act - cc.run(); // assert - assertThat(context).logAtWarning().hasMessageContaining("'-' is found after '--code'. This is invalid."); Path newProjectPath = context.getIdeRoot().resolve(NEW_PROJECT_NAME); assertThat(newProjectPath).exists(); assertThat(context.getIdeHome()).isEqualTo(newProjectPath); assertThat(newProjectPath.resolve(IdeContext.FOLDER_PLUGINS)).exists(); assertThat(newProjectPath.resolve(IdeContext.FOLDER_SOFTWARE)).exists(); assertThat(newProjectPath.resolve(IdeContext.FOLDER_WORKSPACES).resolve(IdeContext.WORKSPACE_MAIN)).exists(); + assertThat(context.getIdeRoot().resolve("_ide/tmp/projects").resolve(NEW_PROJECT_NAME)).doesNotExist(); } @Test @@ -173,6 +129,7 @@ void testIdeVersionTooOldForExistingProject() { @Test void testIdeVersionOk() { // arrange + CreateCommandlet cc = context.getCommandletManager().getCommandlet(CreateCommandlet.class); cc.newProject.setValueAsString(NEW_PROJECT_NAME, context); cc.settingsRepo.setValue(IdeContext.DEFAULT_SETTINGS_REPO_URL); @@ -217,9 +174,39 @@ void testWelcomeMessageDisplayed() { // assert Path newProjectPath = context.getIdeRoot().resolve(NEW_PROJECT_NAME); assertThat(newProjectPath).exists(); + assertThat(context.getIdeHome()).isEqualTo(newProjectPath); + assertThat(newProjectPath.resolve(IdeContext.FOLDER_PLUGINS)).exists(); + assertThat(newProjectPath.resolve(IdeContext.FOLDER_SOFTWARE)).exists(); + assertThat(newProjectPath.resolve(IdeContext.FOLDER_WORKSPACES).resolve(IdeContext.WORKSPACE_MAIN)).exists(); + assertThat(context.getIdeRoot().resolve("_ide/tmp/projects").resolve(NEW_PROJECT_NAME)).doesNotExist(); assertThat(context).logAtInfo().hasMessageContaining("Welcome to your new IDEasy project!"); } + @Test + void testProjectWithInvalidRepositoryNotCreated() { + + // arrange - create a new project that is invalid (does not contain ide.properties file) + GitContextImplMock gitContextImplMock = new GitContextImplMock(context, TEST_RESOURCES.resolve("pypi")); + + context.setGitContext(gitContextImplMock); + CreateCommandlet cc = context.getCommandletManager().getCommandlet(CreateCommandlet.class); + cc.newProject.setValueAsString(NEW_PROJECT_NAME, context); + cc.settingsRepo.setValue(IdeContext.DEFAULT_SETTINGS_REPO_URL); + cc.skipTools.setValue(true); + + // act - run the create command + assertThatThrownBy(() -> cc.run()) + .isInstanceOf(CliException.class) + .hasMessageContaining("This repository does not include an " + EnvironmentVariables.DEFAULT_PROPERTIES + " or " + EnvironmentVariables.LEGACY_PROPERTIES + + " file at the top level or a settings folder with such a file.") + .hasMessageContaining("The repository does not seem to be a valid IDEasy repository. Please verify the repository and try again."); + + // assert + Path newProjectPath = context.getIdeRoot().resolve(NEW_PROJECT_NAME); + assertThat(newProjectPath).doesNotExist(); + assertThat(context.getTempPath().resolve(IdeContext.FOLDER_PROJECTS).resolve(NEW_PROJECT_NAME)).doesNotExist(); + } + @Test void testCreateWithDashPlaceholderAsCliArgument() { // arrange - see https://github.com/devonfw/IDEasy/issues/2106 @@ -234,7 +221,7 @@ void testCreateWithDashPlaceholderAsCliArgument() { assertThat(result).isEqualTo(0); assertThat(context).logAtError().hasNoMessageContaining("not found for commandlet"); assertThat(context).logAtInfo() - .hasMessageContaining("'-' was found for settings repository, the default settings repository"); + .hasMessageContaining("'-' was found for the repository, the default settings repository"); Path newProjectPath = context.getIdeRoot().resolve(NEW_PROJECT_NAME); assertThat(newProjectPath).exists(); } diff --git a/cli/src/test/java/com/devonfw/tools/ide/git/GitContextMock.java b/cli/src/test/java/com/devonfw/tools/ide/git/GitContextMock.java index 2f5c689834..e608dace12 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/git/GitContextMock.java +++ b/cli/src/test/java/com/devonfw/tools/ide/git/GitContextMock.java @@ -53,6 +53,9 @@ public void clone(GitUrl gitUrl, Path repository) { FileAccess fileAccess = this.context.getFileAccess(); fileAccess.mkdirs(repository); + // Create ide.properties to simulate a valid repository + fileAccess.touch(repository.resolve("ide.properties")); + Path gitFolder = repository.resolve(GIT_FOLDER); fileAccess.mkdirs(gitFolder); String branch = gitUrl.branch(); diff --git a/cli/src/test/resources/settings/ide.properties b/cli/src/test/resources/settings/ide.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/documentation/settings.adoc b/documentation/settings.adoc index e9de2335ca..632c2c4426 100644 --- a/documentation/settings.adoc +++ b/documentation/settings.adoc @@ -18,17 +18,18 @@ This gives you the freedom to control and manage the tools with their versions a To setup and customize these settings simply follow the link:usage.adoc#admin[admin usage guide]. Then tell your team to create the project using your project sepcific settings git URL: ``` -ide create «project-name» --code «settings-url» +ide create «project-name» «settings-url» ``` == Code-repository It is even possible to include your settings into your code repository by having the `settings` folder directly on top-level of your code git repository. This allows you to keep settings changes in sync with code changes and manage them in the same pull/merge requests. -To use this approach simply copy the content of https://github.com/devonfw/ide-settings[ide-settings] to a top-level `settings` folder in your code repository root and tell your developers to create the project usining the `--code` option: +To use this approach simply copy the content of https://github.com/devonfw/ide-settings[ide-settings] to a top-level `settings` folder in your code repository. +You can then create the project as normal as IDEasy will automatically detect that you are using a code repository: ``` -ide create «project-name» --code «code-repo-url» +ide create «project-name» «code-repo-url» ``` IDEasy will clone your repository and create a symlink to the settings folder.