Skip to content

#1695: Clone settings to temporary directory, analyse, and then move - #1878

Closed
areinicke wants to merge 28 commits into
devonfw:mainfrom
areinicke:feature/1695-clone-settings-to-temp-dir-for-verification
Closed

#1695: Clone settings to temporary directory, analyse, and then move#1878
areinicke wants to merge 28 commits into
devonfw:mainfrom
areinicke:feature/1695-clone-settings-to-temp-dir-for-verification

Conversation

@areinicke

@areinicke areinicke commented Apr 30, 2026

Copy link
Copy Markdown
Contributor

This PR fixes #1695

Implemented changes:

  • When creating a new project, the settings or code repository is first cloned to a temporary location (at $IDE_ROOT/_ide/tmp/projects/<project name>) where it is analyzed for validity. We check whether an ide.properties file exist either at the top level or within a settings folder at the top level. Only if this passes, do we create a new project at $IDE_ROOT/<project name> and move the files from the temporary location to the final location. The temporary folder is fully deleted after this process.
  • Removed the --code option when creating a project. We now automatically determine if the repository is a code or settings repository and act accordingly.

Checklist for this PR

Make sure everything is checked before merging this PR. For further info please also see
our DoD.

  • When running mvn clean test locally all tests pass and build is successful
  • PR title is of the form #«issue-id»: «brief summary» (e.g. #921: fixed setup.bat). If no issue ID exists, title only.
  • PR top-level comment summarizes what has been done and contains link to addressed issue(s)
  • PR and issue(s) have suitable labels
  • Issue is set to In Progress and assigned to you or there is no issue (might happen for very small PRs)
  • You followed all coding conventions
  • You have added the issue implemented by your PR in CHANGELOG.adoc unless issue is labeled
    with internal#

Note: In some places, I used getFileAccess() to copy and subsequently delete files. I am aware that there is a move function. However, this was always failing for some reason

@github-project-automation github-project-automation Bot moved this to 🆕 New in IDEasy board Apr 30, 2026
@areinicke areinicke self-assigned this Apr 30, 2026
@areinicke areinicke moved this from 🆕 New to 🏗 In progress in IDEasy board Apr 30, 2026
@areinicke areinicke added enhancement New feature or request create Create commandlet used to create new IDEasy projects with "ide create" settings ide-settings repo and replated processes and features git git version management tool integration labels Apr 30, 2026
@coveralls

coveralls commented Apr 30, 2026

Copy link
Copy Markdown
Collaborator

Coverage Report for CI Build 28849265105

Coverage decreased (-0.1%) to 71.962%

Details

  • Coverage decreased (-0.1%) from the base build.
  • Patch coverage: No coverable lines changed in this PR.
  • 44 coverage regressions across 4 files.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

44 previously-covered lines in 4 files lost coverage.

File Lines Losing Coverage Coverage
com/devonfw/tools/ide/commandlet/AbstractUpdateCommandlet.java 20 80.54%
com/devonfw/tools/ide/commandlet/CreateCommandlet.java 11 81.01%
com/devonfw/tools/ide/context/IdeContext.java 7 70.63%
com/devonfw/tools/ide/git/GitUrl.java 6 69.49%

Coverage Stats

Coverage Status
Relevant Lines: 16563
Covered Lines: 12418
Line Coverage: 74.97%
Relevant Branches: 7426
Covered Branches: 4845
Branch Coverage: 65.24%
Branches in Coverage %: Yes
Coverage Strength: 3.18 hits per line

💛 - Coveralls

@areinicke
areinicke marked this pull request as ready for review April 30, 2026 10:08
@areinicke areinicke moved this from 🏗 In progress to Team Review in IDEasy board Apr 30, 2026
@laim2003 laim2003 self-assigned this Apr 30, 2026
@laim2003
laim2003 self-requested a review April 30, 2026 10:55
@satorus satorus self-assigned this Apr 30, 2026
Comment thread cli/src/main/java/com/devonfw/tools/ide/commandlet/AbstractUpdateCommandlet.java Outdated
Comment thread cli/src/main/java/com/devonfw/tools/ide/commandlet/AbstractUpdateCommandlet.java Outdated
Comment thread cli/src/main/java/com/devonfw/tools/ide/commandlet/AbstractUpdateCommandlet.java Outdated
Comment thread cli/src/main/java/com/devonfw/tools/ide/commandlet/AbstractUpdateCommandlet.java Outdated
Co-authored-by: Robin Wenzel <robin@die-wenzels.de>
Comment thread cli/src/main/java/com/devonfw/tools/ide/commandlet/AbstractUpdateCommandlet.java Outdated
@areinicke areinicke moved this from Team Review to 👀 In review in IDEasy board Apr 30, 2026
@areinicke
areinicke requested a review from laim2003 May 6, 2026 08:49

@hohwille hohwille left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@areinicke thanks for your PR. Great that you implemented a test for it and finally started improving GitContextMock what I suggested long time ago when GitContextMock was supposed to be implemented. 👍
This is not a very easy task. Seems in such cases it makes sense to start with a design session before doing the complete PR implementation in the future...
However, should still not be a big change since most of your PR is already perfectly correct.

Comment thread cli/src/main/java/com/devonfw/tools/ide/commandlet/AbstractUpdateCommandlet.java Outdated
Comment thread cli/src/main/java/com/devonfw/tools/ide/commandlet/AbstractUpdateCommandlet.java Outdated
Comment thread cli/src/main/java/com/devonfw/tools/ide/commandlet/AbstractUpdateCommandlet.java Outdated
Comment on lines +104 to +107
// Check if instance of create commandlet. Only then will we analyze the project
if (this instanceof CreateCommandlet) {
analyzeProject();
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This design can be improved.
Option 1: you assume that you only need to analyse this when a project is initially created but not when updated.

Then simply override updateSettings() in CreateCommandlet and call analyseProject() after super.updateSettings(). Then only CreateCommandlet knows of analyseProject() (SoC).

Option 2: you need to analyse whenever you need to clone the settings.

Then this code is wrong since you skip this in case of UpdateCommandlet.
In such case you would need to do this after the cloning of the settings.

IMHO the option to ask for the settings in case of ide update is a kind of auto-repair feature of IDEasy.
Therefore ide update should behave also in the same way that it detects if we cloned an regular settings repo or a code repo with settings included.
But to get all this clean, we might need to revisit the design how create and update try to reuse the existing code/methods from AbstractUpdateCommandlet.
IMHO it would be better to do this on create:

  • prepare a temp folder
  • trigger the reusable functionality that clones the settings into a given project folder where here we provide the temporary folder. If it detected a code repo, it can move the settings to main workspace and proper folder name from the GitUrl and create the symlink to preserve a proper settings folder in the projects root dir.
  • if that fails (neither regular settings repo nor code repo with settings found) we cleanup and abort.
  • if that succeeded we can move the temp folder to the real project folder and continue with the regular logic where we re-initialize the IdeContext on the real project and do the full create/update process.

In case of ide update we can keep everything as is and reuse the same functionality described above in the 2nd point.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This point is still not addressed. The developer taking over this PR should keep the project renaming (move) locally inside the CreateCommandlet and not do this in this class that then makes assumptions about very specific implementation details of CreateCommandlet that do not make any sense for UpdateCommandlet that also extends from this class.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then simply override updateSettings() in CreateCommandlet and call analyseProject() after super.updateSettings(). Then only CreateCommandlet knows of analyseProject() (SoC).

From what I can tell this point has already been implemented. Regarding the other points i'm still looking into it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, Option 1 has already been implemented by @areinicke

Comment thread cli/src/main/java/com/devonfw/tools/ide/commandlet/AbstractUpdateCommandlet.java Outdated
Comment thread cli/src/main/java/com/devonfw/tools/ide/commandlet/AbstractUpdateCommandlet.java Outdated
Comment thread cli/src/main/java/com/devonfw/tools/ide/commandlet/AbstractUpdateCommandlet.java Outdated
Comment on lines +154 to +157
// 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.");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dont delete the entire project.
You can either delete the settings here or IMHO even better would be to just return failure (e.g. false while otherwise true is returned for success) and let the calling logic handle the cleanup so in case of ide update we can just delete the settings and in case of ide create we can delete the temp project.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only deletes the temporary location if the verification fails. Why shouldn't that one be deleted if it is invalid anyway?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. this.context.getIdeHome() usually gives me my project home e.g. ~/projects/IDEasy.
  2. This code is used for ide create and for ide update. You are assuming that this will refer to some temporary directory since you are thinking of your changes in ide create but for ide update your assumption is wrong.
  3. If the project become "invalid" this can have many reasons. Maybe by accident the user deleted some file or folder. fileAccess.delete is a destructive operation. If you as a user will run into the situation that your entire ~/projects/IDEasy folder gets deleted and all your uncomitted work is gone because IDEasy due to some mistake thought that something is "invalid" you might not like the result ;)

Believe me - we already had all such situations and I do not want to go there again.
If we "delete" user content like entire IDE projects or workspaces and we have a real reason to do so, we should use fileAccess.backup since then the data is still there and the user could somehow recover his work in case of an accident.
However, I am still convinced that this is wrong. Keep your clenup of temporary directory only in CreateCommandlet where you created it and can ensure you do not cause severe harm.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This recommendation has also already been implemented

Comment thread cli/src/main/java/com/devonfw/tools/ide/commandlet/CreateCommandlet.java Outdated
@areinicke areinicke moved this from 👀 In review to 🏗 In progress in IDEasy board May 27, 2026
@hohwille hohwille moved this from 🏗 In progress to 👀 In review in IDEasy board Jun 18, 2026
Comment on lines +109 to +110


Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change


String newProjectName = this.newProject.getValue();
Path newProjectPath = this.context.getIdeRoot().resolve(newProjectName);
Path tempProjectPath = this.context.getIdeRoot().resolve("_ide/tmp/projects").resolve(newProjectName);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Path tempProjectPath = this.context.getIdeRoot().resolve("_ide/tmp/projects").resolve(newProjectName);
Path tempProjectPath = this.context.getTempPath().resolve(IdeContext.FOLDER_PROJECTS).resolve(newProjectName);

Path tempProjectPath = this.context.getIdeRoot().resolve("_ide/tmp/projects").resolve(newProjectName);

LOG.info("Creating new IDEasy project in {}", newProjectPath);
if (!this.context.getFileAccess().isEmptyDir(newProjectPath)) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO we should also check the final target project folder for existence.
If we call ide create IDEasy - but $IDE_ROOT/IDEasy already exists, do we want to create a new IDEasy project in tmp folder and then populate everything in order to then fail when we want to move the project?
If the target project already exists, we should not create at all and fail. The user can then call ide update on the target project or he can do rm -rf «project» if the project is totally broken and he wants to recreate it.

// assert
Path newProjectPath = context.getIdeRoot().resolve(NEW_PROJECT_NAME);
assertThat(newProjectPath).doesNotExist();
assertThat(context.getIdeRoot().resolve("_ide/tmp/projects").resolve(NEW_PROJECT_NAME)).doesNotExist();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
assertThat(context.getIdeRoot().resolve("_ide/tmp/projects").resolve(NEW_PROJECT_NAME)).doesNotExist();
assertThat(context.getTempPath().resolve(IdeContext.FOLDER_PROJECTS).resolve(NEW_PROJECT_NAME)).doesNotExist();

@hohwille

Copy link
Copy Markdown
Member

@laim2003 what is the state of this? Can you finally complete this PR or hand it over to someone else completing it.
This PR was created 1/4 year ago and it should be completed and finally merged.

@laim2003 laim2003 moved this from 👀 In review to 🏗 In progress in IDEasy board Jul 31, 2026
laim2003 added a commit to laim2003/IDEasy that referenced this pull request Aug 3, 2026
@laim2003

laim2003 commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

The new PR implementing these changes can be found under: #2249

@laim2003 laim2003 closed this Aug 3, 2026
@github-project-automation github-project-automation Bot moved this from 🏗 In progress to ✅ Done in IDEasy board Aug 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

create Create commandlet used to create new IDEasy projects with "ide create" enhancement New feature or request git git version management tool integration settings ide-settings repo and replated processes and features

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

Clone settings to temporary directory, analyse, and then move

5 participants