Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#786: Upgrade commandlet #957

Open
wants to merge 20 commits into
base: main
Choose a base branch
from

Conversation

salimbouch
Copy link
Contributor

fixes #786

@salimbouch salimbouch self-assigned this Jan 21, 2025
@salimbouch salimbouch marked this pull request as ready for review January 21, 2025 10:58
}

// hardcoding the file extension seems wrong
String fileName = artifactId + "-" + version + "-" + classifier + ".tar.gz";
Copy link
Contributor Author

Choose a reason for hiding this comment

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

right now just hardcoding the file extension, that means this doesnt work for every maven artifact

Copy link
Member

Choose a reason for hiding this comment

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

Simply add an extra parameter for the extension - it should default to .jar.

Copy link
Contributor Author

@salimbouch salimbouch Jan 22, 2025

Choose a reason for hiding this comment

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

Since this method isn't an API (this method is only being used by the method download, which retrieves the download link and downloads the tool), I added a param for extension and a param for a classifier to the download method, so that when we want to download a tool and want to provide an extension and a classifier, we can do that directly through the download method. This caused a couple more changes to the upper hierarchy.

Comment on lines +10 to +21
public void testSnapshotVersionComparisons() {

IdeTestContext context = newContext(PROJECT_BASIC);
UpgradeCommandlet uc = context.getCommandletManager().getCommandlet(UpgradeCommandlet.class);

assertThat(uc.isSnapshotNewer("2024.12.002-beta-12_18_02-SNAPSHOT", "2025.01.001-beta-20250118.022832-8")).isTrue();
assertThat(uc.isSnapshotNewer("2024.12.002-beta-01_01_02-SNAPSHOT", "2024.12.002-beta-20241218.023429-8")).isTrue();
assertThat(
uc.isSnapshotNewer("2024.12.002-beta-12_18_02-SNAPSHOT", "2024.12.002-beta-20241218.023429-8")).isFalse();
assertThat(uc.isSnapshotNewer("SNAPSHOT", "2024.12.002-beta-20241218.023429-8")).isFalse();
assertThat(uc.isSnapshotNewer("someUnknownFormat1", "someUnknownFormat2")).isFalse();
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

only testing the snapshot comparison method as I cant really test the run method with all the download and the script launching and extraction and so on ..

Comment on lines 159 to 162
String scriptContent =
"@echo off\n" + "ping -n 4 127.0.0.1 > nul\n" + "C:\\Windows\\System32\\tar.exe -xzf \"%~1\" -C \"%~2\"\n"
+ "del \"%~f0\"";

Copy link
Contributor Author

Choose a reason for hiding this comment

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

doesnt seem like the most elegant bat file but works. The timeout command doesnt work for some reason so using ping, and I needed to get the whole path of the tar.exe for it to extract.

Copy link
Member

@hohwille hohwille left a comment

Choose a reason for hiding this comment

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

@salimbouch thanks for your PR. Very nice job solving the complex things of this story 👍
I left some review comments for improvement.
Please have a look.

Comment on lines 53 to 59
private String getBaseUrl(String groupId, String artifactId) {

if (isIdeasySnapshot(groupId, artifactId, IdeVersion.get())) {
return MAVEN_SNAPSHOTS;
}
return MAVEN_CENTRAL;
}
Copy link
Member

Choose a reason for hiding this comment

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

this and its usage is wrong.
You implemented MavenRepository specific for our use-case of downloading IDEasy.
IdeVersion.get() needs to be used outside of this class to do the version comparison.
In getMetadata you need to use the version argument that you ignoring here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

Comment on lines 68 to 71
// If it's a resolved snapshot version (contains timestamp), convert back to -SNAPSHOT format for the path
if (pathVersion.matches(".*-\\d{8}\\.\\d{6}-\\d+")) {
pathVersion = pathVersion.replaceAll("-\\d{8}\\.\\d{6}-\\d+", "-SNAPSHOT");
}
Copy link
Member

Choose a reason for hiding this comment

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

This is also misplaced here.
getMetadata(IDEASY_GROUP_ID, IDEASY_ARTIFACT_ID, VersionIdentifier.of("2024.12.002-beta")) should give us
https://repo1.maven.org/maven2/com/devonfw/tools/IDEasy/ide-cli/2024.12.002-beta/ide-cli-2024.12.002-beta.jar
The variant getMetadata(IDEASY_GROUP_ID, IDEASY_ARTIFACT_ID, VersionIdentifier.of("2024.12.002-beta"), "windows-x64", ".tar.gz") should give
https://repo1.maven.org/maven2/com/devonfw/tools/IDEasy/ide-cli/2024.12.002-beta/ide-cli-2024.12.002-beta-windows-x64.tar.gz
Where windows-x64 is called classifier in maven terminology and .tar.gz is the extension (aka type in maven POM but there excluding the dot if you want to make it POM compliant just pass tar.gz with jar as default and add the dot internally in method impl).

Copy link
Contributor Author

@salimbouch salimbouch Jan 22, 2025

Choose a reason for hiding this comment

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

Now getMetadata behaves as you stated. However, I still can't really get rid of this regex. The passed version to the method getMetadata if the version is a snapshot looks like this: 2025.01.001-beta-20250121.023134-9.
We need to make a path out of it, that means we take that version and make 2025.01.001-beta-SNAPSHOT out of it so that the download link is sonatype.org/..../2025.01.001-beta-SNAPSHOT/...2025.01.001-beta-20250121.023134-9...

Comment on lines 64 to 65
SystemInfo sys = this.context.getSystemInfo();
String classifier = sys.getOs() + "-" + sys.getArchitecture();
Copy link
Member

Choose a reason for hiding this comment

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

Also this code is misplaced here and needs to be moved outside of MavenRepository.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done, now passing the classifier as arg to the download method.

Comment on lines 85 to 91
Path tmpDownloadFile = createTempDownload(MAVEN_METADATA_XML);

try {
this.context.getFileAccess().download(metadataUrl, tmpDownloadFile);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(tmpDownloadFile.toFile());
Copy link
Member

Choose a reason for hiding this comment

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

It does not make sense to write the XML to the disc just to then read it.
We should directly load the file into XML in memory without writing temporary files to the disc.

Copy link
Contributor Author

@salimbouch salimbouch Jan 22, 2025

Choose a reason for hiding this comment

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

done, not really sure if I used the right libraries for it, see method fetchXmlMetadata.

Comment on lines 93 to 97
String version = Optional.ofNullable(doc.getElementsByTagName("latest").item(0)).map(Element.class::cast)
.map(Element::getTextContent).orElseGet(
() -> Optional.ofNullable(doc.getElementsByTagName("release").item(0)).map(Element.class::cast)
.map(Element::getTextContent)
.orElseThrow(() -> new IllegalStateException("No latest or release version found in metadata")));
Copy link
Member

Choose a reason for hiding this comment

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

wouldn't XPath help here to make the code more compact and elegant?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

Comment on lines 99 to 101
if (isIdeasySnapshot(groupId, artifactId, version)) {
version = resolveSnapshotVersion(groupId, artifactId, version);
}
Copy link
Member

Choose a reason for hiding this comment

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

this should also not be specific for IDEasy.
If someone provides a version ending with -SNAPSHOT then you should resolve it the way you are doing that for any artifact no matter if IDEasy or not.
Outside when you use all this specific for IDEasy and you have version 2025.01.001-beta-01_21_02-SNAPSHOT simply convert this back to 2025.01.001-beta-SNAPSHOT what seems easy and pass that as version to this method to make it work.

Following Separation of Concerns this class should be generic and make sense for any maven artfact so we can reuse it also for gcviewer, gcloganalyzer, cobigen, or whatever we like.
Everything that is specific for IDEasy and the way we build our version printed by ide -v needs to go to UpgradeCommandlet and related code outside of this repo package.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

Comment on lines 104 to 105
} finally {
this.context.getFileAccess().delete(tmpDownloadFile);
Copy link
Member

Choose a reason for hiding this comment

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

will also be pointless then.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

Comment on lines 116 to 130
Path tmpDownloadFile = createTempDownload(MAVEN_METADATA_XML);

try {
this.context.getFileAccess().download(metadataUrl, tmpDownloadFile);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(tmpDownloadFile.toFile());

String timestamp = Optional.ofNullable(doc.getElementsByTagName("timestamp").item(0)).map(Element.class::cast)
.map(Element::getTextContent)
.orElseThrow(() -> new IllegalStateException("No timestamp found in snapshot metadata"));

String buildNumber = Optional.ofNullable(doc.getElementsByTagName("buildNumber").item(0))
.map(Element.class::cast).map(Element::getTextContent)
.orElseThrow(() -> new IllegalStateException("No buildNumber found in snapshot metadata"));
Copy link
Member

Choose a reason for hiding this comment

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

same here. Also this looks like code duplication that should be avoided by reusing code from a private method.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

Comment on lines 141 to 145
private boolean isIdeasySnapshot(String groupId, String artifactId, String version) {

return IDEASY_GROUP_ID.equals(groupId) && IDEASY_ARTIFACT_ID.equals(artifactId) && version != null
&& version.contains("SNAPSHOT");
}
Copy link
Member

Choose a reason for hiding this comment

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

As stated above

Suggested change
private boolean isIdeasySnapshot(String groupId, String artifactId, String version) {
return IDEASY_GROUP_ID.equals(groupId) && IDEASY_ARTIFACT_ID.equals(artifactId) && version != null
&& version.contains("SNAPSHOT");
}
private boolean isSnapshotVersion(String version) {
return version.endsWith("-SNAPSHOT");
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@Override
public Collection<ToolDependency> findDependencies(String groupId, String artifactId, VersionIdentifier version) {

return Collections.emptyList();
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
return Collections.emptyList();
// We could read POM here and find dependencies but we do not want to reimplement maven here.
// For our use-case we only download bundled packages from maven central so we do KISS for now.
return Collections.emptyList();

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@coveralls
Copy link
Collaborator

Pull Request Test Coverage Report for Build 12915070560

Details

  • 0 of 0 changed or added relevant lines in 0 files are covered.
  • 174 unchanged lines in 4 files lost coverage.
  • Overall coverage decreased (-0.6%) to 67.819%

Files with Coverage Reduction New Missed Lines %
com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java 9 88.46%
com/devonfw/tools/ide/context/IdeContext.java 15 63.92%
com/devonfw/tools/ide/repo/AbstractToolRepository.java 25 61.21%
com/devonfw/tools/ide/context/AbstractIdeContext.java 125 59.22%
Totals Coverage Status
Change from base Build 12891187018: -0.6%
Covered Lines: 7234
Relevant Lines: 10277

💛 - Coveralls

@salimbouch
Copy link
Contributor Author

Also changed the way I retrieve the latest version from metadata.xml. Have a look at this.
The latest element doesn't give the real latest snapshot version. Now I iterate over all version elements and get the latest.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Team Review
Development

Successfully merging this pull request may close these issues.

Add UpgradeCommandlet to automatically update to the latest release of IDEasy
3 participants