Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ This file documents all notable changes to https://github.com/devonfw/IDEasy[IDE

Release with new features and bugfixes:

* https://github.com/devonfw/IDEasy/pull/1596[#1596] Add support for comma-separated workspace values in repository configuration
* https://github.com/devonfw/IDEasy/issues/1349[#1349]: Fix XML merge warning message to include file paths for better debugging
* https://github.com/devonfw/IDEasy/issues/1473[#1473]: option --skip-updates not working
* https://github.com/devonfw/IDEasy/issues/536[#536]: IDEasy complete tries to match commandlets twice
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,27 +96,31 @@ private void doImportRepository(Path repositoryFile, boolean forceMode, String r
return;
}
this.context.debug("Repository configuration: {}", repositoryConfig);
Path repositoryPath = getRepositoryPath(repositoryConfig, repositoryId);
if (Files.isDirectory(repositoryPath.resolve(GitContext.GIT_FOLDER))) {
this.context.info("Repository {} already exists at {}", repositoryId, repositoryPath);
if (!(this.context.isForceMode() || this.context.isForceRepositories())) {
this.context.info("Ignoring repository {} - use --force or --force-repositories to rerun setup.", repositoryId);
return;
}
}
List<Path> repositoryPaths = getRepositoryPaths(repositoryConfig, repositoryId);
Path ideStatusDir = this.context.getIdeHome().resolve(IdeContext.FOLDER_DOT_IDE);
this.context.getFileAccess().mkdirs(ideStatusDir);
Path repositoryCreatedStatusFile = ideStatusDir.resolve("repository." + repositoryId);
if (Files.exists(repositoryCreatedStatusFile)) {
if (!(this.context.isForceMode() || this.context.isForceRepositories())) {
this.context.info("Ignoring repository {} because it was already setup before - use --force or --force-repositories for recreation.", repository);
return;

for (Path repositoryPath : repositoryPaths) {
String workspaceName = getWorkspaceName(repositoryPath);
if (Files.isDirectory(repositoryPath.resolve(GitContext.GIT_FOLDER))) {
this.context.info("Repository {} already exists in workspace {} at {}", repositoryId, workspaceName, repositoryPath);
if (!(this.context.isForceMode() || this.context.isForceRepositories())) {
this.context.info("Ignoring repository {} in workspace {} - use --force or --force-repositories to rerun setup.", repositoryId, workspaceName);
continue;
}
}
Path repositoryCreatedStatusFile = ideStatusDir.resolve("repository." + repositoryId + "." + workspaceName);
if (Files.exists(repositoryCreatedStatusFile)) {
if (!(this.context.isForceMode() || this.context.isForceRepositories())) {
this.context.info("Ignoring repository {} in workspace {} because it was already setup before - use --force or --force-repositories for recreation.", repositoryId, workspaceName);
continue;
}
}
boolean success = cloneOrPullRepository(repositoryPath, gitUrl, repositoryCreatedStatusFile);
if (success) {
buildRepository(repositoryConfig, repositoryPath);
importRepository(repositoryConfig, repositoryPath, repositoryId);
}
}
boolean success = cloneOrPullRepository(repositoryPath, gitUrl, repositoryCreatedStatusFile);
if (success) {
buildRepository(repositoryConfig, repositoryPath);
importRepository(repositoryConfig, repositoryPath, repositoryId);
}
}

Expand All @@ -130,17 +134,27 @@ private boolean cloneOrPullRepository(Path repositoryPath, GitUrl gitUrl, Path r
});
}

private Path getRepositoryPath(RepositoryConfig repositoryConfig, String repositoryId) {
String workspace = repositoryConfig.workspace();
if (workspace == null) {
workspace = IdeContext.WORKSPACE_MAIN;
private List<Path> getRepositoryPaths(RepositoryConfig repositoryConfig, String repositoryId) {
Set<String> workspaces = repositoryConfig.workspaces();
if (workspaces == null || workspaces.isEmpty()) {
workspaces = Set.of(IdeContext.WORKSPACE_MAIN);
}
Path workspacePath = this.context.getIdeHome().resolve(IdeContext.FOLDER_WORKSPACES).resolve(workspace);
String repositoryRelativePath = repositoryConfig.path();
if (repositoryRelativePath == null) {
repositoryRelativePath = repositoryId;
}
return workspacePath.resolve(repositoryRelativePath);
List<Path> repositoryPaths = new java.util.ArrayList<>();
for (String workspace : workspaces) {
Path workspacePath = this.context.getIdeHome().resolve(IdeContext.FOLDER_WORKSPACES).resolve(workspace);
repositoryPaths.add(workspacePath.resolve(repositoryRelativePath));
}
return repositoryPaths;
}

private String getWorkspaceName(Path repositoryPath) {
Path workspacesFolder = this.context.getIdeHome().resolve(IdeContext.FOLDER_WORKSPACES);
Path relativePath = workspacesFolder.relativize(repositoryPath);
return relativePath.getName(0).toString();
}

private boolean buildRepository(RepositoryConfig repositoryConfig, Path repositoryPath) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
*
* @param path Path into which the project is cloned. This path is relative to the workspace.
* @param workingSets The working sets associated with the repository.
* @param workspace Workspace to use for checkout and import. Default is main.
* @param workspaces Workspaces to use for checkout and import. Supports comma-separated values. Default is main.
* @param gitUrl Git URL to use for cloning the project.
* @param gitBranch Git branch to checkout. Git default branch is default.
* @param buildPath The build path for the repository.
Expand All @@ -23,7 +23,7 @@
public record RepositoryConfig(
String path,
String workingSets,
String workspace,
Set<String> workspaces,
String gitUrl,
String gitBranch,
String buildPath,
Expand All @@ -37,7 +37,7 @@ public record RepositoryConfig(
/** {@link RepositoryProperties#getProperty(String) Property name} for {@link #workingSets()}. */
public static final String PROPERTY_WORKING_SETS = "workingsets";

/** {@link RepositoryProperties#getProperty(String) Property name} for {@link #workspace()}. */
/** {@link RepositoryProperties#getProperty(String) Property name} for {@link #workspaces()}. */
public static final String PROPERTY_WORKSPACE = "workspace";

/** {@link RepositoryProperties#getProperty(String) Property name} for {@link #gitUrl()}. */
Expand Down Expand Up @@ -82,9 +82,10 @@ public static RepositoryConfig loadProperties(Path filePath, IdeContext context)
RepositoryProperties properties = new RepositoryProperties(filePath, context);

Set<String> importsSet = properties.getImports();
Set<String> workspacesSet = properties.getWorkspaces();

return new RepositoryConfig(properties.getProperty(PROPERTY_PATH), properties.getProperty(PROPERTY_WORKING_SETS),
properties.getProperty(PROPERTY_WORKSPACE), properties.getProperty(PROPERTY_GIT_URL, true), properties.getProperty(PROPERTY_GIT_BRANCH),
workspacesSet, properties.getProperty(PROPERTY_GIT_URL, true), properties.getProperty(PROPERTY_GIT_BRANCH),
properties.getProperty(PROPERTY_BUILD_PATH), properties.getProperty(PROPERTY_BUILD_CMD), importsSet,
parseBoolean(properties.getProperty(PROPERTY_ACTIVE).trim()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,19 @@ public Set<String> getImports() {
}
}

/**
* @return the workspaces where to clone the repository. Returns a set containing "main" as default if not specified.
*/
public Set<String> getWorkspaces() {

String workspaceProperty = this.properties.getProperty(RepositoryConfig.PROPERTY_WORKSPACE);
if (workspaceProperty != null) {
if (workspaceProperty.isEmpty()) {
return Set.of(IdeContext.WORKSPACE_MAIN);
}
return Arrays.stream(workspaceProperty.split(",")).map(String::trim).collect(Collectors.toUnmodifiableSet());
}
return Set.of(IdeContext.WORKSPACE_MAIN);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,65 @@ public void testSetupSpecificRepositoryWithForceOption() {
assertThat(this.context).logAtSuccess().hasMessage("Successfully ended step 'Setup of repository test'.");
}

@Test
public void testSetupRepositoryWithMultipleWorkspaces() {

// arrange
String workspace1 = "workspace1";
String workspace2 = "workspace2";
RepositoryCommandlet rc = this.context.getCommandletManager().getCommandlet(RepositoryCommandlet.class);
this.properties.setProperty("workspace", workspace1 + "," + workspace2);
saveProperties();
rc.repository.setValueAsString("test", this.context);

// act
rc.run();

// assert
assertThat(context.getIdeHome().resolve(IdeContext.FOLDER_WORKSPACES).resolve(workspace1).resolve(TEST_REPO)).isDirectory();
assertThat(context.getIdeHome().resolve(IdeContext.FOLDER_WORKSPACES).resolve(workspace2).resolve(TEST_REPO)).isDirectory();
assertThat(this.context).logAtSuccess().hasMessage("Successfully ended step 'Setup of repository test'.");
}

@Test
public void testSetupRepositoryWithMultipleWorkspacesWithSpaces() {

// arrange
String workspace1 = "workspace1";
String workspace2 = "workspace2";
String workspace3 = "workspace3";
RepositoryCommandlet rc = this.context.getCommandletManager().getCommandlet(RepositoryCommandlet.class);
this.properties.setProperty("workspace", workspace1 + " , " + workspace2 + ", " + workspace3);
saveProperties();
rc.repository.setValueAsString("test", this.context);

// act
rc.run();

// assert
assertThat(context.getIdeHome().resolve(IdeContext.FOLDER_WORKSPACES).resolve(workspace1).resolve(TEST_REPO)).isDirectory();
assertThat(context.getIdeHome().resolve(IdeContext.FOLDER_WORKSPACES).resolve(workspace2).resolve(TEST_REPO)).isDirectory();
assertThat(context.getIdeHome().resolve(IdeContext.FOLDER_WORKSPACES).resolve(workspace3).resolve(TEST_REPO)).isDirectory();
assertThat(this.context).logAtSuccess().hasMessage("Successfully ended step 'Setup of repository test'.");
}

@Test
public void testSetupRepositoryWithEmptyWorkspaceDefaultsToMain() {

// arrange
RepositoryCommandlet rc = this.context.getCommandletManager().getCommandlet(RepositoryCommandlet.class);
this.properties.setProperty("workspace", "");
saveProperties();
rc.repository.setValueAsString("test", this.context);

// act
rc.run();

// assert
assertThat(context.getIdeHome().resolve(IdeContext.FOLDER_WORKSPACES).resolve(IdeContext.WORKSPACE_MAIN).resolve(TEST_REPO)).isDirectory();
assertThat(this.context).logAtSuccess().hasMessage("Successfully ended step 'Setup of repository test'.");
}

private void saveProperties() {

FileAccess fileAccess = this.context.getFileAccess();
Expand Down
6 changes: 5 additions & 1 deletion documentation/repository.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ import=eclipse
active=true
```

NOTE: To clone a repository into multiple workspaces, simply provide comma-separated workspace names like `workspace=main,test,feature`.
This will clone the repository into each specified workspace during project setup.

.Variables of repository import
[options="header"]
|===
Expand All @@ -32,7 +35,8 @@ This path is relative to the workspace.
|`working sets`|e.g. `ws1,ws2`|(optional) This will create working sets (in eclipse).
Each module (eclipse project) of this project will be part of all these working sets.
Working sets will be automatically created if necessary.
|`workspace`|`main`|Workspace to use for checkout and import.
|`workspace`|`main`|Workspace(s) to use for checkout and import.
Supports comma-separated values to clone the repository into multiple workspaces (e.g., `main,test,feature`).
Default is `main`.
|`git_url`|e.g. `http://github.com/someorg/someproject`|(required) Git URL to use for cloning the project.
|`git_branch`|e.g. `develop`|(optional) Git branch to checkout.
Expand Down