Skip to content

Commit 7039544

Browse files
committed
Rework checksum and signatures computation and display in build websites
Display the individual SHA512 checksums of downloadable artifacts individually in the file tables. Compute the SHA512 checksums in the Java scripts generating the drop-data files and store them in the buildproperties.json (instead of individual files per artifact). Also drop ability to pass a file list to the scripts for drop data generation, as it's practically irrelevant. If the pages for existing drops should be regenerated, the artifacts just have to be downloaded to the build-agent.
1 parent d04e772 commit 7039544

File tree

10 files changed

+231
-161
lines changed

10 files changed

+231
-161
lines changed

JenkinsJobs/Builds/build.jenkinsfile

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -273,10 +273,6 @@ pipeline {
273273
tools {
274274
jdk 'temurin-jdk25-latest'
275275
}
276-
environment {
277-
KEYRING = credentials('secret-subkeys-releng.asc')
278-
KEYRING_PASSPHRASE = credentials('secret-subkeys-releng.asc-passphrase')
279-
}
280276
steps {
281277
dir("${DROP_DIR}/${BUILD_ID}") {
282278
script {
@@ -394,7 +390,7 @@ pipeline {
394390
popd
395391
rm -rf ${DROP_DIR}/${BUILD_ID}/apitoolingreference
396392

397-
# Wait for notarization before checksums and pages got generated.
393+
# Wait for notarization to complete before checksums are generated.
398394
wait
399395
for f in $notarizeLogDir/*.log; do
400396
echo $f
@@ -403,10 +399,6 @@ pipeline {
403399

404400
# Publish Eclipse
405401

406-
pushd ${DROP_DIR}/${BUILD_ID}
407-
bash ${CJE_ROOT}/scripts/produceChecksum.sh eclipse
408-
popd
409-
410402
java \
411403
-DdropDirectory=${DROP_DIR}/${BUILD_ID} \
412404
-DgitBaselineTag=${GIT_BASELINE_TAG} \
@@ -416,6 +408,9 @@ pipeline {
416408
-DdropDirectory=${DROP_DIR}/${BUILD_ID} \
417409
${SCRIPTS}/releng/CompilerSummaryGenerator.java
418410
'''
411+
script {
412+
utilities.pgpSignFile("${DROP_DIR}/${BUILD_ID}/eclipse-${BUILD_ID}-checksums", 'eclipse')
413+
}
419414
}
420415
}
421416
stage('Promote Eclipse') {
@@ -440,10 +435,6 @@ pipeline {
440435
tools {
441436
jdk 'temurin-jdk25-latest'
442437
}
443-
environment {
444-
KEYRING = credentials('secret-subkeys-releng.asc')
445-
KEYRING_PASSPHRASE = credentials('secret-subkeys-releng.asc-passphrase')
446-
}
447438
steps {
448439
dir("${EQUINOX_DROP_DIR}/${BUILD_ID}") {
449440
script {
@@ -475,7 +466,7 @@ pipeline {
475466
unzip -o -j equinox-SDK-$BUILD_ID.zip plugins/*.jar -x plugins/*.source_*
476467
popd
477468

478-
# Wait for notarization to complete
469+
# Wait for notarization to complete before checksums are generated.
479470
wait
480471
for f in $notarizeLogDir/*.log; do
481472
echo $f
@@ -498,14 +489,13 @@ pipeline {
498489
-v
499490
popd
500491

501-
pushd ${EQUINOX_DROP_DIR}/${BUILD_ID}
502-
bash ${CJE_ROOT}/scripts/produceChecksum.sh equinox
503-
popd
504-
505492
java \
506493
-DdropDirectory=${EQUINOX_DROP_DIR}/${BUILD_ID} \
507494
${SCRIPTS}/releng/BuildDropDataGenerator.java mainEquinox
508495
'''
496+
script {
497+
utilities.pgpSignFile("${EQUINOX_DROP_DIR}/${BUILD_ID}/equinox-${BUILD_ID}-checksums", 'equinox')
498+
}
509499
}
510500
}
511501
stage('Promote Equinox') {

JenkinsJobs/Releng/promoteBuild.jenkinsfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ def renameBuildDrop(String baseDropPath, String oldDropID, String oldBuildLabel,
360360
EOF
361361

362362
#Update checksums to new filenames
363-
ssh genie.releng@projects-storage.eclipse.org sed --in-place --expression 's/${oldBuildLabel}/${newBuildLabel}/g' ${targetPath}/checksum/*
363+
ssh genie.releng@projects-storage.eclipse.org sed --in-place --expression 's/${oldBuildLabel}/${newBuildLabel}/g' ${targetPath}/*-checksums
364364
"""
365365

366366
// Update buildproperties.json to new names

JenkinsJobs/shared/utilities.groovy

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,30 @@ def writeJSON(String jsonFilePath, def json) {
6666
writeFile(file: jsonFilePath, text: JsonOutput.prettyPrint(JsonOutput.toJson(json)).replace(' ','\t'), encoding :'UTF-8')
6767
}
6868

69+
def prepareGPGSigning(String client = '') {
70+
def gpgHome = "${WORKSPACE}/tools/gpg/${client}"
71+
withCredentials([ file(credentialsId: 'secret-subkeys-releng.asc', variable: 'KEYRING') ]) {
72+
sh """#!/bin/bash -xe
73+
# Import gpg keys into a clean gpg-homedir
74+
rm -rf "${gpgHome}"
75+
mkdir -p "${gpgHome}"
76+
gpg --homedir "${gpgHome}" --batch --import "\${KEYRING}"
77+
"""
78+
}
79+
return gpgHome
80+
}
81+
82+
def pgpSignFile(String filePath, String client = '') {
83+
def gpgHome = prepareGPGSigning(client)
84+
withCredentials([ string(credentialsId: 'secret-subkeys-releng.asc-passphrase', variable: 'KEYRING_PASSPHRASE') ]) {
85+
sh """
86+
gpg --homedir "${gpgHome}" --batch \
87+
--detach-sign --armor --pinentry-mode loopback --passphrase-fd 0 \
88+
--output ${filePath}.asc ${filePath} <<< "\${KEYRING_PASSPHRASE}"
89+
"""
90+
}
91+
}
92+
6993
// --- website generation ---
7094

7195
def copyStaticWebsiteFiles(String gitRoot, String website) {

cje-production/scripts/produceChecksum.sh

Lines changed: 0 additions & 68 deletions
This file was deleted.

scripts/releng/BuildDropDataGenerator.java

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@
1616
import java.util.Map.Entry;
1717

1818
import utilities.JSON;
19+
import utilities.JSON.Object;
1920
import utilities.OS;
21+
import utilities.OS.FileInfo;
2022

2123
Path DIRECTORY;
22-
Optional<Path> FILES_LIST_FILE;
2324

2425
/**
2526
* Considered JVM properties are:
@@ -30,23 +31,14 @@
3031
* <li>{@code gitReposChanged} (required for {@code mainEclipse}) -- The comma
3132
* separated list of URLs of Git repositories that changed since the
3233
* baseline.</li>
33-
* <li>{@code filesList} (optional) -- path to a file listing all files and
34-
* their size in the directory.<br>
35-
* Can be generated using the UNIX command
36-
* {@code find . -exec stat --format "%n %s" {} \; }</li>
3734
* </ul>
3835
* The generated data files (mainly JSON) are written at locations within the
3936
* specified directory where the website pages expect them.
4037
*/
4138
void main(String[] args) throws IOException {
4239
DIRECTORY = Path.of(OS.readProperty("dropDirectory")).toRealPath();
43-
FILES_LIST_FILE = Optional.ofNullable(System.getProperty("filesList")).map(Path::of);
4440
IO.println("INFO: Generating drop data file for");
4541
IO.println("\t" + DIRECTORY);
46-
FILES_LIST_FILE.ifPresent(list -> {
47-
IO.println("INFO: Reading files from:");
48-
IO.println("\t" + list);
49-
});
5042

5143
switch (args[0]) {
5244
case "mainEclipse" -> mainEclipsePageData();
@@ -57,12 +49,15 @@ void main(String[] args) throws IOException {
5749
}
5850

5951
final Pattern COMMA = Pattern.compile(",");
52+
final String FILENAME = "name";
53+
final String FILE_SIZE = "size";
54+
final String FILE_HASH_TYPE = "sha512";
6055

6156
void mainEclipsePageData() throws IOException {
6257
String gitBaselineTag = OS.readProperty("gitBaselineTag").trim();
6358
List<String> gitReposChanged = List.of(OS.readProperty("gitReposChanged").trim().split(","));
6459

65-
Map<Path, Long> files = OS.listFileTree(DIRECTORY, FILES_LIST_FILE, null, 1);
60+
Map<Path, FileInfo> files = OS.listFileTree(DIRECTORY, 1);
6661
Map<String, String> properties = OS.loadProperties(DIRECTORY.resolve("buildproperties.properties"));
6762
String buildId = properties.get("BUILD_ID");
6863
ZonedDateTime buildDate = buildTimestamp(buildId);
@@ -116,13 +111,15 @@ void mainEclipsePageData() throws IOException {
116111

117112
buildProperties.add("swtBinaries", collectFileEntries(files, filename -> filename.startsWith("swt-")));
118113

114+
writeChecksumsSummaryFile(buildProperties, buildId, "eclipse");
115+
119116
Path file = DIRECTORY.resolve("buildproperties.json");
120117
IO.println("Write Eclipse drop main data to: " + file);
121118
JSON.write(buildProperties, file);
122119
}
123120

124121
void mainEquinoxPageData() throws IOException {
125-
Map<Path, Long> files = OS.listFileTree(DIRECTORY, FILES_LIST_FILE, null, 1);
122+
Map<Path, FileInfo> files = OS.listFileTree(DIRECTORY, 1);
126123
Map<String, String> properties = OS.loadProperties(DIRECTORY.resolve("buildproperties.properties"));
127124
String buildId = properties.get("BUILD_ID");
128125
ZonedDateTime buildDate = buildTimestamp(buildId);
@@ -153,20 +150,21 @@ void mainEquinoxPageData() throws IOException {
153150
buildProperties.add("starterKits", collectFileEntries(files,
154151
filename -> filename.startsWith("EclipseRT-OSGi-StarterKit-") && !OS.isMacTarGZ(filename)));
155152

153+
writeChecksumsSummaryFile(buildProperties, buildId, "equinox");
154+
156155
Path file = DIRECTORY.resolve("buildproperties.json");
157156
IO.println("Write Equinox drop main data to: " + file);
158157
JSON.write(buildProperties, file);
159158
}
160159

161160
void buildLogsPageData() throws IOException {
162-
Path buildLogsDirectory = Path.of("buildlogs");
163-
Path comparatorLogsDirectory = Path.of("buildlogs/comparatorlogs");
164-
Map<Path, Long> files = OS.listFileTree(DIRECTORY, FILES_LIST_FILE, buildLogsDirectory, 3);
161+
Path comparatorLogsDirectory = Path.of("comparatorlogs");
162+
Map<Path, FileInfo> files = OS.listFileTree(DIRECTORY.resolve("buildlogs"), 2);
165163

166164
JSON.Object logFiles = JSON.Object.create();
167-
JSON.Array buildLogs = colleFilesInDirectory(buildLogsDirectory, filename -> filename.startsWith("s"), files);
165+
JSON.Array buildLogs = collectFileEntries(files, filename -> filename.startsWith("s"));
168166
logFiles.add("build", buildLogs);
169-
JSON.Array comparatorLogs = colleFilesInDirectory(comparatorLogsDirectory, _ -> true, files);
167+
JSON.Array comparatorLogs = collectFilesInDirectory(files, comparatorLogsDirectory, _ -> true);
170168
logFiles.add("comparator", comparatorLogs);
171169

172170
Path file = DIRECTORY.resolve("buildlogs/logs.json");
@@ -185,12 +183,12 @@ String previousReleaseAPILabel(Map<String, String> buildProps) {
185183
return major + "." + (minor - 1);
186184
}
187185

188-
JSON.Array collectFileEntries(Map<Path, Long> buildFiles, Predicate<String> filenameFilter) {
189-
return colleFilesInDirectory(null, filenameFilter, buildFiles);
186+
JSON.Array collectFileEntries(Map<Path, FileInfo> buildFiles, Predicate<String> filenameFilter) {
187+
return collectFilesInDirectory(buildFiles, null, filenameFilter);
190188
}
191189

192-
JSON.Array colleFilesInDirectory(Path inDirectory, Predicate<String> filenameFilter, Map<Path, Long> buildFiles) {
193-
Function<Entry<Path, Long>, String> getFilename = f -> f.getKey().getFileName().toString();
190+
JSON.Array collectFilesInDirectory(Map<Path, FileInfo> buildFiles, Path inDirectory, Predicate<String> filenameFilter) {
191+
Function<Entry<Path, FileInfo>, String> getFilename = f -> f.getKey().getFileName().toString();
194192
int expectedNameCount = inDirectory != null ? inDirectory.getNameCount() + 1 : 1;
195193
return buildFiles.entrySet().stream().filter(f -> {
196194
Path file = f.getKey();
@@ -218,7 +216,7 @@ JSON.Array colleFilesInDirectory(Path inDirectory, Predicate<String> filenameFil
218216
return 100;
219217
})).thenComparing(Comparator.naturalOrder());
220218

221-
JSON.Object createFileEntry(String filename, Map<Path, Long> buildFiles, String platform) {
219+
JSON.Object createFileEntry(String filename, Map<Path, FileInfo> buildFiles, String platform) {
222220
Path filePath = Path.of(filename);
223221
JSON.Object file = createFileDescription(filePath, buildFiles.get(filePath));
224222
if (platform != null) {
@@ -227,10 +225,28 @@ JSON.Object createFileEntry(String filename, Map<Path, Long> buildFiles, String
227225
return file;
228226
}
229227

230-
JSON.Object createFileDescription(Path file, Long fileSize) {
228+
void writeChecksumsSummaryFile(JSON.Object buildProperties, String buildId, String client) throws IOException {
229+
Path checksumSummary = DIRECTORY.resolve(client + "-" + buildId + "-checksums");
230+
List<String> lines = buildProperties.members().values().stream() //
231+
.filter(JSON.Array.class::isInstance).map(JSON.Array.class::cast) //
232+
.map(JSON.Array::elements).flatMap(List::stream) //
233+
.filter(JSON.Object.class::isInstance).map(JSON.Object.class::cast) //
234+
.map(Object::members).filter(o -> o.containsKey(FILENAME) && o.containsKey(FILE_HASH_TYPE))
235+
.sorted(Comparator.comparing((Map<String, JSON.Value> o) -> getStringValue(o, FILENAME)))
236+
.map(o -> getStringValue(o, FILE_HASH_TYPE) + " *" + getStringValue(o, FILENAME)).toList();
237+
IO.println("Write checksum summary file to: " + checksumSummary);
238+
Files.write(checksumSummary, lines);
239+
}
240+
241+
String getStringValue(Map<String, JSON.Value> o, String key) {
242+
return ((JSON.String) o.get(key)).characters();
243+
}
244+
245+
JSON.Object createFileDescription(Path file, FileInfo fileInfo) {
231246
JSON.Object fileEntry = JSON.Object.create();
232-
fileEntry.add("name", JSON.String.create(file.toString().replace(File.separatorChar, '/')));
233-
fileEntry.add("size", JSON.String.create(OS.fileSizeAsString(fileSize)));
247+
fileEntry.add(FILENAME, JSON.String.create(file.toString().replace(File.separatorChar, '/')));
248+
fileEntry.add(FILE_SIZE, JSON.String.create(OS.fileSizeAsString(fileInfo.size())));
249+
fileEntry.add(FILE_HASH_TYPE, JSON.String.create(fileInfo.hashSHA512()));
234250
return fileEntry;
235251
}
236252

0 commit comments

Comments
 (0)