Skip to content

Commit 3794d34

Browse files
committed
[Build] Unify clean-ups jobs as Jenkins pipelines and inline scripts
Migrate all clean-up jobs to pure Jenkinsfile/pipeline based jobs. Unify the daily clean-up builds into one job that handles Eclispe and Equinox builds in parallel - Try to move the clean-up of old releases into the daily clean-up so that it just runs on the day after the release? - Move remaining two jobs to the 'Releng' folder as it already contains the manually maintained variant of it. FIXUP] More. TODO: what is currently clean-ing up Y-build drops?! TODO: Delete https://download.eclipse.org/eclipse/workingDir/
1 parent e32eaaa commit 3794d34

File tree

11 files changed

+294
-383
lines changed

11 files changed

+294
-383
lines changed

JenkinsJobs/Cleanup/FOLDER.groovy

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

JenkinsJobs/Cleanup/cleanupDLsite.groovy

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

JenkinsJobs/Cleanup/cleanupReleaseArtifacts.groovy

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

JenkinsJobs/Cleanup/dailyCleanOldBuilds.groovy

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

JenkinsJobs/Releng/FOLDER.groovy

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,52 @@ folder('Releng') {
22
description('Jobs related to routine releng tasks. Some are periodic, some are "manual" jobs ran only when needed.')
33
}
44

5+
pipelineJob('Releng/cleanupBuilds'){
6+
displayName('Daily Cleanup of old Builds')
7+
description('Remove old builds from the downloads servers.')
8+
properties {
9+
pipelineTriggers {
10+
triggers {
11+
cron {
12+
spec('''TZ=America/Toronto
13+
0 4 * * *
14+
0 16 * * *
15+
''')
16+
}
17+
}
18+
}
19+
}
20+
definition {
21+
cpsScm {
22+
lightweight(true)
23+
scm {
24+
github('eclipse-platform/eclipse.platform.releng.aggregator', 'master')
25+
}
26+
scriptPath('JenkinsJobs/Releng/cleanupBuilds.jenkinsfile')
27+
}
28+
}
29+
}
30+
31+
pipelineJob('Releng/cleanupReleaseArtifacts'){
32+
parameters {
33+
booleanParam('REMOVE_Y_BUILDS', false, '''Typically only true in even releases.
34+
True: Remove Y-build directories and move P-build directory to P-builds-old for safekeeping.
35+
False: Remove P-builds-old directory.
36+
''' )
37+
stringParam('RELEASE_RETENTION_COUNT', '3', 'The number of retained releases. For example: 3')
38+
}
39+
definition {
40+
cpsScm {
41+
lightweight(true)
42+
scm {
43+
github('eclipse-platform/eclipse.platform.releng.aggregator', 'master')
44+
}
45+
scriptPath('JenkinsJobs/Releng/cleanupReleaseArtifacts.jenkinsfile')
46+
}
47+
}
48+
}
49+
50+
551
pipelineJob('Releng/deployToMaven'){
652
displayName('Deploy to Maven')
753
description('''\
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
pipeline {
2+
options {
3+
skipDefaultCheckout()
4+
timestamps()
5+
timeout(time: 15, unit: 'MINUTES')
6+
buildDiscarder(logRotator(numToKeepStr:'5'))
7+
}
8+
agent {
9+
label 'basic'
10+
}
11+
environment {
12+
// Download Server locations (would very seldom change)
13+
EP_ROOT = '/home/data/httpd/download.eclipse.org'
14+
EP_ECLIPSE_DROPS = "${EP_ROOT}/eclipse/downloads/drops4"
15+
EP_EQUINOX_DROPS = "${EP_ROOT}/equinox/drops"
16+
17+
SSH = 'ssh [email protected]'
18+
}
19+
stages {
20+
stage('Clean up builds') {
21+
parallel {
22+
stage('Equinox') {
23+
steps {
24+
sshagent (['projects-storage.eclipse.org-bot-ssh']) {
25+
script {
26+
def retainedBuilds = 3 // Keep the three most recent builds
27+
for (buildType in ['I', 'Y']) {
28+
def builds = listSubDirectoriesOnRemote("${EP_EQUINOX_DROPS}", "-name '${buildType}*'") // sorted in ascending order
29+
if (retainedBuilds < builds.size()) {
30+
for (buildDir in builds.subList(0, builds.size() - retainedBuilds)) {
31+
sh "$SSH rm -rf ${EP_EQUINOX_DROPS}/${buildDir}"
32+
}
33+
} else {
34+
echo 'Nothing to clean.'
35+
}
36+
}
37+
}
38+
}
39+
}
40+
}
41+
stage('Eclipse') {
42+
steps {
43+
sshagent (['projects-storage.eclipse.org-bot-ssh']) {
44+
// Among all builds older than five days, keep only the first stable build of each week (starting Monday) and delete all others.
45+
// But keep at least the last four builds regardless of their age and all of those younger than five days.
46+
script {
47+
def BUILD_TYPE = 'I'
48+
def MINIMAL_RETENTION_DAYS = 5 // Keep builds for at least five days
49+
def MINIMAL_RETENTION_COUNT = 4 // Retain at least the four most recent builds
50+
51+
def oldIBuilds = listSubDirectoriesOnRemote("${EP_ECLIPSE_DROPS}", "-ctime +${MINIMAL_RETENTION_DAYS} -name '${BUILD_TYPE}*'") // sort ascending to start with Mondays
52+
echo "Old I-Builds: ${oldIBuilds}"
53+
def allIBuilds = listSubDirectoriesOnRemote("${EP_ECLIPSE_DROPS}", "-name '${BUILD_TYPE}*'").reverse() // sort descending to start with latest
54+
def toRetain = allIBuilds.subList(0, Math.min(allIBuilds.size(), MINIMAL_RETENTION_COUNT)).toSet().sort()
55+
echo "Number of I-builds before cleaning: ${allIBuilds.size()}"
56+
echo "Minimally retained I-Builds: ${toRetain}"
57+
def Set<Integer> retainedWeeks = []
58+
for (oldIBuild in oldIBuilds) {
59+
if (toRetain.contains(oldIBuild)) {
60+
echo "Not removed (since one of 4 newest, even though old): ${oldIBuild}"
61+
continue;
62+
}
63+
def weekOfYear = parseWeekOfYear(oldIBuild)
64+
if (!retainedWeeks.contains(weekOfYear)) {
65+
def isUnstable = sh(script: """$SSH "if [ -f '${EP_ECLIPSE_DROPS}/${oldIBuild}/buildUnstable' ]; then echo 'true'; fi" """, returnStdout: true).toBoolean()
66+
if (!isUnstable) {
67+
retainedWeeks.add(weekOfYear) // Retain the first stable build of a week
68+
echo "Retain stable build ${oldIBuild} for week ${weekOfYear}"
69+
continue;
70+
} else {
71+
echo "Ignore unstable build ${oldIBuild} to be retained for week ${weekOfYear}"
72+
}
73+
}
74+
sh "$SSH rm -rf ${EP_ECLIPSE_DROPS}/${oldIBuild}"
75+
}
76+
def nbuilds = listSubDirectoriesOnRemote("${EP_ECLIPSE_DROPS}", "-name '${BUILD_TYPE}*'").size()
77+
echo "Number of I-builds after cleaning: ${nbuilds}"
78+
}
79+
}
80+
build job: 'Releng/updateIndex', wait: false
81+
}
82+
}
83+
}
84+
}
85+
}
86+
}
87+
88+
private List<String> listSubDirectoriesOnRemote(String remoteDirectory, String pattern) {
89+
def result = sh(script: """$SSH "cd ${remoteDirectory} && find -maxdepth 1 -type d ${pattern}" """, returnStdout: true).trim()
90+
return result.isEmpty() ? [] : result.split('\\s+').collect{ d -> d.startsWith('./') ? d.substring(2) : d }.sort()
91+
}
92+
93+
@NonCPS
94+
private int parseWeekOfYear(String iBuildId) {
95+
def idMatcher = iBuildId =~ /I(?<date>\d{8})-(?<time>\d{4})/
96+
if (!idMatcher.matches()) {
97+
error "buildID: ${iBuildId}, does not match the expected pattern."
98+
}
99+
def date = idMatcher.group('date')
100+
def localDate = java.time.LocalDate.parse("${date.substring(0, 4)}-${date.substring(4, 6)}-${date.substring(6, 8)}")
101+
// return localDate.get(java.time.temporal.IsoFields.WEEK_OF_WEEK_BASED_YEAR)
102+
int mondayDOY = localDate.getDayOfYear() - localDate.getDayOfWeek().ordinal();
103+
// This is actually not absolutly correct but as we only want to now if two dates are in the same week (i.e. have the same Monday), it's sufficient
104+
int weekOfYear = (7 + mondayDOY) / 7;
105+
return weekOfYear == 53 ? 0 : weekOfYear;
106+
}

0 commit comments

Comments
 (0)