Skip to content

Commit ed33cbc

Browse files
authored
Merge branch 'NginxProxyManager:develop' into develop
2 parents ae4a983 + b3de76c commit ed33cbc

File tree

326 files changed

+14182
-20841
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

326 files changed

+14182
-20841
lines changed

.github/workflows/stale.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: 'Close stale issues and PRs'
2+
on:
3+
schedule:
4+
- cron: '30 1 * * *'
5+
workflow_dispatch:
6+
7+
jobs:
8+
stale:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/stale@v9
12+
with:
13+
stale-issue-label: 'stale'
14+
stale-pr-label: 'stale'
15+
stale-issue-message: 'Issue is now considered stale. If you want to keep it open, please comment :+1:'
16+
stale-pr-message: 'PR is now considered stale. If you want to keep it open, please comment :+1:'
17+
close-issue-message: 'Issue was closed due to inactivity.'
18+
close-pr-message: 'PR was closed due to inactivity.'
19+
days-before-stale: 182
20+
days-before-close: 365
21+
operations-per-run: 50

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,7 @@
33
._*
44
.vscode
55
certbot-help.txt
6+
test/node_modules
7+
*/node_modules
8+
docker/dev/dnsrouter-config.json.tmp
9+
docker/dev/resolv.conf

.version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.9.19
1+
2.12.1

Jenkinsfile

Lines changed: 133 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
import groovy.transform.Field
2+
3+
@Field
4+
def shOutput = ""
5+
def buildxPushTags = ""
6+
17
pipeline {
28
agent {
39
label 'docker-multiarch'
@@ -8,14 +14,12 @@ pipeline {
814
ansiColor('xterm')
915
}
1016
environment {
11-
IMAGE = "nginx-proxy-manager"
17+
IMAGE = 'nginx-proxy-manager'
1218
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}"
1722
COMPOSE_INTERACTIVE_NO_CLI = 1
18-
BUILDX_NAME = "${COMPOSE_PROJECT_NAME}"
1923
}
2024
stages {
2125
stage('Environment') {
@@ -26,7 +30,7 @@ pipeline {
2630
}
2731
steps {
2832
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"
3034
}
3135
}
3236
}
@@ -39,7 +43,7 @@ pipeline {
3943
steps {
4044
script {
4145
// 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}"
4347
}
4448
}
4549
}
@@ -52,108 +56,115 @@ pipeline {
5256
sh 'sed -i -E "s/(version-)[0-9]+\\.[0-9]+\\.[0-9]+(-green)/\\1${BUILD_VERSION}\\2/" README.md'
5357
}
5458
}
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+
}
5566
}
5667
}
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+
}
86102
}
87103
}
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'
99108
}
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
111112
}
112113
}
113-
}
114-
stage('Integration Tests Mysql') {
115114
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'
125117
}
126118
post {
127119
always {
128120
// 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'
136127
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+
}
137134
}
138135
}
139136
}
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+
}
141142
when {
142143
not {
143144
equals expected: 'UNSTABLE', actual: currentBuild.result
144145
}
145146
}
146147
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'
150162
}
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+
}
154167
}
155-
156-
archiveArtifacts(artifacts: 'docs/docs.tgz', allowEmptyArchive: false)
157168
}
158169
}
159170
stage('MultiArch Build') {
@@ -163,81 +174,59 @@ pipeline {
163174
}
164175
}
165176
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}"
172178
}
173179
}
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")]
180193
}
181194
}
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}`
195209
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+
}
212214
}
213215
}
214216
}
215-
steps {
216-
script {
217-
def comment = pullRequest.comment("This is an automated message from CI:\n\nDocker 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-
}
220217
}
221218
}
222219
post {
223220
always {
224-
sh 'docker-compose down --remove-orphans --volumes -t 30'
225221
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)
231224
}
232225
failure {
233-
archiveArtifacts(artifacts: 'debug/**.*', allowEmptyArchive: true)
234-
juxtapose event: 'failure'
235-
sh 'figlet "FAILURE"'
226+
archiveArtifacts(artifacts: 'debug/**/*.*', allowEmptyArchive: true)
236227
}
237228
unstable {
238-
archiveArtifacts(artifacts: 'debug/**.*', allowEmptyArchive: true)
239-
juxtapose event: 'unstable'
240-
sh 'figlet "UNSTABLE"'
229+
archiveArtifacts(artifacts: 'debug/**/*.*', allowEmptyArchive: true)
241230
}
242231
}
243232
}

0 commit comments

Comments
 (0)