Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Moved TouchBundles from releng tests to releng tools
Added TouchBundles with VersionBump to simplify unstable build fixes caused by compiler changes. See eclipse-platform/eclipse.platform.releng.aggregator#1931 See eclipse-platform/eclipse.platform.releng.aggregator#1923
- Loading branch information
1 parent
6743d48
commit 0cc5888
Showing
4 changed files
with
351 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
176 changes: 176 additions & 0 deletions
176
bundles/org.eclipse.releng.tools/src/org/eclipse/releng/tools/TouchBundles.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2024 Andrey Loskutov <loskutov@gmx.de> and others. | ||
* | ||
* This program and the accompanying materials | ||
* are made available under the terms of the Eclipse Public License 2.0 | ||
* which accompanies this distribution, and is available at | ||
* https://www.eclipse.org/legal/epl-2.0/ | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
* | ||
* Contributors: | ||
* Andrey Loskutov <loskutov@gmx.de> - initial API and implementation | ||
*******************************************************************************/ | ||
package org.eclipse.releng.tools; | ||
|
||
import java.io.File; | ||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.nio.file.Paths; | ||
import java.nio.file.StandardOpenOption; | ||
import java.util.Arrays; | ||
import java.util.Map; | ||
import java.util.Map.Entry; | ||
import java.util.stream.Collectors; | ||
|
||
@SuppressWarnings("nls") | ||
public class TouchBundles { | ||
|
||
final static String FQU_FILE = "forceQualifierUpdate.txt"; | ||
static String releaseTag; | ||
static String ticketMessage; | ||
|
||
/** | ||
* Tries to map & touch all bundles that are mentioned in artifact | ||
* comparisons. Automatically bumps versions if needed. | ||
* | ||
* @param args | ||
* <ol> | ||
* <li>path to the extracted artifactcomparisons.zip | ||
* <li>path to the root directory with all SDK repositories | ||
* <li>last SDK release tag | ||
* <li>the ticket message (can be empty) | ||
* </ol> | ||
* @throws Exception | ||
*/ | ||
public static void main(String[] args) throws Exception { | ||
if (args.length != 4) { | ||
System.out.println("Arguments: " | ||
+ "1) path to the extracted artifactcomparisons.zip, \n" | ||
+ "2) path to the root directory with all SDK repositories, \n" | ||
+ "3) last SDK release tag, like 'R4_31', \n" | ||
+ "4) the ticket message (can be empty)" | ||
); | ||
System.exit(1); | ||
} | ||
Path artifactsPath = Paths.get(args[0]); | ||
File[] badDirs = artifactsPath.toFile().listFiles(); | ||
if (badDirs == null) { | ||
System.out.println("No files found in " + artifactsPath); | ||
System.exit(1); | ||
} | ||
|
||
Path rootReposDir = Paths.get(args[1]); | ||
File[] gitDirs = rootReposDir.toFile().listFiles(); | ||
if (gitDirs == null) { | ||
System.out.println("No files found in " + rootReposDir); | ||
System.exit(1); | ||
} | ||
|
||
releaseTag = args[2].strip(); | ||
if (releaseTag.isBlank()) { | ||
System.out.println("Last SDK release tag (like 'R4_31') is missing"); | ||
System.exit(1); | ||
} | ||
|
||
ticketMessage = args[3].strip(); | ||
if (ticketMessage.isBlank()) { | ||
ticketMessage = "Touching " + FQU_FILE + " to force bundle rebuild\n"; | ||
} | ||
|
||
Map<String, File> badDirMap = Arrays.asList(badDirs).stream().filter(File::isDirectory) | ||
.collect(Collectors.toMap(File::getName, f -> f)); | ||
|
||
Map<String, File> gitDirMap = Arrays.asList(gitDirs).stream().filter(File::isDirectory) | ||
.collect(Collectors.toMap(File::getName, f -> f)); | ||
|
||
if (gitDirMap.containsKey("eclipse.pde.ui")) { | ||
gitDirMap.put("eclipse.pde", gitDirMap.get("eclipse.pde.ui")); | ||
} | ||
if (gitDirMap.containsKey("eclipse.platform.releng.aggregator")) { | ||
gitDirMap.put("eclipse.platform.releng", | ||
new File(gitDirMap.get("eclipse.platform.releng.aggregator"), "eclipse.platform.releng")); | ||
} | ||
|
||
for (Entry<String, File> entry : badDirMap.entrySet()) { | ||
String dirName = entry.getKey(); | ||
File badDir = entry.getValue(); | ||
File repoDir = gitDirMap.get(dirName); | ||
if (repoDir == null) { | ||
System.err.println("Repo " + dirName + " not found in " + rootReposDir); | ||
continue; | ||
} | ||
|
||
if (repoDir.isDirectory()) { | ||
updateRepo(badDir, repoDir); | ||
} else { | ||
System.err.println("Repo " + repoDir + " is not a directory in " + rootReposDir); | ||
} | ||
} | ||
} | ||
|
||
private static void updateRepo(File badDir, File repoDir) { | ||
System.out.println("Checking " + badDir + " -> " + repoDir); | ||
File[] dirs = badDir.listFiles(); | ||
if (dirs == null) { | ||
System.err.println("No children at " + badDir); | ||
return; | ||
} | ||
for (File dir : dirs) { | ||
File gitDir = new File(repoDir, dir.getName()); | ||
if (isBundleWithChanges(dir)) { | ||
updateFQU(gitDir); | ||
} else { | ||
updateRepo(new File(badDir, dir.getName()), gitDir); | ||
} | ||
} | ||
} | ||
|
||
private static void updateFQU(File bundleRoot) { | ||
if (!bundleRoot.isDirectory()) { | ||
System.err.println("\tCan't update non existing directory " + bundleRoot); | ||
return; | ||
} | ||
System.out.println("\tUpdating " + bundleRoot); | ||
boolean versionBumped = VersionBump.run(bundleRoot.toPath(), releaseTag); | ||
if (versionBumped) { | ||
System.out.println("No need to update " + FQU_FILE); | ||
return; | ||
} | ||
File fquFile = new File(bundleRoot, FQU_FILE); | ||
try { | ||
boolean created; | ||
if (!fquFile.exists()) { | ||
created = true; | ||
Files.createFile(fquFile.toPath()); | ||
} else { | ||
created = false; | ||
} | ||
Path path = fquFile.toPath(); | ||
String content = Files.readString(path); | ||
if (content.endsWith(ticketMessage)) { | ||
// already updated | ||
System.out.println("\t\tAlready updated: " + fquFile); | ||
return; | ||
} | ||
if (created) { | ||
System.out.println("\t\tWill create new file: " + fquFile); | ||
} else { | ||
System.out.println("\t\tWill update file: " + fquFile); | ||
} | ||
if (content.endsWith("\n")) { | ||
Files.write(path, ticketMessage.getBytes(), StandardOpenOption.APPEND); | ||
} else { | ||
Files.write(path, ("\n" + ticketMessage).getBytes(), StandardOpenOption.APPEND); | ||
} | ||
} catch (Exception e) { | ||
System.err.println("Failed to update file " + fquFile); | ||
} | ||
} | ||
|
||
private static boolean isBundleWithChanges(File dir) { | ||
return dir.isDirectory() && new File(dir, "target").isDirectory(); | ||
} | ||
|
||
|
||
} |
173 changes: 173 additions & 0 deletions
173
bundles/org.eclipse.releng.tools/src/org/eclipse/releng/tools/VersionBump.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2024 Andrey Loskutov <loskutov@gmx.de> and others. | ||
* | ||
* This program and the accompanying materials | ||
* are made available under the terms of the Eclipse Public License 2.0 | ||
* which accompanies this distribution, and is available at | ||
* https://www.eclipse.org/legal/epl-2.0/ | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
* | ||
* Contributors: | ||
* Andrey Loskutov <loskutov@gmx.de> - initial API and implementation | ||
*******************************************************************************/ | ||
package org.eclipse.releng.tools; | ||
|
||
import java.io.IOException; | ||
import java.nio.charset.StandardCharsets; | ||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.nio.file.Paths; | ||
import java.util.Objects; | ||
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
|
||
import org.eclipse.jgit.errors.RevisionSyntaxException; | ||
import org.eclipse.jgit.lib.ObjectId; | ||
import org.eclipse.jgit.lib.ObjectLoader; | ||
import org.eclipse.jgit.lib.ObjectReader; | ||
import org.eclipse.jgit.lib.Repository; | ||
import org.eclipse.jgit.revwalk.RevCommit; | ||
import org.eclipse.jgit.revwalk.RevWalk; | ||
import org.eclipse.jgit.storage.file.FileRepositoryBuilder; | ||
import org.eclipse.jgit.treewalk.TreeWalk; | ||
import org.osgi.framework.Version; | ||
|
||
@SuppressWarnings("nls") | ||
public class VersionBump { | ||
|
||
/** | ||
* Checks if the version bump needed for given bundle, and if needed, bumps | ||
* micro segment in manifest and pom | ||
* | ||
* @param args first argument is bundle root path to check, second version SDK | ||
* release tag like 'R4_31' | ||
*/ | ||
public static void main(String[] args) { | ||
if (args.length != 2) { | ||
System.out.println("Arguments: first is path to the bundle root, \n" + "second is the release tag"); | ||
System.exit(1); | ||
} | ||
run(Paths.get(args[0]), args[1]); | ||
} | ||
|
||
/** | ||
* | ||
* @param bundleRoot | ||
* @param releaseTag | ||
* @return true if manifest and pom (if exists) were updated | ||
*/ | ||
public static boolean run(Path bundleRoot, String releaseTag) { | ||
if (!Files.isDirectory(bundleRoot)) { | ||
System.err.println("Bundle root is not a directory: " + bundleRoot); | ||
return false; | ||
} | ||
if (releaseTag == null || releaseTag.isBlank()) { | ||
System.err.println("Release tag missing"); | ||
return false; | ||
} | ||
|
||
String manifestPath = "META-INF/MANIFEST.MF"; | ||
String pomPath = "pom.xml"; | ||
|
||
String oldManifestContent = readFileAtTag(bundleRoot, manifestPath, releaseTag); | ||
String oldTagVersion = getVersionFromManifest(oldManifestContent); | ||
System.out.println("Version at tag " + releaseTag + ": " + oldTagVersion); | ||
|
||
String currentManifestContent = readCurrentFile(bundleRoot, manifestPath); | ||
String currentVersion = getVersionFromManifest(currentManifestContent); | ||
System.out.println("Version checked out : " + currentVersion); | ||
|
||
if (currentVersion != null && Objects.equals(oldTagVersion, currentVersion)) { | ||
Version cv = new Version(currentVersion); | ||
Version updated = new Version(cv.getMajor(), cv.getMinor(), cv.getMicro() + 100, cv.getQualifier()); | ||
System.out.println("Update to: " + updated); | ||
String newManifest = oldManifestContent.replace("Bundle-Version: " + oldTagVersion, | ||
"Bundle-Version: " + updated); | ||
|
||
writeFile(bundleRoot, manifestPath, newManifest); | ||
System.out.println("Updated META-INF/MANIFEST.MF in " + bundleRoot); | ||
|
||
String currentPomContent = readCurrentFile(bundleRoot, pomPath); | ||
if (currentPomContent != null) { | ||
String newPom = currentPomContent.replace("<version>" + oldTagVersion, "<version>" + updated); | ||
writeFile(bundleRoot, pomPath, newPom); | ||
System.out.println("Updated pom.xml in " + bundleRoot); | ||
} | ||
return true; | ||
} else { | ||
System.out.println("No version bump needed"); | ||
return false; | ||
} | ||
|
||
} | ||
|
||
private static void writeFile(Path bundleRoot, String manifestPath, String newManifest) { | ||
try { | ||
Files.write(bundleRoot.resolve(manifestPath), newManifest.getBytes(StandardCharsets.UTF_8)); | ||
} catch (IOException e) { | ||
e.printStackTrace(); | ||
} | ||
} | ||
|
||
private static String readCurrentFile(Path bundleRoot, String relativePath) { | ||
try { | ||
return Files.readString(bundleRoot.resolve(relativePath), StandardCharsets.UTF_8); | ||
} catch (IOException e) { | ||
e.printStackTrace(); | ||
} | ||
return null; | ||
} | ||
|
||
private static Pattern VERSION_PATTERN = Pattern.compile(".*Bundle-Version: (\\d+\\.\\d+\\.\\d+).*", | ||
Pattern.DOTALL); | ||
|
||
private static String getVersionFromManifest(String oldManifestContent) { | ||
if (oldManifestContent == null) { | ||
return null; | ||
} | ||
Matcher matcher = VERSION_PATTERN.matcher(oldManifestContent); | ||
if (matcher.matches()) { | ||
return matcher.group(1); | ||
} | ||
return null; | ||
} | ||
|
||
private static String readFileAtTag(Path filePath, String fileInBundle, String releaseTag) { | ||
try { | ||
FileRepositoryBuilder repoBuilder = new FileRepositoryBuilder(); | ||
repoBuilder.findGitDir(filePath.toFile()); | ||
try (Repository repository = repoBuilder.build()) { | ||
Path workDir = repository.getWorkTree().toPath(); | ||
Path repoRelativePath = workDir.relativize(filePath.resolve(fileInBundle)); | ||
String pathInGit = repoRelativePath.toString().replace('\\', '/'); | ||
|
||
ObjectId treeId = repository.resolve(releaseTag); | ||
if (treeId == null) { | ||
System.err.println("Unable to find tag " + releaseTag + " in repo " + workDir); | ||
return null; | ||
} | ||
try (RevWalk revWalk = new RevWalk(repository)) { | ||
RevCommit commit = revWalk.parseCommit(treeId); | ||
System.out.println( | ||
"Checking repo " + workDir + " at commit " + commit.getName() + " : '" | ||
+ commit.getShortMessage() + "'"); | ||
TreeWalk treeWalk = TreeWalk.forPath(repository, pathInGit, commit.getTree()); | ||
ObjectId blobId = treeWalk.getObjectId(0); | ||
ObjectLoader objectLoader = loadObject(blobId, repository); | ||
byte[] bytes = objectLoader.getBytes(); | ||
return new String(bytes, StandardCharsets.UTF_8); | ||
} | ||
} | ||
} catch (IllegalStateException | RevisionSyntaxException | IOException e) { | ||
e.printStackTrace(); | ||
} | ||
return null; | ||
} | ||
|
||
private static ObjectLoader loadObject(ObjectId objectId, Repository repository) throws IOException { | ||
try (ObjectReader objectReader = repository.newObjectReader()) { | ||
return objectReader.open(objectId); | ||
} | ||
} | ||
} |