1
+ import groovy.transform.Field
2
+
3
+ @Field
4
+ def shOutput = " "
5
+ def buildxPushTags = " "
6
+
1
7
pipeline {
2
8
agent {
3
9
label ' docker-multiarch'
@@ -8,14 +14,12 @@ pipeline {
8
14
ansiColor(' xterm' )
9
15
}
10
16
environment {
11
- IMAGE = " nginx-proxy-manager"
17
+ IMAGE = ' nginx-proxy-manager'
12
18
BUILD_VERSION = getVersion()
13
- MAJOR_VERSION = " 2"
14
- BRANCH_LOWER = " ${ BRANCH_NAME.toLowerCase().replaceAll('/', '-')} "
15
- COMPOSE_PROJECT_NAME = " npm_${ BRANCH_LOWER} _${ BUILD_NUMBER} "
16
- COMPOSE_FILE = ' docker/docker-compose.ci.yml'
19
+ MAJOR_VERSION = ' 2'
20
+ BRANCH_LOWER = " ${ BRANCH_NAME.toLowerCase().replaceAll('\\\\', '-').replaceAll('/', '-').replaceAll('\\.', '-')} "
21
+ BUILDX_NAME = " npm_${ BRANCH_LOWER} _${ BUILD_NUMBER} "
17
22
COMPOSE_INTERACTIVE_NO_CLI = 1
18
- BUILDX_NAME = " ${ COMPOSE_PROJECT_NAME} "
19
23
}
20
24
stages {
21
25
stage(' Environment' ) {
@@ -26,7 +30,7 @@ pipeline {
26
30
}
27
31
steps {
28
32
script {
29
- env . BUILDX_PUSH_TAGS = " -t docker.io/jc21/${ IMAGE} :${ BUILD_VERSION} -t docker.io/jc21/${ IMAGE} :${ MAJOR_VERSION} -t docker.io/jc21/${ IMAGE} :latest"
33
+ buildxPushTags = " -t docker.io/jc21/${ IMAGE} :${ BUILD_VERSION} -t docker.io/jc21/${ IMAGE} :${ MAJOR_VERSION} -t docker.io/jc21/${ IMAGE} :latest"
30
34
}
31
35
}
32
36
}
@@ -39,7 +43,7 @@ pipeline {
39
43
steps {
40
44
script {
41
45
// Defaults to the Branch name, which is applies to all branches AND pr's
42
- env . BUILDX_PUSH_TAGS = " -t docker.io/jc21 /${ IMAGE} :github- ${ BRANCH_LOWER} "
46
+ buildxPushTags = " -t docker.io/nginxproxymanager /${ IMAGE} -dev: ${ BRANCH_LOWER} "
43
47
}
44
48
}
45
49
}
@@ -52,108 +56,115 @@ pipeline {
52
56
sh ' sed -i -E "s/(version-)[0-9]+\\ .[0-9]+\\ .[0-9]+(-green)/\\ 1${BUILD_VERSION}\\ 2/" README.md'
53
57
}
54
58
}
59
+ stage(' Docker Login' ) {
60
+ steps {
61
+ withCredentials([usernamePassword(credentialsId : ' jc21-dockerhub' , passwordVariable : ' dpass' , usernameVariable : ' duser' )]) {
62
+ sh ' docker login -u "${duser}" -p "${dpass}"'
63
+ }
64
+ }
65
+ }
55
66
}
56
67
}
57
- stage(' Frontend' ) {
58
- steps {
59
- sh ' ./scripts/frontend-build'
60
- }
61
- }
62
- stage(' Backend' ) {
63
- steps {
64
- echo ' Checking Syntax ...'
65
- sh ' docker pull nginxproxymanager/nginx-full:certbot-node'
66
- // See: https://github.com/yarnpkg/yarn/issues/3254
67
- sh ''' docker run --rm \\
68
- -v "$(pwd)/backend:/app" \\
69
- -v "$(pwd)/global:/app/global" \\
70
- -w /app \\
71
- nginxproxymanager/nginx-full:certbot-node \\
72
- sh -c "yarn install && yarn eslint . && rm -rf node_modules"
73
- '''
74
-
75
- echo ' Docker Build ...'
76
- sh ''' docker build --pull --no-cache --squash --compress \\
77
- -t "${IMAGE}:ci-${BUILD_NUMBER}" \\
78
- -f docker/Dockerfile \\
79
- --build-arg TARGETPLATFORM=linux/amd64 \\
80
- --build-arg BUILDPLATFORM=linux/amd64 \\
81
- --build-arg BUILD_VERSION="${BUILD_VERSION}" \\
82
- --build-arg BUILD_COMMIT="${BUILD_COMMIT}" \\
83
- --build-arg BUILD_DATE="$(date '+%Y-%m-%d %T %Z')" \\
84
- .
85
- '''
68
+ stage(' Builds' ) {
69
+ parallel {
70
+ stage(' Project' ) {
71
+ steps {
72
+ script {
73
+ // Frontend and Backend
74
+ def shStatusCode = sh(label : ' Checking and Building' , returnStatus : true , script : '''
75
+ set -e
76
+ ./scripts/ci/frontend-build > ${WORKSPACE}/tmp-sh-build 2>&1
77
+ ./scripts/ci/test-and-build > ${WORKSPACE}/tmp-sh-build 2>&1
78
+ ''' )
79
+ shOutput = readFile " ${ env.WORKSPACE} /tmp-sh-build"
80
+ if (shStatusCode != 0 ) {
81
+ error " ${ shOutput} "
82
+ }
83
+ }
84
+ }
85
+ post {
86
+ always {
87
+ sh ' rm -f ${WORKSPACE}/tmp-sh-build'
88
+ }
89
+ failure {
90
+ npmGithubPrComment(" CI Error:\n\n ```\n ${ shOutput} \n ```" , true )
91
+ }
92
+ }
93
+ }
94
+ stage(' Docs' ) {
95
+ steps {
96
+ dir(path : ' docs' ) {
97
+ sh ' yarn install'
98
+ sh ' yarn build'
99
+ }
100
+ }
101
+ }
86
102
}
87
103
}
88
- stage(' Integration Tests Sqlite' ) {
89
- steps {
90
- // Bring up a stack
91
- sh ' docker-compose up -d fullstack-sqlite'
92
- sh ' ./scripts/wait-healthy $(docker-compose ps -q fullstack-sqlite) 120'
93
-
94
- // Run tests
95
- sh ' rm -rf test/results'
96
- sh ' docker-compose up cypress-sqlite'
97
- // Get results
98
- sh ' docker cp -L "$(docker-compose ps -q cypress-sqlite):/test/results" test/'
104
+ stage(' Test Sqlite' ) {
105
+ environment {
106
+ COMPOSE_PROJECT_NAME = " npm_${ BRANCH_LOWER} _${ BUILD_NUMBER} _sqlite"
107
+ COMPOSE_FILE = ' docker/docker-compose.ci.yml:docker/docker-compose.ci.sqlite.yml'
99
108
}
100
- post {
101
- always {
102
- // Dumps to analyze later
103
- sh ' mkdir -p debug'
104
- sh ' docker-compose logs fullstack-sqlite | gzip > debug/docker_fullstack_sqlite.log.gz'
105
- sh ' docker-compose logs db | gzip > debug/docker_db.log.gz'
106
- // Cypress videos and screenshot artifacts
107
- dir(path : ' test/results' ) {
108
- archiveArtifacts allowEmptyArchive : true , artifacts : ' **/*' , excludes : ' **/*.xml'
109
- }
110
- junit ' test/results/junit/*'
109
+ when {
110
+ not {
111
+ equals expected : ' UNSTABLE' , actual : currentBuild. result
111
112
}
112
113
}
113
- }
114
- stage(' Integration Tests Mysql' ) {
115
114
steps {
116
- // Bring up a stack
117
- sh ' docker-compose up -d fullstack-mysql'
118
- sh ' ./scripts/wait-healthy $(docker-compose ps -q fullstack-mysql) 120'
119
-
120
- // Run tests
121
- sh ' rm -rf test/results'
122
- sh ' docker-compose up cypress-mysql'
123
- // Get results
124
- sh ' docker cp -L "$(docker-compose ps -q cypress-mysql):/test/results" test/'
115
+ sh ' rm -rf ./test/results/junit/*'
116
+ sh ' ./scripts/ci/fulltest-cypress'
125
117
}
126
118
post {
127
119
always {
128
120
// Dumps to analyze later
129
- sh ' mkdir -p debug'
130
- sh ' docker-compose logs fullstack-mysql | gzip > debug/docker_fullstack_mysql.log.gz'
131
- sh ' docker-compose logs db | gzip > debug/docker_db.log.gz'
132
- // Cypress videos and screenshot artifacts
133
- dir(path : ' test/results' ) {
134
- archiveArtifacts allowEmptyArchive : true , artifacts : ' **/*' , excludes : ' **/*.xml'
135
- }
121
+ sh ' mkdir -p debug/sqlite'
122
+ sh ' docker logs $(docker-compose ps --all -q fullstack) > debug/sqlite/docker_fullstack.log 2>&1'
123
+ sh ' docker logs $(docker-compose ps --all -q stepca) > debug/sqlite/docker_stepca.log 2>&1'
124
+ sh ' docker logs $(docker-compose ps --all -q pdns) > debug/sqlite/docker_pdns.log 2>&1'
125
+ sh ' docker logs $(docker-compose ps --all -q pdns-db) > debug/sqlite/docker_pdns-db.log 2>&1'
126
+ sh ' docker logs $(docker-compose ps --all -q dnsrouter) > debug/sqlite/docker_dnsrouter.log 2>&1'
136
127
junit ' test/results/junit/*'
128
+ sh ' docker-compose down --remove-orphans --volumes -t 30 || true'
129
+ }
130
+ unstable {
131
+ dir(path : ' testing/results' ) {
132
+ archiveArtifacts(allowEmptyArchive : true , artifacts : ' **/*' , excludes : ' **/*.xml' )
133
+ }
137
134
}
138
135
}
139
136
}
140
- stage(' Docs' ) {
137
+ stage(' Test Mysql' ) {
138
+ environment {
139
+ COMPOSE_PROJECT_NAME = " npm_${ BRANCH_LOWER} _${ BUILD_NUMBER} _mysql"
140
+ COMPOSE_FILE = ' docker/docker-compose.ci.yml:docker/docker-compose.ci.mysql.yml'
141
+ }
141
142
when {
142
143
not {
143
144
equals expected : ' UNSTABLE' , actual : currentBuild. result
144
145
}
145
146
}
146
147
steps {
147
- dir(path : ' docs' ) {
148
- sh ' yarn install'
149
- sh ' yarn build'
148
+ sh ' rm -rf ./test/results/junit/*'
149
+ sh ' ./scripts/ci/fulltest-cypress'
150
+ }
151
+ post {
152
+ always {
153
+ // Dumps to analyze later
154
+ sh ' mkdir -p debug/mysql'
155
+ sh ' docker logs $(docker-compose ps --all -q fullstack) > debug/mysql/docker_fullstack.log 2>&1'
156
+ sh ' docker logs $(docker-compose ps --all -q stepca) > debug/mysql/docker_stepca.log 2>&1'
157
+ sh ' docker logs $(docker-compose ps --all -q pdns) > debug/mysql/docker_pdns.log 2>&1'
158
+ sh ' docker logs $(docker-compose ps --all -q pdns-db) > debug/mysql/docker_pdns-db.log 2>&1'
159
+ sh ' docker logs $(docker-compose ps --all -q dnsrouter) > debug/mysql/docker_dnsrouter.log 2>&1'
160
+ junit ' test/results/junit/*'
161
+ sh ' docker-compose down --remove-orphans --volumes -t 30 || true'
150
162
}
151
-
152
- dir(path : ' docs/.vuepress/dist' ) {
153
- sh ' tar -czf ../../docs.tgz *'
163
+ unstable {
164
+ dir(path : ' testing/results' ) {
165
+ archiveArtifacts(allowEmptyArchive : true , artifacts : ' **/*' , excludes : ' **/*.xml' )
166
+ }
154
167
}
155
-
156
- archiveArtifacts(artifacts : ' docs/docs.tgz' , allowEmptyArchive : false )
157
168
}
158
169
}
159
170
stage(' MultiArch Build' ) {
@@ -163,81 +174,59 @@ pipeline {
163
174
}
164
175
}
165
176
steps {
166
- withCredentials([usernamePassword(credentialsId : ' jc21-dockerhub' , passwordVariable : ' dpass' , usernameVariable : ' duser' )]) {
167
- // Docker Login
168
- sh " docker login -u '${ duser} ' -p '${ dpass} '"
169
- // Buildx with push from cache
170
- sh " ./scripts/buildx --push ${ BUILDX_PUSH_TAGS} "
171
- }
177
+ sh " ./scripts/buildx --push ${ buildxPushTags} "
172
178
}
173
179
}
174
- stage(' Docs Deploy' ) {
175
- when {
176
- allOf {
177
- branch ' master'
178
- not {
179
- equals expected : ' UNSTABLE' , actual : currentBuild. result
180
+ stage(' Docs / Comment' ) {
181
+ parallel {
182
+ stage(' Docs Job' ) {
183
+ when {
184
+ allOf {
185
+ branch pattern : " ^(develop|master)\$ " , comparator : " REGEXP"
186
+ not {
187
+ equals expected : ' UNSTABLE' , actual : currentBuild. result
188
+ }
189
+ }
190
+ }
191
+ steps {
192
+ build wait : false , job : ' nginx-proxy-manager-docs' , parameters : [string(name : ' docs_branch' , value : " $BRANCH_NAME " )]
180
193
}
181
194
}
182
- }
183
- steps {
184
- withCredentials([[$class : ' AmazonWebServicesCredentialsBinding' , accessKeyVariable : ' AWS_ACCESS_KEY_ID' , credentialsId : ' npm-s3-docs' , secretKeyVariable : ' AWS_SECRET_ACCESS_KEY' ]]) {
185
- sh """ docker run --rm \\
186
- --name \$ {COMPOSE_PROJECT_NAME}-docs-upload \\
187
- -e S3_BUCKET=jc21-npm-site \\
188
- -e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID \\
189
- -e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY \\
190
- -v \$ (pwd):/app \\
191
- -w /app \\
192
- jc21/ci-tools \\
193
- scripts/docs-upload /app/docs/.vuepress/dist/
194
- """
195
+ stage(' PR Comment' ) {
196
+ when {
197
+ allOf {
198
+ changeRequest()
199
+ not {
200
+ equals expected : ' UNSTABLE' , actual : currentBuild. result
201
+ }
202
+ }
203
+ }
204
+ steps {
205
+ script {
206
+ npmGithubPrComment(""" Docker Image for build ${ BUILD_NUMBER} is available on
207
+ [DockerHub](https://cloud.docker.com/repository/docker/nginxproxymanager/${ IMAGE} -dev)
208
+ as `nginxproxymanager/${ IMAGE} -dev:${ BRANCH_LOWER} `
195
209
196
- sh """ docker run --rm \\
197
- --name \$ {COMPOSE_PROJECT_NAME}-docs-invalidate \\
198
- -e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID \\
199
- -e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY \\
200
- jc21/ci-tools \\
201
- aws cloudfront create-invalidation --distribution-id EN1G6DEWZUTDT --paths '/*'
202
- """
203
- }
204
- }
205
- }
206
- stage(' PR Comment' ) {
207
- when {
208
- allOf {
209
- changeRequest()
210
- not {
211
- equals expected : ' UNSTABLE' , actual : currentBuild. result
210
+ **Note:** ensure you backup your NPM instance before testing this image! Especially if there are database changes
211
+ **Note:** this is a different docker image namespace than the official image
212
+ """ , true )
213
+ }
212
214
}
213
215
}
214
216
}
215
- steps {
216
- script {
217
- def comment = pullRequest. comment(" This is an automated message from CI:\n\n Docker Image for build ${ BUILD_NUMBER} is available on [DockerHub](https://cloud.docker.com/repository/docker/jc21/${ IMAGE} ) as `jc21/${ IMAGE} :github-${ BRANCH_LOWER} `\n\n **Note:** ensure you backup your NPM instance before testing this PR image! Especially if this PR contains database changes." )
218
- }
219
- }
220
217
}
221
218
}
222
219
post {
223
220
always {
224
- sh ' docker-compose down --remove-orphans --volumes -t 30'
225
221
sh ' echo Reverting ownership'
226
- sh ' docker run --rm -v $(pwd):/data jc21/ci-tools chown -R $(id -u):$(id -g) /data'
227
- }
228
- success {
229
- juxtapose event : ' success'
230
- sh ' figlet "SUCCESS"'
222
+ sh ' docker run --rm -v "$(pwd):/data" jc21/ci-tools chown -R "$(id -u):$(id -g)" /data'
223
+ printResult(true )
231
224
}
232
225
failure {
233
- archiveArtifacts(artifacts : ' debug/**.*' , allowEmptyArchive : true )
234
- juxtapose event : ' failure'
235
- sh ' figlet "FAILURE"'
226
+ archiveArtifacts(artifacts : ' debug/**/*.*' , allowEmptyArchive : true )
236
227
}
237
228
unstable {
238
- archiveArtifacts(artifacts : ' debug/**.*' , allowEmptyArchive : true )
239
- juxtapose event : ' unstable'
240
- sh ' figlet "UNSTABLE"'
229
+ archiveArtifacts(artifacts : ' debug/**/*.*' , allowEmptyArchive : true )
241
230
}
242
231
}
243
232
}
0 commit comments