Skip to content

Commit 3ddcdd7

Browse files
authored
#650: various improvements (git, processContext, step success) (#645)
1 parent a5d7bd3 commit 3ddcdd7

File tree

11 files changed

+115
-118
lines changed

11 files changed

+115
-118
lines changed

CHANGELOG.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Release with new features and bugfixes:
2222
* https://github.com/devonfw/IDEasy/issues/612[#612]: Automatically generated issue URL is still pointing to ide instead of IDEasy
2323
* https://github.com/devonfw/IDEasy/issues/52[#52]: Adjusting Intellij settings in ide-settings
2424
* https://github.com/devonfw/IDEasy/issues/588[#588]: ide create installs wrong Java version
25+
* https://github.com/devonfw/IDEasy/issues/650[#650]: Improve default success message of step
2526

2627
The full list of changes for this release can be found in https://github.com/devonfw/IDEasy/milestone/13?closed=1[milestone 2024.09.002].
2728

cli/src/main/java/com/devonfw/tools/ide/context/AbstractIdeContext.java

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ public abstract class AbstractIdeContext implements IdeContext {
122122

123123
private StepImpl currentStep;
124124

125+
private Boolean online;
126+
125127
/**
126128
* The constructor.
127129
*
@@ -544,20 +546,22 @@ public boolean isOfflineMode() {
544546
@Override
545547
public boolean isOnline() {
546548

547-
boolean online = false;
548-
try {
549-
int timeout = 1000;
550-
//open a connection to github.com and try to retrieve data
551-
//getContent fails if there is no connection
552-
URLConnection connection = new URL("https://www.github.com").openConnection();
553-
connection.setConnectTimeout(timeout);
554-
connection.getContent();
555-
online = true;
556-
557-
} catch (Exception ignored) {
558-
549+
if (this.online == null) {
550+
// we currently assume we have only a CLI process that runs shortly
551+
// therefore we run this check only once to save resources when this method is called many times
552+
try {
553+
int timeout = 1000;
554+
//open a connection to github.com and try to retrieve data
555+
//getContent fails if there is no connection
556+
URLConnection connection = new URL("https://www.github.com").openConnection();
557+
connection.setConnectTimeout(timeout);
558+
connection.getContent();
559+
this.online = Boolean.TRUE;
560+
} catch (Exception ignored) {
561+
this.online = Boolean.FALSE;
562+
}
559563
}
560-
return online;
564+
return this.online.booleanValue();
561565
}
562566

563567
@Override

cli/src/main/java/com/devonfw/tools/ide/context/GitContext.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,4 +203,16 @@ default void reset(Path targetRepository, String branch) {
203203
*/
204204
String retrieveGitUrl(Path repository);
205205

206+
/**
207+
* @param repository the {@link Path} to the folder where the git repository is located.
208+
* @return the name of the current branch.
209+
*/
210+
String determineCurrentBranch(Path repository);
211+
212+
/**
213+
* @param repository the {@link Path} to the folder where the git repository is located.
214+
* @return the name of the default origin.
215+
*/
216+
String determineRemote(Path repository);
217+
206218
}

cli/src/main/java/com/devonfw/tools/ide/context/GitContextImpl.java

Lines changed: 56 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,8 @@
33
import java.net.URL;
44
import java.nio.file.Files;
55
import java.nio.file.Path;
6-
import java.util.AbstractMap;
7-
import java.util.HashMap;
86
import java.util.List;
9-
import java.util.Map;
107
import java.util.Objects;
11-
import java.util.Optional;
128

139
import com.devonfw.tools.ide.cli.CliOfflineException;
1410
import com.devonfw.tools.ide.process.ProcessContext;
@@ -34,7 +30,7 @@ public class GitContextImpl implements GitContext {
3430
public GitContextImpl(IdeContext context) {
3531

3632
this.context = context;
37-
this.processContext = this.context.newProcess().executable("git").withEnvVar("GIT_TERMINAL_PROMPT", "0");
33+
this.processContext = this.context.newProcess().executable("git").withEnvVar("GIT_TERMINAL_PROMPT", "0").errorHandling(ProcessErrorHandling.WARNING);
3834
}
3935

4036
@Override
@@ -56,74 +52,60 @@ public boolean fetchIfNeeded(Path targetRepository, String remote, String branch
5652
}
5753

5854
@Override
59-
public boolean isRepositoryUpdateAvailable(Path targetRepository) {
55+
public boolean isRepositoryUpdateAvailable(Path repository) {
6056

61-
this.processContext.directory(targetRepository);
62-
ProcessResult result;
63-
64-
// get local commit code
65-
result = this.processContext.addArg("rev-parse").addArg("HEAD").run(PROCESS_MODE_FOR_FETCH);
57+
ProcessResult result = this.processContext.directory(repository).addArg("rev-parse").addArg("HEAD").run(PROCESS_MODE_FOR_FETCH);
6658
if (!result.isSuccessful()) {
6759
this.context.warning("Failed to get the local commit hash.");
6860
return false;
6961
}
70-
71-
String local_commit_code = result.getOut().stream().findFirst().orElse("").trim();
72-
62+
String localCommitHash = result.getOut().stream().findFirst().orElse("").trim();
7363
// get remote commit code
7464
result = this.processContext.addArg("rev-parse").addArg("@{u}").run(PROCESS_MODE_FOR_FETCH);
7565
if (!result.isSuccessful()) {
7666
this.context.warning("Failed to get the remote commit hash.");
7767
return false;
7868
}
7969
String remote_commit_code = result.getOut().stream().findFirst().orElse("").trim();
80-
return !local_commit_code.equals(remote_commit_code);
70+
return !localCommitHash.equals(remote_commit_code);
8171
}
8272

8373
@Override
84-
public void pullOrCloneAndResetIfNeeded(String repoUrl, Path targetRepository, String branch, String remoteName) {
74+
public void pullOrCloneAndResetIfNeeded(String repoUrl, Path repository, String branch, String remoteName) {
8575

86-
pullOrCloneIfNeeded(repoUrl, branch, targetRepository);
76+
pullOrCloneIfNeeded(repoUrl, branch, repository);
8777

88-
reset(targetRepository, "master", remoteName);
78+
reset(repository, "master", remoteName);
8979

90-
cleanup(targetRepository);
80+
cleanup(repository);
9181
}
9282

9383
@Override
94-
public void pullOrClone(String gitRepoUrl, Path targetRepository) {
84+
public void pullOrClone(String gitRepoUrl, Path repository) {
9585

96-
pullOrClone(gitRepoUrl, targetRepository, null);
86+
pullOrClone(gitRepoUrl, repository, null);
9787
}
9888

9989
@Override
100-
public void pullOrClone(String gitRepoUrl, Path targetRepository, String branch) {
90+
public void pullOrClone(String gitRepoUrl, Path repository, String branch) {
10191

102-
Objects.requireNonNull(targetRepository);
92+
Objects.requireNonNull(repository);
10393
Objects.requireNonNull(gitRepoUrl);
104-
10594
if (!gitRepoUrl.startsWith("http")) {
10695
throw new IllegalArgumentException("Invalid git URL '" + gitRepoUrl + "'!");
10796
}
108-
109-
if (Files.isDirectory(targetRepository.resolve(GIT_FOLDER))) {
97+
if (Files.isDirectory(repository.resolve(GIT_FOLDER))) {
11098
// checks for remotes
111-
this.processContext.directory(targetRepository);
112-
ProcessResult result = this.processContext.addArg("remote").run(ProcessMode.DEFAULT_CAPTURE);
113-
List<String> remotes = result.getOut();
114-
if (remotes.isEmpty()) {
115-
String message = targetRepository + " is a local git repository with no remote - if you did this for testing, you may continue...\n"
99+
String remote = determineRemote(repository);
100+
if (remote == null) {
101+
String message = repository + " is a local git repository with no remote - if you did this for testing, you may continue...\n"
116102
+ "Do you want to ignore the problem and continue anyhow?";
117103
this.context.askToContinue(message);
118104
} else {
119-
this.processContext.errorHandling(ProcessErrorHandling.WARNING);
120-
121-
if (!this.context.isOffline()) {
122-
pull(targetRepository);
123-
}
105+
pull(repository);
124106
}
125107
} else {
126-
clone(new GitUrl(gitRepoUrl, branch), targetRepository);
108+
clone(new GitUrl(gitRepoUrl, branch), repository);
127109
}
128110
}
129111

@@ -185,89 +167,66 @@ public void clone(GitUrl gitRepoUrl, Path targetRepository) {
185167
}
186168

187169
@Override
188-
public void pull(Path targetRepository) {
189-
190-
this.processContext.directory(targetRepository);
191-
ProcessResult result;
192-
// pull from remote
193-
result = this.processContext.addArg("--no-pager").addArg("pull").addArg("--quiet").run(PROCESS_MODE);
170+
public void pull(Path repository) {
194171

172+
if (this.context.isOffline()) {
173+
this.context.info("Skipping git pull on {} because offline", repository);
174+
return;
175+
}
176+
ProcessResult result = this.processContext.directory(repository).addArg("--no-pager").addArg("pull").addArg("--quiet").run(PROCESS_MODE);
195177
if (!result.isSuccessful()) {
196-
Map<String, String> remoteAndBranchName = retrieveRemoteAndBranchName();
197-
this.context.warning("Git pull for {}/{} failed for repository {}.", remoteAndBranchName.get("remote"), remoteAndBranchName.get("branch"),
198-
targetRepository);
199-
handleErrors(targetRepository, result);
178+
String branchName = determineCurrentBranch(repository);
179+
this.context.warning("Git pull on branch {} failed for repository {}.", branchName, repository);
180+
handleErrors(repository, result);
200181
}
201182
}
202183

203184
@Override
204185
public void fetch(Path targetRepository, String remote, String branch) {
205186

206-
if ((remote == null) || (branch == null)) {
207-
Optional<String[]> remoteAndBranchOpt = getLocalRemoteAndBranch(targetRepository);
208-
if (remoteAndBranchOpt.isEmpty()) {
209-
context.warning("Could not determine the remote or branch for the git repository at {}", targetRepository);
210-
return; // false;
211-
}
212-
String[] remoteAndBranch = remoteAndBranchOpt.get();
213-
if (remote == null) {
214-
remote = remoteAndBranch[0];
215-
}
216-
if (branch == null) {
217-
branch = remoteAndBranch[1];
218-
}
187+
if (branch == null) {
188+
branch = determineCurrentBranch(targetRepository);
219189
}
220-
221-
this.processContext.directory(targetRepository);
222-
ProcessResult result;
223-
224-
result = this.processContext.addArg("fetch").addArg(remote).addArg(branch).run(PROCESS_MODE_FOR_FETCH);
190+
if (remote == null) {
191+
remote = determineRemote(targetRepository);
192+
}
193+
ProcessResult result = this.processContext.directory(targetRepository).addArg("fetch").addArg(remote).addArg(branch).run(PROCESS_MODE_FOR_FETCH);
225194

226195
if (!result.isSuccessful()) {
227196
this.context.warning("Git fetch for '{}/{} failed.'.", remote, branch);
228197
}
229198
}
230199

231-
private Map<String, String> retrieveRemoteAndBranchName() {
232-
233-
Map<String, String> remoteAndBranchName = new HashMap<>();
234-
ProcessResult remoteResult = this.processContext.addArg("branch").addArg("-vv").run(PROCESS_MODE);
235-
List<String> remotes = remoteResult.getOut();
236-
if (!remotes.isEmpty()) {
237-
for (String remote : remotes) {
238-
if (remote.startsWith("*")) {
239-
String checkedOutBranch = remote.substring(remote.indexOf("[") + 1, remote.indexOf("]"));
240-
remoteAndBranchName.put("remote", checkedOutBranch.substring(0, checkedOutBranch.indexOf("/")));
241-
// check if current repo is behind remote and omit message
242-
if (checkedOutBranch.contains(":")) {
243-
remoteAndBranchName.put("branch", checkedOutBranch.substring(checkedOutBranch.indexOf("/") + 1, checkedOutBranch.indexOf(":")));
244-
} else {
245-
remoteAndBranchName.put("branch", checkedOutBranch.substring(checkedOutBranch.indexOf("/") + 1));
246-
}
247-
248-
}
200+
@Override
201+
public String determineCurrentBranch(Path repository) {
202+
203+
ProcessResult remoteResult = this.processContext.directory(repository).addArg("branch").addArg("--show-current").run(ProcessMode.DEFAULT_CAPTURE);
204+
if (remoteResult.isSuccessful()) {
205+
List<String> remotes = remoteResult.getOut();
206+
if (!remotes.isEmpty()) {
207+
assert (remotes.size() == 1);
208+
return remotes.get(0);
249209
}
250210
} else {
251-
return Map.ofEntries(new AbstractMap.SimpleEntry<>("remote", "unknown"), new AbstractMap.SimpleEntry<>("branch", "unknown"));
211+
this.context.warning("Failed to determine current branch of git repository {}", repository);
252212
}
253-
254-
return remoteAndBranchName;
213+
return null;
255214
}
256215

257-
private Optional<String[]> getLocalRemoteAndBranch(Path repositoryPath) {
258-
259-
this.processContext.directory(repositoryPath);
260-
ProcessResult result = this.processContext.addArg("rev-parse").addArg("--abbrev-ref").addArg("--symbolic-full-name").addArg("@{u}")
261-
.run(PROCESS_MODE_FOR_FETCH);
262-
if (result.isSuccessful()) {
263-
String upstream = result.getOut().stream().findFirst().orElse("");
264-
if (upstream.contains("/")) {
265-
return Optional.of(upstream.split("/", 2)); // Split into remote and branch
216+
@Override
217+
public String determineRemote(Path repository) {
218+
219+
ProcessResult remoteResult = this.processContext.directory(repository).addArg("remote").run(ProcessMode.DEFAULT_CAPTURE);
220+
if (remoteResult.isSuccessful()) {
221+
List<String> remotes = remoteResult.getOut();
222+
if (!remotes.isEmpty()) {
223+
assert (remotes.size() == 1);
224+
return remotes.get(0);
266225
}
267226
} else {
268-
this.context.warning("Failed to determine the remote tracking branch.");
227+
this.context.warning("Failed to determine current origin of git repository {}", repository);
269228
}
270-
return Optional.empty();
229+
return null;
271230
}
272231

273232
@Override

cli/src/main/java/com/devonfw/tools/ide/process/ProcessResultImpl.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.devonfw.tools.ide.process;
22

3+
import java.util.Collections;
34
import java.util.List;
45

56
/**
@@ -24,8 +25,16 @@ public ProcessResultImpl(int exitCode, List<String> out, List<String> err) {
2425

2526
super();
2627
this.exitCode = exitCode;
27-
this.out = out;
28-
this.err = err;
28+
if (out == null) {
29+
this.out = Collections.emptyList();
30+
} else {
31+
this.out = out;
32+
}
33+
if (err == null) {
34+
this.err = Collections.emptyList();
35+
} else {
36+
this.err = err;
37+
}
2938
}
3039

3140
@Override

cli/src/main/java/com/devonfw/tools/ide/step/StepImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ private void end(Boolean newSuccess, Throwable error, boolean suppress, String m
156156
if (message != null) {
157157
this.context.success(message, args);
158158
} else if (!this.silent) {
159-
this.context.success(this.name);
159+
this.context.success("Successfully ended step '{}'.", this.name);
160160
}
161161
this.context.debug("Step '{}' ended successfully.", this.name);
162162
} else {

cli/src/test/java/com/devonfw/tools/ide/commandlet/UpdateCommandletTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,6 @@ public void testRunUpdateSoftwareDoesNotFailOnFailedSoftwareInstallations() {
8080
assertThat(context).logAtError().hasMessage("Installation of java failed!");
8181
assertThat(context).logAtError().hasMessage("Installation of mvn failed!");
8282
assertThat(context).logAtSuccess().hasMessage("Successfully updated settings repository.");
83-
assertThat(context).logAtSuccess().hasMessage("Install or update software");
83+
assertThat(context).logAtSuccess().hasMessageContaining("Install or update software");
8484
}
8585
}

cli/src/test/java/com/devonfw/tools/ide/context/GitContextMock.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,16 @@ public boolean isRepositoryUpdateAvailable(Path targetRepository) {
7777

7878
return false;
7979
}
80+
81+
@Override
82+
public String determineCurrentBranch(Path repository) {
83+
84+
return "main";
85+
}
86+
87+
@Override
88+
public String determineRemote(Path repository) {
89+
90+
return "origin";
91+
}
8092
}

cli/src/test/java/com/devonfw/tools/ide/process/ProcessContextImplTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,8 @@ public void enablingBackgroundProcessShouldNotBeAwaitedAndShouldNotPassStreams(P
168168

169169
verify(this.processMock, never()).waitFor();
170170

171-
assertThat(result.getOut()).isNull();
172-
assertThat(result.getErr()).isNull();
171+
assertThat(result.getOut()).isEmpty();
172+
assertThat(result.getErr()).isEmpty();
173173

174174
}
175175

cli/src/test/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudioTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ private void checkInstallation(IdeTestContext context) {
8181
// commandlet - android-studio
8282
assertThat(context.getSoftwarePath().resolve("android-studio/.ide.software.version")).exists().hasContent("2024.1.1.1");
8383
assertThat(context).logAtSuccess().hasMessage("Successfully installed android-studio in version 2024.1.1.1");
84-
assertThat(context).logAtSuccess().hasMessage("Install plugin: mockedPlugin");
84+
assertThat(context).logAtSuccess().hasMessageContaining("Install plugin: mockedPlugin");
8585
assertThat(context.getPluginsPath().resolve("android-studio").resolve("mockedPlugin").resolve("MockedClass.class")).exists();
8686
}
8787

0 commit comments

Comments
 (0)