Skip to content

Commit b656876

Browse files
committed
[RelEng] Add job to touch projects with unanticipated comparator errors
1 parent 007bb44 commit b656876

3 files changed

Lines changed: 116 additions & 11 deletions

File tree

JenkinsJobs/Releng/prepareNextDevCycle.jenkinsfile

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -399,14 +399,7 @@ pipeline {
399399
echo "Skipping submodule without changes: ${submodulePath}"
400400
return
401401
}
402-
def submoduleURL = sh(script: "git config remote.origin.url", returnStdout: true).trim()
403-
// Extract repository path from e.g.: https://github.com/eclipse-platform/eclipse.platform.git
404-
def expectedPrefix = 'https://github.com/'
405-
def expectedSuffix = '.git'
406-
if (!submoduleURL.startsWith(expectedPrefix) || !submoduleURL.endsWith(expectedSuffix)) {
407-
error "Unexpected of submodule URL: ${submoduleURL}"
408-
}
409-
def repoName = submoduleURL.substring(expectedPrefix.length(), submoduleURL.length() - expectedSuffix.length())
402+
def repoName = githubAPI.getCurrentRepositoriesGithubName()
410403
githubAPI.createPullRequest(repoName, prHeadline, """\
411404
Prepare development of Eclipse ${NEXT_RELEASE_VERSION}.
412405
This complements:
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// Constants read by job creation
2+
private static final _JOB_DESCRIPTION = '''
3+
For a a build with <em>comparator-errors</em>, touches all affected projects to enforce an update of their qualifier and creates PRs with thes corresponding changes.
4+
'''
5+
6+
pipeline {
7+
options {
8+
timestamps()
9+
timeout(time: 30, unit: 'MINUTES')
10+
buildDiscarder(logRotator(numToKeepStr:'10', artifactNumToKeepStr:'2'))
11+
}
12+
parameters {
13+
string(name: 'buildId', trim: true, description: '''
14+
The identifier of the build with comparator-errors whoose affected Plugins should be touched.<br>
15+
For example: <code>I20260111-0430</code>
16+
''')
17+
string(name: 'message', defaultValue: 'Enforce qualifier update', description: '''
18+
The message appended to all touched qualifier-update files
19+
''')
20+
}
21+
agent {
22+
label 'basic'
23+
}
24+
stages {
25+
stage('Checkout Submodules') {
26+
steps {
27+
sh '''#!/bin/bash -xe
28+
git submodule update --init --recursive --remote --depth 1
29+
git config --global user.email 'releng-bot@eclipse.org'
30+
git config --global user.name 'Eclipse Releng Bot'
31+
'''
32+
}
33+
}
34+
stage('Touch projects with errors') {
35+
steps {
36+
script {
37+
38+
def comparatorLog = sh(script: "curl --fail https://download.eclipse.org/eclipse/downloads/drops4/${buildId}/buildlogs/comparatorlogs/buildtimeComparatorUnanticipated.log.txt", returnStdout: true)
39+
def errorEntries = comparatorLog.split(/(?m)^\d+\. +/).toList()
40+
errorEntries = errorEntries.subList(1, errorEntries.size()) // Drop header
41+
for(entry in errorEntries) {
42+
def path = entry.readLines()[0].trim()
43+
if(path.endsWith('/pom.xml') || path.endsWith('/.tycho-consumer-pom.xml')) {
44+
path = path.substring(0, path.lastIndexOf('/'))
45+
} else {
46+
error("Unexpected path end: ${path}")
47+
}
48+
if (!fileExists("${path}/META-INF/MANIFEST.MF")) {
49+
error("Computed path is not a Plugin root: ${path}")
50+
}
51+
def forceQualifierUpdateFile = "${path}/forceQualifierUpdate.txt"
52+
sh """
53+
echo 'Touching: ${path}'
54+
if [ ! -f ${forceQualifierUpdateFile} ]; then
55+
echo '# To force a version qualifier update add the bug here' >> ${forceQualifierUpdateFile}
56+
fi
57+
# Ensure file terminates with a newline
58+
lastChar=\$(tail -c1 ${forceQualifierUpdateFile} | od -An -tx1)
59+
if [ ! "\${lastChar}" = "0a" ] && [ ! "\${lastChar}" = "0d" ]; then
60+
echo '' >> ${forceQualifierUpdateFile}
61+
fi
62+
echo '${message}' >> ${forceQualifierUpdateFile}
63+
"""
64+
}
65+
}
66+
}
67+
}
68+
stage('Create PRs') {
69+
steps {
70+
script {
71+
def utilities = load "JenkinsJobs/shared/utilities.groovy"
72+
utilities.setDryRun(false)
73+
def githubAPI = load "JenkinsJobs/shared/githubAPI.groovy"
74+
githubAPI.setDryRun(true)
75+
76+
utilities.runHereAndForEachGitSubmodule{ submodulePath ->
77+
def boolean isUnchanged = sh(script: 'git status --short --ignore-submodules', returnStdout: true).trim().isEmpty()
78+
if (isUnchanged) {
79+
echo "Skipping repository without changes: ${submodulePath}"
80+
return
81+
}
82+
def branch = 'enforce-qualifier-update'
83+
def msg = 'Enforce qualifier update for project(s) with comparator errors'
84+
sh """
85+
echo 'Committing changes in ${submodulePath}'
86+
git checkout -B '${branch}' HEAD
87+
git commit --all --message '${msg}'
88+
"""
89+
90+
utilities.gitPushBranch(branch, branch)
91+
def repoName = githubAPI.getCurrentRepositoriesGithubName()
92+
def prURL = githubAPI.createPullRequest(repoName, msg, """\
93+
Enforce qualifier update for project(s) with comparator error in build ${buildId}.
94+
""".stripIndent(), branch)
95+
echo "Created ${prURL}"
96+
}
97+
}
98+
}
99+
}
100+
}
101+
}

JenkinsJobs/shared/githubAPI.groovy

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11

22
@groovy.transform.Field
3-
def boolean IS_DRY_RUN = true
3+
def boolean _GH_API_IS_DRY_RUN = true
44

55
def setDryRun(boolean isDryRun) {
6-
IS_DRY_RUN = isDryRun
6+
_GH_API_IS_DRY_RUN = isDryRun
77
}
88

99
/** Returns a list of all repositories in the specified organization.*/
@@ -72,7 +72,7 @@ def queryGithubAPI(String method, String endpoint, Map<String, Object> queryPara
7272
def params = writeJSON(json: queryParameters, returnText: true)
7373
query += "-d '" + params + "'"
7474
}
75-
if (IS_DRY_RUN && !method.isEmpty()) {
75+
if (_GH_API_IS_DRY_RUN && !method.isEmpty()) {
7676
echo "Query (not send): ${query}"
7777
return null
7878
}
@@ -92,4 +92,15 @@ private boolean isFailed(Map response, int successCode) {
9292
return response?.errors || (response?.status && response.status?.toInteger() != successCode)
9393
}
9494

95+
def getCurrentRepositoriesGithubName() {
96+
def submoduleURL = sh(script: "git config remote.origin.url", returnStdout: true).trim()
97+
// Extract repository path from e.g.: https://github.com/eclipse-platform/eclipse.platform.git
98+
def expectedPrefix = 'https://github.com/'
99+
def expectedSuffix = '.git'
100+
if (!submoduleURL.startsWith(expectedPrefix) || !submoduleURL.endsWith(expectedSuffix)) {
101+
error "Unexpected of submodule URL: ${submoduleURL}"
102+
}
103+
return submoduleURL.substring(expectedPrefix.length(), submoduleURL.length() - expectedSuffix.length())
104+
}
105+
95106
return this

0 commit comments

Comments
 (0)