• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

devonfw / IDEasy / 15922744112

27 Jun 2025 09:15AM UTC coverage: 68.593% (+0.3%) from 68.252%
15922744112

Pull #1375

github

web-flow
Merge edf7289bc into 7cf498bd7
Pull Request #1375: #742: Show warning when git repo name does not meet name convention.

3279 of 5190 branches covered (63.18%)

Branch coverage included in aggregate %.

8362 of 11781 relevant lines covered (70.98%)

3.14 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.37
cli/src/main/java/com/devonfw/tools/ide/commandlet/CreateCommandlet.java
1
package com.devonfw.tools.ide.commandlet;
2

3
import java.nio.file.Files;
4
import java.nio.file.Path;
5
import java.util.function.Predicate;
6

7
import com.devonfw.tools.ide.context.IdeContext;
8
import com.devonfw.tools.ide.git.GitContext;
9
import com.devonfw.tools.ide.git.GitUrl;
10
import com.devonfw.tools.ide.io.FileAccess;
11
import com.devonfw.tools.ide.property.FlagProperty;
12
import com.devonfw.tools.ide.property.StringProperty;
13
import com.devonfw.tools.ide.step.Step;
14
import com.devonfw.tools.ide.version.IdeVersion;
15

16
/**
17
 * {@link Commandlet} to create a new IDEasy instance
18
 */
19
public class CreateCommandlet extends AbstractUpdateCommandlet {
20

21
  /** {@link StringProperty} for the name of the new project */
22
  public final StringProperty newProject;
23

24
  /** {@link FlagProperty} for creating a project with settings inside a code repository */
25
  public final FlagProperty codeRepositoryFlag;
26

27
  /**
28
   * The constructor.
29
   *
30
   * @param context the {@link IdeContext}.
31
   */
32
  public CreateCommandlet(IdeContext context) {
33

34
    super(context);
3✔
35
    this.newProject = add(new StringProperty("", true, "project"));
11✔
36
    this.codeRepositoryFlag = add(new FlagProperty("--code"));
9✔
37
    add(this.settingsRepo);
5✔
38
  }
1✔
39

40
  @Override
41
  public String getName() {
42

43
    return "create";
2✔
44
  }
45

46
  @Override
47
  public boolean isIdeHomeRequired() {
48

49
    return false;
2✔
50
  }
51

52
  @Override
53
  public void run() {
54

55
    String newProjectName = this.newProject.getValue();
5✔
56
    Path newProjectPath = this.context.getIdeRoot().resolve(newProjectName);
6✔
57

58
    this.context.info("Creating new IDEasy project in {}", newProjectPath);
10✔
59
    if (!this.context.getFileAccess().isEmptyDir(newProjectPath)) {
6!
60
      this.context.askToContinue("Directory " + newProjectPath + " already exists. Do you want to continue?");
×
61
    } else {
62
      this.context.getFileAccess().mkdirs(newProjectPath);
5✔
63
    }
64

65
    initializeProject(newProjectPath);
3✔
66
    this.context.setIdeHome(newProjectPath);
4✔
67
    this.context.verifyIdeMinVersion(true);
4✔
68
    super.run();
2✔
69
    this.context.verifyIdeMinVersion(true);
4✔
70
    this.context.getFileAccess().writeFileContent(IdeVersion.getVersionString(), newProjectPath.resolve(IdeContext.FILE_SOFTWARE_VERSION));
8✔
71
    this.context.success("Successfully created new project '{}'.", newProjectName);
10✔
72

73
    logWelcomeMessage(newProjectPath);
3✔
74
  }
1✔
75

76
  private void initializeProject(Path newInstancePath) {
77

78
    FileAccess fileAccess = this.context.getFileAccess();
4✔
79
    fileAccess.mkdirs(newInstancePath.resolve(IdeContext.FOLDER_SOFTWARE));
5✔
80
    fileAccess.mkdirs(newInstancePath.resolve(IdeContext.FOLDER_PLUGINS));
5✔
81
    fileAccess.mkdirs(newInstancePath.resolve(IdeContext.FOLDER_WORKSPACES).resolve(IdeContext.WORKSPACE_MAIN));
7✔
82
  }
1✔
83

84
  /**
85
   * Handles cases for settings and code repository during creation.
86
   */
87
  @Override
88
  protected void processRepository() {
89
    RepositoryStrategy repositoryStrategy = new SettingsRepositoryStrategy();
4✔
90
    if (isCodeRepository()) {
3✔
91
      repositoryStrategy = new CodeRepositoryStrategy();
4✔
92
    }
93

94
    processRepositoryUsingStrategy(repositoryStrategy);
3✔
95
  }
1✔
96

97
  private void processRepositoryUsingStrategy(RepositoryStrategy strategy) {
98
    Step step = strategy.createNewStep(this.context);
5✔
99
    String repository = this.settingsRepo.getValue();
5✔
100
    if (repository == null || repository.isBlank()) {
5!
101
      repository = strategy.handleBlankRepository(this.context);
×
102
    }
103
    if ("-".equals(repository)) {
4✔
104
      repository = IdeContext.DEFAULT_SETTINGS_REPO_URL;
2✔
105
    }
106
    GitUrl gitUrl = GitUrl.of(repository);
3✔
107
    strategy.checkProjectNameConvention(this.context, gitUrl.getProjectName());
6✔
108
    strategy.initializeRepository(this.context, gitUrl);
5✔
109
    strategy.resolveStep(step);
3✔
110
  }
1✔
111

112
  /**
113
   * Strategy for handling repository.
114
   */
115
  interface RepositoryStrategy {
116

117
    /**
118
     * Handler for blank repository, displays warning and asks for input of repository URL.
119
     *
120
     * @param context ide context
121
     * @return repository url from user input
122
     */
123
    String handleBlankRepository(IdeContext context);
124

125
    /**
126
     * Check the given project name, displays warning when name does not meet convention.
127
     *
128
     * @param context ide context
129
     * @param projectName the project name of repository
130
     */
131
    void checkProjectNameConvention(IdeContext context, String projectName);
132

133
    /**
134
     * Initialize the given Git repository.
135
     *
136
     * @param context ide context
137
     * @param gitUrl URL of the git repository
138
     */
139
    void initializeRepository(IdeContext context, GitUrl gitUrl);
140

141
    /**
142
     * Create a new commandlet step.
143
     *
144
     * @param context ide context
145
     * @return the created new commandlet Step
146
     */
147
    Step createNewStep(IdeContext context);
148

149
    /**
150
     * Resolve the given commandlet step.
151
     *
152
     * @param step to resolve
153
     */
154
    void resolveStep(Step step);
155
  }
156

157
  /**
158
   * Strategy implementation for code repository.
159
   */
160
  static class CodeRepositoryStrategy implements RepositoryStrategy {
3✔
161

162
    @Override
163
    public String handleBlankRepository(IdeContext context) {
164
      String message = """
×
165
          No code repository was given after '--code'.
166
          Please give the code repository below that includes your settings folder.
167
          Further details can be found here: https://github.com/devonfw/IDEasy/blob/main/documentation/settings.adoc
168
          Code repository URL:
169
          """;
170
      return context.askForInput(message);
×
171
    }
172

173
    @Override
174
    public void checkProjectNameConvention(IdeContext context, String projectName) {
175
      if (projectName.contains(IdeContext.SETTINGS_REPOSITORY_KEYWORD)) {
4!
176
        String warningTemplate = """
2✔
177
            Your git URL is pointing to the project name {} that contains the keyword '{}'.
178
            Therefore we assume that you did a mistake by adding the '--code' option to the ide project creation.
179
            Do you really want to create the project?
180
            """;
181
        context.askToContinue(warningTemplate, projectName, IdeContext.SETTINGS_REPOSITORY_KEYWORD);
13✔
182
      }
183
    }
1✔
184

185
    @Override
186
    public void initializeRepository(IdeContext context, GitUrl gitUrl) {
187
      // clone the given repository into IDE_HOME/workspaces/main
188
      Path codeRepoPath = context.getWorkspacePath().resolve(gitUrl.getProjectName());
6✔
189
      context.getGitContext().pullOrClone(gitUrl, codeRepoPath);
5✔
190

191
      // check for settings folder and create symlink to IDE_HOME/settings
192
      Path settingsFolder = codeRepoPath.resolve(IdeContext.FOLDER_SETTINGS);
4✔
193
      if (Files.exists(settingsFolder)) {
5!
194
        context.getFileAccess().symlink(settingsFolder, context.getSettingsPath());
×
195
        // create a file in IDE_HOME with the current local commit id
196
        context.getGitContext().saveCurrentCommitId(codeRepoPath, context.getSettingsCommitIdPath());
×
197
      } else {
198
        context.warning("No settings folder was found inside the code repository.");
3✔
199
      }
200
    }
1✔
201

202
    @Override
203
    public Step createNewStep(IdeContext context) {
204
      return context.newStep("Clone code repository");
4✔
205
    }
206

207
    @Override
208
    public void resolveStep(Step step) {
209
      step.success("Successfully updated code repository.");
3✔
210
    }
1✔
211
  }
212

213
  /**
214
   * Strategy implementation for settings repository.
215
   */
216
  static class SettingsRepositoryStrategy implements RepositoryStrategy {
3✔
217

218
    @Override
219
    public String handleBlankRepository(IdeContext context) {
220
      Path settingsPath = context.getSettingsPath();
×
221
      String message = "Missing your settings at " + settingsPath + " and no SETTINGS_URL is defined.\n"
×
222
          + "Further details can be found here: https://github.com/devonfw/IDEasy/blob/main/documentation/settings.adoc\n"
223
          + "Please contact the technical lead of your project to get the SETTINGS_URL for your project.\n"
224
          + "In case you just want to test IDEasy you may simply hit return to install the default settings.\n" + "Settings URL ["
225
          + IdeContext.DEFAULT_SETTINGS_REPO_URL + "]:";
226
      return context.askForInput(message, IdeContext.DEFAULT_SETTINGS_REPO_URL);
×
227
    }
228

229
    @Override
230
    public void checkProjectNameConvention(IdeContext context, String projectName) {
231
      if (!projectName.contains(IdeContext.SETTINGS_REPOSITORY_KEYWORD)) {
4✔
232
        String warningTemplate = """
2✔
233
            Your git URL is pointing to the project name {} that does not contain the keyword ''{}''.
234
            Therefore we assume that you forgot to add the '--code' option to the ide project creation.
235
            Do you really want to create the project?
236
            """;
237
        context.askToContinue(warningTemplate, projectName, IdeContext.SETTINGS_REPOSITORY_KEYWORD);
13✔
238
      }
239
    }
1✔
240

241
    @Override
242
    public void initializeRepository(IdeContext context, GitUrl gitUrl) {
243
      Path settingsPath = context.getSettingsPath();
3✔
244
      GitContext gitContext = context.getGitContext();
3✔
245
      gitContext.pullOrClone(gitUrl, settingsPath);
4✔
246
      context.getGitContext().saveCurrentCommitId(settingsPath, context.getSettingsCommitIdPath());
6✔
247
    }
1✔
248

249
    @Override
250
    public Step createNewStep(IdeContext context) {
251
      return context.newStep("Clone settings repository");
4✔
252
    }
253

254
    @Override
255
    public void resolveStep(Step step) {
256
      step.success("Successfully updated settings repository.");
3✔
257
    }
1✔
258
  }
259

260
  @Override
261
  protected boolean isCodeRepository() {
262
    return this.codeRepositoryFlag.isTrue();
4✔
263
  }
264

265
  private void logWelcomeMessage(Path newProjectPath) {
266
    GitUrl gitUrl = GitUrl.of(newProjectPath.toString());
4✔
267
    Path codeRepoPath = this.context.getWorkspacePath().resolve(gitUrl.getProjectName());
7✔
268
    Path settingsFolder = codeRepoPath.resolve(IdeContext.FOLDER_SETTINGS);
4✔
269
    if (Files.exists(settingsFolder)) {
5!
270
      Predicate<Path> welcomePredicate = path -> String.valueOf(path.getFileName()).startsWith("welcome.");
×
271
      Path welcomeFilePath = this.context.getFileAccess().findFirst(settingsFolder, welcomePredicate, false);
×
272
      if (welcomeFilePath != null) {
×
273
        this.context.info(this.context.getFileAccess().readFileContent(welcomeFilePath));
×
274
      }
275
    }
276
  }
1✔
277
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc