├── .gitattributes
├── .github
├── CODEOWNERS
├── dependabot.yml
└── renovate.json
├── .gitignore
├── Jenkinsfile
├── Makefile
├── README.md
├── bin
├── branding-files.list
├── branding.list
├── branding.py
├── indexGenerator.py
└── test_branding.py
├── branding
├── README.md
├── common
├── description-file
├── jenkins-experimental.mk
├── jenkins-rc.mk
├── jenkins-stable-rc.mk
├── jenkins-stable.mk
├── jenkins.mk
├── license-mit
└── test.mk
├── credentials
├── Makefile
├── README.md
├── apple.conf
├── sandbox.gpg
├── ssh
│ ├── id_rsa
│ ├── id_rsa.pub
│ └── known_hosts
├── test.ascii.key
├── test.crt
├── test.csr
├── test.gpg
├── test.gpg.password.txt
├── test.key
├── test.keychain
├── test.keychain.password.txt
├── test.mk
├── test.pkcs12
├── test.pkcs12.password.txt
└── test.secret.gpg
├── deb
├── build
│ ├── build.sh
│ └── debian
│ │ ├── control
│ │ ├── copyright
│ │ ├── jenkins.default
│ │ ├── jenkins.dirs
│ │ ├── jenkins.init
│ │ ├── jenkins.install
│ │ ├── jenkins.logrotate
│ │ ├── jenkins.postinst
│ │ ├── jenkins.postrm
│ │ ├── rules
│ │ └── source
│ │ └── format
├── publish
│ ├── contents
│ │ └── binary
│ │ │ └── .htaccess
│ ├── publish.sh
│ └── release.conf
└── setup.sh
├── docker-compose.yaml
├── env
├── azure.mk
├── release.mk
└── test.mk
├── make.ps1
├── molecule
├── default
│ ├── Dockerfile.j2
│ ├── converge.yml
│ ├── install-deb.yml
│ ├── install-rpm.yml
│ ├── install-suse.yml
│ ├── molecule.yml
│ └── verify.yml
└── servlet
│ ├── Dockerfile.j2
│ ├── configure-tomcat.yml
│ ├── converge.yml
│ ├── molecule.yml
│ └── verify.yml
├── msi
├── build
│ ├── .gitignore
│ ├── License.rtf
│ ├── Update-JenkinsVersion.ps1
│ ├── banner.bmp
│ ├── build.ps1
│ ├── jenkins.bmp
│ ├── jenkins.exe.config
│ ├── jenkins.ico
│ ├── jenkins.wixproj
│ ├── jenkins.wxs
│ ├── jenkins_en-US.wxl
│ ├── nuget.exe
│ └── packages.config
├── docs
│ └── build-msi-locally.md
└── publish
│ ├── publish.ps1
│ └── publish.sh
├── pkgConfig
└── httpd.conf
├── prep.sh
├── requirements.txt
├── rpm
├── build
│ ├── SOURCES
│ │ └── jenkins.repo
│ ├── SPECS
│ │ └── jenkins.spec
│ └── build.sh
├── publish
│ └── publish.sh
└── setup.sh
├── setup.mk
├── suse
├── build
│ ├── SOURCES
│ │ ├── jenkins.init.in
│ │ ├── jenkins.logrotate
│ │ ├── jenkins.repo
│ │ └── jenkins.sysconfig.in
│ ├── SPECS
│ │ └── jenkins.spec
│ └── build.sh
└── publish
│ └── publish.sh
├── systemd
├── jenkins.conf
├── jenkins.service
├── jenkins.sh
└── migrate.sh
├── templates
├── base.html
├── footer.html
├── header.debian.html
├── header.msi.html
├── header.opensuse.html
├── header.redhat.html
├── header.root.html
├── header.war.html
└── index.html
└── war
└── publish
└── publish.sh
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Handle line endings automatically for files detected as text
2 | # and leave all files detected as binary untouched.
3 | * text=auto
4 |
5 | # Git will always convert line endings to LF on checkout. You should use this for files that must keep LF endings, even on Windows.
6 | * text eol=lf
7 |
8 | #
9 | # The above will handle all files NOT found below
10 | #
11 | # These files are text and should be normalized (Convert crlf => lf)
12 | *.css text
13 | *.groovy text
14 | *.htm text
15 | *.html text
16 | *.java text
17 | *.js text
18 | *.json text
19 | *.jelly text
20 | *.jellytag text
21 | *.less text
22 | *.properties text
23 | *.ps1 -text
24 | *.py text
25 | *.rb text
26 | *.rtf -text
27 | *.sh text
28 | *.txt text
29 | *.xml text
30 |
31 | # These files are binary and should be left untouched
32 | # (binary is a macro for -text -diff)
33 | *.bmp binary
34 | *.class binary
35 | *.gz binary
36 | *.tgz binary
37 | *.ear binary
38 | *.exe binary
39 | *.gif binary
40 | *.gpg binary
41 | *.hpi binary
42 | *.ico binary
43 | *.jar binary
44 | *.jpg binary
45 | *.jpeg binary
46 | *.keychain binary
47 | *.png binary
48 | *.war binary
49 | *.zip binary
50 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @jenkinsci/core
2 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
2 | ---
3 | version: 2
4 | updates:
5 | - package-ecosystem: "pip"
6 | directory: "/"
7 | schedule:
8 | interval: "weekly"
9 |
--------------------------------------------------------------------------------
/.github/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3 | "extends": [
4 | "config:recommended",
5 | ":semanticCommitsDisabled",
6 | "schedule:earlyMondays"
7 | ],
8 | "enabledManagers": [
9 | "npm",
10 | "custom.regex"
11 | ],
12 | "packageRules": [
13 | {
14 | "matchDatasources": [
15 | "npm"
16 | ],
17 | "addLabels": [
18 | "javascript"
19 | ],
20 | "minimumReleaseAge": "3 days"
21 | }
22 | ],
23 | "customManagers": [
24 | {
25 | "customType": "regex",
26 | "managerFilePatterns": [
27 | "/templates/base.html/"
28 | ],
29 | "matchStrings": [
30 | "webcomponentsjs@(?.*?)/"
31 | ],
32 | "depNameTemplate": "@webcomponents/webcomponentsjs",
33 | "datasourceTemplate": "npm"
34 | },
35 | {
36 | "customType": "regex",
37 | "managerFilePatterns": [
38 | "/templates/base.html/"
39 | ],
40 | "matchStrings": [
41 | "lit@(?.*?)/"
42 | ],
43 | "depNameTemplate": "lit",
44 | "datasourceTemplate": "npm"
45 | }
46 | ],
47 | "rebaseWhen": "conflicted"
48 | }
49 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.msi
2 | *.war
3 | *.zip
4 | *.deb
5 | *.rpm
6 | *.log
7 | target
8 | generated
9 | .iml
10 | .idea/
11 | *.orig
12 |
13 | venv/
14 |
15 |
--------------------------------------------------------------------------------
/Jenkinsfile:
--------------------------------------------------------------------------------
1 | def jobProperties = [
2 | buildDiscarder(logRotator(numToKeepStr: '50', artifactNumToKeepStr: '5')),
3 | disableConcurrentBuilds(abortPrevious: true)
4 | ]
5 |
6 | if (env.BRANCH_IS_PRIMARY) {
7 | jobProperties << pipelineTriggers([cron('@weekly')]) // Run at least weekly on the primary branch to assure we test recent releases
8 | }
9 |
10 | properties(jobProperties)
11 |
12 | podTemplate(
13 | inheritFrom: 'jnlp-maven-17',
14 | workingDir: '/home/jenkins/agent',
15 | containers: [
16 | containerTemplate(name: 'jnlp', image: 'jenkinsciinfra/packaging:latest')
17 | ],
18 | envVars: [
19 | envVar(key: 'HOME', value: '/home/jenkins/agent/workspace'),
20 | ],
21 | ) {
22 | nodeWithTimeout(POD_LABEL) {
23 | withEnv([
24 | "BUILDENV=${WORKSPACE}/env/test.mk",
25 | "BRANDING_DIR=${WORKSPACE}/branding",
26 | "BRAND=${WORKSPACE}/branding/jenkins.mk",
27 | "GPG_FILE=${WORKSPACE}/credentials/sandbox.gpg",
28 | "GPG_KEYNAME=Bogus Test",
29 | "GPG_PASSPHRASE=s3cr3t",
30 | "GPG_PASSPHRASE_FILE=${WORKSPACE}/credentials/test.gpg.password.txt",
31 | "HOME=/home/jenkins/agent/workspace",
32 | "WAR=${WORKSPACE}/jenkins.war",
33 | "MSI=${WORKSPACE}/jenkins.msi",
34 | "RELEASELINE=-experimental",
35 | ]) {
36 | stage('Preparation') {
37 | checkout scm
38 | sh './prep.sh'
39 | }
40 |
41 | stage('Build') {
42 | sh 'make package && python3 -m pytest bin --junitxml target/junit.xml'
43 | junit 'target/junit.xml'
44 | def results = '*.war, target/debian/*.deb, target/rpm/*.rpm, target/suse/*.rpm'
45 | stash includes: results, name: 'results'
46 | archiveArtifacts results
47 | }
48 | }
49 | }
50 | }
51 |
52 | nodeWithTimeout('docker') {
53 | stage('Test') {
54 | checkout scm
55 | unstash 'results'
56 | infra.withDockerCredentials {
57 | ansiColor('xterm') {
58 | sh '''
59 | cat /proc/cpuinfo
60 | cat /proc/meminfo
61 | python3 -m venv venv
62 | . venv/bin/activate
63 | pip install -U pip wheel
64 | pip install -r requirements.txt
65 | ANSIBLE_FORCE_COLOR=true molecule test
66 | ANSIBLE_FORCE_COLOR=true molecule test -s servlet
67 | deactivate
68 | '''.stripIndent()
69 | }
70 | }
71 | }
72 | }
73 |
74 | void nodeWithTimeout(String label, Closure body) {
75 | node(label) {
76 | timeout(time: 1, unit: 'HOURS') {
77 | body()
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # refers to the definition of a release target
2 | BRAND ?= ./branding/test.mk
3 | include ${BRAND}
4 |
5 | # refers to the definition of the release process execution environment
6 | BUILDENV ?=./env/test.mk
7 | include ${BUILDENV}
8 |
9 | # refers to whereabouts of code-signing keys
10 | # CREDENTIAL ?=./credentials/test.mk
11 |
12 | include ${CREDENTIAL}
13 |
14 | include ./setup.mk
15 |
16 | PACKAGE_BUILDER_VERSION:=0.1
17 |
18 | #######################################################
19 |
20 | clean:
21 | rm -rf ${TARGET}
22 |
23 | setup:
24 | bash -ex -c 'for f in */setup.sh; do $$f; done'
25 |
26 | package: war deb rpm suse
27 |
28 | publish: war.publish deb.publish rpm.publish suse.publish
29 |
30 | test: deb.test rpm.test suse.test
31 |
32 | war: ${WAR}
33 | war.publish: ${WAR}
34 | ./war/publish/publish.sh
35 |
36 |
37 |
38 | deb: ${DEB}
39 | ${DEB}: ${WAR} $(shell find deb/build -type f)
40 | ./deb/build/build.sh
41 | deb.publish: ${DEB} $(shell find deb/publish -type f)
42 | ./deb/publish/publish.sh
43 |
44 |
45 |
46 | rpm: ${RPM}
47 | ${RPM}: ${WAR} $(shell find rpm/build -type f)
48 | ./rpm/build/build.sh
49 | rpm.publish: ${RPM} $(shell find rpm/publish -type f)
50 | ./rpm/publish/publish.sh
51 |
52 | suse: ${SUSE}
53 | ${SUSE}: ${WAR} $(shell find suse/build -type f)
54 | ./suse/build/build.sh
55 | suse.publish: ${SUSE} $(shell find suse/publish -type f)
56 | ./suse/publish/publish.sh
57 |
58 | msi.publish:
59 | ./msi/publish/publish.sh
60 |
61 | ${CLI}:
62 | @mkdir ${TARGET} || true
63 | wget -O $@.tmp ${JENKINS_URL}jnlpJars/jenkins-cli.jar
64 | mv $@.tmp $@
65 |
66 |
67 |
68 | test.local.setup:
69 | # start a test Apache server that acts as package server
70 | # we'll refer to this as 'test.pkg.jenkins.io'
71 | @mkdir -p ${TESTDIR} || true
72 | docker run --rm -t -i -p 9200:80 -v ${TESTDIR}:/var/www/html fedora/apache
73 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Native package script for Jenkins
2 |
3 | This repository contains scripts for packaging `jenkins.war` into various platform-specific native packages.
4 | The following platforms are currently supported:
5 |
6 | * Windows MSI: `msi/`
7 | * RedHat/CentOS RPM: `rpm/`
8 | * Debian/Ubuntu DEB: `deb/`
9 | * OpenSUSE RPM: `suse/`
10 |
11 | # Pre-requisites
12 | Running the main package script requires a Linux environment (currently Ubuntu, see [JENKINS-27744](https://issues.jenkins-ci.org/browse/JENKINS-27744).)
13 | Run `make setup` to install (most of the) necessary tools. Alternatively you can manually install the following onto a base install of Ubuntu:
14 | * make
15 | * unzip
16 | * devscripts
17 | * debhelper
18 | * rpm
19 | * expect
20 | * createrepo-c
21 | * ruby
22 | * net-sftp (`gem install net-sftp`)
23 | * maven
24 | * java
25 |
26 | You also need a Jenkins instance with [dist-fork plugin](https://wiki.jenkins-ci.org/display/JENKINS/DistFork+Plugin)
27 | installed. URL of this Jenkins can be fed into `make` via the `JENKINS_URL` variable.
28 | This Jenkins needs to have a Windows build agent that has [WiX Toolset](http://wixtoolset.org/) (currently 3.5), msbuild, [cygwin](https://www.cygwin.com/) and .net 2.0. This build agent is used to build MSI packages, which
29 | can be only built on Windows.
30 |
31 | You'll also need a `jenkins.war` file that you are packaging, which comes from the release process.
32 | The location of this file is set via the `WAR` variable.
33 |
34 | Remark:
35 |
36 | A docker image is available to run following script
37 |
38 | [](https://hub.docker.com/r/jenkinsciinfra/packaging)
39 |
40 | Run `docker-compose run --rm packaging bash` to get a shell in the official Docker image for this repository.
41 |
42 | # Generating packages
43 | Run `./prep.sh` to perform the preparatory actions of downloading the WAR and importing the GPG key.
44 | Run `make package` to build all the native packages.
45 | At minimum, you have to specify the `WAR` variable that points to the war file to be packaged and a branding file (for licensing and package descriptions).
46 | You will probably need to pass in the build environment and credentials.
47 |
48 | For example:
49 | ```shell
50 | make package BRAND=./branding/jenkins.mk BUILDENV=./env/test.mk CREDENTIAL=./credentials/test.mk
51 | ```
52 |
53 | Packages will be placed into `target/` directory.
54 | See the definition of the `package` goal for how to build individual packages selectively.
55 |
56 | # Running functional tests
57 |
58 | The functional tests require Python 3 and Docker.
59 | Having built the packages as described above, run the functional tests with:
60 |
61 | ```shell
62 | python3 -m venv venv
63 | source venv/bin/activate
64 | pip install -r requirements.txt
65 | molecule test
66 | deactivate
67 | ```
68 |
69 | # Publishing packages
70 | This repository contains scripts for copying packages over to a remote web server to publish them.
71 | Run `make publish` to publish all native packages.
72 |
73 | See the definition of the `publish` goal for individual package publishment.
74 |
75 | ## Running local tests
76 | These tests install packages from a web server where they are published. So if you want to
77 | run tests prior to publishing them, you need to create a temporary web server that you can mess up.
78 |
79 | The default branding & environment (`branding/test.mk` and `env/test.mk`) are designed to support
80 | this scenario. To make local testing work, you also need to have `/etc/hosts` entry that maps
81 | `test.pkg.jenkins.io` hostname to `127.0.0.1`, and your computer has to be running ssh that
82 | lets you login as you.
83 |
84 | Once you verified the above prerequisites, open another terminal and run `make test.local.setup`
85 | This will run a docker container that acts as your throw-away package web server. When done, Ctrl+C
86 | to kill it.
87 |
88 | # Branding
89 | `branding/` directory contains `*.mk` files that control the branding of the generated packages.
90 | It also include text files which are used for large, branded text blocks (license and descriptions).
91 | Specify the branding file via the `BRAND` variable.
92 |
93 | You can create your own branding definition to customize the package generation process.
94 | See [branding readme](branding/README.md) for more details. In the rest of the packaging script files,
95 | these branding parameters are referenced via `@@NAME@@` and get substituted by `bin/branding.py`.
96 | To escape a string normally like @@VALUE@@, add an additional two @@ symbols as a prefix: @@@@VALUE@@.
97 |
98 | # Environment
99 | `env/` directory contains `*.mk` files that control the environment into which
100 | you publish packages. Specify the environment file via the `BUILDENV` variable.
101 |
102 | You can create your own environment definition to customize the package generation process.
103 | See [environment readme](env/README.md) for more details.
104 |
105 | # Credentials
106 | `credentials/` directory contains `test.mk` file that controls the locations of code-signing keys,
107 | their passwords, and certificates. Specify the credentials file via the `CREDENTIAL` variable.
108 |
109 | For production use, you need to create your own credentials file. See [credentials readme](credentials/README.md)
110 | for more details.
111 |
112 | # TODO (mostly note to myself)
113 | * Split resource templates to enable customization
114 |
--------------------------------------------------------------------------------
/bin/branding-files.list:
--------------------------------------------------------------------------------
1 | DESCRIPTION_FILE
--------------------------------------------------------------------------------
/bin/branding.list:
--------------------------------------------------------------------------------
1 | PRODUCTNAME
2 | ARTIFACTNAME
3 | CAMELARTIFACTNAME
4 | VENDOR
5 | SUMMARY
6 | PORT
7 | MSI_PRODUCTCODE
8 | AUTHOR
9 | LICENSE
10 | HOMEPAGE
11 | CHANGELOG_PAGE
12 | ORGANIZATION
13 | ----------------------------------
14 | RELEASELINE
15 | RPM_URL
16 | SUSE_URL
17 | DEB_URL
18 | LICENSE_TEXT
19 | LICENSE_TEXT_DEB
20 | LICENSE_TEXT_COMMENTED
21 |
--------------------------------------------------------------------------------
/bin/branding.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import os
4 | import re
5 | import string
6 | import sys
7 |
8 | # Applies branding to files/folders with simple templating
9 | # Usage is 'python branding.py {file or folder}'
10 | # Env variables to use are given in BRANDING_ENV_VARIABLE_LIST
11 | # Env variables giving *paths* to read content for templating are given in BRANDING_ENV_PATH_LIST
12 | # Author Sam Van Oort
13 |
14 | BRANDING_ENV_VARIABLE_LIST = "branding.list"
15 | BRANDING_ENV_PATH_LIST = "branding-files.list"
16 |
17 |
18 | class CustomTemplate(string.Template):
19 | delimiter = "@@"
20 | pattern = r""" %(delim)s(?:
21 | (?P) | # Nope, taken care of by the delimiter not being a valid id character
22 | (?P%(id)s) | # delimiter and a Python identifier
23 | (?P%(id)s) | # we don't support braced identifiers, since it's surrounded by delimiters
24 | (?P) # no matches
25 | )%(delim)s """ % dict(
26 | delim=re.escape("@@"), id=string.Template.idpattern
27 | )
28 |
29 |
30 | def clean_text_lines(textcontent):
31 | """Splits file content by line boundaries, strips leading/trailing whitespace,
32 | and removes comments with # and -- prefixes and whitespace lines"""
33 | lines = map(lambda x: x.strip(), textcontent.splitlines())
34 | lines = filter(
35 | lambda x: x and not x.startswith("#") and not x.startswith("--"), lines
36 | )
37 | return lines
38 |
39 |
40 | def read_env_variable_list(path):
41 | """Read a list of environment variables from a file (one per line) and get a dict of var:value"""
42 | with open(path, "r") as env_file:
43 | lines = clean_text_lines(env_file.read())
44 | return {x: os.environ.get(x) for x in lines}
45 |
46 |
47 | def read_file_content(value_path_dictionary):
48 | """For a {variable_name:file_path} dictionary, read each file and
49 | return a dictionary of {variable:file_content}
50 |
51 | If paths are null/empty, they are not read to result."""
52 | output = {}
53 | filtered = filter(lambda x: x[1] and x[1].strip(), value_path_dictionary.items())
54 | for variable, path in filtered:
55 | with open(path, "r") as f:
56 | output[variable] = f.read()
57 | return output
58 |
59 |
60 | def read_branding_variables(base_path, env_variables_list, file_variables_list):
61 | """Read branding variables from files/environment and return result"""
62 |
63 | raw_variables = read_env_variable_list(os.path.join(base_path, env_variables_list))
64 | file_variables = read_env_variable_list(
65 | os.path.join(base_path, file_variables_list)
66 | )
67 | raw_variables.update(
68 | read_file_content(file_variables)
69 | ) # Add file content variables
70 | return raw_variables
71 |
72 |
73 | def apply_template(input_string, branding_map):
74 | """Applies templating in a back-compatible fashion"""
75 | return CustomTemplate(input_string).substitute(branding_map)
76 |
77 |
78 | def apply_templating_to_file(path, branding_map):
79 | """Do IN-PLACE search and replace using string templating for a each file
80 | Throws Exceptions if I/O fails or substitution is missing vars (safety check)
81 | """
82 | with open(path, "r+") as f:
83 | f_content = apply_template(f.read(), branding_map)
84 | f.seek(0)
85 | f.write(f_content)
86 | f.truncate() # This removes any original content beyond the end of templated content
87 |
88 |
89 | def apply_templating_to_folder(path, branding_map):
90 | """Walks through all contents of folder recursively, and applies templating"""
91 | for root, dirnames, filenames in os.walk(path):
92 | for filename in filenames:
93 | apply_templating_to_file(os.path.join(root, filename), branding_map)
94 |
95 |
96 | # Importable as a library without executing it
97 | if __name__ == "__main__":
98 | if len(sys.argv) != 2:
99 | raise Exception("Usage: branding.py [file or folder name]")
100 | path = sys.argv[1]
101 |
102 | mypath = os.path.dirname(os.path.realpath(__file__))
103 | branding_values = read_branding_variables(
104 | mypath, BRANDING_ENV_VARIABLE_LIST, BRANDING_ENV_PATH_LIST
105 | )
106 |
107 | # List of branding values that are allowed to be blank
108 | allowed_blank = ["RELEASELINE"]
109 | # Remove branding values with nothing set so we fail early if they are used in a template
110 | # except for values where blank is explicitly allows
111 | branding_values = {
112 | k: v for k, v in branding_values.items() if k in allowed_blank or v
113 | }
114 |
115 | # Apply templating to files or content of folder
116 | if os.path.isfile(path):
117 | apply_templating_to_file(path, branding_values)
118 | elif os.path.isdir(path):
119 | apply_templating_to_folder(path, branding_values)
120 | else:
121 | raise Exception("Supplied path must be file or directory")
122 |
--------------------------------------------------------------------------------
/bin/indexGenerator.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import getopt
4 | import jinja2
5 | import os
6 | import pathlib
7 | import sys
8 |
9 |
10 | def basename(path):
11 | return os.path.basename(path)
12 |
13 |
14 | class IndexGenerator:
15 | DISTRIBUTIONS = {
16 | "debian": {
17 | "extension": ".deb",
18 | "template": "header.debian.html",
19 | "web_url": os.getenv("DEB_URL"),
20 | },
21 | "redhat": {
22 | "extension": ".rpm",
23 | "template": "header.redhat.html",
24 | "web_url": os.getenv("RPM_URL"),
25 | },
26 | "opensuse": {
27 | "extension": ".rpm",
28 | "template": "header.opensuse.html",
29 | "web_url": os.getenv("SUSE_URL"),
30 | },
31 | "war": {"extension": ".war", "template": "header.war.html", "web_url": "unset"},
32 | "windows": {
33 | "extension": ".msi",
34 | "template": "header.msi.html",
35 | "web_url": "unset",
36 | },
37 | }
38 |
39 | HELP_MESSAGE = """
40 | Generate header.html for package distribution site
41 | It supports debian, redhat and opensuse packages
42 |
43 | indexGenerator.py
44 | -d : Which package distribution to target
45 | -o : Where to create the HEADER.html
46 |
47 | ex:
48 | indexGenerator.py
49 | -d debian
50 | -o /packages/website/debian
51 | """
52 |
53 | packages = []
54 | targetFile = ""
55 | template_file = ""
56 | template_directory = "templates"
57 | repositories = []
58 |
59 | def __init__(self, argv):
60 |
61 | self.artifact = os.getenv("ARTIFACTNAME", "jenkins")
62 | self.releaseline = os.getenv("RELEASELINE", "")
63 | self.download_url = os.getenv("URL", "null")
64 | self.organization = os.getenv("ORGANIZATION", "jenkins.io")
65 | self.product_name = os.getenv("PRODUCTNAME", "Jenkins")
66 | self.distribution = os.getenv("OS_FAMILY", "debian")
67 | self.gpg_pub_key_info_file = os.getenv("GPGPUBKEYINFO", ".")
68 | self.target_directory = "./target/" + self.distribution
69 |
70 | try:
71 | opts, args = getopt.getopt(
72 | argv, "hd:o:", ["targetDir=", "distribution=", "gpg-key-info-file="]
73 | )
74 | except getopt.GetoptError:
75 | print(self.HELP_MESSAGE)
76 | sys.exit(2)
77 | for opt, arg in opts:
78 | if opt == "-h":
79 | print(self.HELP_MESSAGE)
80 | sys.exit()
81 | elif opt in ("-d", "--distribution"):
82 | self.distribution = arg
83 | self.target_directory = "./target/" + self.distribution
84 | os.makedirs(self.target_directory, exist_ok=True)
85 | elif opt in ("-g", "--gpg-key-info-file"):
86 | self.gpg_pub_key_info_file = arg
87 | elif opt in ("-o", "--targetDir"):
88 | self.target_directory = arg
89 | self.targetFile = self.target_directory + "/HEADER.html"
90 |
91 | self.targetFile = self.target_directory + "/HEADER.html"
92 | self.footer = self.target_directory + "/FOOTER.html"
93 | self.index = self.target_directory + "/index.html"
94 | self.template_file = self.DISTRIBUTIONS[self.distribution]["template"]
95 | self.root_dir = os.path.dirname(self.target_directory[0:-1])
96 | self.root_header = self.root_dir + "/HEADER.html"
97 | self.root_footer = self.root_dir + "/FOOTER.html"
98 | self.web_url = self.DISTRIBUTIONS[self.distribution]["web_url"]
99 |
100 | def show_information(self):
101 | print("Product Name: " + self.product_name)
102 | print("Download URL: " + self.download_url)
103 | print("Organization: " + self.organization)
104 | print("Artifact Name: " + self.artifact)
105 | print("Distribution: " + self.distribution)
106 | print("Web URL: " + str(self.web_url))
107 | print("Number of Packages found: " + str(len(self.packages)))
108 | print("Template file: " + self.template_file)
109 | print("Repository header generated: " + self.targetFile)
110 | print("Repository index generated: " + self.index)
111 | print("Repository footer generated: " + self.footer)
112 | print("Root header generated: " + self.root_header)
113 | print("Root footer generated: " + self.root_footer)
114 | print("GPG Key Info File: " + self.gpg_pub_key_info_file)
115 |
116 | def generate_root_header(self):
117 |
118 | contexts = {
119 | "product_name": self.product_name,
120 | "repositories": self.repositories,
121 | }
122 |
123 | env = jinja2.Environment(
124 | loader=jinja2.FileSystemLoader(self.template_directory)
125 | )
126 | template = env.get_template("header.root.html")
127 |
128 | with open(self.root_header, "w") as f:
129 | f.write(template.render(contexts))
130 |
131 | def generate_root_footer(self):
132 |
133 | contexts = {}
134 |
135 | env = jinja2.Environment(
136 | loader=jinja2.FileSystemLoader(self.template_directory)
137 | )
138 | template = env.get_template("footer.html")
139 |
140 | with open(self.root_footer, "w") as f:
141 | f.write(template.render(contexts))
142 |
143 | def generate_footer(self):
144 |
145 | contexts = {"product_name": self.product_name}
146 |
147 | env = jinja2.Environment(
148 | loader=jinja2.FileSystemLoader(self.template_directory)
149 | )
150 | template = env.get_template("footer.html")
151 |
152 | with open(self.footer, "w") as f:
153 | f.write(template.render(contexts))
154 |
155 | def fetch_pubkeyinfo(self):
156 | pub_key_info = ""
157 |
158 | if self.gpg_pub_key_info_file != ".":
159 | gpg_pub_key = pathlib.Path(self.gpg_pub_key_info_file)
160 | if gpg_pub_key.is_file():
161 | with open(self.gpg_pub_key_info_file, "r") as gpg_pub_key:
162 | pub_key_info = gpg_pub_key.read()
163 |
164 | return pub_key_info
165 |
166 | def generate_repository_header(self):
167 | contexts = {
168 | "product_name": self.product_name,
169 | "url": self.download_url,
170 | "organization": self.organization,
171 | "artifactName": self.artifact,
172 | "os_family": self.distribution,
173 | "packages": self.packages,
174 | "releaseline": self.releaseline,
175 | "web_url": self.web_url,
176 | "pub_key_info": self.fetch_pubkeyinfo(),
177 | }
178 |
179 | env = jinja2.Environment(
180 | loader=jinja2.FileSystemLoader(self.template_directory)
181 | )
182 | env.filters["basename"] = basename
183 | template = env.get_template(self.template_file)
184 |
185 | with open(self.targetFile, "w") as f:
186 | f.write(template.render(contexts))
187 |
188 | def generate_repository_index(self):
189 | contexts = {
190 | "header": self.template_file,
191 | "product_name": self.product_name,
192 | "url": self.download_url,
193 | "organization": self.organization,
194 | "artifactName": self.artifact,
195 | "os_family": self.distribution,
196 | "packages": self.packages,
197 | "releaseline": self.releaseline,
198 | "web_url": self.web_url,
199 | "pub_key_info": self.fetch_pubkeyinfo(),
200 | }
201 |
202 | env = jinja2.Environment(
203 | loader=jinja2.FileSystemLoader(self.template_directory)
204 | )
205 | env.filters["basename"] = basename
206 | templateIndex = env.get_template("index.html")
207 |
208 | with open(self.index, "w") as f:
209 | f.write(templateIndex.render(contexts))
210 |
211 |
212 | if __name__ == "__main__":
213 | headerGenerator = IndexGenerator(sys.argv[1:])
214 | headerGenerator.show_information()
215 | headerGenerator.generate_repository_header()
216 | headerGenerator.generate_footer()
217 | headerGenerator.generate_repository_index()
218 | headerGenerator.generate_root_header()
219 | headerGenerator.generate_root_footer()
220 |
--------------------------------------------------------------------------------
/bin/test_branding.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import branding
4 | import os
5 | import string
6 | import tempfile
7 | import unittest
8 |
9 | RAW_CONTENT = """
10 | PRODUCTNAME
11 | ARTIFACTNAME
12 |
13 | SUMMARY
14 | PORT
15 |
16 | AUTHOR
17 | # Not here
18 | LICENSE
19 | HOMEPAGE
20 | CHANGELOG_PAGE
21 | ----------------------------------
22 |
23 | SUSE_URL
24 | # INVALID
25 | DEB_URL
26 | LICENSE_TEXT
27 |
28 | """
29 |
30 | SHORT_VARS = """
31 | TESTVAR
32 | """
33 |
34 | # NOMATCH is a section that should *not* be treated as a variable for substitution to
35 | # Avoid issues with curly braces
36 | TEMPLATED_CONTENT = (
37 | "My @@VAR@@ is @@FILECONTENT@@ and I have @@@@ESCAPES@@ and @@{NOMATCH}@@ stuff"
38 | )
39 | TEMPLATE_VARS = {"VAR": "SPECIAL", "FILECONTENT": "gooooooober"}
40 |
41 | # Shows that substitutions were performed, and NOMATCH does not get handled as a substitution variable
42 | TEMPLATE_EXPECTED = (
43 | "My SPECIAL is gooooooober and I have @@ESCAPES@@ and @@{NOMATCH}@@ stuff"
44 | )
45 |
46 |
47 | class TestBranding(unittest.TestCase):
48 | def test_clean_lines(self):
49 | cleaned = set(branding.clean_text_lines(RAW_CONTENT))
50 | expected = {
51 | "PRODUCTNAME",
52 | "ARTIFACTNAME",
53 | "SUMMARY",
54 | "PORT",
55 | "AUTHOR",
56 | "LICENSE",
57 | "HOMEPAGE",
58 | "CHANGELOG_PAGE",
59 | "SUSE_URL",
60 | "DEB_URL",
61 | "LICENSE_TEXT",
62 | }
63 | invalid_results = cleaned ^ expected # Items in one set but not the other
64 | self.assertFalse(invalid_results)
65 |
66 | def test_read_env_list(self):
67 | temp = tempfile.NamedTemporaryFile()
68 | temp.write(SHORT_VARS.encode())
69 | temp.seek(0)
70 | os.environ["TESTVAR"] = "testvalue"
71 | vals = branding.read_env_variable_list(temp.name)
72 | self.assertEqual(1, len(vals))
73 | self.assertEqual("testvalue", vals["TESTVAR"])
74 |
75 | def test_read_file_content(self):
76 | """Write file and then read, using path from env"""
77 | temp = tempfile.NamedTemporaryFile()
78 | temp.write(RAW_CONTENT.encode())
79 | temp.seek(0)
80 |
81 | os.environ["FILEPATH"] = temp.name
82 | vals = branding.read_file_content({"FILEPATH": temp.name})
83 | self.assertEqual(RAW_CONTENT, vals["FILEPATH"])
84 |
85 | def test_templating(self):
86 | output = branding.apply_template(TEMPLATED_CONTENT, TEMPLATE_VARS)
87 | self.assertEqual(TEMPLATE_EXPECTED, output)
88 |
89 | def test_missing_variable(self):
90 | """Prove branding will fail if branding variable is undefined"""
91 |
92 | try:
93 | output = branding.apply_template(
94 | "My @@UNDEFINED_VALUE@@ is going to fail", {"going": "to fail"}
95 | )
96 | self.fail("Should throw KeyError")
97 | except KeyError:
98 | pass
99 |
100 | def test_in_place_templating(self):
101 | temp = tempfile.NamedTemporaryFile()
102 | temp.write(TEMPLATED_CONTENT.encode())
103 | temp.seek(0)
104 | branding.apply_templating_to_file(temp.name, TEMPLATE_VARS)
105 | temp.seek(0)
106 | self.assertEqual(TEMPLATE_EXPECTED, temp.read().decode())
107 |
108 |
109 | if __name__ == "__main__":
110 | unittest.main()
111 |
--------------------------------------------------------------------------------
/branding/README.md:
--------------------------------------------------------------------------------
1 | # Branding Definition
2 | Branding definition file has the following variables
3 |
4 | * `RELEASELINE`: used only for OSS Jenkins releases. This variable selects one of the 4 release lines that we
5 | maintain (empty for mainline releases, "-rc" for RCs, "-stable" for LTS, and "-stable-rc" for LTS RCs.)
6 | * `PRODUCTNAME`: Short human readable name of the product. Should be something like "Acme Foo Bar Zot".
7 | Used as the title of the product.
8 | * `SUMMARY`: One line human readable description of what the product does.
9 | * `ARTIFACTNAME`: Alpha-numeric lower-case (plus '-' and '_') only machine name of the product. Used as the stem of the file names.
10 | * `CAMELARTIFACTNAME`: Alpha-numeric machine name of the product, but in CamelCase (such as FooBarZot.)
11 | By convention this name should not have '-' or '_'
12 | * `VENDOR`: Short human readable name of the entity that generates the package.
13 | * `PORT`: TCP/IP port that Jenkins will bind to out of the box.
14 | * `MSI_PRODUCTCODE`: Windows installer uses UUID to identify which MSI files are of the same lineage.
15 | If two MSIs have the same UUID, one will overwrite another. So if you are to produce your own MSI,
16 | you need to use a different UUID.
17 | * `AUTHOR`: Author name & email for distributed package, i.e. Bob Smith
18 | * `LICENSE`: License(s) for this distribution, such as 'Apache 2.0'
19 | * `HOMEPAGE`: homepage URL for this distribution of Jenkins (where users should go for more information)
20 | * `CHANGELOG_PAGE`: URL that users should visit to see the changelog for this distribution of Jenkins
21 |
22 | # Branding Files
23 | Each of these is an (absolute) path to a file containing a larger blob of brand-specific information.
24 | The file is read to the environment variable, and then templated in as with the variables above
25 |
26 | * `DESCRIPTION_FILE`: path to file containing the RPM description section (see 'description-file' in branding for an example)
27 |
28 | # Special handling:
29 |
30 | License files are handled specially:
31 | * `LICENSE_FILE` is the path of a file containing the license/copyright text body
32 |
33 | This is transformed specially (by setup.mk) for use in branding each different package:
34 |
35 | * `LICENSE_TEXT` is the actual file contents
36 | * `LICENSE_TEXT_COMMENTED` is the license text, split to 80 character lines with #-style comment at the start of each line
37 | * `LICENSE_TEXT_DEB` is formatted for a Debian copyright file, with a . between each paragraph, and one whitespace before each line
38 |
--------------------------------------------------------------------------------
/branding/common:
--------------------------------------------------------------------------------
1 | # this isn't a release line by itself but instead defines the commonality of the all OSS release lines.
2 |
3 | export PRODUCTNAME=Jenkins
4 | export ARTIFACTNAME=jenkins
5 | export CAMELARTIFACTNAME=Jenkins
6 | export VENDOR=Jenkins project
7 | export SUMMARY=Jenkins Automation Server
8 | export PORT=8080
9 |
10 | export MSI_PRODUCTCODE=415933d8-4104-47c3-aee9-66b31de07a57
11 | export AUTHOR=Kohsuke Kawaguchi
12 | export LICENSE=MIT/X License, GPL/CDDL, ASL2
13 | export HOMEPAGE=https://www.jenkins.io/
14 | export CHANGELOG_PAGE=https://www.jenkins.io/changelog
15 |
16 | # figure out the directory of this file
17 | BRANDING_DIR:=$(shell dirname "$(realpath $(lastword $(MAKEFILE_LIST)))")
18 |
19 | export DESCRIPTION_FILE=$(BRANDING_DIR)/description-file
20 | export LICENSE_FILE=$(BRANDING_DIR)/license-mit
21 |
--------------------------------------------------------------------------------
/branding/description-file:
--------------------------------------------------------------------------------
1 | Jenkins is the leading open source automation server supported by a large and growing community of developers, testers, designers and other people interested in continuous integration, continuous delivery and modern software delivery practices. Built on the Java Virtual Machine (JVM), it provides more than 2,000 plugins that extend Jenkins to automate with practically any technology software delivery teams use. In 2022, Jenkins reached 300,000 known installations making it the most widely deployed automation server.
2 |
3 | For more information, see https://www.jenkins.io.
4 |
--------------------------------------------------------------------------------
/branding/jenkins-experimental.mk:
--------------------------------------------------------------------------------
1 | export RELEASELINE=-experimental
2 | export ORGANIZATION=jenkins.io
3 | include branding/common
4 |
--------------------------------------------------------------------------------
/branding/jenkins-rc.mk:
--------------------------------------------------------------------------------
1 | export RELEASELINE=-rc
2 | include branding/common
3 |
--------------------------------------------------------------------------------
/branding/jenkins-stable-rc.mk:
--------------------------------------------------------------------------------
1 | export RELEASELINE=-stable-rc
2 | include branding/common
3 |
--------------------------------------------------------------------------------
/branding/jenkins-stable.mk:
--------------------------------------------------------------------------------
1 | export RELEASELINE=-stable
2 | include branding/common
3 |
--------------------------------------------------------------------------------
/branding/jenkins.mk:
--------------------------------------------------------------------------------
1 | export RELEASELINE=
2 | export ORGANIZATION=jenkins.io
3 | include branding/common
4 |
--------------------------------------------------------------------------------
/branding/license-mit:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2004-, Kohsuke Kawaguchi, Sun Microsystems, Inc., and a number of other of contributers
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 |
--------------------------------------------------------------------------------
/branding/test.mk:
--------------------------------------------------------------------------------
1 | #
2 | # Profile for testing release process
3 | #
4 | export RELEASELINE=
5 |
6 | export PRODUCTNAME=Jenkins Test
7 | export ARTIFACTNAME=jenkinstest
8 | export CAMELARTIFACTNAME=JenkinsTest
9 | export VENDOR=Jenkins Test project
10 | export SUMMARY=Jenkins Automation Server (Test)
11 | export PORT=7777
12 |
13 | export MSI_PRODUCTCODE=e76baa9f-2bb2-49e5-b518-8a5b7d1cd084
14 | export AUTHOR=Bogus user
15 | export LICENSE=MIT/X License, GPL/CDDL, ASL2
16 | export HOMEPAGE=http://test.jenkins.io/
17 | export CHANGELOG_PAGE=http://test.jenkins.io/changelog
18 |
19 | export ORGANIZATION=example.org
20 |
21 | # figure out the directory of this file
22 | BRANDING_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
23 |
24 | export DESCRIPTION_FILE=$(BRANDING_DIR)/description-file
25 | export LICENSE_FILE=$(BRANDING_DIR)/license-mit
26 |
--------------------------------------------------------------------------------
/credentials/Makefile:
--------------------------------------------------------------------------------
1 | test.crt: test.key test.csr apple.conf
2 | openssl x509 -in test.csr -out test.crt -req -signkey test.key -days 36500 -extfile apple.conf -extensions extensions
3 |
4 | test.pkcs12: test.key test.crt
5 | openssl pkcs12 -export -inkey test.key -in test.crt -out test.pkcs12 -password pass:s3cr3t
6 |
7 | # generate keychain file to go through the signing process
8 | test.keychain: test.pkcs12
9 | @rm $@ 2>&1 > /dev/null || true
10 | security create-keychain -p s3cr3t `pwd`/test.keychain
11 | security import test.pkcs12 -k `pwd`/test.keychain -t agg -f pkcs12 -A -P s3cr3t
12 |
13 |
--------------------------------------------------------------------------------
/credentials/README.md:
--------------------------------------------------------------------------------
1 | # Code-signing credentials
2 | Different platforms want private keys and certificates in different formats.
3 | To correctly sign all the supported formats, you need your keys in the following format:
4 |
5 | * Code-signing key and certificate in PKCS12 format for Windows
6 | * OS X keychain file that contains a valid installer signing certificate issued from Apple.
7 | This requires you to be a member of the Mac Developer Program. Create a separate keychain,
8 | add your code signing key and certificate, and use this keychain file.
9 | * GPG secret/public keypair in separate GPG public keyring and GPG secret keyring.
10 |
11 | `test.mk` contains the variable definitions to point to those files.
12 |
13 | ## Creating your own GPG key
14 |
15 | Generate a new GPG key with `gpg --full-generate-key`:
16 |
17 | * When asked what kind of key you want, select "(1) RSA and RSA (default)".
18 | * When asked what key size you want, enter "4096" bits.
19 | * When asked how long the key should be valid, enter "0" (key does not expire).
20 | * When asked for your real name, enter "Bogus Test".
21 | * When asked for your email address, enter "noreply@jenkins-ci.org".
22 | * When asked for a comment, enter "This is test only key".
23 | * When asked for the secret password, enter the password from `test.gpg.password.txt`.
24 |
25 | Export your public key & private key
26 |
27 | gpg --export KEYID > test.gpg
28 | gpg --export --armor KEYID > test.ascii.key
29 | gpg --export-secret-keys KEYID > test.secret.gpg
30 | cat test.gpg >sandbox.gpg
31 | cat test.secret.gpg >>sandbox.gpg
32 |
33 | Verify the newly created keyring. Note that the keyring options must have some directory name parts in it, or else it's treated as they are in `~/.gnupg`
34 |
35 | gpg --no-default-keyring --keyring=./test.gpg --secret-keyring=./test.secret.gpg --list-keys
36 | gpg --no-default-keyring --keyring=./test.gpg --secret-keyring=./test.secret.gpg --list-secret-keys
37 |
--------------------------------------------------------------------------------
/credentials/apple.conf:
--------------------------------------------------------------------------------
1 | [ req ]
2 | distinguished_name = req_name
3 | prompt = no
4 | [ req_name ]
5 | CN = my-test-installer
6 | [ extensions ]
7 | basicConstraints=critical,CA:false
8 | keyUsage=critical,digitalSignature
9 | extendedKeyUsage=critical,1.2.840.113635.100.4.13
10 | 1.2.840.113635.100.6.1.14=critical,DER:0500
11 |
--------------------------------------------------------------------------------
/credentials/sandbox.gpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jenkinsci/packaging/621e33ede4493dbc702152435a777a982c30d633/credentials/sandbox.gpg
--------------------------------------------------------------------------------
/credentials/ssh/id_rsa:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIIEowIBAAKCAQEAw6bQJN8ceL5T7FaNs2QdSEnGgLKy5zvpuORDJLd0Q/wTm5DV
3 | MVxqJzT8hCtL7a4D1NBPaBm6pAvlxCnKMhdZwSi+e2zuzRokOuivlAHyiV7le9Ln
4 | 1K/pKkDchAIz8P3YWLt1YZJERDUI8nXW9MC8ZOEt/IudmLTsZQcSr8lXOFIwNZe4
5 | b/NSr/9sxvSnYQqw5q6j1ZxdjW/KtXPQapU+PObZ/31jzTH9W966LpoF8XYo0xRA
6 | hJvy3f+NxbSVPhjH422wHCeeyfI/+B/xYlVNC3yYR4ONvXbAXsewB0aRhnOfh+sS
7 | kzotOCDMBZHOjKrg27MLs0dfrmjxGffF2Vq+JQIDAQABAoIBAELefZ9Mfg+qhUZu
8 | YqngWr29MVIFQW4UpRIjOeuPo/YkbpMp0iO3wTQ7QN7vaVkHs5mFxM4AlTDCPDpq
9 | SggKwQtqoIfQuGFzQNS9eFzuuXVH8Mj8UW343Ykqd/PKSPRh3hKdp0W81wY01iUA
10 | L4KhaQJVkAETur5Zf74bx8A64UuG+qWbDUGlRGCRk/pl9xGB1z0FQ7Api/6gQd2A
11 | Tnu6ASmQfoKeDsDDOBVy8sHv7HlkU9msowD9TdOj7Gxx9DoPryX6GlAhgi//+jyA
12 | qUCf03kdey5aCVKFVUIOkxpDxYRI0etW0ef0rww+DJDpL7pT0kWMf4sqxgmxPTly
13 | TaOnl+ECgYEA4GpfL7GTPTFvhatxi78TlaATTzjmzPYLrxOF8EHQM3Tz/nDbDknX
14 | x5YtQdq0cv2TNdR2uZ0AyuzZ06j6axyBCJWKgtErN+SO01+Qxa9rcv+Vw7NtdTGs
15 | GUrMa7CU/X4t8jt6UiObIgGRNbvu93ANeEzjIOFn9S9QKQ0vrtfW/W0CgYEA3zAV
16 | /z5rt/AThnajCRPv5c/o9c2TykKy3DFFUdgNTEwnHE04D+xoqH1eoTMNoNXdVbI0
17 | 1C5WTzCpYLuKmbl/aZEwvidi6ssTpYHcviAAz8iqN/TL9Ys5XmJ3iJViNK3IxxHB
18 | TRLMiBC057tS8ZZLRa756weEZ2TUYRydxFntaJkCgYAV/nbbvsSWb7zlVdsn/g8W
19 | T/z0e7grCEY232v2Ew0rrd+n5Tmi2dvbBL3kwWGED5QY53zHTjrgqHvkwZ/hVYbT
20 | 54wOrB9XOABDeQ9AQKQAPkpYRsKIhNjAFdOZDlJb0b0BC5E+cZznpU2s/YE7IPFB
21 | BBASjeTZY8ywaUluEltQtQKBgCi2idy000uLdNRbgeQfCez/Hzzvkl0cC6qVJlMG
22 | uW5Imf3UrDxjYLgTnpaDTKIhQS3nwzFNfpsVgmBN9buTFgX44U5euvGft+bCKLVZ
23 | +yvsK/jnI+mXyxBHoAx/S5nWdcCyoXNg0YSkn4uCJWBCjVqZz6crCOEfiIpqgPEX
24 | gnJJAoGBAKvDah87FijEJRBiaroef5buG1jr9pNCBoXIGbvZ1sFwkGWQGgrH6Y3s
25 | EBD083+BBCcIMvzy2leB692axxGhtdyCxfPRN7KiZgT/YC6cCDL1yzhSHtZ8kamb
26 | N8Qqs+wVE4YIdELB+VgKTho1v4gAyzZNuMJMhne6qH+oxNfGUgER
27 | -----END RSA PRIVATE KEY-----
28 |
--------------------------------------------------------------------------------
/credentials/ssh/id_rsa.pub:
--------------------------------------------------------------------------------
1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDptAk3xx4vlPsVo2zZB1IScaAsrLnO+m45EMkt3RD/BObkNUxXGonNPyEK0vtrgPU0E9oGbqkC+XEKcoyF1nBKL57bO7NGiQ66K+UAfKJXuV70ufUr+kqQNyEAjPw/dhYu3VhkkRENQjyddb0wLxk4S38i52YtOxlBxKvyVc4UjA1l7hv81Kv/2zG9KdhCrDmrqPVnF2Nb8q1c9BqlT485tn/fWPNMf1b3roumgXxdijTFECEm/Ld/43FtJU+GMfjbbAcJ57J8j/4H/FiVU0LfJhHg429dsBex7AHRpGGc5+H6xKTOi04IMwFkc6MquDbswuzR1+uaPEZ98XZWr4l olblak@winterfell
2 |
--------------------------------------------------------------------------------
/credentials/ssh/known_hosts:
--------------------------------------------------------------------------------
1 | |1|3Ao1unSiaoLJcBH+jj4LxlUJvU8=|9VCo6soeOkBokfDfbckMBvnE/6k= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFnJjx5araEbR3BvluFk5ONHqZSVZW1osdn4NuC/UBFPxwcEkkECK0EHR+WTxfTLGybJCTh3H5hTDady7W0EyIs=
2 | |1|Orovxffw11DXksUZda8iwv3XcME=|OIrRb9oqBvY2esPMc+I0K70HLSs= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFnJjx5araEbR3BvluFk5ONHqZSVZW1osdn4NuC/UBFPxwcEkkECK0EHR+WTxfTLGybJCTh3H5hTDady7W0EyIs=
3 |
--------------------------------------------------------------------------------
/credentials/test.ascii.key:
--------------------------------------------------------------------------------
1 | -----BEGIN PGP PUBLIC KEY BLOCK-----
2 |
3 | mQINBGIgHG8BEAD1EcibFpYRfEakMtky2E2pVqbwbTNH+jUr9XjMuyltEmIvlnNW
4 | W1ZzAlKY9hIM1zOhXp3jO3LCschvb6Rff8CuV0i+3g4rPi35i8Ur3MVkr7yTelge
5 | sF8ywZrAL3zhJDkeUChbKgWHB5HKdL/ZkEBci7TbHzSolGlKPA0YcAmE0jROfXal
6 | VBT7jcwJ2xx7RGYoRn5UHpJ2N5eRj96+wpI2SbZcNXaLSGd+rZNd9Q/4Xozw2Mzs
7 | PXCGUlk1tDfPSv91PHbYj1h1bIiU4iOISTOQJay5MjTyVHEho6LJ4s8PVsiG0/hB
8 | bEo8r2Izw75GShD7A9ZYUxlj8IqtzMjvNLxakN3U6lwLbcOYSDf6l2uIYl5UOhaf
9 | X9JeGll//hXSRiDQOwnO2LxqXwZ/uRP/IvoygswdKCPqot0Sl4q5VkfTt3PWNmEa
10 | dVDl52pj2GW4/REL8ouqGmaHwusuxxRekbYYXxqWTKoicoyTamcxKLrEBJ3vTIsS
11 | 4CQDl2hO67Gk1wzbdnTY7vzt1+8FlexKeu1XB1bv6VQSoJRdKPtfx5ZMdM6416hN
12 | VAdTGfCNEqBZn2KP3kPkHtc4/+BGKfBZDJwbPSta2VdvgGWTSQqia8vgPRFn9waS
13 | +nJKVCR1btoVBOX1F3N8VWl939J9V2bnMAj6AlbFeuxIB8C/8BSIShma+QARAQAB
14 | tDtCb2d1cyBUZXN0IChUaGlzIGlzIHRlc3Qgb25seSBrZXkpIDxub3JlcGx5QGpl
15 | bmtpbnMtY2kub3JnPokCUgQTAQgAPBYhBNkdPgAgAQfkIZUk3UJxW1biEbBCBQJi
16 | IBxvAhsDBQsJCAcCAyICAQYVCgkICwIEFgIDAQIeBwIXgAAKCRBCcVtW4hGwQgLB
17 | D/4m17etiSMd6i/eWM8Z3EXiGC4+lZRq0eJ+n0HDDcVG4PEmUWwNCpe5x12iJXF4
18 | XApWOFxyC6ptTHMYPxiYr5VebJaSqzYlIb+gJY2GGoFGvvLr+A746SmmWannWkG8
19 | hfi37V7gBIhQ45kOAY91XR7Vxr12b2Xg1QeLaOTktAXeZV/b5UYLxuhm6FUGtQdw
20 | X13W+xtfjRjUkSSVkdaf9wXX3gW6i+ihrT1deL/PenfoPGJCIGV3/qNr5CkP7v0O
21 | BD7sUAmZyqwWo8HjK4fVSY4Sr0akG6QPQoE4WdaldZB8AJmJ/nwiIlFFnOrism5e
22 | rQlSq1XTCniEzIQPoLr9SY4vzC+ZuZArBqfedAEh8qut1Pl0unEvkBoe6bSxeF/W
23 | WOzL9J+LVwgoulUR2FjRZiCelCJFp5u6DpaV3P3ljsfvijhEips/4YPpYyuAQBWm
24 | x9RXf6Sx/vBx79bfts2jgJwIouCxLUsJf7lTgrZuurRkmdPu/rcOnDMWr3cAuFqa
25 | oWQOT2ktunQz53lLbXoIRzYOJCLmf2eVTyCSU5NGF5Del+wIJhnwAJi5u5m3RwUk
26 | lMNhCJ4vLWiq87ngSfxJG4s0BECdfDtUMzNwGNRNA825GPEIoliogA+lH0UkuDPo
27 | i8kdlmJlmUbZ2OR7EEjVDNMmOB5V4DdDaNhovjOvZB+cNLkCDQRiIBxvARAAyFyj
28 | RqO9/nV6/EmDk9TUYIBSSrCJJOIdKXMgpXup9ILxy9mXpZPOX7mAyvw/u3zRYjQt
29 | vB+jp+1OwZ5hgy9FBxs4JYFzT+PaNwOdeEK5woEqJMOUCWpiI9ljNFOIubqspLaa
30 | JGaUj6wr5ajWvwoC0wy22t77fIRf09fMmhtQ6D6aLS+gQ7bABVwcwNrObSjder0w
31 | Sb+deh+2tzSchby0w8Yn5RuVcnQhygfNiK2uqXrUROnkpY5r2JeWm853C4nog9rN
32 | MEAStAxdvjb6/GJSJ8UZdtlyIqsyWZEPYnRmYi4zvoP7yksC4Qr97yWBXv73lTsW
33 | KWlumRqk8KmJwh0oerR0AGmMIjoS/ihcY3QfnjHuDZ4y+Z9X8ATHa/eRcMexIZZe
34 | jAFQtbt6G5OfxJQ6cMV611MdjAgzjlLaODnCfhpT33gxoYmTG4ZNtnytHqugd3VK
35 | WYXRBOhnFpi/NswnbE9o/FKwzAwFfnznPa5XhyW9GTzEENhJLjajOnV8+VwaiYpB
36 | q0CY705wmnwRNbkerV/tX6j4oU2aoGy4ngW5XBDXcjGJuvdEeRP1QStKV2NnKcWY
37 | FsjyJ9MQSeKGZ1RkJwOUvOHd14GAQp+xJzd0JbfFMeq22WRsFlpdFV5RtUNe+3bo
38 | BJRWsBPIiou+iZUCJcruUdECNPK9dKgNqOo3ru0AEQEAAYkCNgQYAQgAIBYhBNkd
39 | PgAgAQfkIZUk3UJxW1biEbBCBQJiIBxvAhsMAAoJEEJxW1biEbBC1WoP/27gtSCD
40 | 99++rK4KS0N06kHi7b1zQH1N0em7764zc9OvIhcwQJW0QW7Fd8GBmeFApAaGkYPp
41 | D5FFxpaI8aGnfrkZxZ3CGj/kQhJQgRWoWyoQ+NdEM2QTEBiAGFq8HQiHDevC0rTF
42 | cxNIn/drDnJE+COvEmaCoKX++5sR3YXefIl7qdAHRa5yUCi4Dt62jD6Xvdnm+Bdc
43 | RxgDomtlzXby01WoS3wu6+YzoMGgVVpCsHaz3iSuboVVce90vTccsmpeEiEfAP3n
44 | zZ+Wtk96LUKdttm5fJq7FQXuF0a8gqwsDqnZksqrVcvSQAYR8Q9TaEsDIFZcfO/b
45 | otpdZkBmfRxLRK/tz6jGPvLf5q4vEWYARCizHaycmhaf3wDckl6s+2bsbf3ErpWI
46 | N5fG6AeE750RSO9tcVSmJFUzZ1wfIyifbDNCaKgrfv9r1Cg5zdbWP47ZoEZS3OZ+
47 | 5BAGJZNZo7jbExG8gZwjjH7N3ctNpTlOBRbef3FYPaTxMfpDO295yyqmD6bvCm/T
48 | atoU8dHfKlnxp5kEPqTudGSgUnBeD4d7u8CSbGn8ZEMM1Ev0P0iK48rqzJLeqple
49 | 7wx2WUbMYEB/f7aIbyUSAOzuJp01AAOElGoynT0zeIqexQh0pRDyyPMUffm1gE4O
50 | cBMVenZ3qy5zyY5xyBxrvVLICEhag09VUcXj
51 | =wRQC
52 | -----END PGP PUBLIC KEY BLOCK-----
53 |
--------------------------------------------------------------------------------
/credentials/test.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIERTCCAy2gAwIBAgIJALm//tP6yofwMA0GCSqGSIb3DQEBCwUAMIG4MQswCQYD
3 | VQQGEwJVUzEQMA4GA1UECAwHTm93aGVyZTEVMBMGA1UEBwwMTm93aGVyZSBDaXR5
4 | MR4wHAYDVQQKDBVCb2d1cyBUZXN0aW5nIENvbXBhbnkxHjAcBgNVBAsMFURvIE5v
5 | dCBVc2UgRGVwYXJ0bWVudDEZMBcGA1UEAwwQTXIuU2VsZmllIFNpZ25lcjElMCMG
6 | CSqGSIb3DQEJARYWbm9yZXBseUBqZW5raW5zLWNpLm9yZzAgFw0xNTA0MDUxNzI3
7 | NTlaGA8yMTE1MDMxMjE3Mjc1OVowgbgxCzAJBgNVBAYTAlVTMRAwDgYDVQQIDAdO
8 | b3doZXJlMRUwEwYDVQQHDAxOb3doZXJlIENpdHkxHjAcBgNVBAoMFUJvZ3VzIFRl
9 | c3RpbmcgQ29tcGFueTEeMBwGA1UECwwVRG8gTm90IFVzZSBEZXBhcnRtZW50MRkw
10 | FwYDVQQDDBBNci5TZWxmaWUgU2lnbmVyMSUwIwYJKoZIhvcNAQkBFhZub3JlcGx5
11 | QGplbmtpbnMtY2kub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
12 | vRHgamoEgcF1FqN0YusXKWZuZL7iAy1wLs9zeUj5HxwuHmF6MBKCvF44JU3A6BIx
13 | 7xOaLbb+G6qZj0MlpVzl2ra54PWn7KffGgOF8bxJ6CnYaBXpJfrBW+ORTfbV9tGS
14 | Nhqzc0Z1Gfe/+EgFuKuD6FmPJpUIzdMFrnfs9k0In1sP+VbdlUyFsvshlv6zTmYy
15 | gNKKroXODqYXYyEkS9RV3YvIzhIHx4PmTN9XIOo71ZwieRM1aVBv4lIxGqPF08f/
16 | x/fP5Nm/aWkT7S1vQ9VGtd4J4TxVs2tlKndtUaB0wlGIEXRk0cxIQ2fFaPhnjqjo
17 | 0pJJbbqFAHF0qYm4PYtyMwIDAQABo04wTDAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB
18 | /wQEAwIHgDAXBgNVHSUBAf8EDTALBgkqhkiG92NkBA0wEwYKKoZIhvdjZAYBDgEB
19 | /wQCBQAwDQYJKoZIhvcNAQELBQADggEBAE7p6Qg3QMuiiORtK/eA9P5rTpG7iARS
20 | uZRT+7VHt78gzIqen0oGJjBB1/1dM2lJuxiQNyTPbtz0TZh5RyHi52rQ9L0OHkqF
21 | JGZy3f7hgrWVJ0rlABA6MvsXUVUgq2aMcs0kjmbs5no9aaVQkBh7NveSjT+g6Kqj
22 | 5x8jowA2v46BI3zbvsZHvwYqdCk4r4o/HFOAYw5CuwABBUH8MG7HSXgMYzIm7UnV
23 | tjT6b0Tttdw8NLvxwRqmIESrabB+/TXHhzVp8Wm8V+brhK42qtR3Rqx5WurworUE
24 | 06agnSx5X1YRKReo6Iw0nUwxbrKL4VwYPBcuGDdPM7OI0UBWR+V3n1w=
25 | -----END CERTIFICATE-----
26 |
--------------------------------------------------------------------------------
/credentials/test.csr:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE REQUEST-----
2 | MIIC/jCCAeYCAQAwgbgxCzAJBgNVBAYTAlVTMRAwDgYDVQQIDAdOb3doZXJlMRUw
3 | EwYDVQQHDAxOb3doZXJlIENpdHkxHjAcBgNVBAoMFUJvZ3VzIFRlc3RpbmcgQ29t
4 | cGFueTEeMBwGA1UECwwVRG8gTm90IFVzZSBEZXBhcnRtZW50MRkwFwYDVQQDDBBN
5 | ci5TZWxmaWUgU2lnbmVyMSUwIwYJKoZIhvcNAQkBFhZub3JlcGx5QGplbmtpbnMt
6 | Y2kub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvRHgamoEgcF1
7 | FqN0YusXKWZuZL7iAy1wLs9zeUj5HxwuHmF6MBKCvF44JU3A6BIx7xOaLbb+G6qZ
8 | j0MlpVzl2ra54PWn7KffGgOF8bxJ6CnYaBXpJfrBW+ORTfbV9tGSNhqzc0Z1Gfe/
9 | +EgFuKuD6FmPJpUIzdMFrnfs9k0In1sP+VbdlUyFsvshlv6zTmYygNKKroXODqYX
10 | YyEkS9RV3YvIzhIHx4PmTN9XIOo71ZwieRM1aVBv4lIxGqPF08f/x/fP5Nm/aWkT
11 | 7S1vQ9VGtd4J4TxVs2tlKndtUaB0wlGIEXRk0cxIQ2fFaPhnjqjo0pJJbbqFAHF0
12 | qYm4PYtyMwIDAQABoAAwDQYJKoZIhvcNAQELBQADggEBAHwqbR5qArzPP/5Ck+kc
13 | OVtQnjLb3bwzCbf6vl6Zr4JNBUHGpxCgR9CvtRBh+inpn8Zh7HSSOPRCqJPTL8q7
14 | WtGRMgdLsGT0whT2UbZSpcXM4HZAQ53qsrpCRkL+k/qlbmhvgdvwYxpEv0YHI8UO
15 | 6oByogpqrRfauyts7rKQbbfuwdhNU434RpJt6484i3xQVsC/km9DGCa7hbqUvZX1
16 | EGkzX6b99KZ13ILGPkUg04xTvoxkqzXGzyO07t88nT623q2v+g16lNGN4rDczdUG
17 | IAn12+2cE405Ld7ylLuVNlsDWHsGX6TytgwMMa3ACN7vjiroCMwVnCzx5JFoIgds
18 | 2DQ=
19 | -----END CERTIFICATE REQUEST-----
20 |
--------------------------------------------------------------------------------
/credentials/test.gpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jenkinsci/packaging/621e33ede4493dbc702152435a777a982c30d633/credentials/test.gpg
--------------------------------------------------------------------------------
/credentials/test.gpg.password.txt:
--------------------------------------------------------------------------------
1 | s3cr3t
2 |
--------------------------------------------------------------------------------
/credentials/test.key:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIIEogIBAAKCAQEAvRHgamoEgcF1FqN0YusXKWZuZL7iAy1wLs9zeUj5HxwuHmF6
3 | MBKCvF44JU3A6BIx7xOaLbb+G6qZj0MlpVzl2ra54PWn7KffGgOF8bxJ6CnYaBXp
4 | JfrBW+ORTfbV9tGSNhqzc0Z1Gfe/+EgFuKuD6FmPJpUIzdMFrnfs9k0In1sP+Vbd
5 | lUyFsvshlv6zTmYygNKKroXODqYXYyEkS9RV3YvIzhIHx4PmTN9XIOo71ZwieRM1
6 | aVBv4lIxGqPF08f/x/fP5Nm/aWkT7S1vQ9VGtd4J4TxVs2tlKndtUaB0wlGIEXRk
7 | 0cxIQ2fFaPhnjqjo0pJJbbqFAHF0qYm4PYtyMwIDAQABAoIBAHAEI11oqnrlzyU2
8 | ekIQ3owcr9LodKdFSG2zYsq8vTv9SiWdwvKwRNytRb50LpJQFV1706C6BhsGHCyQ
9 | r8ElJNlL4Ryy7mZ7nuaep8DsuSzffeNM9/EUe3KhhPkYAPRWfbWoZCEr4T0dV5MV
10 | uK4Mj/4c8X7+VVT8bSVM0Aus4Crol5JfzTLfgWtjUF3v9BaGSKssU76QGtqV0Zlp
11 | OvMgu5xtH7ArjqvSVWMFEVFRjc40roRRqX9UMzpolAOOUrsk/n2XeMu3SPH2Y4KJ
12 | sc1SvpVabZXgfwoDinesCa1QUq9naLEMAByyK6Y9uZFVUDV0F9yKTGjlzoJ8HwXh
13 | g2X0IAECgYEA6Q84dKE9EVVroRtlg3/Bx3ea5AD421cSHJkTv6CmpAyFdADhbNJS
14 | EZjrxs2PYudayEWlUjZdoNqYI+OdSs7Bs6ld0qWGqD8/v3SmcrJpcm5+uhzoLPMN
15 | 8P5UG+0QE3iFtUUwNSd+/3j0Ame1Or+PnEc5ddkWHlvV4+SyPD99zjMCgYEAz64t
16 | f3wB0WOsl7V8AVJ2vvHD9gpvsQFCTVdJNEW5h/SSABw1H2fbS0QJKSqJjyry6kS6
17 | g7/mQ8qYmFSFXvnKqGgx4WByu7+le6eRew7fZSS8/pb0NY1RG7J2zhm7PFeFxt/b
18 | UhO5mEaG21po2fr7JXSttslzv0egYbuv1nRPzAECgYBZVJwvGB5wJm26suWWIcIE
19 | 0rNr8XNxn04x5/rJ2KoG90Wv0SaWr4cFd7fn26K6JjOF0Cwt9uisXx0xpG0F33of
20 | gyuTMh8LHjMxD2U9UWVZl0C71ZioogEV/mX+zj77N5cIhByWQy1KfvIIeffdLM++
21 | 9w3vPeZcfJbfYyluLmfqQQKBgF5HLMJd0hlzDSvFqGiVPfDKofH0pOWOs8GWaVYA
22 | fQv5+7lvFLKQHB4b4ai9dbr3fVTaJG2g1PBbbVBhtjX6YYR34IT2mr8ebgondMSP
23 | aNxqhB1y+6O/5l0TdBl11ui6trEkeFTXPX6iLaAwd77Uz+QeBqoe45um8WjMojNR
24 | k9QBAoGAWbinFVDJR7jnan0QaXN3yxHYrKphohvDPmsz34dPGbEw24/Yd/GW1igg
25 | myoj2+cSC42Ri/SlkC6cDiwIzesWONK+DFsJogDrDdqbFBfXylW0bUw4F4Lf00Sk
26 | F+oa01qOfJ/Y2eTMFsRD5L8uzOtQv2iZ07GFd300LGdoRWehhOQ=
27 | -----END RSA PRIVATE KEY-----
28 |
--------------------------------------------------------------------------------
/credentials/test.keychain:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jenkinsci/packaging/621e33ede4493dbc702152435a777a982c30d633/credentials/test.keychain
--------------------------------------------------------------------------------
/credentials/test.keychain.password.txt:
--------------------------------------------------------------------------------
1 | s3cr3t
--------------------------------------------------------------------------------
/credentials/test.mk:
--------------------------------------------------------------------------------
1 | # Contains bogus keys and certificates just so that we can go through the whole motion of signing bits
2 | # For actual use, you need your own keys and valid certificates. see README.md
3 |
4 | CREDENTIAL_DIR:=$(abspath $(dir $(lastword $(MAKEFILE_LIST))))/
5 |
6 | export GPG_KEYRING :=${CREDENTIAL_DIR}test.gpg
7 | export GPG_PUBLIC_KEY :=${CREDENTIAL_DIR}test.ascii.key
8 | export GPG_SECRET_KEYRING :=${CREDENTIAL_DIR}test.secret.gpg
9 | # file that contains GPG passphrase
10 | export GPG_PASSPHRASE_FILE:=$(CREDENTIAL_DIR)test.gpg.password.txt
11 |
12 | export PKCS12_FILE :=$(CREDENTIAL_DIR)test.pkcs12
13 | export PKCS12_PASSWORD_FILE:=$(CREDENTIAL_DIR)test.pkcs12.password.txt
14 |
15 | export KEYCHAIN_FILE :=${CREDENTIAL_DIR}test.keychain
16 | export KEYCHAIN_PASSWORD_FILE:=${CREDENTIAL_DIR}test.keychain.password.txt
17 |
--------------------------------------------------------------------------------
/credentials/test.pkcs12:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jenkinsci/packaging/621e33ede4493dbc702152435a777a982c30d633/credentials/test.pkcs12
--------------------------------------------------------------------------------
/credentials/test.pkcs12.password.txt:
--------------------------------------------------------------------------------
1 | s3cr3t
--------------------------------------------------------------------------------
/credentials/test.secret.gpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jenkinsci/packaging/621e33ede4493dbc702152435a777a982c30d633/credentials/test.secret.gpg
--------------------------------------------------------------------------------
/deb/build/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -eux
2 |
3 | # build a debian package from a release build
4 |
5 | hostname
6 | dir=$(dirname "$0")
7 |
8 | # tmp dir
9 | D=$(mktemp -d)
10 | trap 'rm -rf "${D}"' EXIT
11 |
12 | # debian packaging needs to touch the file in the source tree, so do this in tmp dir
13 | # so that multiple builds can go on concurrently
14 | cp -R "${dir}"/* "${D}"
15 | cp "${BASE}/systemd/jenkins.service" "${D}/debian"
16 | cp "${BASE}/systemd/jenkins.sh" "${D}"
17 | cp "${BASE}/systemd/migrate.sh" "${D}"
18 | cp "${BASE}/systemd/jenkins.conf" "${D}/debian/jenkins.tmpfiles"
19 |
20 | # Create a description temp file
21 | sed -i.bak -e 's/^\s*$/./' -e 's/^/ /' "${DESCRIPTION_FILE}"
22 |
23 | # Expand variables in the definition
24 | "${BASE}/bin/branding.py" "${D}"
25 |
26 | # Rewrite the file
27 | mv "${DESCRIPTION_FILE}.bak" "${DESCRIPTION_FILE}"
28 |
29 | cat >"${D}/debian/changelog" <= 3.2-14), net-tools, sysvinit-utils (>= 2.88dsf-50)
12 | Pre-Depends: ${misc:Pre-Depends}
13 | Description: @@DESCRIPTION_FILE@@
14 |
--------------------------------------------------------------------------------
/deb/build/debian/copyright:
--------------------------------------------------------------------------------
1 | Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
2 | Upstream-Name: Jenkins
3 | Upstream-Contact: http://jenkins.io/
4 | Source: https://github.com/jenkinsci/jenkins
5 |
6 | Files: *
7 | Copyright: 2004-, @@AUTHOR@@, Sun Microsystems, Inc., and a number of other of contributors
8 | License: @@LICENSE@@
9 | @@LICENSE_TEXT_DEB@@
10 |
--------------------------------------------------------------------------------
/deb/build/debian/jenkins.default:
--------------------------------------------------------------------------------
1 | # defaults for Jenkins automation server
2 |
3 | # pulled in from the init script; makes things easier.
4 | NAME=@@ARTIFACTNAME@@
5 |
6 | # arguments to pass to java
7 |
8 | # Allow graphs etc. to work even when an X server is present
9 | JAVA_ARGS="-Djava.awt.headless=true"
10 |
11 | #JAVA_ARGS="-Xmx256m"
12 |
13 | # make jenkins listen on IPv4 address
14 | #JAVA_ARGS="-Djava.net.preferIPv4Stack=true"
15 |
16 | PIDFILE=/var/run/$NAME/$NAME.pid
17 |
18 | # user and group to be invoked as (default to jenkins)
19 | JENKINS_USER=$NAME
20 | JENKINS_GROUP=$NAME
21 |
22 | # location of the jenkins war file
23 | JENKINS_WAR=/usr/share/java/$NAME.war
24 |
25 | # jenkins home location
26 | JENKINS_HOME=/var/lib/$NAME
27 |
28 | # set this to false if you don't want Jenkins to run by itself
29 | # in this set up, you are expected to provide a servlet container
30 | # to host jenkins.
31 | RUN_STANDALONE=true
32 |
33 | # log location. this may be a syslog facility.priority
34 | JENKINS_LOG=/var/log/$NAME/$NAME.log
35 | #JENKINS_LOG=daemon.info
36 |
37 | # Whether to enable web access logging or not.
38 | # Set to "yes" to enable logging to /var/log/$NAME/access_log
39 | JENKINS_ENABLE_ACCESS_LOG="no"
40 |
41 | # OS LIMITS SETUP
42 | # comment this out to observe /etc/security/limits.conf
43 | # this is on by default because http://github.com/jenkinsci/jenkins/commit/2fb288474e980d0e7ff9c4a3b768874835a3e92e
44 | # reported that Ubuntu's PAM configuration doesn't include pam_limits.so, and as a result the # of file
45 | # descriptors are forced to 1024 regardless of /etc/security/limits.conf
46 | MAXOPENFILES=8192
47 |
48 | # set the umask to control permission bits of files that Jenkins creates.
49 | # 027 makes files read-only for group and inaccessible for others, which some security sensitive users
50 | # might consider benefitial, especially if Jenkins runs in a box that's used for multiple purposes.
51 | # Beware that 027 permission would interfere with sudo scripts that run on the master (JENKINS-25065.)
52 | #
53 | # Note also that the particularly sensitive part of $JENKINS_HOME (such as credentials) are always
54 | # written without 'others' access. So the umask values only affect job configuration, build records,
55 | # that sort of things.
56 | #
57 | # If commented out, the value from the OS is inherited, which is normally 022 (as of Ubuntu 12.04,
58 | # by default umask comes from pam_umask(8) and /etc/login.defs
59 |
60 | # UMASK=027
61 |
62 | # port for HTTP connector (default 8080; disable with -1)
63 | HTTP_PORT=@@PORT@@
64 |
65 |
66 | # servlet context, important if you want to use apache proxying
67 | PREFIX=/$NAME
68 |
69 | # arguments to pass to jenkins.
70 | # full list available from java -jar jenkins.war --help
71 | # --javaHome=$JAVA_HOME
72 | # --httpListenAddress=$HTTP_HOST (default 0.0.0.0)
73 | # --httpPort=$HTTP_PORT (default 8080; disable with -1)
74 | # --httpsPort=$HTTP_PORT
75 | # --argumentsRealm.passwd.$ADMIN_USER=[password]
76 | # --argumentsRealm.roles.$ADMIN_USER=admin
77 | # --webroot=~/.jenkins/war
78 | # --prefix=$PREFIX
79 |
80 | JENKINS_ARGS="--webroot=/var/cache/$NAME/war --httpPort=$HTTP_PORT"
81 |
--------------------------------------------------------------------------------
/deb/build/debian/jenkins.dirs:
--------------------------------------------------------------------------------
1 | # moved from rules install
2 | usr/share/@@ARTIFACTNAME@@
3 |
4 | # this is where JENKINS_HOME is stored, so let's leave it as is for now
5 | var/lib/@@ARTIFACTNAME@@
6 |
7 | # Store jenkins log file in it's own directory since they can become rather large and in the future
8 | # rotating logs can be easily added.
9 | var/log/@@ARTIFACTNAME@@
10 |
11 | # Cache directory for the unpacked jenkins.war file.
12 | var/cache/@@ARTIFACTNAME@@
13 |
--------------------------------------------------------------------------------
/deb/build/debian/jenkins.init:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env /lib/init/init-d-script
2 | # /etc/init.d/jenkins
3 | # debian-compatible jenkins startup script.
4 | # Amelia A Lewis
5 | #
6 | ### BEGIN INIT INFO
7 | # Provides: @@ARTIFACTNAME@@
8 | # Required-Start: $remote_fs $syslog $network
9 | # Required-Stop: $remote_fs $syslog $network
10 | # Default-Start: 2 3 4 5
11 | # Default-Stop: 0 1 6
12 | # Short-Description: Start @@PRODUCTNAME@@ at boot time
13 | # Description: Controls @@SUMMARY@@
14 | ### END INIT INFO
15 |
16 | DAEMON=none
17 | COMMAND_NAME=java
18 | NAME="@@ARTIFACTNAME@@"
19 | DESC="@@SUMMARY@@"
20 |
21 | check_arguments() {
22 | # Exit if not supposed to run standalone
23 | if [ "${RUN_STANDALONE}" = "false" ]; then
24 | echo "ERROR: Not configured to run standalone" >&2
25 | return 2
26 | fi
27 |
28 | # Make sure there exists a java executable, it may not be always the case
29 | JAVA=$(command -v "${COMMAND_NAME}")
30 | if [ -z "${JAVA}" ]; then
31 | echo "ERROR: No Java executable found in current PATH: ${PATH}" >&2
32 | echo "If you actually have Java installed on the system make sure the executable is in the aforementioned path and that 'command -v ${COMMAND_NAME}' returns the Java executable path" >&2
33 | return 2
34 | fi
35 |
36 | # Make sure we run as root, since setting the max open files through
37 | # ulimit requires root access
38 | if [ "$(id -u)" -gt 0 ]; then
39 | echo "The ${NAME} init script can only be run as root" >&2
40 | return 2
41 | fi
42 | }
43 |
44 | check_tcp_port() {
45 | service=$1
46 | assigned=$2
47 | default=$3
48 | assigned_address=$4
49 | default_address=$5
50 |
51 | if [ -n "${assigned}" ]; then
52 | port=${assigned}
53 | else
54 | port=${default}
55 | fi
56 |
57 | if [ -n "${assigned_address}" ]; then
58 | address=${assigned_address}
59 | else
60 | address=${default_address}
61 | fi
62 |
63 | count=$(netstat --listen --numeric-ports | grep "${address}:${port}[[:space:]]" | grep -c .)
64 |
65 | if [ "${count}" -gt 0 ]; then
66 | echo "The selected ${service} port (${port}) on address ${address} seems to be in use by another program "
67 | echo "Please select another address/port combination to use for ${NAME}"
68 | return 2
69 | fi
70 | }
71 |
72 | do_start_cmd_override() {
73 | check_arguments || return "$?"
74 |
75 | # load environments
76 | if [ -r /etc/default/locale ]; then
77 | . /etc/default/locale
78 | export LANG LANGUAGE
79 | elif [ -r /etc/environment ]; then
80 | . /etc/environment
81 | export LANG LANGUAGE
82 | fi
83 | export JENKINS_HOME
84 |
85 | # the default location is /var/run/jenkins/jenkins.pid but the parent directory needs to be created
86 | mkdir -p "$(dirname "${PIDFILE}")" || return 2
87 | chown "${JENKINS_USER}" "$(dirname "${PIDFILE}")" || return 2
88 |
89 | # Verify that the jenkins port is not already in use, winstone does not exit
90 | # even for BindException
91 | check_tcp_port "http" "${HTTP_PORT}" "@@PORT@@" "${HTTP_HOST}" "0.0.0.0" || return 2
92 |
93 | # If the var MAXOPENFILES is enabled in /etc/default/jenkins then set the max open files to the
94 | # proper value
95 | if [ -n "${MAXOPENFILES}" ]; then
96 | [ "${VERBOSE}" != no ] && echo "Setting up max open files limit to ${MAXOPENFILES}"
97 | ulimit -n "${MAXOPENFILES}" || return 2
98 | fi
99 | # notify of explicit umask
100 | if [ -n "${UMASK}" ]; then
101 | [ "${VERBOSE}" != no ] && echo "Setting umask to ${UMASK}"
102 | fi
103 |
104 | # enable access log
105 | if [ "${JENKINS_ENABLE_ACCESS_LOG}" = "yes" ]; then
106 | JENKINS_ARGS="${JENKINS_ARGS} --accessLoggerClassName=winstone.accesslog.SimpleAccessLogger --simpleAccessLogger.format=combined --simpleAccessLogger.file=/var/log/${NAME}/access_log"
107 | fi
108 |
109 | # start-stop-daemon --chuid/--group doesn't prepare environment variables
110 | # like HOME, USER, LOGNAME or USERNAME, so re-export these
111 | SHELL=$(awk -F: "\$1 == \"${JENKINS_USER}\" {print \$NF}" /etc/passwd)
112 | [ -n "${SHELL}" ] || SHELL=/bin/bash
113 | HOME="${JENKINS_HOME}" \
114 | SHELL="${SHELL}" \
115 | USER="${JENKINS_USER}" \
116 | LOGNAME="${JENKINS_USER}" \
117 | USERNAME="${JENKINS_USER}" \
118 | PWD="${JENKINS_HOME}" \
119 | eval \
120 | start-stop-daemon \
121 | --start \
122 | --quiet \
123 | --oknodo \
124 | --background \
125 | --no-close \
126 | --make-pidfile \
127 | --pidfile "${PIDFILE}" \
128 | --chdir "${JENKINS_HOME}" \
129 | --chuid "${JENKINS_USER}" \
130 | --user "${JENKINS_USER}" \
131 | --group "${JENKINS_GROUP}" \
132 | --name "${COMMAND_NAME}" \
133 | --exec "${JAVA}" \
134 | ${UMASK:+--umask ${UMASK}} \
135 | -- ${JAVA_ARGS} -jar "${JENKINS_WAR}" ${JENKINS_ARGS} >>"${JENKINS_LOG}" 2>&1
136 | RETVAL="$?"
137 | [ "${RETVAL}" = 2 ] && return 2
138 | # Verify the process did in fact start successfully and didn't just bomb out
139 | sleep 1
140 | ATTEMPT=1
141 | while [ ${ATTEMPT} -le 30 ]; do
142 | pidofproc -p "${PIDFILE}" "${JAVA}" >/dev/null && break
143 | [ "${ATTEMPT}" = 30 ] && return 2
144 | sleep 1
145 | ATTEMPT=$((ATTEMPT + 1))
146 | done
147 | return "${RETVAL}"
148 | }
149 |
150 | do_stop_cmd_override() {
151 | check_arguments || return "$?"
152 | start-stop-daemon \
153 | --stop \
154 | --quiet \
155 | --oknodo \
156 | --pidfile "${PIDFILE}" \
157 | --chdir "${JENKINS_HOME}" \
158 | --chuid "${JENKINS_USER}" \
159 | --user "${JENKINS_USER}" \
160 | --group "${JENKINS_GROUP}" \
161 | --name "${COMMAND_NAME}" \
162 | --exec "${JAVA}" \
163 | --retry=TERM/30/KILL/5
164 | RETVAL="$?"
165 | [ "${RETVAL}" = 2 ] && return 2
166 | # Wait for children to finish too if this is a daemon that forks
167 | # and if the daemon is only ever run from this initscript.
168 | # If the above conditions are not satisfied then add some other code
169 | # that waits for the process to drop all resources that could be
170 | # needed by services started subsequently. A last resort is to
171 | # sleep for some time.
172 | start-stop-daemon \
173 | --stop \
174 | --quiet \
175 | --oknodo \
176 | --pidfile "${PIDFILE}" \
177 | --chdir "${JENKINS_HOME}" \
178 | --chuid "${JENKINS_USER}" \
179 | --user "${JENKINS_USER}" \
180 | --group "${JENKINS_GROUP}" \
181 | --name "${COMMAND_NAME}" \
182 | --exec "${JAVA}" \
183 | --retry=0/30/KILL/5
184 | [ "$?" = 2 ] && return 2
185 | # Many daemons don't delete their pidfiles when they exit.
186 | rm -f "${PIDFILE}"
187 | return "${RETVAL}"
188 | }
189 |
190 | do_status_override() {
191 | check_arguments || return "$?"
192 | status_of_proc "${JAVA}" "${NAME}" -p "${PIDFILE}"
193 | }
194 |
--------------------------------------------------------------------------------
/deb/build/debian/jenkins.install:
--------------------------------------------------------------------------------
1 | @@ARTIFACTNAME@@ usr/bin
2 | @@ARTIFACTNAME@@.war usr/share/java
3 | migrate usr/share/@@ARTIFACTNAME@@
4 |
--------------------------------------------------------------------------------
/deb/build/debian/jenkins.logrotate:
--------------------------------------------------------------------------------
1 | /var/log/@@ARTIFACTNAME@@/@@ARTIFACTNAME@@.log /var/log/@@ARTIFACTNAME@@/access_log {
2 | weekly
3 | copytruncate
4 | missingok
5 | rotate 52
6 | compress
7 | delaycompress
8 | notifempty
9 | }
10 |
--------------------------------------------------------------------------------
/deb/build/debian/jenkins.postinst:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # postinst script for @@ARTIFACTNAME@@
3 | #
4 | # see: dh_installdeb(1)
5 |
6 | set -e
7 |
8 | # summary of how this script can be called:
9 | # * `configure'
10 | # * `abort-upgrade'
11 | # * `abort-remove' `in-favour'
12 | #
13 | # * `abort-remove'
14 | # * `abort-deconfigure' `in-favour'
15 | # `removing'
16 | #
17 | # for details, see http://www.debian.org/doc/debian-policy/ or
18 | # the debian-policy package
19 |
20 | case "$1" in
21 | configure)
22 | if [ -d /run/systemd/system ]; then
23 | # TODO --value would eliminate the need for cut, but older versions of systemd do not support it
24 | JENKINS_USER=$(systemctl show @@ARTIFACTNAME@@ --property=User 2>/dev/null | cut -d= -f2-)
25 | JENKINS_GROUP=$(systemctl show @@ARTIFACTNAME@@ --property=Group 2>/dev/null | cut -d= -f2-)
26 | elif [ -r /etc/default/@@ARTIFACTNAME@@ ]; then
27 | . /etc/default/@@ARTIFACTNAME@@
28 | fi
29 | : "${JENKINS_USER:=@@ARTIFACTNAME@@}"
30 | : "${JENKINS_GROUP:=@@ARTIFACTNAME@@}"
31 |
32 | # Create @@ARTIFACTNAME@@ group and user if they don't exist.
33 | # sometimes tools that users want Jenkins to run need a shell,
34 | # so use /bin/bash. See JENKINS-4830
35 | if ! getent group "$JENKINS_GROUP" >/dev/null; then
36 | addgroup --system --quiet "$JENKINS_GROUP"
37 | fi
38 | if ! id "$JENKINS_USER" >/dev/null 2>&1; then
39 | adduser --system --quiet --home /var/lib/@@ARTIFACTNAME@@ --no-create-home \
40 | --ingroup "$JENKINS_GROUP" --disabled-password --shell /bin/bash \
41 | --gecos '@@PRODUCTNAME@@' \
42 | "$JENKINS_USER"
43 | fi
44 |
45 | # directories needed for jenkins
46 | # we don't do -R because it can take a long time on big installation
47 | chown "${JENKINS_USER}:${JENKINS_GROUP}" /var/lib/@@ARTIFACTNAME@@ /var/log/@@ARTIFACTNAME@@
48 | # we don't do "chmod 750" so that the user can choose the pemission for g and o on their own
49 | chmod u+rwx /var/lib/@@ARTIFACTNAME@@ /var/log/@@ARTIFACTNAME@@
50 |
51 | # make sure jenkins can delete everything in /var/cache/jenkins to
52 | # re-explode war.
53 | chown -R "${JENKINS_USER}:${JENKINS_GROUP}" /var/cache/@@ARTIFACTNAME@@
54 | chmod -R 750 /var/cache/@@ARTIFACTNAME@@
55 |
56 | # older installations may use /var/run/jenkins
57 | # so make sure that they can delete too.
58 | if [ -d "/var/run/@@ARTIFACTNAME@@" ]; then
59 | chown -R "${JENKINS_USER}:${JENKINS_GROUP}" /var/run/@@ARTIFACTNAME@@
60 | chmod -R 750 /var/run/@@ARTIFACTNAME@@
61 | fi
62 |
63 | /usr/share/@@ARTIFACTNAME@@/migrate /etc/default/@@ARTIFACTNAME@@ || true
64 | ;;
65 |
66 | abort-upgrade | abort-remove | abort-deconfigure) ;;
67 |
68 | \
69 | *)
70 | echo "postinst called with unknown argument \`$1'" >&2
71 | exit 1
72 | ;;
73 | esac
74 |
75 | # dh_installdeb will replace this with shell code automatically
76 | # generated by other debhelper scripts.
77 |
78 | #DEBHELPER#
79 |
80 | exit 0
81 |
--------------------------------------------------------------------------------
/deb/build/debian/jenkins.postrm:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -e
4 |
5 | case "$1" in
6 | purge)
7 | if [ -x "$(command -v deluser)" ]; then
8 | deluser --quiet --system @@ARTIFACTNAME@@ || echo "failed to remove @@ARTIFACTNAME@@ system user" >&2
9 | else
10 | userdel @@ARTIFACTNAME@@ || echo "failed to remove @@ARTIFACTNAME@@ system user" >&2
11 | fi
12 | if [ -x "$(command -v delgroup)" ]; then
13 | delgroup --quiet --system --only-if-empty @@ARTIFACTNAME@@ || echo "failed to remove @@ARTIFACTNAME@@ system user" >&2
14 | else
15 | groupdel @@ARTIFACTNAME@@ || echo "failed to remove @@ARTIFACTNAME@@ system group" >&2
16 | fi
17 | rm -rf /var/lib/@@ARTIFACTNAME@@ /var/log/@@ARTIFACTNAME@@ \
18 | /var/run/@@ARTIFACTNAME@@ /var/cache/@@ARTIFACTNAME@@
19 | ;;
20 |
21 | remove | upgrade | failed-upgrade | abort-install | abort-upgrade | disappear) ;;
22 |
23 | \
24 | *)
25 | echo "postrm called with unknown argument \`$1'" >&2
26 | exit 1
27 | ;;
28 | esac
29 |
30 | #DEBHELPER#
31 |
32 | exit 0
33 |
--------------------------------------------------------------------------------
/deb/build/debian/rules:
--------------------------------------------------------------------------------
1 | #!/usr/bin/make -f
2 |
3 | %:
4 | dh $@
5 |
6 | # debian doesn't support the zstd compression which is the default on Ubuntu
7 | # see https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=892664
8 | override_dh_builddeb:
9 | dh_builddeb -- -Zxz
10 |
--------------------------------------------------------------------------------
/deb/build/debian/source/format:
--------------------------------------------------------------------------------
1 | 3.0 (native)
2 |
--------------------------------------------------------------------------------
/deb/publish/contents/binary/.htaccess:
--------------------------------------------------------------------------------
1 | Options -Indexes
2 |
--------------------------------------------------------------------------------
/deb/publish/publish.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -euxo pipefail
4 |
5 | : "${AGENT_WORKDIR:=/tmp}"
6 | : "${GPG_KEYNAME:?Require valid gpg keyname}"
7 | : "${DEB:?Require Debian package}"
8 | : "${DEBDIR:? Require where to put binary files}"
9 | : "${DEB_WEBDIR:? Require where to put repository index and other web contents}"
10 | : "${DEB_URL:? Require Debian repository Url}"
11 |
12 | # $$ Contains current pid
13 | D="$AGENT_WORKDIR/$$"
14 |
15 | # Convert string to array to correctly escape cli parameter
16 | SSH_OPTS=($SSH_OPTS)
17 |
18 | bin="$(dirname "$0")"
19 |
20 | function clean() {
21 | rm -rf "$D"
22 | }
23 |
24 | # Generate and publish site content
25 | function generateSite() {
26 | cp -R "$bin/contents/." "$D/contents"
27 |
28 | gpg --export -a --output "$D/contents/${ORGANIZATION}.key" "${GPG_KEYNAME}"
29 | echo "$(gpg --import-options show-only --import $D/contents/${ORGANIZATION}.key)" >"$D/contents/${ORGANIZATION}.key.info"
30 |
31 | "$BASE/bin/indexGenerator.py" \
32 | --distribution debian \
33 | --gpg-key-info-file "${D}/contents/${ORGANIZATION}.key.info" \
34 | --targetDir "$D/html"
35 |
36 | "$BASE/bin/branding.py" "$D"
37 |
38 | # build package index
39 | # see http://wiki.debian.org/SecureApt for more details
40 | cp "${DEB}" "$D/binary/"
41 |
42 | pushd "$D"
43 | apt-ftparchive packages binary >binary/Packages
44 | apt-ftparchive contents binary >binary/Contents
45 | popd
46 |
47 | # Remote ftparchive-merge
48 | # https://github.com/kohsuke/apt-ftparchive-merge
49 | pushd $D/binary
50 | mvn -V org.kohsuke:apt-ftparchive-merge:1.6:merge -Durl="$DEB_URL/binary/" -Dout=../merged
51 | popd
52 |
53 | # Local ftparchive-merge
54 |
55 | cat $D/merged/Packages >$D/binary/Packages
56 | gzip -9c "$D/merged/Packages" >"$D/binary/Packages.gz"
57 | bzip2 -c "$D/merged/Packages" >"$D/binary/Packages.bz2"
58 | lzma -c "$D/merged/Packages" >"$D/binary/Packages.lzma"
59 | gzip -9c "$D/merged/Contents" >"$D/binary/Contents.gz"
60 |
61 | apt-ftparchive -c "$bin/release.conf" release "$D/binary" >"$D/binary/Release"
62 | }
63 |
64 | function init() {
65 | mkdir -p "$D/binary" "$D/contents" "$D/html"
66 |
67 | # where to put binary files
68 | mkdir -p "$DEBDIR" # where to put binary files
69 |
70 | # where to put repository index and other web contents
71 | mkdir -p "$DEB_WEBDIR"
72 | ## On remote serve
73 | # shellcheck disable=SC2029
74 | ssh "${SSH_OPTS[@]}" "$PKGSERVER" mkdir -p "$DEBDIR/"
75 | }
76 |
77 | function skipIfAlreadyPublished() {
78 | if ssh "${SSH_OPTS[@]}" "$PKGSERVER" test -e "${DEBDIR}/$(basename "$DEB")"; then
79 | echo "File already published, nothing else todo"
80 | return 0
81 | fi
82 | return 1
83 | }
84 |
85 | # Upload Debian Package
86 | function uploadPackage() {
87 | rsync \
88 | --verbose \
89 | --recursive \
90 | --compress \
91 | --ignore-existing \
92 | --progress \
93 | "$DEB" "$DEBDIR/"
94 |
95 | rsync \
96 | --archive \
97 | --verbose \
98 | --compress \
99 | --ignore-existing \
100 | --progress \
101 | -e "ssh ${SSH_OPTS[*]}" \
102 | "${DEB}" "$PKGSERVER:${DEBDIR// /\\ }"
103 | }
104 |
105 | function uploadPackageSite() {
106 | cp \
107 | "$D"/binary/Packages* \
108 | "$D"/binary/Release \
109 | "$D"/binary/Release.gpg \
110 | "$D"/binary/Contents* \
111 | "$D"/contents/binary
112 |
113 | rsync \
114 | --verbose \
115 | --recursive \
116 | --compress \
117 | --progress \
118 | "$D/contents/" "$DEB_WEBDIR/"
119 |
120 | rsync \
121 | --archive \
122 | --compress \
123 | --progress \
124 | --verbose \
125 | -e "ssh ${SSH_OPTS[*]}" \
126 | "$D/contents/" "$PKGSERVER:${DEB_WEBDIR// /\\ }/"
127 | }
128 |
129 | function uploadHtmlSite() {
130 | # Html file need to be located in the binary directory
131 | rsync \
132 | --include "HEADER.html" \
133 | --include "FOOTER.html" \
134 | --exclude "*" \
135 | --compress \
136 | --recursive \
137 | --progress \
138 | --verbose \
139 | "$D/html/" "$DEBDIR/"
140 |
141 | rsync \
142 | --archive \
143 | --compress \
144 | --include "index.html" \
145 | --exclude "*" \
146 | --progress \
147 | --verbose \
148 | -e "ssh ${SSH_OPTS[*]}" \
149 | "$D/html/" "$PKGSERVER:${DEB_WEBDIR// /\\ }/"
150 |
151 | rsync \
152 | --archive \
153 | --compress \
154 | --include "HEADER.html" \
155 | --include "FOOTER.html" \
156 | --exclude "*" \
157 | --progress \
158 | --verbose \
159 | -e "ssh ${SSH_OPTS[*]}" \
160 | "$D/html/" "$PKGSERVER:${DEBDIR// /\\ }/"
161 | }
162 |
163 | function show() {
164 | echo "Parameters:"
165 | echo "DEB: $DEB"
166 | echo "DEBDIR: $DEBDIR"
167 | echo "DEB_WEBDIR: $DEB_WEBDIR"
168 | echo "SSH_OPTS: ${SSH_OPTS[*]}"
169 | echo "PKGSERVER: $PKGSERVER"
170 | echo "GPG_KEYNAME: $GPG_KEYNAME"
171 | echo "---"
172 | }
173 |
174 | function signSite() {
175 | # sign the release file
176 | if [ -f "$D/binary/Release.gpg" ]; then
177 | rm "$D/binary/Release.gpg"
178 | fi
179 |
180 | gpg \
181 | --batch \
182 | --pinentry-mode loopback \
183 | --digest-algo=sha256 \
184 | -u "$GPG_KEYNAME" \
185 | --passphrase-file "$GPG_PASSPHRASE_FILE" \
186 | -abs \
187 | -o "$D/binary/Release.gpg" \
188 | "$D/binary/Release"
189 | }
190 |
191 | show
192 | ## Disabling this function allow us to recreate and sign the repository.
193 | # the debian package won't be overrided as we use the parameter '--ignore-existing'
194 | #skipIfAlreadyPublished
195 | init
196 | generateSite
197 | signSite
198 |
199 | if ! skipIfAlreadyPublished; then
200 | uploadPackage
201 | uploadPackageSite
202 | fi
203 |
204 | uploadHtmlSite
205 | clean
206 |
--------------------------------------------------------------------------------
/deb/publish/release.conf:
--------------------------------------------------------------------------------
1 | // Used to drive apt-ftparchive
2 | APT::FTPArchive::Release::Origin "jenkins.io";
3 | APT::FTPArchive::Release::Suite "binary";
4 | APT::FTPArchive::Release::Architectures "all";
5 |
6 |
--------------------------------------------------------------------------------
/deb/setup.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -eux
2 |
3 | sudo apt-get install -y devscripts apt-utils || true
4 |
5 | exit 0
6 |
--------------------------------------------------------------------------------
/docker-compose.yaml:
--------------------------------------------------------------------------------
1 | # docker exec -i -t packaging_packaging_1 gpg --import --batch credentials/sandbox.gpg
2 | version: '3'
3 | volumes:
4 | sshd:
5 | pkgserver:
6 | services:
7 | packaging:
8 | image: jenkinsciinfra/packaging:latest
9 | command: "sleep 99d"
10 | environment:
11 | - "BUILDENV=/srv/releases/jenkins/env/test.mk"
12 | - "BRANDING_DIR=/srv/releases/jenkins/branding"
13 | - "BRAND=/srv/releases/jenkins/branding/jenkins.mk"
14 | - "GPG_FILE=/srv/releases/jenkins/credentials/sandbox.gpg"
15 | - "GPG_KEYNAME=Bogus Test"
16 | - "GPG_PASSPHRASE=s3cr3t"
17 | - "GPG_PASSPHRASE_FILE=/srv/releases/jenkins/credentials/test.gpg.password.txt"
18 | - "WAR=/srv/releases/jenkins/jenkins.war"
19 | - "MSI=/srv/releases/jenkins/jenkins.msi"
20 | - "RELEASELINE=-experimental"
21 | volumes:
22 | - ".:/srv/releases/jenkins"
23 | - "./credentials/ssh:/home/jenkins/.ssh"
24 | working_dir: "/srv/releases/jenkins"
25 |
26 | remote:
27 | image: jenkinsciinfra/packaging:latest
28 | user: root # In order to start, sshd needs to be root
29 | command: "/usr/sbin/sshd -D"
30 | ports:
31 | - "2222:22"
32 | volumes:
33 | - "./credentials/ssh/id_rsa.pub:/home/jenkins/.ssh/authorized_keys:ro"
34 | - sshd:/run/sshd
35 | - "pkgserver:/srv/releases/jenkins"
36 |
37 | pkgserver:
38 | image: httpd
39 | ports:
40 | - "80:80"
41 | volumes:
42 | - "./pkgConfig/httpd.conf:/usr/local/apache2/conf/httpd.conf"
43 | - "./target:/usr/local/apache2/htdocs"
44 |
--------------------------------------------------------------------------------
/env/azure.mk:
--------------------------------------------------------------------------------
1 | #
2 | # Environment definition for dry-run of the packaging process
3 | #
4 | # the host to publish bits to
5 | # Temporary real pkgserver
6 | export PKGSERVER=mirrorbrain@20.186.155.37
7 | export SSH_OPTS=-p 22 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null
8 | export SCP_OPTS=-P 22 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null
9 |
10 | # where to put binary files
11 | export WARDIR=/srv/releases/jenkins/war${RELEASELINE}
12 | export MSIDIR=/srv/releases/jenkins/windows${RELEASELINE}
13 | export DEBDIR=/srv/releases/jenkins/debian${RELEASELINE}/binary
14 | export RPMDIR=/srv/releases/jenkins/redhat${RELEASELINE}
15 | export SUSEDIR=/srv/releases/jenkins/opensuse${RELEASELINE}
16 |
17 | # where to put repository index and other web contents
18 | export RPM_WEBDIR=/srv/releases/jenkins/redhat${RELEASELINE}
19 | export MSI_WEBDIR=/srv/releases/jenkins/windows${RELEASELINE}
20 | export SUSE_WEBDIR=/srv/releases/jenkins/opensuse${RELEASELINE}
21 | export DEB_WEBDIR=/srv/releases/jenkins/debian${RELEASELINE}
22 | export WAR_WEBDIR=/srv/releases/jenkins/war${RELEASELINE}
23 |
24 | # URL to the aforementioned webdir.
25 | WEBSERVER=pkg.jenkins.io
26 | export RPM_URL=https://${WEBSERVER}/redhat${RELEASELINE}
27 | export SUSE_URL=https://${WEBSERVER}/opensuse${RELEASELINE}
28 | export DEB_URL=https://${WEBSERVER}/debian${RELEASELINE}
29 |
--------------------------------------------------------------------------------
/env/release.mk:
--------------------------------------------------------------------------------
1 | #
2 | # Environment definition for official OSS Jenkins packaging
3 | #
4 |
5 | # JENKINS used to generate MSI packages
6 | export JENKINS_URL=https://cloudbees.ci.cloudbees.com/
7 |
8 | # the host to publish bits to
9 | export PKGSERVER=mirrorbrain@pkg.origin.jenkins.io
10 | export SSH_OPTS=-p 22
11 | export SCP_OPTS=-P 22
12 |
13 | # where to put binary files
14 | export WARDIR=/srv/releases/jenkins/war${RELEASELINE}
15 | export MSIDIR=/srv/releases/jenkins/windows${RELEASELINE}
16 | export DEBDIR=/srv/releases/jenkins/debian${RELEASELINE}
17 | export RPMDIR=/srv/releases/jenkins/redhat${RELEASELINE}
18 | export SUSEDIR=/srv/releases/jenkins/opensuse${RELEASELINE}
19 |
20 | # where to put repository index and other web contents
21 | export RPM_WEBDIR=/var/www/pkg.jenkins.io.staging/redhat${RELEASELINE}
22 | export SUSE_WEBDIR=/var/www/pkg.jenkins.io.staging/opensuse${RELEASELINE}
23 | export DEB_WEBDIR=/var/www/pkg.jenkins.io.staging/debian${RELEASELINE}
24 | export WAR_WEBDIR=/var/www/pkg.jenkins.io.staging/war${RELEASELINE}
25 | export MSI_WEBDIR=/var/www/pkg.jenkins.io.staging/windows${RELEASELINE}
26 |
27 | # URL to the aforementioned webdir
28 | export RPM_URL=https://pkg.jenkins.io/redhat${RELEASELINE}
29 | export SUSE_URL=https://pkg.jenkins.io/opensuse${RELEASELINE}
30 | export DEB_URL=https://pkg.jenkins.io/debian${RELEASELINE}
31 |
--------------------------------------------------------------------------------
/env/test.mk:
--------------------------------------------------------------------------------
1 | #
2 | # Environment definition for dry-run of the packaging process
3 | #
4 |
5 | # JENKINS used to generate MSI packages
6 | export JENKINS_URL=https://cloudbees.ci.cloudbees.com/
7 |
8 | # the host to publish bits to
9 | export PKGSERVER=jenkins@remote
10 | # Testing both with and without SSH_OPTS
11 | #export SSH_OPTS=-p 22
12 | #export SCP_OPTS=-P 22
13 | export SSH_OPTS=-p 22
14 | export SCP_OPTS=-P 22
15 |
16 | # where to put binary files
17 | export TESTDIR=$(realpath .)/pkg.jenkins.io
18 | export WARDIR=${TESTDIR}/war${RELEASELINE}
19 | export MSIDIR=${TESTDIR}/windows${RELEASELINE}
20 | export DEBDIR=${TESTDIR}/debian${RELEASELINE}/binary
21 | export RPMDIR=${TESTDIR}/redhat${RELEASELINE}
22 | export SUSEDIR=${TESTDIR}/opensuse${RELEASELINE}
23 |
24 | # where to put repository index and other web contents
25 | export RPM_WEBDIR=${TESTDIR}/redhat${RELEASELINE}
26 | export SUSE_WEBDIR=${TESTDIR}/opensuse${RELEASELINE}
27 | export DEB_WEBDIR=${TESTDIR}/debian${RELEASELINE}
28 | export WAR_WEBDIR=${TESTDIR}/war${RELEASELINE}
29 | export MSI_WEBDIR=${TESTDIR}/windows${RELEASELINE}
30 |
31 | # URL to the aforementioned webdir.
32 | WEBSERVER=pkg.jenkins.io
33 | export RPM_URL=https://${WEBSERVER}/redhat${RELEASELINE}
34 | export SUSE_URL=https://${WEBSERVER}/opensuse${RELEASELINE}
35 | export DEB_URL=https://${WEBSERVER}/debian${RELEASELINE}
36 |
--------------------------------------------------------------------------------
/make.ps1:
--------------------------------------------------------------------------------
1 | [CmdletBinding()]
2 | Param(
3 | [Parameter(Position=1)]
4 | [String] $target = "package"
5 | )
6 |
7 | # # refers to the definition of a release target
8 | # BRAND:=./branding/test.mk
9 | # include ${BRAND}
10 |
11 | # # refers to the definition of the release process execution environment
12 | # BUILDENV:=./env/test.mk
13 | # include ${BUILDENV}
14 |
15 | # # refers to whereabouts of code-signing keys
16 | # CREDENTIAL:=./credentials/test.mk
17 | # include ${CREDENTIAL}
18 |
19 | # include ./setup.mk
20 |
21 | # PACKAGE_BUILDER_VERSION:=0.1
22 |
23 | # #######################################################
24 |
25 | # clean:
26 | # rm -rf ${TARGET}
27 |
28 | $global:msiDone = $false
29 | $global:chocolateyDone = $false
30 |
31 | function Setup() {
32 | Get-ChildItem -Recurse -Include setup.ps1 -File | ForEach-Object {
33 | Push-Location (Split-Path -Parent $_)
34 | try {
35 | & $_
36 | } finally {
37 | Pop-Location
38 | }
39 | }
40 | }
41 |
42 | function New-Msi() {
43 | if(-not $global:msiDone) {
44 | Push-Location ./msi/build
45 | try {
46 | & ./build.ps1
47 | $global:msiDone = $true
48 | } finally {
49 | Pop-Location
50 | }
51 | }
52 | }
53 |
54 | function Publish-Msi() {
55 | New-Msi
56 | Push-Location ./msi/publish
57 | try {
58 | & ./publish.ps1
59 | } finally {
60 | Pop-Location
61 | }
62 | }
63 |
64 | function New-Chocolatey() {
65 | New-Msi
66 | if(-not $global:chocolateyDone) {
67 | Push-Location ./chocolatey/build
68 | try {
69 | & ./build.ps1
70 | $global:chocolateyDone = $true
71 | } finally {
72 | Pop-Location
73 | }
74 | }
75 | }
76 |
77 | function Publish-Chocolatey() {
78 | New-Chocolatey
79 | Push-Location ./chocolatey/publish
80 | try {
81 | & ./publish.ps1
82 | } finally {
83 | Pop-Location
84 | }
85 | }
86 |
87 | function Publish() {
88 | @(
89 | (Get-Item function:Publish-Msi)
90 | ) | ForEach-Object {
91 | & $_
92 | }
93 | }
94 |
95 | function New-Package() {
96 | @(
97 | (Get-Item function:New-Msi)
98 | ) | ForEach-Object {
99 | Write-Host $_.Name.Replace("New-", "") -BackgroundColor 'White' -ForegroundColor 'Black'
100 | & $_
101 | Write-Host "`n`n"
102 | }
103 | }
104 |
105 | Setup
106 | switch -wildcard ($target) {
107 | # release targets
108 | "package" { New-Package }
109 | "msi" { New-Msi }
110 | "chocolatey" { New-Chocolatey }
111 | "clean" { Clean }
112 |
113 | default { Write-Error "No target '$target'" ; Exit -1 }
114 | }
115 |
--------------------------------------------------------------------------------
/molecule/default/Dockerfile.j2:
--------------------------------------------------------------------------------
1 | # Molecule managed
2 |
3 | {% if item.registry is defined %}
4 | FROM {{ item.registry.url }}/{{ item.image }}
5 | {% else %}
6 | FROM {{ item.image }}
7 | {% endif %}
8 |
9 | {% if item.env is defined %}
10 | {% for var, value in item.env.items() %}
11 | {% if value %}
12 | ENV {{ var }} {{ value }}
13 | {% endif %}
14 | {% endfor %}
15 | {% endif %}
16 |
17 | RUN if [ $(command -v apt-get) ]; then export DEBIAN_FRONTEND=noninteractive && apt-get update && apt-get install -y python3 sudo bash ca-certificates iproute2 python3-apt python3-psutil aptitude rsync && apt-get clean && rm -rf /var/lib/apt/lists/*; \
18 | elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install /usr/bin/python3 /usr/bin/python3-config /usr/bin/dnf-3 sudo bash iproute $(dnf info python3-libdnf5 &>/dev/null && echo python3-libdnf5) python3-psutil rsync && dnf clean all; \
19 | elif [ $(command -v yum) ]; then yum makecache fast && yum install -y /usr/bin/python /usr/bin/python2-config sudo yum-plugin-ovl bash iproute python-psutil rsync && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \
20 | elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python311 python311-psutil sudo bash iproute2 rsync && zypper clean -a; \
21 | elif [ $(command -v apk) ]; then apk update && apk add --no-cache python3 sudo bash ca-certificates rsync; \
22 | elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python3 sudo bash ca-certificates iproute2 rsync && xbps-remove -O; fi
23 |
--------------------------------------------------------------------------------
/molecule/default/converge.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Converge
3 | hosts: all
4 | become: true
5 | tasks:
6 | - include_tasks: install-deb.yml
7 | when: ansible_os_family == 'Debian'
8 | - include_tasks: install-rpm.yml
9 | when: ansible_os_family == 'RedHat'
10 | - include_tasks: install-suse.yml
11 | when: ansible_os_family == 'Suse'
12 |
--------------------------------------------------------------------------------
/molecule/default/install-deb.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - package:
3 | name:
4 | - fontconfig
5 | state: present
6 | update_cache: true
7 | - package:
8 | name:
9 | - openjdk-17-jre
10 | state: present
11 | - find:
12 | paths: /var/tmp/target/debian
13 | file_type: file
14 | patterns: "*.deb"
15 | register: package_list
16 | - assert:
17 | that:
18 | - package_list.matched == 1
19 | - apt:
20 | deb: "{{ package_list.files[0].path }}"
21 |
--------------------------------------------------------------------------------
/molecule/default/install-rpm.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - package:
3 | name:
4 | - fontconfig
5 | state: present
6 | update_cache: true
7 | - package:
8 | name:
9 | - java-17-openjdk
10 | state: present
11 | when: ansible_distribution != 'Amazon' and (ansible_distribution != 'CentOS' or ansible_distribution_major_version != '10')
12 | - package:
13 | name:
14 | - java-17-amazon-corretto
15 | state: present
16 | when: ansible_distribution == 'Amazon'
17 | - package:
18 | name:
19 | - java-21-openjdk
20 | state: present
21 | when: ansible_distribution == 'CentOS' and ansible_distribution_major_version == '10'
22 | - file:
23 | path: /var/tmp/target/credentials
24 | state: directory
25 | - copy:
26 | src: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') }}/credentials/test.ascii.key"
27 | dest: /var/tmp/target/credentials/test.ascii.key
28 | - rpm_key:
29 | state: present
30 | key: /var/tmp/target/credentials/test.ascii.key
31 | - find:
32 | paths: /var/tmp/target/rpm
33 | file_type: file
34 | patterns: "*.rpm"
35 | register: package_list
36 | - assert:
37 | that:
38 | - package_list.matched == 1
39 | - package:
40 | name: "{{ package_list.files[0].path }}"
41 | state: present
42 |
--------------------------------------------------------------------------------
/molecule/default/install-suse.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - package:
3 | name:
4 | - dejavu-fonts
5 | - fontconfig
6 | - java-17-openjdk
7 | state: present
8 | update_cache: true
9 | - file:
10 | path: /var/tmp/target/credentials
11 | state: directory
12 | - copy:
13 | src: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') }}/credentials/test.ascii.key"
14 | dest: /var/tmp/target/credentials/test.ascii.key
15 | - rpm_key:
16 | state: present
17 | key: /var/tmp/target/credentials/test.ascii.key
18 | - find:
19 | paths: /var/tmp/target/suse
20 | file_type: file
21 | patterns: "*.rpm"
22 | register: package_list
23 | - assert:
24 | that:
25 | - package_list.matched == 1
26 | - package:
27 | name: "{{ package_list.files[0].path }}"
28 | state: present
29 | - zypper_repository:
30 | name: jenkins
31 | state: absent
32 |
--------------------------------------------------------------------------------
/molecule/default/molecule.yml:
--------------------------------------------------------------------------------
1 | ---
2 | dependency:
3 | name: galaxy
4 | driver:
5 | name: docker
6 |
7 | platforms:
8 | # deb
9 | - name: debian-11 # EOL 2026-06-30
10 | image: dokken/debian-11:latest
11 | override_command: false
12 | volumes:
13 | - ${MOLECULE_PROJECT_DIRECTORY}/target:/var/tmp/target
14 | - /sys/fs/cgroup:/sys/fs/cgroup:rw
15 | cgroupns_mode: host
16 | privileged: true
17 | - name: debian-12 # EOL 2028-06-10
18 | image: dokken/debian-12:latest
19 | override_command: false
20 | volumes:
21 | - ${MOLECULE_PROJECT_DIRECTORY}/target:/var/tmp/target
22 | - /sys/fs/cgroup:/sys/fs/cgroup:rw
23 | cgroupns_mode: host
24 | privileged: true
25 | - name: ubuntu-22-04 # EOL 2027-04-01
26 | image: dokken/ubuntu-22.04:latest
27 | override_command: false
28 | volumes:
29 | - ${MOLECULE_PROJECT_DIRECTORY}/target:/var/tmp/target
30 | - /sys/fs/cgroup:/sys/fs/cgroup:rw
31 | cgroupns_mode: host
32 | privileged: true
33 | - name: ubuntu-24-04 # EOL 2029-04-01
34 | image: dokken/ubuntu-24.04:latest
35 | override_command: false
36 | volumes:
37 | - ${MOLECULE_PROJECT_DIRECTORY}/target:/var/tmp/target
38 | - /sys/fs/cgroup:/sys/fs/cgroup:rw
39 | cgroupns_mode: host
40 | privileged: true
41 | # rpm
42 | - name: almalinux-9 # EOL 2027-05-31
43 | image: dokken/almalinux-9:latest
44 | override_command: false
45 | volumes:
46 | - ${MOLECULE_PROJECT_DIRECTORY}/target:/var/tmp/target
47 | - /sys/fs/cgroup:/sys/fs/cgroup:rw
48 | cgroupns_mode: host
49 | privileged: true
50 | - name: rockylinux-9 # 2032-05-31
51 | image: dokken/rockylinux-9:latest
52 | override_command: false
53 | volumes:
54 | - ${MOLECULE_PROJECT_DIRECTORY}/target:/var/tmp/target
55 | - /sys/fs/cgroup:/sys/fs/cgroup:rw
56 | cgroupns_mode: host
57 | privileged: true
58 | - name: amazonlinux-2023 # EOL 2029-06-30
59 | image: dokken/amazonlinux-2023:latest
60 | override_command: false
61 | volumes:
62 | - ${MOLECULE_PROJECT_DIRECTORY}/target:/var/tmp/target
63 | - /sys/fs/cgroup:/sys/fs/cgroup:rw
64 | cgroupns_mode: host
65 | privileged: true
66 | - name: centos-stream-9 # EOL 2027-05-31
67 | image: dokken/centos-stream-9:latest
68 | override_command: false
69 | volumes:
70 | - ${MOLECULE_PROJECT_DIRECTORY}/target:/var/tmp/target
71 | - /sys/fs/cgroup:/sys/fs/cgroup:rw
72 | cgroupns_mode: host
73 | privileged: true
74 | - name: centos-stream-10 # EOL 2030-01-01
75 | image: dokken/centos-stream-10:latest
76 | override_command: false
77 | volumes:
78 | - ${MOLECULE_PROJECT_DIRECTORY}/target:/var/tmp/target
79 | - /sys/fs/cgroup:/sys/fs/cgroup:rw
80 | cgroupns_mode: host
81 | privileged: true
82 | - name: fedora-41 # EOL 2025-11-19
83 | image: dokken/fedora-41:latest
84 | override_command: false
85 | volumes:
86 | - ${MOLECULE_PROJECT_DIRECTORY}/target:/var/tmp/target
87 | - /sys/fs/cgroup:/sys/fs/cgroup:rw
88 | cgroupns_mode: host
89 | privileged: true
90 | - name: oraclelinux-9 # EOL 2032-06-30
91 | image: dokken/oraclelinux-9:latest
92 | override_command: false
93 | volumes:
94 | - ${MOLECULE_PROJECT_DIRECTORY}/target:/var/tmp/target
95 | - /sys/fs/cgroup:/sys/fs/cgroup:rw
96 | cgroupns_mode: host
97 | privileged: true
98 | # suse
99 | - name: opensuse-leap-15.6 # EOL 2025-12-01
100 | image: dokken/opensuse-leap-15.6:latest
101 | override_command: false
102 | volumes:
103 | - ${MOLECULE_PROJECT_DIRECTORY}/target:/var/tmp/target
104 | - /sys/fs/cgroup:/sys/fs/cgroup:rw
105 | cgroupns_mode: host
106 | privileged: true
107 | provisioner:
108 | name: ansible
109 | verifier:
110 | name: ansible
111 |
--------------------------------------------------------------------------------
/molecule/default/verify.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Verify
3 | hosts: all
4 | tasks:
5 | - file:
6 | path: /etc/systemd/system/jenkins.service.d
7 | state: directory
8 | when: ansible_service_mgr == 'systemd'
9 | - stat:
10 | path: /etc/systemd/system/jenkins.service.d/override.conf
11 | register: drop_in
12 | when: ansible_service_mgr == 'systemd'
13 | - assert:
14 | that:
15 | - not drop_in.stat.exists
16 | - copy:
17 | dest: /etc/systemd/system/jenkins.service.d/override.conf
18 | content: |
19 | [Service]
20 | Environment="JAVA_OPTS=-Djava.awt.headless=true -Xmx256m -Dhudson.model.DirectoryBrowserSupport.CSP=\"default-src 'self';\""
21 | TimeoutStartSec=600
22 | when: ansible_service_mgr == 'systemd'
23 | - systemd:
24 | daemon_reload: true
25 | when: ansible_service_mgr == 'systemd'
26 | - pids:
27 | name: java
28 | register: service_pids
29 | - assert:
30 | that:
31 | - (service_pids.pids | length) == 0
32 | fail_msg: "{{ service_pids.pids|join(',') }}"
33 | - service:
34 | name: jenkins
35 | state: started
36 | - uri:
37 | url: "http://127.0.0.1:8080/login"
38 | return_content: true
39 | register: result
40 | until: result.status == 200
41 | retries: 20
42 | delay: 5
43 | - assert:
44 | that:
45 | - "'Sign in - Jenkins ' in result.content"
46 | fail_msg: "{{ result.content }}"
47 | - pids:
48 | name: java
49 | register: service_pids
50 | - assert:
51 | that:
52 | - (service_pids.pids | length) == 1
53 | fail_msg: "{{ service_pids.pids | join(',') }}"
54 | - service:
55 | name: jenkins
56 | state: stopped
57 | - pids:
58 | name: java
59 | register: service_pids
60 | - assert:
61 | that:
62 | - (service_pids.pids | length) == 0
63 | fail_msg: "{{ service_pids.pids | join(',') }}"
64 |
--------------------------------------------------------------------------------
/molecule/servlet/Dockerfile.j2:
--------------------------------------------------------------------------------
1 | # Molecule managed
2 |
3 | {% if item.registry is defined %}
4 | FROM {{ item.registry.url }}/{{ item.image }}
5 | {% else %}
6 | FROM {{ item.image }}
7 | {% endif %}
8 |
9 | {% if item.env is defined %}
10 | {% for var, value in item.env.items() %}
11 | {% if value %}
12 | ENV {{ var }} {{ value }}
13 | {% endif %}
14 | {% endfor %}
15 | {% endif %}
16 |
17 | RUN if [ $(command -v apt-get) ]; then export DEBIAN_FRONTEND=noninteractive && apt-get update && apt-get install -y python3 sudo bash ca-certificates iproute2 python3-apt python3-lxml python3-psutil aptitude rsync && apt-get clean && rm -rf /var/lib/apt/lists/*; \
18 | elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install /usr/bin/python3 /usr/bin/python3-config /usr/bin/dnf-3 sudo bash iproute python3-psutil rsync && dnf clean all; \
19 | elif [ $(command -v yum) ]; then yum makecache fast && yum install -y /usr/bin/python /usr/bin/python2-config sudo yum-plugin-ovl bash iproute python-psutil rsync && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \
20 | elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python3 python3-psutil sudo bash iproute2 rsync && zypper clean -a; \
21 | elif [ $(command -v apk) ]; then apk update && apk add --no-cache python3 sudo bash ca-certificates rsync; \
22 | elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python3 sudo bash ca-certificates iproute2 rsync && xbps-remove -O; fi
23 |
--------------------------------------------------------------------------------
/molecule/servlet/configure-tomcat.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - copy:
3 | dest: "/usr/local/tomcat/bin/setenv.sh"
4 | content: "export CATALINA_OPTS=-DJENKINS_HOME=/var/tmp/jenkins_home"
5 | mode: "0755"
6 | - xml:
7 | path: "/usr/local/tomcat/conf/server.xml"
8 | xpath: "/Server/Service/Engine/Host"
9 | set_children:
10 | - Valve:
11 | className: "org.apache.catalina.valves.AccessLogValve"
12 | directory: "logs"
13 | prefix: "localhost_access_log"
14 | suffix: ".txt"
15 | pattern: '%h %l %u %t "%r" %s %b'
16 | - Valve:
17 | className: "org.apache.catalina.valves.RemoteIpValve"
18 | remoteIpHeader: "X-Forwarded-For"
19 | proxiesHeader: "X-Forwarded-By"
20 | protocolHeader: "X-Forwarded-Proto"
21 |
--------------------------------------------------------------------------------
/molecule/servlet/converge.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Converge
3 | hosts: all
4 | tasks:
5 | - include_tasks: configure-tomcat.yml
6 | when: ansible_hostname == 'tomcat-10'
7 |
--------------------------------------------------------------------------------
/molecule/servlet/molecule.yml:
--------------------------------------------------------------------------------
1 | ---
2 | dependency:
3 | name: galaxy
4 | driver:
5 | name: docker
6 | platforms:
7 | - name: tomcat-10
8 | image: tomcat:10-jdk17-temurin
9 | volumes:
10 | - ${MOLECULE_PROJECT_DIRECTORY}/jenkins.war:/usr/local/tomcat/webapps/jenkins.war
11 | provisioner:
12 | name: ansible
13 | verifier:
14 | name: ansible
15 |
--------------------------------------------------------------------------------
/molecule/servlet/verify.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Verify
3 | hosts: all
4 | tasks:
5 | - pids:
6 | name: java
7 | register: service_pids
8 | - assert:
9 | that:
10 | - (service_pids.pids | length) == 0
11 | fail_msg: "{{ service_pids.pids | join(',') }}"
12 | - command:
13 | cmd: /usr/local/tomcat/bin/catalina.sh start
14 | when: ansible_hostname == 'tomcat-10'
15 | - uri:
16 | url: "http://127.0.0.1:8080/jenkins/login"
17 | return_content: true
18 | register: result
19 | until: result.status == 200
20 | retries: 20
21 | delay: 5
22 | - assert:
23 | that:
24 | - "'Sign in - Jenkins ' in result.content"
25 | fail_msg: "{{ result.content }}"
26 | - pids:
27 | name: java
28 | register: service_pids
29 | - assert:
30 | that:
31 | - (service_pids.pids | length) == 1
32 | fail_msg: "{{ service_pids.pids | join(',') }}"
33 | - file:
34 | path: "/var/tmp/jenkins_home"
35 | register: jenkins_dir
36 | - assert:
37 | that:
38 | - "jenkins_dir.state == 'directory'"
39 | fail_msg: "{{ jenkins_dir.state }}"
40 | - command:
41 | cmd: /usr/local/tomcat/bin/catalina.sh stop
42 | when: ansible_hostname == 'tomcat-10'
43 | - pids:
44 | name: java
45 | register: service_pids
46 | - assert:
47 | that:
48 | - (service_pids.pids | length) == 0
49 | fail_msg: "{{ service_pids.pids | join(',') }}"
50 |
--------------------------------------------------------------------------------
/msi/build/.gitignore:
--------------------------------------------------------------------------------
1 | msiext-1.5/
2 | msiext-1.5.zip
3 | packages/
4 | tmp/
5 | bin/
6 | obj/
7 |
--------------------------------------------------------------------------------
/msi/build/License.rtf:
--------------------------------------------------------------------------------
1 | {\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Calibri;}}
2 | {\*\generator Riched20 10.0.17134}\viewkind4\uc1
3 | \pard\sa200\sl276\slmult1\qj\b\f0\fs22\lang9 The MIT License\par
4 | \b0 Copyright (c) 2004-, Kohsuke Kawaguchi, Sun Microsystems, Inc., and a number of other of contributors\par
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\par
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\par
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\par
8 | }
9 |
--------------------------------------------------------------------------------
/msi/build/Update-JenkinsVersion.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .Synopsis
3 | Upgrades the version information in the register from the current Jenkins war file.
4 | .Description
5 | The purpose of this script is to update the version of Jenkins in the registry
6 | when the user may have upgraded the war file in place. The script probes the
7 | registry for information about the Jenkins install (path to war, etc.) and
8 | then grabs the version information from the war to update the values in the
9 | registry so they match the version of the war file.
10 |
11 | This will help with security scanners that look in the registry for versions
12 | of software and flag things when they are too low. The information in the
13 | registry may be very old compared to what version of the war file is
14 | actually installed on the system.
15 | #>
16 |
17 |
18 | # Self-elevate the script if required
19 | if (-Not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')) {
20 | # We may be running under powershell.exe or pwsh.exe, make sure we relaunch the same one.
21 | $Executable = [System.Diagnostics.Process]::GetCurrentProcess().MainModule.FileName
22 | if ([int](Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -ge 6000) {
23 | # Launching with RunAs to get elevation
24 | $CommandLine = "-File `"" + $MyInvocation.MyCommand.Path + "`" " + $MyInvocation.UnboundArguments
25 | Start-Process -FilePath $Executable -Verb Runas -ArgumentList $CommandLine
26 | Exit
27 | }
28 | }
29 |
30 | function New-TemporaryDirectory {
31 | $Parent = [System.IO.Path]::GetTempPath()
32 | do {
33 | $Name = [System.IO.Path]::GetRandomFileName()
34 | $Item = New-Item -Path $Parent -Name $Name -ItemType "Directory" -ErrorAction SilentlyContinue
35 | } while (-not $Item)
36 | return $Item.FullName
37 | }
38 |
39 | function Exit-Script($Message, $Fatal = $False) {
40 | $ExitCode = 0
41 | if($Fatal) {
42 | Write-Error $Message
43 | } else {
44 | Write-Host $Message
45 | }
46 | Read-Host "Press ENTER to continue"
47 | Exit $ExitCode
48 | }
49 |
50 | # Let's find the location of the war file...
51 | $JenkinsDir = Get-ItemPropertyValue -Path HKLM:\Software\Jenkins\InstalledProducts\Jenkins -Name InstallLocation -ErrorAction SilentlyContinue
52 |
53 | if (($Null -eq $JenkinsDir) -or [String]::IsNullOrWhiteSpace($JenkinsDir)) {
54 | Exit-Script -Message "Jenkins does not seem to be installed. Please verify you have previously installed using the MSI installer" -Fatal $True
55 | }
56 |
57 | $WarPath = Join-Path $JenkinsDir "jenkins.war"
58 | if(-Not (Test-Path $WarPath)) {
59 | Exit-Script -Message "Could not find war file at location found in registry, please verify Jenkins installation" -Fatal $True
60 | }
61 |
62 | # Get the MANIFEST.MF file from the war file to get the version of Jenkins
63 | $TempWorkDir = New-TemporaryDirectory
64 | $ManifestFile = Join-Path $TempWorkDir "MANIFEST.MF"
65 | $Zip = [IO.Compression.ZipFile]::OpenRead($WarPath)
66 | $Zip.Entries | Where-Object { $_.Name -like "MANIFEST.MF" } | ForEach-Object { [System.IO.Compression.ZipFileExtensions]::ExtractToFile($_, $ManiFestFile, $True) }
67 | $Zip.Dispose()
68 |
69 | $JenkinsVersion = $(Get-Content $ManiFestFile | Select-String -Pattern "^Jenkins-Version:\s*(.*)" | ForEach-Object { $_.Matches } | ForEach-Object { $_.Groups[1].Value } | Select-Object -First 1)
70 | Remove-Item -Path $ManifestFile
71 |
72 | # Convert the Jenkins version into what should be in the registry
73 | $VersionItems = $JenkinsVersion.Split(".") | ForEach-Object { [int]::Parse($_) }
74 |
75 | # Use the same encoding algorithm as the installer to encode the version into the correct format
76 | $RegistryEncodedVersion = 0
77 | $Major = $VersionItems[0]
78 | if ($VersionItems.Length -le 2) {
79 | $Minor = 0
80 | if (($VersionItems.Length -gt 1) -and ($VersionItems[1] -gt 255)) {
81 | $Minor = $VersionItems[1]
82 | $RegistryEncodedVersion = $RegistryEncodedVersion -bor ((($Major -band 0xff) -shl 24) -bor 0x00ff0000 -bor (($Minor * 10) -band 0x0000ffff))
83 | }
84 | else {
85 | $RegistryEncodedVersion = $RegistryEncodedVersion -bor (($Major -band 0xff) -shl 24)
86 | }
87 | }
88 | else {
89 | $Minor = $VersionItems[1]
90 | if ($Minor -gt 255) {
91 | $RegistryEncodedVersion = $RegistryEncodedVersion -bor ((($Major -band 0xff) -shl 24) -bor 0x00ff0000 -bor ((($Minor * 10) + $VersionItems[2]) -band 0x0000ffff))
92 | }
93 | else {
94 | $RegistryEncodedVersion = $RegistryEncodedVersion -bor ((($Major -band 0xff) -shl 24) -bor (($Minor -band 0xff) -shl 16) -bor ($VersionItems[2] -band 0x0000ffff))
95 | }
96 | }
97 |
98 | $ProductName = "Jenkins $JenkinsVersion"
99 |
100 | # Find the registry key for Jenkins in the Installer\Products area and CurrentVersion\Uninstall
101 | $JenkinsProductsRegistryKey = Get-ChildItem -Path HKLM:\SOFTWARE\Classes\Installer\Products | Where-Object { $_.GetValue("ProductName", "").StartsWith("Jenkins") }
102 |
103 | $JenkinsUninstallRegistryKey = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall | Where-Object { $_.GetValue("DisplayName", "").StartsWith("Jenkins") }
104 |
105 | if (($Null -eq $JenkinsProductsRegistryKey) -or ($Null -eq $JenkinsUninstallRegistryKey)) {
106 | Exit-Script -Message "Could not find the product information for Jenkins" -Fatal $True
107 | }
108 |
109 | # Update the Installer\Products area
110 | $RegistryPath = $JenkinsProductsRegistryKey.Name.Substring($JenkinsProductsRegistryKey.Name.IndexOf("\"))
111 |
112 | $OldProductName = $JenkinsProductsRegistryKey.GetValue("ProductName", "")
113 | if ($OldProductName -ne $ProductName) {
114 | Set-ItemProperty -Path HKLM:$RegistryPath -Name "ProductName" -Type String -Value $ProductName
115 | }
116 |
117 | $OldVersion = $JenkinsProductsRegistryKey.GetValue("Version", 0)
118 | if ($OldVersion -ne $RegistryEncodedVersion) {
119 | Set-ItemProperty -Path HKLM:$RegistryPath -Name "Version" -Type DWord -Value $RegistryEncodedVersion
120 | }
121 |
122 | # Update the Uninstall area
123 | $RegistryPath = $JenkinsUninstallRegistryKey.Name.Substring($JenkinsUninstallRegistryKey.Name.IndexOf("\"))
124 | $OldDisplayName = $JenkinsUninstallRegistryKey.GetValue("DisplayName", "")
125 | if ($OldDisplayName -ne $ProductName) {
126 | Set-ItemProperty -Path HKLM:$RegistryPath -Name "DisplayName" -Type String -Value $ProductName
127 | }
128 |
129 | $OldDisplayVersion = $JenkinsUninstallRegistryKey.GetValue("DisplayVersion", "")
130 | $DisplayVersion = "{0}.{1}.{2}" -f ($RegistryEncodedVersion -shr 24), (($RegistryEncodedVersion -shr 16) -band 0xff), ($RegistryEncodedVersion -band 0xffff)
131 | if ($OldDisplayVersion -ne $DisplayVersion) {
132 | Set-ItemProperty -Path HKLM:$RegistryPath -Name "DisplayVersion" -Type String -Value $DisplayVersion
133 | }
134 |
135 | $OldVersion = $JenkinsUninstallRegistryKey.GetValue("Version", 0)
136 | if ($OldVersion -ne $RegistryEncodedVersion) {
137 | Set-ItemProperty -Path HKLM:$RegistryPath -Name "Version" -Type DWord -Value $RegistryEncodedVersion
138 | }
139 |
140 | $OldVersionMajor = $JenkinsUninstallRegistryKey.GetValue("VersionMajor", 0)
141 | $VersionMajor = $RegistryEncodedVersion -shr 24
142 | if ($OldVersionMajor -ne $VersionMajor) {
143 |
144 | Set-ItemProperty -Path HKLM:$RegistryPath -Name "VersionMajor" -Type DWord -Value $VersionMajor
145 | }
146 |
147 | $OldVersionMinor = $JenkinsUninstallRegistryKey.GetValue("VersionMinor", 0)
148 | $VersionMinor = ($RegistryEncodedVersion -shr 16) -band 0xff
149 | if ($OldVersionMinor -ne $VersionMinor) {
150 | Set-ItemProperty -Path HKLM:$RegistryPath -Name "VersionMinor" -Type DWord -Value $VersionMinor
151 | }
152 |
153 | Read-Host "Press ENTER to continue"
154 |
--------------------------------------------------------------------------------
/msi/build/banner.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jenkinsci/packaging/621e33ede4493dbc702152435a777a982c30d633/msi/build/banner.bmp
--------------------------------------------------------------------------------
/msi/build/build.ps1:
--------------------------------------------------------------------------------
1 | [CmdletBinding()]
2 | Param(
3 | [String] $War = $env:WAR,
4 | [string] $MSBuildPath = '',
5 | [bool] $UseTracing = $false,
6 | [String] $ProductName = $env:PRODUCTNAME,
7 | [String] $ProductSummary = $env:SUMMARY,
8 | [String] $ProductVendor = $env:VENDOR,
9 | [String] $ArtifactName = $env:ARTIFACTNAME,
10 | [String] $BannerBmp = '',
11 | [String] $DialogBmp = '',
12 | [String] $InstallerIco = ''
13 | )
14 |
15 | function Set-CodeSigningSignature {
16 | param (
17 | $Path,
18 | $JenkinsVersion
19 | )
20 |
21 | if((-not ([System.String]::IsNullOrWhiteSpace($env:PKCS12_FILE)) -and (Test-Path $env:PKCS12_FILE)) -and (-not [System.String]::IsNullOrWhiteSpace($env:SIGN_STOREPASS))) {
22 | Write-Host "Signing $Path"
23 | # always disable tracing here
24 | Set-PSDebug -Trace 0
25 | $retries = 10
26 | $i = $retries
27 | # Create an array of timestamp servers that includes each of the known timestamp servers duplicated $retries times so that the list won't be exhausted during retry
28 | # Start with digicert because we purchased the code signing certificate from digicert
29 | $timestampservers = "http://timestamp.digicert.com", "http://rfc3161timestamp.globalsign.com/advanced", "http://timestamp.sectigo.com/", "http://timestamp.verisign.com/scripts/timstamp.dll" * $retries
30 | for(; $i -gt 0; $i--) {
31 | # Pop first entry from timestamp server array, use it as timestamp server for this attempt
32 | $timestamp, $timestampservers = $timestampservers
33 | # Submit SHA256 digest to RFC 3161 timestamp server
34 | $p = Start-Process -Wait -PassThru -NoNewWindow -FilePath "signtool.exe" -ArgumentList "sign /v /f `"${env:PKCS12_FILE}`" /p ${env:SIGN_STOREPASS} /tr $timestamp /td SHA256 /fd SHA256 /d `"Jenkins Automation Server ${JenkinsVersion}`" /du `"https://jenkins.io`" $Path"
35 | $p.WaitForExit()
36 | # we will retry up to $retries times until we get a good exit code
37 | if($p.ExitCode -eq 0) {
38 | break
39 | } else {
40 | Start-Sleep -Seconds 15
41 | }
42 | }
43 |
44 | if($i -le 0) {
45 | Write-Error "signtool did not complete successfully after $retries tries"
46 | exit -1
47 | }
48 |
49 | if($UseTracing) { Set-PSDebug -Trace 1 }
50 |
51 | Write-Host "Checking the signature"
52 | # It will print the entire certificate chain with details
53 | signtool verify /v /pa /all $Path
54 | }
55 | }
56 |
57 | if($UseTracing) { Set-PSDebug -Trace 1 }
58 |
59 | if([String]::IsNullOrWhiteSpace($War)) {
60 | Write-Error "Missing jenkins WAR path"
61 | exit 1
62 | }
63 |
64 | $ErrorActionPreference = "Stop"
65 |
66 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
67 |
68 | Add-Type -Assembly System.IO.Compression.FileSystem
69 |
70 | $tmpDir = Join-Path $PSScriptRoot "tmp"
71 |
72 | if(!(Test-Path $tmpDir)) {
73 | New-Item -ItemType Directory -Path $tmpDir -Force -Confirm:$false | Out-Null
74 | } else {
75 | Get-ChildItem tmp\* | Remove-Item -Force
76 | }
77 |
78 | if(!(Test-Path (Join-Path $PSScriptRoot 'msiext-1.5/WixExtensions/WixCommonUiExtension.dll'))) {
79 | Invoke-WebRequest -Uri "https://github.com/dblock/msiext/releases/download/1.5/msiext-1.5.zip" -OutFile (Join-Path $PSScriptRoot 'msiext-1.5.zip') -UseBasicParsing
80 | [IO.Compression.ZipFile]::ExtractToDirectory((Join-Path $PSScriptRoot 'msiext-1.5.zip'), $PSScriptRoot)
81 | }
82 |
83 | Write-Host "Extracting components"
84 | if($UseTracing) { Set-PSDebug -Trace 0 }
85 | # get the components we need from the war file
86 |
87 | $maniFestFile = Join-Path $tmpDir "MANIFEST.MF"
88 | $zip = [IO.Compression.ZipFile]::OpenRead($War)
89 | $zip.Entries | Where-Object {$_.Name -like 'MANIFEST.MF'} | ForEach-Object { [System.IO.Compression.ZipFileExtensions]::ExtractToFile($_, $maniFestFile, $true)}
90 |
91 | $JenkinsVersion = $(Get-Content $maniFestFile | Select-String -Pattern "^Jenkins-Version:\s*(.*)" | ForEach-Object { $_.Matches } | ForEach-Object { $_.Groups[1].Value } | Select-Object -First 1)
92 | Write-Host "JenkinsVersion = $JenkinsVersion"
93 |
94 | $zip.Entries | Where-Object {$_.Name -like "jenkins-core-${JenkinsVersion}.jar"} | ForEach-Object {[System.IO.Compression.ZipFileExtensions]::ExtractToFile($_, [System.IO.Path]::Combine($tmpDir, "core.jar"), $true)}
95 | $zip.Dispose()
96 |
97 | $zip = [IO.Compression.ZipFile]::OpenRead([System.IO.Path]::Combine($tmpDir, 'core.jar'))
98 | $zip.Entries | Where-Object {$_.Name -like 'jenkins.exe'} | ForEach-Object {[System.IO.Compression.ZipFileExtensions]::ExtractToFile($_, [System.IO.Path]::Combine($tmpDir, "jenkins.exe"), $true)}
99 | $zip.Dispose()
100 |
101 | $zip = [IO.Compression.ZipFile]::OpenRead([System.IO.Path]::Combine($tmpDir, 'core.jar'))
102 | $zip.Entries | Where-Object {$_.Name -like 'jenkins.xml'} | ForEach-Object {[System.IO.Compression.ZipFileExtensions]::ExtractToFile($_, [System.IO.Path]::Combine($tmpDir, "jenkins.xml"), $true)}
103 | $zip.Dispose()
104 | if($UseTracing) { Set-PSDebug -Trace 1 }
105 |
106 | $isLts = $JenkinsVersion.Split('.').Length -gt 2
107 |
108 | Write-Host "Restoring packages before build"
109 | # restore the Wix package
110 | & "./nuget.exe" restore -PackagesDirectory "packages"
111 |
112 | Write-Host "Building MSI"
113 | if($MSBuildPath -ne '') {
114 | if($MSBuildPath.ToLower().EndsWith('msbuild.exe')) {
115 | $MSBuildPath = [System.IO.Path]::GetDirectoryName($MSBuildPath)
116 | }
117 | $env:PATH = $env:PATH + ";" + $MSBuildPath
118 | } else {
119 | # try to find it with vswhere
120 | $MSBuildPath = & 'C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe' -products * -latest -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe
121 | if(($MSBuildPath -ne '') -and $MSBuildPath.ToLower().EndsWith('msbuild.exe')) {
122 | $MSBuildPath = [System.IO.Path]::GetDirectoryName($MSBuildPath)
123 | }
124 | $env:PATH = $env:PATH + ";" + $MSBuildPath
125 | }
126 |
127 | # Sign the Update-JenkinsVersion.ps1 script if we have PKCS files
128 | Copy-Item -Force -Path .\Update-JenkinsVersion.ps1 -Destination tmp
129 | Set-CodeSigningSignature -Path .\tmp\Update-JenkinsVersion.ps1 -JenkinsVersion $JenkinsVersion
130 |
131 | msbuild "jenkins.wixproj" /p:Stable="${isLts}" /p:WAR="${War}" /p:Configuration=Release /p:DisplayVersion=$JenkinsVersion /p:ProductName="${ProductName}" /p:ProductSummary="${ProductSummary}" /p:ProductVendor="${ProductVendor}" /p:ArtifactName="${ArtifactName}" /p:BannerBmp="${BannerBmp}" /p:DialogBmp="${DialogBmp}" /p:InstallerIco="${InstallerIco}"
132 |
133 | Get-ChildItem .\bin\Release -Filter *.msi -Recurse |
134 | Foreach-Object {
135 | Set-CodeSigningSignature -Path $($_.FullName) -JenkinsVersion $JenkinsVersion
136 |
137 | $sha256 = (Get-FileHash -Algorithm SHA256 -Path $_.FullName).Hash.ToString().ToLower()
138 | Set-Content -Path "$($_.FullName).sha256" -Value "$sha256 $($_.Name)" -Force
139 | $env:MSI_SHA256 = $sha256
140 | }
141 |
142 | if ($UseTracing) { Set-PSDebug -Trace 0 }
143 |
--------------------------------------------------------------------------------
/msi/build/jenkins.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jenkinsci/packaging/621e33ede4493dbc702152435a777a982c30d633/msi/build/jenkins.bmp
--------------------------------------------------------------------------------
/msi/build/jenkins.exe.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/msi/build/jenkins.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jenkinsci/packaging/621e33ede4493dbc702152435a777a982c30d633/msi/build/jenkins.ico
--------------------------------------------------------------------------------
/msi/build/jenkins.wixproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | x64
7 | 3.5
8 | {49c7ae2b-d9d1-4b32-9d11-474f1be86658}
9 | 2.0
10 | False
11 | jenkins-$(DisplayVersion)
12 | jenkins-$(DisplayVersion)-stable
13 | Package
14 | true
15 | True
16 | false
17 | 1076
18 | en-US
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | 1 && int.TryParse(items[1], out minor) && minor > 255) {
33 | EncodedVersion = string.Format("{0}.255.{1}", items[0], minor * 10);
34 | } else {
35 | EncodedVersion = string.Format("{0}.0", DisplayVersion);
36 | }
37 | } else {
38 | int minor = 0;
39 | if(int.TryParse(items[1], out minor) && minor > 255) {
40 | EncodedVersion = string.Format("{0}.255.{1}", items[0], (minor * 10) + int.Parse(items[2]));
41 | } else {
42 | EncodedVersion = string.Format("{0}.{1}.{2}", items[0], items[1], int.Parse(items[2]));
43 | }
44 | }
45 | ]]>
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | $(EncodedVersion)
64 |
65 |
66 | {415933D8-4104-47C3-AEE9-66B31DE07A57}
67 |
68 |
69 | $(DisplayVersion)
70 |
71 |
72 | tmp\jenkins.war
73 |
74 |
75 | $(WAR)
76 |
77 |
78 |
79 | Jenkins
80 |
81 |
82 | $(ProductName)
83 |
84 |
85 |
86 | Jenkins Automation Server
87 |
88 |
89 | $(ProductSummary)
90 |
91 |
92 |
93 | Jenkins Project
94 |
95 |
96 | $(ProductVendor)
97 |
98 |
99 |
100 | Jenkins
101 |
102 |
103 | $(ArtifactName)
104 |
105 |
106 |
107 |
108 | jenkins.ico
109 |
110 |
111 | $(InstallerIco)
112 |
113 |
114 |
115 | jenkins.bmp
116 |
117 |
118 | $(DialogBmp)
119 |
120 |
121 |
122 | banner.bmp
123 |
124 |
125 | $(BannerBmp)
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 | bin\$(Configuration)\
144 | obj\$(Configuration)\
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 | $(WixExtDir)\WixUIExtension.dll
158 | WixUIExtension
159 |
160 |
161 | $(WixExtDir)\WixNetFxExtension.dll
162 | WixNetFxExtension
163 |
164 |
165 | $(WixExtDir)\WixUtilExtension.dll
166 | WixUtilExtension
167 |
168 |
169 | .\msiext-1.5\WixExtensions\WixCommonUIExtension.dll
170 | WixCommonUIExtension
171 |
172 |
173 | $(WixExtDir)\WixFirewallExtension.dll
174 | WixCommonUIExtension
175 |
176 |
177 |
178 |
179 |
--------------------------------------------------------------------------------
/msi/build/jenkins_en-US.wxl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | [ProductName] Setup
5 | Select Java home directory (JDK or JRE)
6 | Please select the path of a Java Development Kit or Java Runtime Environment. Only Java 17 and 21 are supported by Jenkins.
7 | &Change...
8 | Invalid Java Directory
9 | Failed to find compatible Java version (17 or 21) in [JAVA_HOME]
10 |
11 |
12 | Browse to the Java Home directory
13 | {\WixUI_Font_Title}Select Java folder
14 |
15 |
16 | Run service as LocalSystem (not recommended)
17 | Enables a firewall exception for the Java running Jenkins on port [PORTNUMBER] (not recommended).
18 | Starts the Jenkins service after install.
19 |
20 |
--------------------------------------------------------------------------------
/msi/build/nuget.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jenkinsci/packaging/621e33ede4493dbc702152435a777a982c30d633/msi/build/nuget.exe
--------------------------------------------------------------------------------
/msi/build/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/msi/docs/build-msi-locally.md:
--------------------------------------------------------------------------------
1 | # How to build a Jenkins MSI on your Windows machine
2 |
3 | ## Pre-requisites
4 |
5 | ### Jenkins WAR file
6 |
7 | First of all, you should get the Jenkins war file that will be inside that MSI file.
8 | You can get it from the official Jenkins website or from [the Jenkins update center](https://updates.jenkins.io/).
9 |
10 | Check [Jenkins download page](https://www.jenkins.io/download/) and download the latest weekly version of Jenkins for example.
11 |
12 | ### Git
13 |
14 | There are quite a few ways to get Git on Windows, but the most straightforward is to see what the [official Git website recommends](https://git-scm.com/download/win).
15 |
16 | ### Install MSBuild
17 |
18 | You can install [MSBuild](https://aka.ms/vs/17/release/vs_BuildTools.exe) from Visual Studio or from the [Build Tools for Visual Studio](https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2022).
19 |
20 | This command line tool is used to build the MSI file.
21 |
22 | ### Install .NET Framework 3.5
23 |
24 | You may already have it installed on your machine, but not activated.
25 | You can activate it from the Windows Features dialog box.
26 |
27 | To access this dialog box, press the keys ⊞ Win + R , then enter the command `appwiz.cpl` and push enter.
28 | Search for
29 |
30 | > Turn Windows features on or off.
31 |
32 | Tick the `.NET Framework 3.5` entry and install.
33 |
34 | Important: now run Windows Update to check for security updates.
35 |
36 | If it is not installed yet, you can install [.NET Framework 3.5](https://dotnet.microsoft.com/en-us/download/dotnet-framework/net35-sp1) from the Windows Features.
37 |
38 | ### Check if you have PowerShell
39 |
40 | In recent versions of Windows, PowerShell is already installed and accessible through the [terminal](https://support.microsoft.com/en-us/topic/6453ce98-da91-476f-8651-5c14d5777c20#:~:text=In%20Windows%2011%2022H2%2C%20the,an%20instance%20of%20Windows%20Terminal) application.
41 | At the time of writing, the pre-installed version is `5.1.22621.963`.
42 | You can also install the latest version from the [Microsoft Store](https://www.microsoft.com/en-us/p/powershell/9mz1snwt0n5d?activetab=pivot:overviewtab) (7.3.2 at the time of writing).
43 |
44 | ## Build the MSI
45 |
46 | ### Clone the Jenkins packaging repository
47 |
48 | Choose your `git` tool and clone the [Jenkins packaging repository](https://github.com/jenkinsci/packaging.git) on your machine.
49 |
50 | ### Prepare the build
51 |
52 | Open a `terminal` and go to the folder where you cloned the repository. For example `C:\jenkinsci\packaging\`.
53 | You now have to declare where you downloaded the Jenkins war file so the build can find it.
54 |
55 | ```powershell
56 | $env:War = "$env:USERPROFILE\jenkins.war"
57 | ```
58 |
59 | If you ever moved it into your repository clone folder, you can use this command instead:
60 |
61 | ```powershell
62 | $env:War = "C:\jenkinsci\packaging\msi\build\jenkins.war"
63 | ```
64 |
65 | ### Build the MSI
66 |
67 | Enter the subfolder `msi\build` and run the following command:
68 |
69 | ```powershell
70 | .\build.ps1
71 | ```
72 |
73 | You should get an output similar to:
74 |
75 | ```powershell
76 | Extracting components
77 | JenkinsVersion = 2.392
78 | Restoring packages before build
79 | All packages listed in packages.config are already installed.
80 | Building MSI
81 | MSBuild version 17.4.0+18d5aef85 for .NET Framework
82 | Build started 01/12/2022 20:53:30.
83 | Project "C:\jenkinsci\packaging\msi\build\jenkins.wixproj" on node 1 (default targets).
84 | SetConstants:
85 | EncodedVersion = 2.255.3920
86 | Compile:
87 | Skipping target "Compile" because all output files are up-to-date with respect to the input files.
88 | AssignCultures:
89 | Culture: en-US
90 | Link:
91 | C:\jenkinsci\packaging\msi\build\packages\WiX.3.11.1\build\..\tools\Light.exe -out C:\jenkinsci\packaging\msi\build\bi
92 | n\Release\en-US\jenkins-2.392.msi -pdbout C:\jenkinsci\packaging\msi\build\bin\Release\en-US\jenkins-2.392.wixpdb -sw1076 -cultures:en-US -ext C:\S
93 | upport\users\jenkinsci\packaging\packaging\msi\build\packages\WiX.3.11.1\build\..\tools\\WixUIExtension.dll -ext C:\jenkinsci\packaging\msi\bu
94 | ild\packages\WiX.3.11.1\build\..\tools\\WixNetFxExtension.dll -ext C:\jenkinsci\packaging\msi\build\packages\WiX.3.11.1\build\..\tools\\WixUtilExte
95 | nsion.dll -ext .\msiext-1.5\WixExtensions\WixCommonUIExtension.dll -ext C:\jenkinsci\packaging\msi\build\packages\WiX.3.11.1\build\..\tools\\WixFir
96 | ewallExtension.dll -fv -loc jenkins_en-US.wxl -spdb -contentsfile obj\Release\jenkins.wixproj.BindContentsFileListen-US.txt -outputsfile obj\Release\jenkins.wixproj.BindOutputs
97 | FileListen-US.txt -builtoutputsfile obj\Release\jenkins.wixproj.BindBuiltOutputsFileListen-US.txt -wixprojectfile C:\jenkinsci\packaging\msi\build\
98 | jenkins.wixproj obj\Release\jenkins.wixobj
99 | Windows Installer XML Toolset Linker version 3.11.1.2318
100 | Copyright (c) .NET Foundation and contributors. All rights reserved.
101 |
102 | jenkins -> C:\jenkinsci\packaging\msi\build\bin\Release\en-US\jenkins-2.392.msi
103 | Done Building Project "C:\jenkinsci\packaging\msi\build\jenkins.wixproj" (default targets).
104 |
105 |
106 | Build succeeded.
107 | 0 Warning(s)
108 | 0 Error(s)
109 |
110 | Time Elapsed 00:00:08.26
111 | ```
112 |
113 | ## Locate the generated MSI file
114 |
115 | The MSI file is located in the `.\bin\Release\en-US\` folder.
116 | You will find there the generated MSI file and its `sha256` file.
117 |
118 | ```powershell
119 | ls
120 |
121 | Directory: C:\jenkinsci\packaging\msi\build\bin\Release\en-US
122 |
123 |
124 | Mode LastWriteTime Length Name
125 | ---- ------------- ------ ----
126 | -a---- 01/12/2022 20:53 105107456 jenkins-2.392.msi
127 | -a---- 01/12/2022 20:53 84 jenkins-2.392.msi.sha256
128 | ```
129 |
--------------------------------------------------------------------------------
/msi/publish/publish.ps1:
--------------------------------------------------------------------------------
1 | function Export-Variables($file) {
2 | Get-Content $file | Select-String -Pattern "^export"| ForEach-Object {
3 | $array= $_[0].ToString().split("=")
4 | $array[0] = $array[0].Replace("export","").Trim()
5 | if($array[1].Contains('${')) {
6 | $array[1] = $ExecutionContext.InvokeCommand.ExpandString($array[1].Replace('${', '${env:'))
7 | } elseif($array[1] -match '\$\(([^)]*)\)(.*)') {
8 | $command = $Matches[1].Trim()
9 | $rest = $Matches[2]
10 | if($command.StartsWith('realpath')) {
11 | $command = Invoke-Expression -Command $command.Replace('realpath', 'Resolve-Path')
12 | } else {
13 | Write-Error "Unknown command to convert: $command"
14 | }
15 | $array[1] = '{0}{1}' -f $command,$rest
16 | $array[1] = $ExecutionContext.InvokeCommand.ExpandString($array[1])
17 | }
18 | [System.Environment]::SetEnvironmentVariable($array[0], $array[1])
19 | }
20 | }
21 |
22 | if(($null -ne $env:BRAND) -and (Test-Path $env:BRAND)) {
23 | Export-Variables .\$env:BRAND
24 | }
25 |
26 | Export-Variables .\$env:BUILDENV
27 |
28 | Write-Host "Copying binaries to ${env:MSIDIR}"
29 |
30 | if(!(Test-Path $env:MSIDIR)) {
31 | New-Item -ItemType Directory -Path $env:MSIDIR
32 | }
33 |
34 | Get-ChildItem -Path '.\msi\build\bin\Release\en-US\*' -File -Include *.msi,*.msi.sha256 | Copy-Item -Destination $env:MSIDIR
35 |
36 | Get-ChildItem -Path $env:MSIDIR
37 |
--------------------------------------------------------------------------------
/msi/publish/publish.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -euxo pipefail
4 |
5 | : "${AGENT_WORKDIR:=/tmp}"
6 | : "${MSI:?Require Jenkins War file}"
7 | : "${MSIDIR:? Require where to put binary files}"
8 |
9 | # Convert string to array to correctly escape cli parameter
10 | SSH_OPTS=($SSH_OPTS)
11 |
12 | # $$ Contains current pid
13 | D="$AGENT_WORKDIR/$$"
14 |
15 | function clean() {
16 | rm -rf "$D"
17 | }
18 |
19 | # Generate and publish site content
20 | function generateSite() {
21 | "$BASE/bin/indexGenerator.py" \
22 | --distribution windows \
23 | --targetDir "$MSIDIR"
24 | }
25 |
26 | function init() {
27 | mkdir -p $D
28 |
29 | mkdir -p "${MSIDIR}/${VERSION}/"
30 |
31 | ssh "${SSH_OPTS[@]}" "$PKGSERVER" mkdir -p "$MSIDIR/${VERSION}/"
32 | }
33 |
34 | function skipIfAlreadyPublished() {
35 | if ssh "${SSH_OPTS[@]}" "$PKGSERVER" test -e "${MSIDIR}/${VERSION}/$(basename "$MSI")"; then
36 | echo "File already published, nothing else todo"
37 | exit 0
38 |
39 | fi
40 | }
41 |
42 | function uploadPackage() {
43 | cp "${ARTIFACTNAME}-${VERSION}${RELEASELINE}.msi" "${MSI}"
44 |
45 | sha256sum "${MSI}" >"${MSI_SHASUM}"
46 |
47 | cat "${MSI_SHASUM}"
48 |
49 | # Local
50 | rsync \
51 | --compress \
52 | --verbose \
53 | --recursive \
54 | --ignore-existing \
55 | --progress \
56 | "${MSI}" "${MSIDIR}/${VERSION}/"
57 |
58 | rsync \
59 | --compress \
60 | --ignore-existing \
61 | --recursive \
62 | --progress \
63 | --verbose \
64 | "${MSI_SHASUM}" "${MSIDIR}/${VERSION}/"
65 |
66 | # Remote
67 | rsync \
68 | --archive \
69 | --compress \
70 | --verbose \
71 | --ignore-existing \
72 | --progress \
73 | -e "ssh ${SSH_OPTS[*]}" \
74 | "${MSI}" "$PKGSERVER:${MSIDIR}/${VERSION}/"
75 |
76 | rsync \
77 | --archive \
78 | --compress \
79 | --verbose \
80 | --ignore-existing \
81 | --progress \
82 | -e "ssh ${SSH_OPTS[*]}" \
83 | "${MSI_SHASUM}" "$PKGSERVER:${MSIDIR}/${VERSION}/"
84 |
85 | # Update the symlink to point to most recent Windows build
86 | #
87 | # Remove anything in current directory named 'latest'
88 | # This is a safety measure just in case something was left there previously
89 | rm -rf latest
90 |
91 | # Create a local symlink pointing to the MSI file in the VERSION directory.
92 | # Don't need VERSION directory or MSI locally, just the unresolved symlink.
93 | # The jenkins.io page downloads http://mirrors.jenkins-ci.org/windows/latest
94 | # and assumes it points to the most recent MSI file.
95 | ln -s ${VERSION}/"$(basename "$MSI")" latest
96 |
97 | # Copy the symlink to PKGSERVER in the root of MSIDIR
98 | # Overwrites the existing symlink on the destination
99 | rsync \
100 | --archive \
101 | --links \
102 | --verbose \
103 | -e "ssh ${SSH_OPTS[*]}" \
104 | latest "$PKGSERVER:${MSIDIR}/"
105 |
106 | # Remove the local symlink
107 | rm latest
108 | }
109 |
110 | # The site need to be located in the binary directory
111 | function uploadSite() {
112 | rsync \
113 | --compress \
114 | --verbose \
115 | --recursive \
116 | --progress \
117 | -e "ssh ${SSH_OPTS[*]}" \
118 | "${D}/" "${MSIDIR// /\\ }/"
119 |
120 | rsync \
121 | --archive \
122 | --compress \
123 | --verbose \
124 | --progress \
125 | -e "ssh ${SSH_OPTS[*]}" \
126 | "${D}/" "$PKGSERVER:${MSIDIR// /\\ }/"
127 | }
128 |
129 | function show() {
130 | echo "Parameters:"
131 | echo "MSI: $MSI"
132 | echo "MSIDIR: $MSIDIR"
133 | echo "SSH_OPTS: ${SSH_OPTS[*]}"
134 | echo "PKGSERVER: $PKGSERVER"
135 | echo "---"
136 | }
137 |
138 | show
139 | skipIfAlreadyPublished
140 | init
141 | generateSite
142 | uploadPackage
143 | uploadSite
144 |
--------------------------------------------------------------------------------
/prep.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -eux
2 | set -o pipefail
3 | cd "$(dirname "$0")"
4 |
5 | # TODO jenkins-infra/release performs similar preparatory actions: downloading
6 | # the WAR and importing the GPG key. A common interface for the preparatory
7 | # actions should be designed that meets the needs of both local testing and
8 | # releases, ideally implemented in the Makefile. Then both this repository and
9 | # jenkins-infra/release should be refactored to consume the new functionality.
10 |
11 | if [[ ! -f $WAR ]]; then
12 | jv download
13 | fi
14 |
15 | if ! gpg --fingerprint "${GPG_KEYNAME}"; then
16 | gpg --import --batch "${GPG_FILE}"
17 | fi
18 |
19 | # produces: jenkins.war
20 | exit 0
21 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | ansible==10.7.0
2 | jinja2==3.1.6
3 | molecule-plugins[docker]==23.7.0
4 |
--------------------------------------------------------------------------------
/rpm/build/SOURCES/jenkins.repo:
--------------------------------------------------------------------------------
1 | [@@ARTIFACTNAME@@]
2 | name=@@PRODUCTNAME@@
3 | baseurl=@@RPM_URL@@
4 | gpgcheck=1
5 |
--------------------------------------------------------------------------------
/rpm/build/SPECS/jenkins.spec:
--------------------------------------------------------------------------------
1 | # TODO:
2 | # - how to add to the trusted service of the firewall?
3 |
4 | %define workdir %{_var}/lib/@@ARTIFACTNAME@@
5 |
6 | Name: @@ARTIFACTNAME@@
7 | Version: %{ver}
8 | Release: 1.1
9 | Summary: @@SUMMARY@@
10 | Source: jenkins.war
11 | Source1: jenkins.service
12 | Source2: jenkins.sh
13 | Source3: migrate.sh
14 | Source4: jenkins.conf
15 | URL: @@HOMEPAGE@@
16 | License: @@LICENSE@@
17 | BuildRoot: %{_tmppath}/build-%{name}-%{version}
18 | # Unfortunately the Oracle Java RPMs do not register as providing anything (including "java" or "jdk")
19 | # So either we make a hard requirement on the OpenJDK or none at all
20 | # Only workaround would be to use a java virtual package, see https://github.com/keystep/virtual-java-rpm
21 | # TODO: If re-enable, fix the matcher for Java 17
22 | # Requires: java >= 1:1.8.0
23 | Requires: procps
24 | Requires(pre): /usr/sbin/useradd, /usr/sbin/groupadd
25 | BuildArch: noarch
26 | %systemd_requires
27 |
28 | %description
29 | @@DESCRIPTION_FILE@@
30 |
31 | Authors:
32 | --------
33 | @@AUTHOR@@
34 |
35 | %prep
36 | %setup -q -T -c
37 |
38 | %build
39 |
40 | %install
41 | rm -rf "%{buildroot}"
42 | %__install -D -m0644 "%{SOURCE0}" "%{buildroot}%{_javadir}/%{name}.war"
43 | %__install -D -m0644 "%{SOURCE1}" "%{buildroot}%{_unitdir}/%{name}.service"
44 | %__install -D -m0755 "%{SOURCE2}" "%{buildroot}%{_bindir}/%{name}"
45 | %__install -D -m0755 "%{SOURCE3}" "%{buildroot}%{_datadir}/%{name}/migrate"
46 | %__install -D -m0755 "%{SOURCE4}" "%{buildroot}%{_tmpfilesdir}/%{name}.conf"
47 |
48 | %pre
49 | /usr/bin/getent group %{name} &>/dev/null || /usr/sbin/groupadd -r %{name} &>/dev/null
50 | # SUSE version had -o here, but in Fedora -o isn't allowed without -u
51 | /usr/bin/getent passwd %{name} &>/dev/null || /usr/sbin/useradd -g %{name} -s /bin/false -r -c "@@SUMMARY@@" \
52 | -d "%{workdir}" %{name} &>/dev/null
53 |
54 | %post
55 | if [ $1 -eq 1 ]; then
56 | %__install -d -m 0755 -o %{name} -g %{name} %{workdir}
57 | %__install -d -m 0750 -o %{name} -g %{name} %{_localstatedir}/cache/%{name}
58 | elif [ -f "%{_sysconfdir}/sysconfig/%{name}" ]; then
59 | %{_datadir}/%{name}/migrate "/etc/sysconfig/%{name}" || true
60 | fi
61 | %systemd_post %{name}.service
62 |
63 | %preun
64 | if [ $1 -eq 0 ]; then
65 | %__rm -rf %{_localstatedir}/cache/%{name}/war
66 | fi
67 | %systemd_preun %{name}.service
68 |
69 | %postun
70 | %systemd_postun_with_restart %{name}.service
71 |
72 | %files
73 | %{_javadir}/%{name}.war
74 | %ghost %{workdir}
75 | %ghost %{_localstatedir}/cache/%{name}
76 | %{_unitdir}/%{name}.service
77 | %{_bindir}/%{name}
78 | %{_datadir}/%{name}/migrate
79 | %{_tmpfilesdir}/%{name}.conf
80 |
81 | %changelog
82 | * Mon Nov 06 2023 minfrin@sharp.fm
83 | - added unix domain socket support
84 | * Mon Jun 19 2023 projects@unixadm.org
85 | - removed sysv initscript for el>=7
86 | - removed logrotate config
87 | - avoid re-chowning workdir and cachedir on upgrades
88 | * Sat Apr 19 2014 mbarr@mbarr.net
89 | - Removed the jenkins.repo installation. Per https://issues.jenkins-ci.org/browse/JENKINS-22690
90 | * Wed Sep 28 2011 kk@kohsuke.org
91 | - See [@@CHANGELOG_PAGE@@] for complete details
92 |
--------------------------------------------------------------------------------
/rpm/build/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -eux
2 |
3 | # prepare fresh directories
4 | D=$(mktemp -d)
5 | trap 'rm -rf "${D}"' EXIT
6 |
7 | cp -R "$(dirname "$0")"/* "${D}"
8 | cp "${BASE}/systemd/jenkins.service" "${D}/SOURCES"
9 | cp "${BASE}/systemd/jenkins.sh" "${D}/SOURCES"
10 | cp "${BASE}/systemd/migrate.sh" "${D}/SOURCES"
11 | cp "${BASE}/systemd/jenkins.conf" "${D}/SOURCES"
12 | "${BASE}/bin/branding.py" "${D}"
13 |
14 | cp "${WAR}" "${D}/SOURCES/jenkins.war"
15 |
16 | pushd "${D}"
17 | mkdir -p BUILD RPMS SRPMS
18 | rpmbuild -ba --define="_topdir ${PWD}" --define="_tmppath ${PWD}/tmp" --define="ver ${VERSION}" SPECS/jenkins.spec
19 |
20 | # sign the results
21 | find RPMS -type f -name '*.rpm' -exec rpmsign --addsign '{}' \;
22 | find RPMS -type f -name '*.rpm' -exec rpm -qpi '{}' \;
23 | popd
24 |
25 | mkdir -p "$(dirname "${RPM}")"
26 | mv "${D}"/RPMS/noarch/*.rpm "${RPM}"
27 |
28 | exit 0
29 |
--------------------------------------------------------------------------------
/rpm/publish/publish.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -euxo pipefail
3 |
4 | : "${AGENT_WORKDIR:=/tmp}"
5 | : "${GPG_KEYNAME:?Require valid gpg keyname}"
6 | : "${RPMDIR:?Require where to put binary files}"
7 | : "${RPM_WEBDIR:?Require where to put index and other web contents}"
8 | : "${RPM_URL:?Require rpm repository url}"
9 | : "${RELEASELINE?Require rpm release line}"
10 | : "${BASE:? Required base directory}"
11 |
12 | # $$ Contains current pid
13 | D="$AGENT_WORKDIR/$$"
14 |
15 | # Convert string to array to correctly escape cli parameter
16 | SSH_OPTS=($SSH_OPTS)
17 |
18 | function clean() {
19 | rm -rf $D
20 | }
21 |
22 | function generateSite() {
23 | gpg --export -a --output "$D/${ORGANIZATION}.key" "${GPG_KEYNAME}"
24 | echo "$(gpg --import-options show-only --import $D/${ORGANIZATION}.key)" >"$D/${ORGANIZATION}.key.info"
25 |
26 | "$BASE/bin/indexGenerator.py" \
27 | --distribution redhat \
28 | --gpg-key-info-file "${D}/${ORGANIZATION}.key.info" \
29 | --targetDir "$D"
30 |
31 | "$BASE/bin/branding.py" "$D"
32 |
33 | cp "$RPM" "$D/RPMS/noarch"
34 |
35 | cat >"$D/${ARTIFACTNAME}.repo" <"$JENKINS_PID_FILE"
137 | return 0
138 | else
139 | return 1
140 | fi
141 | }
142 |
143 | case "$1" in
144 | start)
145 | echo -n "Starting @@PRODUCTNAME@@ "
146 | /sbin/checkproc -k -p "$JENKINS_PID_FILE" "$JAVA_HOME/bin/java" >/var/log/@@ARTIFACTNAME@@.rc 2>&1
147 | CHECK=$?
148 | if [ $CHECK -eq 7 ]; then
149 | rm -f "$JENKINS_PID_FILE"
150 | if [ -x "$JENKINS_INIT_SHELL" ]; then
151 | startproc -n $JENKINS_NICE -s -e -l /var/log/@@ARTIFACTNAME@@.rc -p "$JENKINS_PID_FILE" /bin/su -l -s "$JENKINS_INIT_SHELL" -c "$JAVA_CMD $PARAMS &" "$JENKINS_USER"
152 | else
153 | HOME=$JENKINS_HOME startproc -n $JENKINS_NICE -s -e -l /var/log/@@ARTIFACTNAME@@.rc -u "$JENKINS_USER" -p "$JENKINS_PID_FILE" $JAVA_CMD $PARAMS
154 | fi
155 | attempt=1
156 | is_started=false
157 | while [ $attempt -le 30 ]; do
158 | if is_running; then
159 | is_started=true
160 | break
161 | fi
162 | sleep 1
163 | attempt=$((attempt + 1))
164 | done
165 | if $is_started; then
166 | rc_status -v
167 | else
168 | rc_failed
169 | rc_status -v
170 | fi
171 | else
172 | rc_failed $CHECK
173 | rc_status -v
174 | fi
175 | ;;
176 | stop)
177 | echo -n "Shutting down @@PRODUCTNAME@@ "
178 | /sbin/killproc -p "$JENKINS_PID_FILE" "$JAVA_HOME/bin/java"
179 | rc_status -v
180 | ;;
181 | try-restart | condrestart)
182 | if test "$1" = "condrestart"; then
183 | echo "${attn} Use try-restart ${done}(LSB)${attn} rather than condrestart ${warn}(RH)${norm}"
184 | fi
185 | $0 status
186 | if test $? = 0; then
187 | $0 restart
188 | else
189 | rc_reset # Not running is not a failure.
190 | fi
191 | rc_status
192 | ;;
193 | restart)
194 | $0 stop
195 | $0 start
196 | rc_status
197 | ;;
198 | force-reload)
199 | echo -n "Reload service @@PRODUCTNAME@@ "
200 | $0 try-restart
201 | rc_status
202 | ;;
203 | reload)
204 | rc_failed 3
205 | rc_status -v
206 | ;;
207 | status)
208 | echo -n "Checking for service @@PRODUCTNAME@@ "
209 | /sbin/checkproc -p "$JENKINS_PID_FILE" "$JAVA_HOME/bin/java"
210 | rc_status -v
211 | ;;
212 | probe)
213 | ## Optional: Probe for the necessity of a reload, print out the
214 | ## argument to this init script which is required for a reload.
215 | ## Note: probe is not (yet) part of LSB (as of 1.9)
216 |
217 | test "$JENKINS_CONFIG" -nt "$JENKINS_PID_FILE" && echo reload
218 | ;;
219 | *)
220 | echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload|probe}"
221 | exit 1
222 | ;;
223 | esac
224 | rc_exit
225 |
--------------------------------------------------------------------------------
/suse/build/SOURCES/jenkins.logrotate:
--------------------------------------------------------------------------------
1 | /var/log/@@ARTIFACTNAME@@/@@ARTIFACTNAME@@.log /var/log/@@ARTIFACTNAME@@/access_log {
2 | compress
3 | dateext
4 | maxage 365
5 | rotate 99
6 | size=+4096k
7 | notifempty
8 | missingok
9 | create 644
10 | copytruncate
11 | }
12 |
--------------------------------------------------------------------------------
/suse/build/SOURCES/jenkins.repo:
--------------------------------------------------------------------------------
1 | [@@ARTIFACTNAME@@]
2 | name=@@PRODUCTNAME@@
3 | enabled=1
4 | autorefresh=0
5 | baseurl=@@SUSE_URL@@
6 | type=rpm-md
7 | keeppackages=0
8 |
--------------------------------------------------------------------------------
/suse/build/SOURCES/jenkins.sysconfig.in:
--------------------------------------------------------------------------------
1 | ## Path: Development/@@PRODUCTNAME@@
2 | ## Description: @@SUMMARY@@
3 | ## Type: string
4 | ## Default: "~~HOME~~"
5 | ## ServiceRestart: @@ARTIFACTNAME@@
6 | #
7 | # Directory where Jenkins store its configuration and working
8 | # files (checkouts, build reports, artifacts, ...).
9 | #
10 | JENKINS_HOME="~~HOME~~"
11 |
12 | ## Type: string
13 | ## Default: "/bin/bash"
14 | ## ServiceRestart: @@ARTIFACTNAME@@
15 | #
16 | # Shell used to initialize the Jenkins server's environment.
17 | # Setting this option to the path of a shell executable allows
18 | # initialization of the Jenkins server environment using
19 | # standard shell startup scripts.
20 | # Disabling this option causes the Jenkins server to be run
21 | # with a minimal environment.
22 | #
23 | JENKINS_INIT_SHELL="/bin/bash"
24 |
25 | ## Type: string
26 | ## Default: ""
27 | ## ServiceRestart: @@ARTIFACTNAME@@
28 | #
29 | # Java runtime to run Jenkins
30 | # When left empty, the current system default JRE, as defined
31 | # by update-alternatives(8), is used.
32 | #
33 | JENKINS_JAVA_HOME=""
34 |
35 | ## Type: string
36 | ## Default: "@@ARTIFACTNAME@@"
37 | ## ServiceRestart: @@ARTIFACTNAME@@
38 | #
39 | # Unix user account that runs the Jenkins daemon
40 | # Be careful when you change this, as you need to update
41 | # permissions of $JENKINS_HOME and /var/log/@@ARTIFACTNAME@@,
42 | # and if you have already run Jenkins, potentially other
43 | # directories such as /var/cache/@@ARTIFACTNAME@@ .
44 | #
45 | JENKINS_USER="@@ARTIFACTNAME@@"
46 |
47 | ## Type: integer(-20:20)
48 | ## Default: 0
49 | ## ServiceRestart: @@ARTIFACTNAME@@
50 | #
51 | # The nice level at which the Jenkins server (and its build jobs) run.
52 | #
53 | JENKINS_NICE="0"
54 |
55 | ## Type: string
56 | ## Default: "-Djava.awt.headless=true"
57 | ## ServiceRestart: @@ARTIFACTNAME@@
58 | #
59 | # Options to pass to java when running Jenkins.
60 | #
61 | JENKINS_JAVA_OPTIONS="-Djava.awt.headless=true"
62 |
63 | ## Type: integer(0:65535)
64 | ## Default: @@PORT@@
65 | ## ServiceRestart: @@ARTIFACTNAME@@
66 | #
67 | # Port Jenkins is listening on.
68 | # Set to -1 to disable
69 | #
70 | JENKINS_PORT="@@PORT@@"
71 |
72 |
73 | ## Type: integer(1:9)
74 | ## Default: 5
75 | ## ServiceRestart: @@ARTIFACTNAME@@
76 | #
77 | # Debug level for logs -- the higher the value, the more verbose.
78 | # 5 is INFO.
79 | #
80 | JENKINS_DEBUG_LEVEL="5"
81 |
82 | ## Type: yesno
83 | ## Default: no
84 | ## ServiceRestart: @@ARTIFACTNAME@@
85 | #
86 | # Whether to enable access logging or not.
87 | #
88 | JENKINS_ENABLE_ACCESS_LOG="no"
89 |
90 | ## Type: string
91 | ## Default: ""
92 | ## ServiceRestart: @@ARTIFACTNAME@@
93 | #
94 | # Pass arbitrary arguments to Jenkins.
95 | # Full option list: java -jar @@ARTIFACTNAME@@.war --help
96 | #
97 | JENKINS_ARGS=""
98 |
--------------------------------------------------------------------------------
/suse/build/SPECS/jenkins.spec:
--------------------------------------------------------------------------------
1 | # TODO:
2 | # - how to add to the trusted service of the firewall?
3 |
4 | %define workdir %{_var}/lib/@@ARTIFACTNAME@@
5 |
6 | Name: @@ARTIFACTNAME@@
7 | Version: %{ver}
8 | Release: 1.2
9 | Summary: @@SUMMARY@@
10 | Source: jenkins.war
11 | Source1: jenkins.init.in
12 | Source2: jenkins.sysconfig.in
13 | Source3: jenkins.logrotate
14 | Source4: jenkins.repo
15 | Source5: jenkins.service
16 | Source6: jenkins.sh
17 | Source7: migrate.sh
18 | URL: @@HOMEPAGE@@
19 | Group: Development/Tools/Building
20 | License: @@LICENSE@@
21 | BuildRoot: %{_tmppath}/build-%{name}-%{version}
22 | # Unfortunately the Oracle Java RPMs do not register as providing anything (including "java" or "jdk")
23 | # So either we make a hard requirement on the OpenJDK or none at all
24 | # Only workaround would be to use a java virtual package, see https://github.com/keystep/virtual-java-rpm
25 | # TODO: Fix the query for Java 17 if it is reenabled
26 | # Requires: java >= 1:1.8.0
27 | Requires: procps
28 | Requires(pre): /usr/sbin/useradd, /usr/sbin/groupadd
29 | #PreReq: %{fillup_prereq}
30 | BuildArch: noarch
31 |
32 | %description
33 | @@DESCRIPTION_FILE@@
34 |
35 |
36 |
37 |
38 | Authors:
39 | --------
40 | @@AUTHOR@@
41 |
42 | %prep
43 | %setup -q -T -c
44 |
45 | %build
46 |
47 | %install
48 | rm -rf "%{buildroot}"
49 | %__install -D -m0644 "%{SOURCE0}" "%{buildroot}%{_javadir}/%{name}.war"
50 | %__install -d "%{buildroot}%{workdir}"
51 | %__install -d "%{buildroot}%{workdir}/plugins"
52 |
53 | %__install -d "%{buildroot}/var/log/%{name}"
54 | %__install -d "%{buildroot}/var/cache/%{name}"
55 |
56 | %__install -D -m0755 "%{SOURCE1}" "%{buildroot}/etc/init.d/%{name}"
57 | %__sed -i 's,~~WAR~~,%{_javadir}/%{name}.war,g' "%{buildroot}/etc/init.d/%{name}"
58 | %__install -d "%{buildroot}/usr/sbin"
59 | %__ln_s "../../etc/init.d/%{name}" "%{buildroot}/usr/sbin/rc%{name}"
60 |
61 | %__install -D -m0644 "%{SOURCE2}" "%{buildroot}/etc/sysconfig/%{name}"
62 | %__sed -i 's,~~HOME~~,%{workdir},g' "%{buildroot}/etc/sysconfig/%{name}"
63 |
64 | %__install -D -m0644 "%{SOURCE3}" "%{buildroot}/etc/logrotate.d/%{name}"
65 |
66 | %__install -D -m0644 "%{SOURCE4}" "%{buildroot}/etc/zypp/repos.d/%{name}.repo"
67 |
68 | %__install -D -m0644 "%{SOURCE5}" "%{buildroot}%{_unitdir}/%{name}.service"
69 | %__install -D -m0755 "%{SOURCE6}" "%{buildroot}%{_bindir}/%{name}"
70 | %__install -d "%{buildroot}%{_datadir}/%{name}"
71 | %__install -D -m0755 "%{SOURCE7}" "%{buildroot}%{_datadir}/%{name}/migrate"
72 |
73 | %pre
74 | /usr/bin/getent group %{name} &>/dev/null || /usr/sbin/groupadd -r %{name} &>/dev/null
75 | # SUSE version had -o here, but in Fedora -o isn't allowed without -u
76 | /usr/bin/getent passwd %{name} &>/dev/null || /usr/sbin/useradd -g %{name} -s /bin/false -r -c "@@SUMMARY@@" \
77 | -d "%{workdir}" %{name} &>/dev/null
78 |
79 | %post
80 | %{_datadir}/%{name}/migrate "/etc/sysconfig/%{name}" || true
81 | %systemd_post %{name}.service
82 |
83 | %preun
84 | %systemd_preun %{name}.service
85 |
86 | %postun
87 | %systemd_postun_with_restart %{name}.service
88 |
89 | %clean
90 | %__rm -rf "%{buildroot}"
91 |
92 | %files
93 | %defattr(-,root,root)
94 | %{_javadir}/%{name}.war
95 | %attr(0755,%{name},%{name}) %dir %{workdir}
96 | %attr(0750,%{name},%{name}) /var/log/%{name}
97 | %attr(0750,%{name},%{name}) /var/cache/%{name}
98 | %config(noreplace) /etc/logrotate.d/%{name}
99 | %config(noreplace) /etc/init.d/%{name}
100 | %config(noreplace) /etc/sysconfig/%{name}
101 | %config(noreplace) /etc/zypp/repos.d/%{name}.repo
102 | /usr/sbin/rc%{name}
103 | %{_unitdir}/%{name}.service
104 | %{_bindir}/%{name}
105 | %dir %{_datadir}/%{name}
106 | %{_datadir}/%{name}/migrate
107 |
108 | %changelog
109 | * Wed Sep 28 2011 kk@kohsuke.org
110 | - See [@@CHANGELOG_PAGE@@] for complete details
111 |
--------------------------------------------------------------------------------
/suse/build/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -eux
2 |
3 | # prepare fresh directories
4 | D=$(mktemp -d)
5 | trap 'rm -rf "${D}"' EXIT
6 |
7 | cp -R "$(dirname "$0")"/* "${D}"
8 | cp "${BASE}/systemd/jenkins.service" "${D}/SOURCES"
9 | cp "${BASE}/systemd/jenkins.sh" "${D}/SOURCES"
10 | cp "${BASE}/systemd/migrate.sh" "${D}/SOURCES"
11 | "${BASE}/bin/branding.py" "${D}"
12 |
13 | cp "${WAR}" "${D}/SOURCES/jenkins.war"
14 |
15 | pushd "${D}"
16 | mkdir -p BUILD RPMS SRPMS
17 | rpmbuild -ba --define="_topdir ${PWD}" --define="_tmppath ${PWD}/tmp" --define="ver ${VERSION}" SPECS/jenkins.spec
18 |
19 | # sign the results
20 | find RPMS -type f -name '*.rpm' -exec rpmsign --addsign '{}' \;
21 | find RPMS -type f -name '*.rpm' -exec rpm -qpi '{}' \;
22 | popd
23 |
24 | mkdir -p "$(dirname "${SUSE}")"
25 | mv "${D}"/RPMS/noarch/*.rpm "${SUSE}"
26 |
27 | exit 0
28 |
--------------------------------------------------------------------------------
/suse/publish/publish.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -euxo pipefail
4 |
5 | : "${AGENT_WORKDIR:=/tmp}"
6 | : "${GPG_KEYNAME:?Required valid gpg keyname}"
7 | : "${BASE:?Require base directory}"
8 | : "${SUSEDIR:? Require where to put binary files}"
9 | : "${SUSE_WEBDIR:? Require where to put repository index and other web contents}"
10 |
11 | # $$ Contains current pid
12 | D="$AGENT_WORKDIR/$$"
13 |
14 | # Convert string to array to correctly escape cli parameter
15 | SSH_OPTS=($SSH_OPTS)
16 | SCP_OPTS=($SCP_OPTS)
17 |
18 | function clean() {
19 | rm -rf $D
20 | }
21 |
22 | function generateSite() {
23 | "$BASE/bin/indexGenerator.py" \
24 | --distribution opensuse \
25 | --targetDir "${D}"
26 |
27 | gpg --export -a --output "$D/repodata/repomd.xml.key" "${GPG_KEYNAME}"
28 |
29 | "$BASE/bin/branding.py" $D
30 |
31 | cp "$SUSE" $D/RPMS/noarch
32 | }
33 |
34 | function init() {
35 | # where to put binary files
36 | mkdir -p "$SUSEDIR/" # Local
37 |
38 | # shellcheck disable=SC2029
39 | ssh "${SSH_OPTS[@]}" "$PKGSERVER" mkdir -p "'$SUSEDIR/'" # Remote
40 |
41 | # where to put repository index and other web contents
42 | mkdir -p "$SUSE_WEBDIR"
43 |
44 | mkdir -p $D/RPMS/noarch $D/repodata
45 | }
46 |
47 | function skipIfAlreadyPublished() {
48 | if ssh "${SSH_OPTS[@]}" "$PKGSERVER" "test -e ${SUSEDIR}/$(basename $SUSE)"; then
49 | echo "File already published, nothing else todo"
50 | exit 0
51 |
52 | fi
53 | }
54 |
55 | function show() {
56 | echo "Parameters:"
57 | echo "SUSE: $SUSE"
58 | echo "SUSEDIR: $SUSEDIR"
59 | echo "SUSE_WEBDIR: $SUSE_WEBDIR"
60 | echo "SSH_OPTS: ${SSH_OPTS[*]}"
61 | echo "PKGSERVER: $PKGSERVER"
62 | echo "GPG_KEYNAME: $GPG_KEYNAME"
63 | echo "---"
64 | }
65 |
66 | function uploadPackage() {
67 | rsync \
68 | --recursive \
69 | --verbose \
70 | --compress \
71 | --ignore-existing \
72 | --progress \
73 | "$SUSE" "$SUSEDIR/" # Local
74 |
75 | rsync \
76 | --archive \
77 | --verbose \
78 | --compress \
79 | --ignore-existing \
80 | --progress \
81 | -e "ssh ${SSH_OPTS[*]}" \
82 | "${SUSE}" "$PKGSERVER:${SUSEDIR// /\\ }" # Remote
83 | }
84 |
85 | function uploadSite() {
86 | pushd $D
87 | rsync \
88 | --recursive \
89 | --verbose \
90 | --compress \
91 | --progress \
92 | --exclude RPMS \
93 | --exclude "HEADER.html" \
94 | --exclude "FOOTER.html" \
95 | . "$SUSE_WEBDIR/" #Local
96 |
97 | # shellcheck disable=SC2029
98 | rsync \
99 | --archive \
100 | --verbose \
101 | --compress \
102 | --progress \
103 | -e "ssh ${SSH_OPTS[*]}" \
104 | --exclude RPMS \
105 | --exclude "HEADER.html" \
106 | --exclude "FOOTER.html" \
107 | . "$PKGSERVER:${SUSE_WEBDIR// /\\ }/" # Remote
108 |
109 | # generate index on the server
110 | # server needs 'createrepo' pacakge
111 | # Disable this for now as not critical
112 | # createrepc --update -o "$SUSE_WEBDIR" "$SUSEDIR/" #Local
113 | # cp "${SUSE_WEBDIR// /\\ }/repodata/repomd.xml" repodata/ # Local
114 |
115 | # shellcheck disable=SC2029
116 | ssh "${SSH_OPTS[@]}" "$PKGSERVER" createrepo --update -o "'$SUSE_WEBDIR'" "'$SUSEDIR/'" # Remote
117 |
118 | scp \
119 | "${SCP_OPTS[@]}" \
120 | "$PKGSERVER:${SUSE_WEBDIR// /\\ }/repodata/repomd.xml" \
121 | repodata/ # Remote
122 |
123 | gpg \
124 | --batch \
125 | --pinentry-mode loopback \
126 | -u "$GPG_KEYNAME" \
127 | -a \
128 | --detach-sign \
129 | --passphrase-file "$GPG_PASSPHRASE_FILE" \
130 | --yes \
131 | repodata/repomd.xml
132 |
133 | scp \
134 | "${SCP_OPTS[@]}" \
135 | repodata/repomd.xml.asc \
136 | "$PKGSERVER:${SUSE_WEBDIR// /\\ }/repodata/"
137 |
138 | cp repodata/repomd.xml.asc "${SUSE_WEBDIR// /\\ }/repodata/"
139 |
140 | # Following html need to be located inside the binary directory
141 | rsync \
142 | --compress \
143 | --verbose \
144 | --recursive \
145 | --include "HEADER.html" \
146 | --include "FOOTER.html" \
147 | --exclude "*" \
148 | --progress \
149 | . "$SUSEDIR/"
150 |
151 | rsync \
152 | --archive \
153 | --compress \
154 | --verbose \
155 | -e "ssh ${SSH_OPTS[*]}" \
156 | --include "HEADER.html" \
157 | --include "FOOTER.html" \
158 | --exclude "*" \
159 | --progress \
160 | . "$PKGSERVER:${SUSEDIR// /\\ }/"
161 |
162 | popd
163 | }
164 |
165 | show
166 | ## Disabling this function allow us to recreate and sign the Suse repository.
167 | # the rpm package won't be overrided as we use the parameter '--ignore-existing' when we upload it
168 | #skipIfAlreadyPublished
169 | init
170 | uploadPackage
171 | generateSite
172 | uploadSite
173 | clean
174 |
--------------------------------------------------------------------------------
/systemd/jenkins.conf:
--------------------------------------------------------------------------------
1 | D /run/jenkins 0770 jenkins jenkins -
2 |
--------------------------------------------------------------------------------
/systemd/jenkins.service:
--------------------------------------------------------------------------------
1 | #
2 | # This file is managed by systemd(1). Do NOT edit this file manually!
3 | # To override these settings, run:
4 | #
5 | # systemctl edit @@ARTIFACTNAME@@
6 | #
7 | # For more information about drop-in files, see:
8 | #
9 | # https://www.freedesktop.org/software/systemd/man/systemd.unit.html
10 | #
11 |
12 | [Unit]
13 | Description=Jenkins Continuous Integration Server
14 | Requires=network.target
15 | After=network.target
16 | StartLimitBurst=5
17 | StartLimitIntervalSec=5m
18 |
19 | [Service]
20 | Type=notify
21 | NotifyAccess=main
22 | ExecStart=/usr/bin/@@ARTIFACTNAME@@
23 | Restart=on-failure
24 | SuccessExitStatus=143
25 |
26 | # Configures the time to wait for start-up. If Jenkins does not signal start-up
27 | # completion within the configured time, the service will be considered failed
28 | # and will be shut down again. Takes a unit-less value in seconds, or a time span
29 | # value such as "5min 20s". Pass "infinity" to disable the timeout logic.
30 | #TimeoutStartSec=90
31 |
32 | # Unix account that runs the Jenkins daemon
33 | # Be careful when you change this, as you need to update the permissions of
34 | # $JENKINS_HOME, $JENKINS_LOG, and (if you have already run Jenkins)
35 | # $JENKINS_WEBROOT.
36 | User=@@ARTIFACTNAME@@
37 | Group=@@ARTIFACTNAME@@
38 |
39 | # Directory where Jenkins stores its configuration and workspaces
40 | Environment="JENKINS_HOME=/var/lib/@@ARTIFACTNAME@@"
41 | WorkingDirectory=/var/lib/@@ARTIFACTNAME@@
42 |
43 | # Location of the Jenkins WAR
44 | #Environment="JENKINS_WAR=/usr/share/java/@@ARTIFACTNAME@@.war"
45 |
46 | # Location of the exploded WAR
47 | Environment="JENKINS_WEBROOT=%C/@@ARTIFACTNAME@@/war"
48 |
49 | # Location of the Jenkins log. By default, systemd-journald(8) is used.
50 | #Environment="JENKINS_LOG=%L/@@ARTIFACTNAME@@/@@ARTIFACTNAME@@.log"
51 |
52 | # The Java home directory. When left empty, JENKINS_JAVA_CMD and PATH are consulted.
53 | #Environment="JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64"
54 |
55 | # The Java executable. When left empty, JAVA_HOME and PATH are consulted.
56 | #Environment="JENKINS_JAVA_CMD=/etc/alternatives/java"
57 |
58 | # Arguments for the Jenkins JVM
59 | Environment="JAVA_OPTS=-Djava.awt.headless=true"
60 |
61 | # Unix Domain Socket to listen on for local HTTP requests. Default is disabled.
62 | #Environment="JENKINS_UNIX_DOMAIN_PATH=/run/jenkins/jenkins.socket"
63 |
64 | # IP address to listen on for HTTP requests.
65 | # The default is to listen on all interfaces (0.0.0.0).
66 | #Environment="JENKINS_LISTEN_ADDRESS="
67 |
68 | # Port to listen on for HTTP requests. Set to -1 to disable.
69 | # To be able to listen on privileged ports (port numbers less than 1024),
70 | # add the CAP_NET_BIND_SERVICE capability to the AmbientCapabilities
71 | # directive below.
72 | Environment="JENKINS_PORT=@@PORT@@"
73 |
74 | # IP address to listen on for HTTPS requests. Default is disabled.
75 | #Environment="JENKINS_HTTPS_LISTEN_ADDRESS="
76 |
77 | # Port to listen on for HTTPS requests. Default is disabled.
78 | # To be able to listen on privileged ports (port numbers less than 1024),
79 | # add the CAP_NET_BIND_SERVICE capability to the AmbientCapabilities
80 | # directive below.
81 | #Environment="JENKINS_HTTPS_PORT=443"
82 |
83 | # Path to the keystore in JKS format (as created by the JDK's keytool).
84 | # Default is disabled.
85 | #Environment="JENKINS_HTTPS_KEYSTORE=/path/to/keystore.jks"
86 |
87 | # Password to access the keystore defined in JENKINS_HTTPS_KEYSTORE.
88 | # Default is disabled.
89 | #Environment="JENKINS_HTTPS_KEYSTORE_PASSWORD=s3cR3tPa55w0rD"
90 |
91 | # IP address to listen on for HTTP2 requests. Default is disabled.
92 | #Environment="JENKINS_HTTP2_LISTEN_ADDRESS="
93 |
94 | # HTTP2 port to listen on. Default is disabled.
95 | # To be able to listen on privileged ports (port numbers less than 1024),
96 | # add the CAP_NET_BIND_SERVICE capability to the AmbientCapabilities
97 | # directive below.
98 | #Environment="JENKINS_HTTP2_PORT="
99 |
100 | # Controls which capabilities to include in the ambient capability set for the
101 | # executed process. Takes a whitespace-separated list of capability names, e.g.
102 | # CAP_SYS_ADMIN, CAP_DAC_OVERRIDE, CAP_SYS_PTRACE. Ambient capability sets are
103 | # useful if you want to execute a process as a non-privileged user but still
104 | # want to give it some capabilities. For example, add the CAP_NET_BIND_SERVICE
105 | # capability to be able to listen on privileged ports (port numbers less than
106 | # 1024).
107 | #AmbientCapabilities=CAP_NET_BIND_SERVICE
108 |
109 | # Debug level for logs. The higher the value, the more verbose. 5 is INFO.
110 | #Environment="JENKINS_DEBUG_LEVEL=5"
111 |
112 | # Set to true to enable logging to /var/log/@@ARTIFACTNAME@@/access_log.
113 | #Environment="JENKINS_ENABLE_ACCESS_LOG=false"
114 |
115 | # Servlet context (important if you want to use reverse proxying)
116 | #Environment="JENKINS_PREFIX=/@@ARTIFACTNAME@@"
117 |
118 | # Arbitrary additional arguments to pass to Jenkins.
119 | # Full option list: java -jar @@ARTIFACTNAME@@.war --help
120 | #Environment="JENKINS_OPTS="
121 |
122 | # Maximum core file size. If unset, the value from the OS is inherited.
123 | #LimitCORE=infinity
124 |
125 | # Maximum file size. If unset, the value from the OS is inherited.
126 | #LimitFSIZE=infinity
127 |
128 | # File descriptor limit. If unset, the value from the OS is inherited.
129 | #LimitNOFILE=8192
130 |
131 | # Maximum number of processes. If unset, the value from the OS is inherited.
132 | #LimitNPROC=32768
133 |
134 | # Set the umask to control the permission bits of files that Jenkins creates.
135 | #
136 | # 0027 makes files read-only for group and inaccessible for others, which some
137 | # security sensitive users might consider beneficial, especially if Jenkins
138 | # is running on a server that is used for multiple purposes. Beware that 0027
139 | # permissions would interfere with sudo scripts that run on the controller
140 | # (see JENKINS-25065).
141 | #
142 | # Note also that the particularly sensitive parts of $JENKINS_HOME (such as
143 | # credentials) are always written without 'other' access. So the umask values
144 | # only affect job configuration, build records, etc.
145 | #
146 | # If unset, the value from the OS is inherited, which is normally 0022.
147 | # The default umask comes from pam_umask(8) and /etc/login.defs.
148 | #UMask=0022
149 |
150 | [Install]
151 | WantedBy=multi-user.target
152 |
--------------------------------------------------------------------------------
/systemd/jenkins.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | die() {
4 | echo "$(basename "$0"): $*" >&2
5 | exit 1
6 | }
7 |
8 | check_env() {
9 | required=true
10 | for var in "$@"; do
11 | if [ "${var}" = '--' ]; then
12 | required=false
13 | continue
14 | fi
15 |
16 | val=$(eval echo "\$${var}")
17 | if $required && [ -z "${val}" ]; then
18 | die "check_env: ${var} must be non-empty"
19 | fi
20 | done
21 | }
22 |
23 | infer_java_cmd() {
24 | if [ -n "${JENKINS_JAVA_CMD}" ] && [ -x "${JENKINS_JAVA_CMD}" ]; then
25 | return 0
26 | fi
27 |
28 | if [ -n "${JAVA_HOME}" ] && [ -x "${JAVA_HOME}/bin/java" ]; then
29 | JENKINS_JAVA_CMD="${JAVA_HOME}/bin/java"
30 | return 0
31 | fi
32 |
33 | JENKINS_JAVA_CMD="$(command -v java)" || return "$?"
34 | }
35 |
36 | infer_jenkins_opts() {
37 | inferred_jenkins_opts=""
38 |
39 | if [ -n "${JENKINS_WEBROOT}" ]; then
40 | inferred_jenkins_opts="${inferred_jenkins_opts} --webroot='${JENKINS_WEBROOT}'"
41 | fi
42 |
43 | if [ -n "${JENKINS_LOG}" ]; then
44 | inferred_jenkins_opts="${inferred_jenkins_opts} --logfile='${JENKINS_LOG}'"
45 | fi
46 |
47 | if [ -n "${JENKINS_PORT}" ]; then
48 | inferred_jenkins_opts="${inferred_jenkins_opts} --httpPort=${JENKINS_PORT}"
49 | fi
50 |
51 | if [ -n "${JENKINS_LISTEN_ADDRESS}" ]; then
52 | inferred_jenkins_opts="${inferred_jenkins_opts} --httpListenAddress=${JENKINS_LISTEN_ADDRESS}"
53 | fi
54 |
55 | if [ -n "${JENKINS_UNIX_DOMAIN_PATH}" ]; then
56 | inferred_jenkins_opts="${inferred_jenkins_opts} --httpUnixDomainPath=${JENKINS_UNIX_DOMAIN_PATH}"
57 | fi
58 |
59 | if [ -n "${JENKINS_HTTPS_PORT}" ]; then
60 | inferred_jenkins_opts="${inferred_jenkins_opts} --httpsPort=${JENKINS_HTTPS_PORT}"
61 | fi
62 |
63 | if [ -n "${JENKINS_HTTPS_LISTEN_ADDRESS}" ]; then
64 | inferred_jenkins_opts="${inferred_jenkins_opts} --httpsListenAddress=${JENKINS_HTTPS_LISTEN_ADDRESS}"
65 | fi
66 |
67 | if [ -n "${JENKINS_HTTPS_KEYSTORE}" ]; then
68 | inferred_jenkins_opts="${inferred_jenkins_opts} --httpsKeyStore='${JENKINS_HTTPS_KEYSTORE}'"
69 | fi
70 |
71 | if [ -n "${JENKINS_HTTPS_KEYSTORE_PASSWORD}" ]; then
72 | inferred_jenkins_opts="${inferred_jenkins_opts} --httpsKeyStorePassword='${JENKINS_HTTPS_KEYSTORE_PASSWORD}'"
73 | fi
74 |
75 | if [ -n "${JENKINS_HTTP2_PORT}" ]; then
76 | inferred_jenkins_opts="${inferred_jenkins_opts} --http2Port=${JENKINS_HTTP2_PORT}"
77 | fi
78 |
79 | if [ -n "${JENKINS_HTTP2_LISTEN_ADDRESS}" ]; then
80 | inferred_jenkins_opts="${inferred_jenkins_opts} --http2ListenAddress=${JENKINS_HTTP2_LISTEN_ADDRESS}"
81 | fi
82 |
83 | if [ -n "${JENKINS_DEBUG_LEVEL}" ] && [ "${JENKINS_DEBUG_LEVEL}" -ne 5 ]; then
84 | inferred_jenkins_opts="${inferred_jenkins_opts} --debug=${JENKINS_DEBUG_LEVEL}"
85 | fi
86 |
87 | if [ -n "${JENKINS_PREFIX}" ]; then
88 | inferred_jenkins_opts="${inferred_jenkins_opts} --prefix='${JENKINS_PREFIX}'"
89 | fi
90 |
91 | if [ -n "${JENKINS_OPTS}" ]; then
92 | inferred_jenkins_opts="${inferred_jenkins_opts} ${JENKINS_OPTS}"
93 | fi
94 |
95 | if [ -n "${JENKINS_ENABLE_ACCESS_LOG}" ] && $JENKINS_ENABLE_ACCESS_LOG; then
96 | inferred_jenkins_opts="${inferred_jenkins_opts} --accessLoggerClassName=winstone.accesslog.SimpleAccessLogger"
97 | inferred_jenkins_opts="${inferred_jenkins_opts} --simpleAccessLogger.format=combined"
98 | inferred_jenkins_opts="${inferred_jenkins_opts} --simpleAccessLogger.file='/var/log/@@ARTIFACTNAME@@/access_log'"
99 | fi
100 | }
101 |
102 | main() {
103 | if [ -n "${JENKINS_HOME}" ]; then
104 | [ -d "${JENKINS_HOME}" ] || die "${JENKINS_HOME} is not a directory"
105 | fi
106 | [ -f "${JENKINS_WAR}" ] || die "${JENKINS_WAR} is not a file"
107 |
108 | infer_java_cmd || die 'failed to find a valid Java installation'
109 |
110 | infer_jenkins_opts
111 |
112 | java_opts_tmp="${JAVA_OPTS}"
113 | unset JAVA_OPTS
114 | unset JENKINS_DEBUG_LEVEL
115 | unset JENKINS_ENABLE_ACCESS_LOG
116 | unset JENKINS_HTTP2_LISTEN_ADDRESS
117 | unset JENKINS_HTTP2_PORT
118 | unset JENKINS_HTTPS_KEYSTORE
119 | unset JENKINS_HTTPS_KEYSTORE_PASSWORD
120 | unset JENKINS_HTTPS_LISTEN_ADDRESS
121 | unset JENKINS_HTTPS_PORT
122 | java_cmd="${JENKINS_JAVA_CMD}"
123 | unset JENKINS_JAVA_CMD
124 | unset JENKINS_UNIX_DOMAIN_PATH
125 | unset JENKINS_LISTEN_ADDRESS
126 | unset JENKINS_LOG
127 | unset JENKINS_OPTS
128 | unset JENKINS_PORT
129 | unset JENKINS_PREFIX
130 | jenkins_war_tmp="${JENKINS_WAR}"
131 | unset JENKINS_WAR
132 | unset JENKINS_WEBROOT
133 | eval exec \
134 | "${java_cmd}" \
135 | ${java_opts_tmp} \
136 | -jar "${jenkins_war_tmp}" \
137 | ${inferred_jenkins_opts}
138 | }
139 |
140 | if [ -z "${JENKINS_OPTS}" ]; then
141 | JENKINS_OPTS="$*"
142 | else
143 | JENKINS_OPTS="${JENKINS_OPTS} $*"
144 | fi
145 |
146 | if [ -z "${JENKINS_WAR}" ]; then
147 | JENKINS_WAR=/usr/share/java/@@ARTIFACTNAME@@.war
148 | fi
149 |
150 | check_env \
151 | JENKINS_WAR \
152 | -- \
153 | JAVA_HOME \
154 | JENKINS_DEBUG_LEVEL \
155 | JENKINS_ENABLE_ACCESS_LOG \
156 | JENKINS_HOME \
157 | JENKINS_HTTP2_LISTEN_ADDRESS \
158 | JENKINS_HTTP2_PORT \
159 | JENKINS_HTTPS_KEYSTORE \
160 | JENKINS_HTTPS_KEYSTORE_PASSWORD \
161 | JENKINS_HTTPS_LISTEN_ADDRESS \
162 | JAVA_OPTS \
163 | JENKINS_HTTPS_PORT \
164 | JENKINS_JAVA_CMD \
165 | JENKINS_UNIX_DOMAIN_PATH \
166 | JENKINS_LISTEN_ADDRESS \
167 | JENKINS_LOG \
168 | JENKINS_OPTS \
169 | JENKINS_PORT \
170 | JENKINS_PREFIX \
171 | JENKINS_WEBROOT
172 |
173 | main
174 |
175 | exit 0
176 |
--------------------------------------------------------------------------------
/systemd/migrate.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -e
4 |
5 | die() {
6 | echo "$(basename "$0"): $*" >&2
7 | exit 1
8 | }
9 |
10 | usage() {
11 | echo "$(basename "$0"): $*" >&2
12 | echo "Usage: $(basename "$0") "
13 | exit 2
14 | }
15 |
16 | NEW_JAVA_OPTS_DEFAULT="-Djava.awt.headless=true"
17 | NEW_JENKINS_DEBUG_LEVEL_DEFAULT="5"
18 | NEW_JENKINS_GROUP_DEFAULT="@@ARTIFACTNAME@@"
19 | NEW_JENKINS_HOME_DEFAULT="/var/lib/@@ARTIFACTNAME@@"
20 | NEW_JENKINS_LOG_DEFAULT="/var/log/@@ARTIFACTNAME@@/@@ARTIFACTNAME@@.log"
21 | NEW_JENKINS_MAXOPENFILES_DEFAULT="8192"
22 | NEW_JENKINS_PORT_DEFAULT="@@PORT@@"
23 | NEW_JENKINS_USER_DEFAULT="@@ARTIFACTNAME@@"
24 | NEW_JENKINS_WAR_DEFAULT="/usr/share/java/@@ARTIFACTNAME@@.war"
25 | NEW_JENKINS_WEBROOT_DEFAULT="/var/cache/@@ARTIFACTNAME@@/war"
26 |
27 | NEW_JAVA_HOME=""
28 | NEW_JAVA_OPTS="${NEW_JAVA_OPTS_DEFAULT}"
29 | NEW_JENKINS_DEBUG_LEVEL="${NEW_JENKINS_DEBUG_LEVEL_DEFAULT}"
30 | NEW_JENKINS_ENABLE_ACCESS_LOG=false
31 | NEW_JENKINS_GROUP="${NEW_JENKINS_GROUP_DEFAULT}"
32 | NEW_JENKINS_HOME="${NEW_JENKINS_HOME_DEFAULT}"
33 | NEW_JENKINS_HTTP2_LISTEN_ADDRESS=""
34 | NEW_JENKINS_HTTP2_PORT=""
35 | NEW_JENKINS_HTTPS_KEYSTORE=""
36 | NEW_JENKINS_HTTPS_KEYSTORE_PASSWORD=""
37 | NEW_JENKINS_HTTPS_LISTEN_ADDRESS=""
38 | NEW_JENKINS_HTTPS_PORT=""
39 | NEW_JENKINS_JAVA_CMD=""
40 | NEW_JENKINS_LISTEN_ADDRESS=""
41 | NEW_JENKINS_LOG="${NEW_JENKINS_LOG_DEFAULT}"
42 | NEW_JENKINS_MAXOPENFILES="${NEW_JENKINS_MAXOPENFILES_DEFAULT}"
43 | NEW_JENKINS_OPTS=""
44 | NEW_JENKINS_PORT="${NEW_JENKINS_PORT_DEFAULT}"
45 | NEW_JENKINS_PREFIX=""
46 | NEW_JENKINS_UMASK=""
47 | NEW_JENKINS_USER="${NEW_JENKINS_USER_DEFAULT}"
48 | NEW_JENKINS_WAR="${NEW_JENKINS_WAR_DEFAULT}"
49 | NEW_JENKINS_WEBROOT="${NEW_JENKINS_WEBROOT_DEFAULT}"
50 |
51 | has_prefix=false
52 |
53 | read_old_options() {
54 | # This could only be the case for deb
55 | if [ -n "${HTTP_PORT}" ] && [ "${HTTP_PORT}" -gt 0 ]; then
56 | # Normalize to rpm convention
57 | JENKINS_PORT="${HTTP_PORT}"
58 | fi
59 |
60 | if [ -n "${JENKINS_ARGS}" ]; then
61 | if [ -n "${NAME}" ]; then
62 | # For deb, these are all the arguments, except for the JENKINS_ENABLE_ACCESS_LOG additions
63 | webroot_quoted=false
64 | TMP_JENKINS_WEBROOT="$(printf '%s' "${JENKINS_ARGS}" | sed -n "s/.*--webroot=[\"']\\([[:alnum:][:space:]+,-\\./:;@\\_]*\\)[\"'].*/\\1/p")"
65 | [ -n "${TMP_JENKINS_WEBROOT}" ] && webroot_quoted=true
66 | [ -z "${TMP_JENKINS_WEBROOT}" ] && TMP_JENKINS_WEBROOT="$(printf '%s' "${JENKINS_ARGS}" | sed -n 's/.*--webroot=\([[:alnum:][:punct:]]*\).*/\1/p')"
67 |
68 | log_quoted=false
69 | TMP_JENKINS_LOG="$(printf '%s' "${JENKINS_ARGS}" | sed -n "s/.*--logfile=[\"']\\([[:alnum:][:space:]+,-\\./:;@\\_]*\\)[\"'].*/\\1/p")"
70 | [ -n "${TMP_JENKINS_LOG}" ] && log_quoted=true
71 | [ -z "${TMP_JENKINS_LOG}" ] && TMP_JENKINS_LOG="$(printf '%s' "${JENKINS_ARGS}" | sed -n 's/.*--logfile=\([[:alnum:][:punct:]]*\).*/\1/p')"
72 |
73 | TMP_JENKINS_PORT="$(printf '%s' "${JENKINS_ARGS}" | sed -n 's/.*--httpPort=\([[:alnum:][:punct:]]*\).*/\1/p')"
74 |
75 | TMP_JENKINS_LISTEN_ADDRESS="$(printf '%s' "${JENKINS_ARGS}" | sed -n 's/.*--httpListenAddress=\([[:alnum:][:punct:]]*\).*/\1/p')"
76 |
77 | TMP_JENKINS_HTTPS_PORT="$(printf '%s' "${JENKINS_ARGS}" | sed -n 's/.*--httpsPort=\([[:alnum:][:punct:]]*\).*/\1/p')"
78 |
79 | TMP_JENKINS_HTTPS_LISTEN_ADDRESS="$(printf '%s' "${JENKINS_ARGS}" | sed -n 's/.*--httpsListenAddress=\([[:alnum:][:punct:]]*\).*/\1/p')"
80 |
81 | keystore_quoted=false
82 | TMP_JENKINS_HTTPS_KEYSTORE="$(printf '%s' "${JENKINS_ARGS}" | sed -n "s/.*--httpsKeyStore=[\"']\\([[:alnum:][:space:]+,-\\./:;@\\_]*\\)[\"'].*/\\1/p")"
83 | [ -n "${TMP_JENKINS_HTTPS_KEYSTORE}" ] && keystore_quoted=true
84 | [ -z "${TMP_JENKINS_HTTPS_KEYSTORE}" ] && TMP_JENKINS_HTTPS_KEYSTORE="$(printf '%s' "${JENKINS_ARGS}" | sed -n 's/.*--httpsKeyStore=\([[:alnum:][:punct:]]*\).*/\1/p')"
85 |
86 | keystore_password_quoted=false
87 | TMP_JENKINS_HTTPS_KEYSTORE_PASSWORD="$(printf '%s' "${JENKINS_ARGS}" | sed -n "s/.*--httpsKeyStorePassword=[\"']\\([[:alnum:][:space:]+,-\\./:;@\\_]*\\)[\"'].*/\\1/p")"
88 | [ -n "${TMP_JENKINS_HTTPS_KEYSTORE_PASSWORD}" ] && keystore_password_quoted=true
89 | [ -z "${TMP_JENKINS_HTTPS_KEYSTORE_PASSWORD}" ] && TMP_JENKINS_HTTPS_KEYSTORE_PASSWORD="$(printf '%s' "${JENKINS_ARGS}" | sed -n 's/.*--httpsKeyStorePassword=\([[:alnum:][:punct:]]*\).*/\1/p')"
90 |
91 | TMP_JENKINS_HTTP2_PORT="$(printf '%s' "${JENKINS_ARGS}" | sed -n 's/.*--http2Port=\([[:alnum:][:punct:]]*\).*/\1/p')"
92 |
93 | TMP_JENKINS_HTTP2_LISTEN_ADDRESS="$(printf '%s' "${JENKINS_ARGS}" | sed -n 's/.*--http2ListenAddress=\([[:alnum:][:punct:]]*\).*/\1/p')"
94 |
95 | TMP_JENKINS_DEBUG_LEVEL="$(printf '%s' "${JENKINS_ARGS}" | sed -n 's/.*--debug=\([[:alnum:][:punct:]]*\).*/\1/p')"
96 |
97 | prefix_quoted=false
98 | TMP_PREFIX="$(printf '%s' "${JENKINS_ARGS}" | sed -n "s/.*--prefix=[\"']\\([[:alnum:][:space:]+,-\\./:;@\\_]*\\)[\"'].*/\\1/p")"
99 | [ -n "${TMP_PREFIX}" ] && prefix_quoted=true
100 | [ -z "${TMP_PREFIX}" ] && TMP_PREFIX="$(printf '%s' "${JENKINS_ARGS}" | sed -n 's/.*--prefix=\([[:alnum:][:punct:]]*\).*/\1/p')"
101 |
102 | [ -n "${TMP_JENKINS_WEBROOT}" ] && JENKINS_WEBROOT="${TMP_JENKINS_WEBROOT}"
103 | [ -n "${TMP_JENKINS_LOG}" ] && JENKINS_LOG="${TMP_JENKINS_LOG}"
104 | [ -n "${TMP_JENKINS_PORT}" ] && JENKINS_PORT="${TMP_JENKINS_PORT}"
105 | [ -n "${TMP_JENKINS_LISTEN_ADDRESS}" ] && JENKINS_LISTEN_ADDRESS="${TMP_JENKINS_LISTEN_ADDRESS}"
106 | [ -n "${TMP_JENKINS_HTTPS_PORT}" ] && JENKINS_HTTPS_PORT="${TMP_JENKINS_HTTPS_PORT}"
107 | [ -n "${TMP_JENKINS_HTTPS_LISTEN_ADDRESS}" ] && JENKINS_HTTPS_LISTEN_ADDRESS="${TMP_JENKINS_HTTPS_LISTEN_ADDRESS}"
108 | [ -n "${TMP_JENKINS_HTTPS_KEYSTORE}" ] && JENKINS_HTTPS_KEYSTORE="${TMP_JENKINS_HTTPS_KEYSTORE}"
109 | [ -n "${TMP_JENKINS_HTTPS_KEYSTORE_PASSWORD}" ] && JENKINS_HTTPS_KEYSTORE_PASSWORD="${TMP_JENKINS_HTTPS_KEYSTORE_PASSWORD}"
110 | [ -n "${TMP_JENKINS_HTTP2_PORT}" ] && JENKINS_HTTP2_PORT="${TMP_JENKINS_HTTP2_PORT}"
111 | [ -n "${TMP_JENKINS_HTTP2_LISTEN_ADDRESS}" ] && JENKINS_HTTP2_LISTEN_ADDRESS="${TMP_JENKINS_HTTP2_LISTEN_ADDRESS}"
112 | [ -n "${TMP_JENKINS_DEBUG_LEVEL}" ] && JENKINS_DEBUG_LEVEL="${TMP_JENKINS_DEBUG_LEVEL}"
113 | [ -n "${TMP_PREFIX}" ] && PREFIX="${TMP_PREFIX}"
114 | [ -n "${TMP_PREFIX}" ] && has_prefix=true
115 |
116 | if $webroot_quoted; then
117 | JENKINS_ARGS="$(printf '%s' "${JENKINS_ARGS}" | sed "s/--webroot=[\"'][[:alnum:][:space:]+,-\\./:;@\\_]*[\"']//g")"
118 | else
119 | JENKINS_ARGS="$(printf '%s' "${JENKINS_ARGS}" | sed 's/--webroot=[[:alnum:][:punct:]]*//g')"
120 | fi
121 |
122 | if $log_quoted; then
123 | JENKINS_ARGS="$(printf '%s' "${JENKINS_ARGS}" | sed "s/--logfile=[\"'][[:alnum:][:space:]+,-\\./:;@\\_]*[\"']//g")"
124 | else
125 | JENKINS_ARGS="$(printf '%s' "${JENKINS_ARGS}" | sed 's/--logfile=[[:alnum:][:punct:]]*//g')"
126 | fi
127 |
128 | JENKINS_ARGS="$(printf '%s' "${JENKINS_ARGS}" | sed 's/--httpPort=[[:alnum:][:punct:]]*//g')"
129 |
130 | JENKINS_ARGS="$(printf '%s' "${JENKINS_ARGS}" | sed 's/--httpListenAddress=[[:alnum:][:punct:]]*//g')"
131 |
132 | JENKINS_ARGS="$(printf '%s' "${JENKINS_ARGS}" | sed 's/--httpsPort=[[:alnum:][:punct:]]*//g')"
133 |
134 | JENKINS_ARGS="$(printf '%s' "${JENKINS_ARGS}" | sed 's/--httpsListenAddress=[[:alnum:][:punct:]]*//g')"
135 |
136 | if $keystore_quoted; then
137 | JENKINS_ARGS="$(printf '%s' "${JENKINS_ARGS}" | sed "s/--httpsKeyStore=[\"'][[:alnum:][:space:]+,-\\./:;@\\_]*[\"']//g")"
138 | else
139 | JENKINS_ARGS="$(printf '%s' "${JENKINS_ARGS}" | sed 's/--httpsKeyStore=[[:alnum:][:punct:]]*//g')"
140 | fi
141 |
142 | if $keystore_password_quoted; then
143 | JENKINS_ARGS="$(printf '%s' "${JENKINS_ARGS}" | sed "s/--httpsKeyStorePassword=[\"'][[:alnum:][:space:]+,-\\./:;@\\_]*[\"']//g")"
144 | else
145 | JENKINS_ARGS="$(printf '%s' "${JENKINS_ARGS}" | sed 's/--httpsKeyStorePassword=[[:alnum:][:punct:]]*//g')"
146 | fi
147 |
148 | JENKINS_ARGS="$(printf '%s' "${JENKINS_ARGS}" | sed 's/--http2Port=[[:alnum:][:punct:]]*//g')"
149 |
150 | JENKINS_ARGS="$(printf '%s' "${JENKINS_ARGS}" | sed 's/--http2ListenAddress=[[:alnum:][:punct:]]*//g')"
151 |
152 | JENKINS_ARGS="$(printf '%s' "${JENKINS_ARGS}" | sed 's/--debug=[[:alnum:][:punct:]]*//g')"
153 |
154 | if $prefix_quoted; then
155 | JENKINS_ARGS="$(printf '%s' "${JENKINS_ARGS}" | sed "s/--prefix=[\"'][[:alnum:][:space:]+,-\\./:;@\\_]*[\"']//g")"
156 | else
157 | JENKINS_ARGS="$(printf '%s' "${JENKINS_ARGS}" | sed 's/--prefix=[[:alnum:][:punct:]]*//g')"
158 | fi
159 |
160 | # All that remains are the extra arguments
161 | NEW_JENKINS_OPTS="$(printf '%s' "${JENKINS_ARGS}" | sed 's/^[[:space:]]*//g')"
162 | NEW_JENKINS_OPTS="$(printf '%s' "${JENKINS_ARGS}" | sed 's/[[:space:]]*$//g')"
163 | else
164 | # For rpm and suse, these are extra arguments
165 | NEW_JENKINS_OPTS="$(printf '%s' "${JENKINS_ARGS}" | sed 's/^[[:space:]]*//g')"
166 | NEW_JENKINS_OPTS="$(printf '%s' "${JENKINS_ARGS}" | sed 's/[[:space:]]*$//g')"
167 | fi
168 | fi
169 |
170 | if [ -n "${JENKINS_USER}" ]; then
171 | NEW_JENKINS_USER="${JENKINS_USER}"
172 | fi
173 |
174 | if [ -n "${JENKINS_GROUP}" ]; then
175 | NEW_JENKINS_GROUP="${JENKINS_GROUP}"
176 | fi
177 |
178 | if [ -n "${JENKINS_HOME}" ] && [ -d "${JENKINS_HOME}" ]; then
179 | NEW_JENKINS_HOME="${JENKINS_HOME}"
180 | fi
181 |
182 | if [ -n "${JENKINS_WAR}" ] && [ -f "${JENKINS_WAR}" ]; then
183 | NEW_JENKINS_WAR="${JENKINS_WAR}"
184 | fi
185 | if [ "${NEW_JENKINS_WAR}" = "/usr/share/@@ARTIFACTNAME@@/@@ARTIFACTNAME@@.war" ]; then
186 | # deb
187 | NEW_JENKINS_WAR="${NEW_JENKINS_WAR_DEFAULT}"
188 | elif [ "${NEW_JENKINS_WAR}" = "/usr/lib/@@ARTIFACTNAME@@/@@ARTIFACTNAME@@.war" ]; then
189 | # rpm
190 | NEW_JENKINS_WAR="${NEW_JENKINS_WAR_DEFAULT}"
191 | fi
192 |
193 | if [ -n "${JENKINS_WEBROOT}" ] && [ -d "${JENKINS_WEBROOT}" ]; then
194 | NEW_JENKINS_WEBROOT="${JENKINS_WEBROOT}"
195 | fi
196 |
197 | if [ -n "${JENKINS_LOG}" ]; then
198 | NEW_JENKINS_LOG="${JENKINS_LOG}"
199 | fi
200 |
201 | if [ -n "${JENKINS_JAVA_HOME}" ] && [ -d "${JENKINS_JAVA_HOME}" ]; then
202 | NEW_JAVA_HOME="${JENKINS_JAVA_HOME}"
203 | fi
204 |
205 | if [ -n "${JENKINS_JAVA_CMD}" ] && [ -x "${JENKINS_JAVA_CMD}" ]; then
206 | NEW_JENKINS_JAVA_CMD="${JENKINS_JAVA_CMD}"
207 | fi
208 |
209 | if [ -n "${JAVA_ARGS}" ]; then
210 | NEW_JAVA_OPTS="${JAVA_ARGS}"
211 | elif [ -n "${JENKINS_JAVA_OPTIONS}" ]; then
212 | NEW_JAVA_OPTS="${JENKINS_JAVA_OPTIONS}"
213 | fi
214 |
215 | if [ -n "${JENKINS_LISTEN_ADDRESS}" ]; then
216 | NEW_JENKINS_LISTEN_ADDRESS="${JENKINS_LISTEN_ADDRESS}"
217 | fi
218 |
219 | if [ -n "${JENKINS_PORT}" ] && [ "${JENKINS_PORT}" -gt 0 ]; then
220 | NEW_JENKINS_PORT="${JENKINS_PORT}"
221 | fi
222 |
223 | if [ -n "${JENKINS_HTTPS_LISTEN_ADDRESS}" ]; then
224 | NEW_JENKINS_HTTPS_LISTEN_ADDRESS="${JENKINS_HTTPS_LISTEN_ADDRESS}"
225 | fi
226 |
227 | if [ -n "${JENKINS_HTTPS_PORT}" ] && [ "${JENKINS_HTTPS_PORT}" -gt 0 ]; then
228 | NEW_JENKINS_HTTPS_PORT="${JENKINS_HTTPS_PORT}"
229 | fi
230 |
231 | if [ -n "${JENKINS_HTTPS_KEYSTORE}" ] && [ -f "${JENKINS_HTTPS_KEYSTORE}" ]; then
232 | NEW_JENKINS_HTTPS_KEYSTORE="${JENKINS_HTTPS_KEYSTORE}"
233 | fi
234 |
235 | if [ -n "${JENKINS_HTTPS_KEYSTORE_PASSWORD}" ]; then
236 | NEW_JENKINS_HTTPS_KEYSTORE_PASSWORD="${JENKINS_HTTPS_KEYSTORE_PASSWORD}"
237 | fi
238 |
239 | if [ -n "${JENKINS_HTTP2_LISTEN_ADDRESS}" ]; then
240 | NEW_JENKINS_HTTP2_LISTEN_ADDRESS="${JENKINS_HTTP2_LISTEN_ADDRESS}"
241 | fi
242 |
243 | if [ -n "${JENKINS_HTTP2_PORT}" ] && [ "${JENKINS_HTTP2_PORT}" -gt 0 ]; then
244 | NEW_JENKINS_HTTP2_PORT="${JENKINS_HTTP2_PORT}"
245 | fi
246 |
247 | if [ -n "${JENKINS_DEBUG_LEVEL}" ] && [ "${JENKINS_DEBUG_LEVEL}" -gt 0 ]; then
248 | NEW_JENKINS_DEBUG_LEVEL="${JENKINS_DEBUG_LEVEL}"
249 | fi
250 |
251 | if [ -n "${JENKINS_ENABLE_ACCESS_LOG}" ] && [ "${JENKINS_ENABLE_ACCESS_LOG}" = "yes" ]; then
252 | NEW_JENKINS_ENABLE_ACCESS_LOG=true
253 | fi
254 |
255 | if [ -n "${PREFIX}" ] && $has_prefix; then
256 | NEW_JENKINS_PREFIX="${PREFIX}"
257 | fi
258 |
259 | if [ -n "${MAXOPENFILES}" ] && [ "${MAXOPENFILES}" -gt 0 ]; then
260 | NEW_JENKINS_MAXOPENFILES="${MAXOPENFILES}"
261 | fi
262 |
263 | if [ -n "${UMASK}" ]; then
264 | NEW_JENKINS_UMASK="${UMASK}"
265 | fi
266 | }
267 |
268 | migrate_options() {
269 | if [ -f /etc/systemd/system/@@ARTIFACTNAME@@.service.d/override.conf ]; then
270 | if grep -q '\-\-handlerCount' /etc/systemd/system/@@ARTIFACTNAME@@.service.d/override.conf; then
271 | sed -ibak -r -e 's/--handlerCount[A-Za-z]+=[0-9]+//g' /etc/systemd/system/@@ARTIFACTNAME@@.service.d/override.conf
272 | fi
273 | return
274 | fi
275 |
276 | tmpfile=$(mktemp)
277 | edited=false
278 |
279 | echo '[Service]' >>"${tmpfile}"
280 |
281 | if [ "${NEW_JENKINS_USER}" != "${NEW_JENKINS_USER_DEFAULT}" ]; then
282 | NEW_JENKINS_USER="$(printf '%s' "${NEW_JENKINS_USER}" | sed -e 's/"/\\"/g')"
283 | echo "User=${NEW_JENKINS_USER}" >>"${tmpfile}"
284 | edited=true
285 | fi
286 |
287 | if [ "${NEW_JENKINS_GROUP}" != "${NEW_JENKINS_GROUP_DEFAULT}" ]; then
288 | NEW_JENKINS_GROUP="$(printf '%s' "${NEW_JENKINS_GROUP}" | sed -e 's/"/\\"/g')"
289 | echo "Group=${NEW_JENKINS_GROUP}" >>"${tmpfile}"
290 | edited=true
291 | fi
292 |
293 | if [ "${NEW_JENKINS_HOME}" != "${NEW_JENKINS_HOME_DEFAULT}" ]; then
294 | NEW_JENKINS_HOME="$(printf '%s' "${NEW_JENKINS_HOME}" | sed -e 's/"/\\"/g')"
295 | echo "Environment=\"JENKINS_HOME=${NEW_JENKINS_HOME}\"" >>"${tmpfile}"
296 | echo "WorkingDirectory=${NEW_JENKINS_HOME}" >>"${tmpfile}"
297 | edited=true
298 | fi
299 |
300 | if [ "${NEW_JENKINS_WAR}" != "${NEW_JENKINS_WAR_DEFAULT}" ]; then
301 | NEW_JENKINS_WAR="$(printf '%s' "${NEW_JENKINS_WAR}" | sed -e 's/"/\\"/g')"
302 | echo "Environment=\"JENKINS_WAR=${NEW_JENKINS_WAR}\"" >>"${tmpfile}"
303 | edited=true
304 | fi
305 |
306 | if [ "${NEW_JENKINS_WEBROOT}" != "${NEW_JENKINS_WEBROOT_DEFAULT}" ]; then
307 | NEW_JENKINS_WEBROOT="$(printf '%s' "${NEW_JENKINS_WEBROOT}" | sed -e 's/"/\\"/g')"
308 | echo "Environment=\"JENKINS_WEBROOT=${NEW_JENKINS_WEBROOT}\"" >>"${tmpfile}"
309 | edited=true
310 | fi
311 |
312 | if [ "${NEW_JENKINS_LOG}" != "${NEW_JENKINS_LOG_DEFAULT}" ]; then
313 | NEW_JENKINS_LOG="$(printf '%s' "${NEW_JENKINS_LOG}" | sed -e 's/"/\\"/g')"
314 | echo "Environment=\"JENKINS_LOG=${NEW_JENKINS_LOG}\"" >>"${tmpfile}"
315 | edited=true
316 | fi
317 |
318 | if [ -n "${NEW_JAVA_HOME}" ]; then
319 | NEW_JENKINS_HOME="$(printf '%s' "${NEW_JENKINS_HOME}" | sed -e 's/"/\\"/g')"
320 | echo "Environment=\"JAVA_HOME=${NEW_JAVA_HOME}\"" >>"${tmpfile}"
321 | edited=true
322 | fi
323 |
324 | if [ -n "${NEW_JENKINS_JAVA_CMD}" ]; then
325 | NEW_JENKINS_JAVA_CMD="$(printf '%s' "${NEW_JENKINS_JAVA_CMD}" | sed -e 's/"/\\"/g')"
326 | echo "Environment=\"JENKINS_JAVA_CMD=${NEW_JENKINS_JAVA_CMD}\"" >>"${tmpfile}"
327 | edited=true
328 | fi
329 |
330 | if [ "${NEW_JAVA_OPTS}" != "${NEW_JAVA_OPTS_DEFAULT}" ]; then
331 | NEW_JAVA_OPTS="$(printf '%s' "${NEW_JAVA_OPTS}" | sed -e 's/"/\\"/g')"
332 | echo "Environment=\"JAVA_OPTS=${NEW_JAVA_OPTS}\"" >>"${tmpfile}"
333 | edited=true
334 | fi
335 |
336 | if [ -n "${NEW_JENKINS_LISTEN_ADDRESS}" ]; then
337 | NEW_JENKINS_LISTEN_ADDRESS="$(printf '%s' "${NEW_JENKINS_LISTEN_ADDRESS}" | sed -e 's/"/\\"/g')"
338 | echo "Environment=\"JENKINS_LISTEN_ADDRESS=${NEW_JENKINS_LISTEN_ADDRESS}\"" >>"${tmpfile}"
339 | edited=true
340 | fi
341 |
342 | privileged_port=false
343 |
344 | if [ "${NEW_JENKINS_PORT}" != "${NEW_JENKINS_PORT_DEFAULT}" ]; then
345 | [ "${NEW_JENKINS_PORT}" -lt 1024 ] && privileged_port=true
346 | NEW_JENKINS_PORT="$(printf '%s' "${NEW_JENKINS_PORT}" | sed -e 's/"/\\"/g')"
347 | echo "Environment=\"JENKINS_PORT=${NEW_JENKINS_PORT}\"" >>"${tmpfile}"
348 | edited=true
349 | fi
350 |
351 | if [ -n "${NEW_JENKINS_HTTPS_LISTEN_ADDRESS}" ]; then
352 | NEW_JENKINS_HTTPS_LISTEN_ADDRESS="$(printf '%s' "${NEW_JENKINS_HTTPS_LISTEN_ADDRESS}" | sed -e 's/"/\\"/g')"
353 | echo "Environment=\"JENKINS_HTTPS_LISTEN_ADDRESS=${NEW_JENKINS_HTTPS_LISTEN_ADDRESS}\"" >>"${tmpfile}"
354 | edited=true
355 | fi
356 |
357 | if [ -n "${NEW_JENKINS_HTTPS_PORT}" ]; then
358 | [ "${NEW_JENKINS_HTTPS_PORT}" -lt 1024 ] && privileged_port=true
359 | NEW_JENKINS_HTTPS_PORT="$(printf '%s' "${NEW_JENKINS_HTTPS_PORT}" | sed -e 's/"/\\"/g')"
360 | echo "Environment=\"JENKINS_HTTPS_PORT=${NEW_JENKINS_HTTPS_PORT}\"" >>"${tmpfile}"
361 | edited=true
362 | fi
363 |
364 | if [ -n "${NEW_JENKINS_HTTPS_KEYSTORE}" ]; then
365 | NEW_JENKINS_HTTPS_KEYSTORE="$(printf '%s' "${NEW_JENKINS_HTTPS_KEYSTORE}" | sed -e 's/"/\\"/g')"
366 | echo "Environment=\"JENKINS_HTTPS_KEYSTORE=${NEW_JENKINS_HTTPS_KEYSTORE}\"" >>"${tmpfile}"
367 | edited=true
368 | fi
369 |
370 | if [ -n "${NEW_JENKINS_HTTPS_KEYSTORE_PASSWORD}" ]; then
371 | NEW_JENKINS_HTTPS_KEYSTORE_PASSWORD="$(printf '%s' "${NEW_JENKINS_HTTPS_KEYSTORE_PASSWORD}" | sed -e 's/"/\\"/g')"
372 | echo "Environment=\"JENKINS_HTTPS_KEYSTORE_PASSWORD=${NEW_JENKINS_HTTPS_KEYSTORE_PASSWORD}\"" >>"${tmpfile}"
373 | edited=true
374 | fi
375 |
376 | if [ -n "${NEW_JENKINS_HTTP2_LISTEN_ADDRESS}" ]; then
377 | NEW_JENKINS_HTTP2_LISTEN_ADDRESS="$(printf '%s' "${NEW_JENKINS_HTTP2_LISTEN_ADDRESS}" | sed -e 's/"/\\"/g')"
378 | echo "Environment=\"JENKINS_HTTP2_LISTEN_ADDRESS=${NEW_JENKINS_HTTP2_LISTEN_ADDRESS}\"" >>"${tmpfile}"
379 | edited=true
380 | fi
381 |
382 | if [ -n "${NEW_JENKINS_HTTP2_PORT}" ]; then
383 | [ "${NEW_JENKINS_HTTP2_PORT}" -lt 1024 ] && privileged_port=true
384 | NEW_JENKINS_HTTP2_PORT="$(printf '%s' "${NEW_JENKINS_HTTP2_PORT}" | sed -e 's/"/\\"/g')"
385 | echo "Environment=\"JENKINS_HTTP2_PORT=${NEW_JENKINS_HTTP2_PORT}\"" >>"${tmpfile}"
386 | edited=true
387 | fi
388 |
389 | if $privileged_port; then
390 | echo "AmbientCapabilities=CAP_NET_BIND_SERVICE" >>"${tmpfile}"
391 | edited=true
392 | fi
393 |
394 | if [ "${NEW_JENKINS_DEBUG_LEVEL}" != "${NEW_JENKINS_DEBUG_LEVEL_DEFAULT}" ]; then
395 | NEW_JENKINS_DEBUG_LEVEL="$(printf '%s' "${NEW_JENKINS_DEBUG_LEVEL}" | sed -e 's/"/\\"/g')"
396 | echo "Environment=\"JENKINS_DEBUG_LEVEL=${NEW_JENKINS_DEBUG_LEVEL}\"" >>"${tmpfile}"
397 | edited=true
398 | fi
399 |
400 | if $NEW_JENKINS_ENABLE_ACCESS_LOG; then
401 | echo "Environment=\"JENKINS_ENABLE_ACCESS_LOG=${NEW_JENKINS_ENABLE_ACCESS_LOG}\"" >>"${tmpfile}"
402 | edited=true
403 | fi
404 |
405 | if [ -n "${NEW_JENKINS_PREFIX}" ]; then
406 | NEW_JENKINS_PREFIX="$(printf '%s' "${NEW_JENKINS_PREFIX}" | sed -e 's/"/\\"/g')"
407 | echo "Environment=\"JENKINS_PREFIX=${NEW_JENKINS_PREFIX}\"" >>"${tmpfile}"
408 | edited=true
409 | fi
410 |
411 | if [ -n "${NEW_JENKINS_OPTS}" ]; then
412 | NEW_JENKINS_OPTS="$(printf '%s' "${NEW_JENKINS_OPTS}" | sed -e 's/"/\\"/g')"
413 | echo "Environment=\"JENKINS_OPTS=${NEW_JENKINS_OPTS}\"" >>"${tmpfile}"
414 | edited=true
415 | fi
416 |
417 | if [ "${NEW_JENKINS_MAXOPENFILES}" != "${NEW_JENKINS_MAXOPENFILES_DEFAULT}" ]; then
418 | NEW_JENKINS_MAXOPENFILES="$(printf '%s' "${NEW_JENKINS_MAXOPENFILES}" | sed -e 's/"/\\"/g')"
419 | echo "LimitNOFILE=${NEW_JENKINS_MAXOPENFILES}" >>"${tmpfile}"
420 | edited=true
421 | fi
422 |
423 | if [ -n "${NEW_JENKINS_UMASK}" ]; then
424 | NEW_JENKINS_UMASK="$(printf '%s' "${NEW_JENKINS_UMASK}" | sed -e 's/"/\\"/g')"
425 | echo "UMask=${NEW_JENKINS_UMASK}" >>"${tmpfile}"
426 | edited=true
427 | fi
428 |
429 | if $edited; then
430 | mkdir -p /etc/systemd/system/@@ARTIFACTNAME@@.service.d
431 | mv "${tmpfile}" /etc/systemd/system/@@ARTIFACTNAME@@.service.d/override.conf
432 | else
433 | rm -f "${tmpfile}"
434 | fi
435 | }
436 |
437 | main() {
438 | from=$1
439 |
440 | [ -f "${from}" ] || die "${from} does not exist"
441 | . "${from}"
442 | read_old_options
443 | migrate_options
444 | }
445 |
446 | [ $# -gt 1 ] && usage "too many arguments specified"
447 | [ $# -lt 1 ] && usage "too few arguments specified"
448 | main "$1"
449 |
450 | exit 0
451 |
--------------------------------------------------------------------------------
/templates/base.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | {% block head %}
10 | {{ os_family | capitalize}} {{product_name | capitalize }} Packages
11 | {% endblock %}
12 |
13 |
14 |
15 |
19 |
20 |
24 |
25 |
29 |
30 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
{% block title %}{{product_name | capitalize }} {{ os_family | capitalize}} Packages{% endblock %}
65 |
66 | {% block distribution_instruction %}{% endblock %}
67 |
68 | {% block java_instructions %}
69 |
70 | You will need to explicitly install a supported Java runtime environment (JRE), either from your distribution
71 | (as described above) or another Java vendor (e.g., Adoptium ).
72 |
73 |
74 |
75 | Weekly Release Line
76 |
77 |
78 |
79 | Supported Java versions for the weekly release line are:
80 |
81 |
82 |
83 | 2.463 (June 2024) and newer
84 | Java 17 or Java 21
85 |
86 | 2.419 (August 2023) and newer
87 | Java 11, Java 17, or Java 21
88 |
89 | 2.357 (June 2022) and newer
90 | Java 11 or Java 17
91 |
92 | 2.164 (February 2019) and newer
93 | Java 8 or Java 11
94 |
95 | 2.54 (April 2017) and newer
96 | Java 8
97 |
98 | 1.612 (May 2015) and newer
99 | Java 7
100 |
101 |
102 |
105 |
106 |
107 | Supported Java versions for the LTS release line are:
108 |
109 |
110 |
111 | 2.479.1 (October 2024) and newer
112 | Java 17 or Java 21
113 |
114 | 2.426.1 (November 2023) and newer
115 | Java 11, Java 17 or Java 21
116 |
117 | 2.361.1 (September 2022) and newer
118 | Java 11 or Java 17
119 |
120 | 2.346.1 (June 2022) and newer
121 | Java 8, Java 11, or Java 17
122 |
123 | 2.164.1 (March 2019) and newer
124 | Java 8 or Java 11
125 |
126 | 2.60.1 (June 2017) and newer
127 | Java 8
128 |
129 | 1.625.1 (October 2015) and newer
130 | Java 7
131 |
132 | {% endblock %}
133 |
134 |
135 | See the installation guide for more information, including how {{ product_name }} is run and where the configuration is stored, etc.
136 |
137 |
138 |
139 |
140 |
141 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
--------------------------------------------------------------------------------
/templates/footer.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
32 |
--------------------------------------------------------------------------------
/templates/header.debian.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block distribution_instruction %}
4 |
5 |
6 | This is the Debian package repository of {{product_name}} to automate installation and upgrade.
7 |
8 | To use this repository, first add the key to your system (for the Weekly Release Line):
9 |
10 |
11 |
12 | sudo wget -O /etc/apt/keyrings/jenkins-keyring.asc \
13 | {{web_url}}/{{organization}}-2023.key
14 |
15 |
16 | Then add a Jenkins apt repository entry:
17 |
18 |
19 |
20 | echo "deb [signed-by=/etc/apt/keyrings/jenkins-keyring.asc]" \
21 | {{ web_url }} binary/ | sudo tee \
22 | /etc/apt/sources.list.d/jenkins.list > /dev/null
23 |
24 |
25 |
26 |
27 | Update your local package index, then finally install {{product_name}}:
28 |
29 |
30 |
31 | sudo apt-get update
32 | sudo apt-get install fontconfig openjdk-17-jre
33 | sudo apt-get install {{artifactName}}
34 |
35 |
36 |
37 |
38 | The apt packages were signed using this key:
39 |
40 |
41 | {{ pub_key_info|trim }}
42 | {% endblock %}
43 |
44 | {% block individual_package_instruction %}
45 |
46 |
47 | If you need *.deb for a specific version, use these.
48 |
49 |
50 | {% endblock %}
51 |
--------------------------------------------------------------------------------
/templates/header.msi.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block distribution_instruction %}
4 |
5 |
6 | This is the MSI package repository of {{product_name}} for installation.
7 |
8 | {% endblock %}
9 |
10 | {% block individual_package_instruction %}{% endblock %}
11 | {% block java_instructions %}{% endblock %}
12 |
--------------------------------------------------------------------------------
/templates/header.opensuse.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block distribution_instruction %}
4 |
5 | To use this repository, run the following command:
6 |
7 |
8 |
9 | sudo zypper addrepo -f {{web_url}}/ {{artifactName}}
10 |
11 |
12 |
13 |
14 | With that set up, the {{ product_name }} package can be installed with:
15 |
16 |
17 |
18 | zypper install dejavu-fonts fontconfig java-17-openjdk
19 | zypper install {{ artifactName }}
20 |
21 |
22 |
23 | {% endblock %}
24 |
25 | {% block individual_package_instruction %}
26 | If you need *.rpm for a specific version, use these.
27 | {% endblock %}
28 |
--------------------------------------------------------------------------------
/templates/header.redhat.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block distribution_instruction %}
4 |
5 |
6 | To install Jenkins on Red Hat Enterprise Linux, AlmaLinux, Rocky Linux, Oracle Linux, or another Red
7 | Hat based distribution, you can utilize the instructions provided in our Red Hat Enterprise Linux installation
9 | guide.
10 |
11 |
12 |
13 | To install Jenkins on Fedora, use the instructions provided in our
14 | Fedora installation guide .
15 |
16 |
17 | {% endblock %}
18 |
19 | {% block individual_package_instruction %}
20 | If you need *.rpm for a specific version, use these.
21 | {% endblock %}
22 |
--------------------------------------------------------------------------------
/templates/header.root.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block title %}Jenkins Core Packages{% endblock %}
4 |
5 | {% block distribution_instruction %}{% endblock %}
6 | {% block java_instructions %}{% endblock %}
7 |
8 | {% block individual_package_instruction %}{% endblock %}
9 |
--------------------------------------------------------------------------------
/templates/header.war.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block distribution_instruction %}
4 |
5 |
6 | This is the WAR package repository of {{ product_name }} for installation.
7 |
8 | {% endblock %}
9 |
10 | {% block java_instructions %}
11 |
12 | You will need to explicitly install a supported Java runtime environment (JRE),
13 | e.g. Eclipse Temurin .
14 |
15 |
16 |
17 | To determine the Java version that is supported for your Jenkins environment, please refer to the Java support policy.
18 |
19 |
20 | {% endblock %}
21 |
22 | {% block individual_package_instruction %}
23 |
24 |
25 | If you need *.war for a specific version, use these.
26 |
27 |
28 | {% endblock %}
29 |
--------------------------------------------------------------------------------
/templates/index.html:
--------------------------------------------------------------------------------
1 | {% include header %}
2 | {% include "footer.html" %}
3 |
--------------------------------------------------------------------------------
/war/publish/publish.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -euxo pipefail
4 |
5 | : "${AGENT_WORKDIR:=/tmp}"
6 | : "${WAR:?Require Jenkins War file}"
7 | : "${WARDIR:? Require where to put binary files}"
8 | : "${WAR_WEBDIR:? Require where to put repository index and other web contents}"
9 |
10 | # $$ Contains current pid
11 | D="$AGENT_WORKDIR/$$"
12 |
13 | function clean() {
14 | rm -rf "$D"
15 | }
16 |
17 | # Convert string to array to correctly escape cli parameter
18 | SSH_OPTS=($SSH_OPTS)
19 |
20 | # Generate and publish site content
21 | function generateSite() {
22 | "$BASE/bin/indexGenerator.py" \
23 | --distribution war \
24 | --targetDir "$D"
25 | }
26 |
27 | function init() {
28 | mkdir -p $D
29 |
30 | mkdir -p "${WARDIR}/${VERSION}/"
31 |
32 | ssh "${SSH_OPTS[@]}" "$PKGSERVER" mkdir -p "$WARDIR/${VERSION}/"
33 | }
34 |
35 | function skipIfAlreadyPublished() {
36 | if ssh "${SSH_OPTS[@]}" "$PKGSERVER" test -e "${WARDIR}/${VERSION}/${ARTIFACTNAME}.war"; then
37 | echo "File already published, nothing else todo"
38 | exit 0
39 | fi
40 | }
41 |
42 | function uploadPackage() {
43 | sha256sum "${WAR}" | sed "s, .*, ${ARTIFACTNAME}.war," >"${WAR_SHASUM}"
44 | cat "${WAR_SHASUM}"
45 |
46 | # Local
47 | rsync \
48 | --compress \
49 | --recursive \
50 | --verbose \
51 | --ignore-existing \
52 | --progress \
53 | "${WAR}" "${WARDIR}/${VERSION}/${ARTIFACTNAME}.war"
54 |
55 | rsync \
56 | --compress \
57 | --recursive \
58 | --verbose \
59 | --ignore-existing \
60 | --progress \
61 | "${WAR_SHASUM}" "${WARDIR}/${VERSION}/"
62 |
63 | # Remote
64 | rsync \
65 | --archive \
66 | --compress \
67 | --verbose \
68 | -e "ssh ${SSH_OPTS[*]}" \
69 | --ignore-existing \
70 | --progress \
71 | "${WAR}" "$PKGSERVER:${WARDIR}/${VERSION}/${ARTIFACTNAME}.war"
72 |
73 | rsync \
74 | --archive \
75 | --compress \
76 | --verbose \
77 | -e "ssh ${SSH_OPTS[*]}" \
78 | --ignore-existing \
79 | --progress \
80 | "${WAR_SHASUM}" "$PKGSERVER:${WARDIR}/${VERSION}/"
81 | }
82 |
83 | # Site html need to be located in the binary directory
84 | function uploadSite() {
85 | rsync \
86 | --compress \
87 | --recursive \
88 | --verbose \
89 | --include "HEADER.html" \
90 | --include "FOOTER.html" \
91 | --exclude "*" \
92 | --progress \
93 | -e "ssh ${SSH_OPTS[*]}" \
94 | "${D}/" "${WARDIR// /\\ }/"
95 |
96 | rsync \
97 | --archive \
98 | --compress \
99 | --verbose \
100 | --include "HEADER.html" \
101 | --include "FOOTER.html" \
102 | --exclude "*" \
103 | --progress \
104 | -e "ssh ${SSH_OPTS[*]}" \
105 | "${D}/" "$PKGSERVER:${WARDIR// /\\ }/"
106 | }
107 |
108 | function show() {
109 | echo "Parameters:"
110 | echo "WAR: $WAR"
111 | echo "WARDIR: $WARDIR"
112 | echo "SSH_OPTS: ${SSH_OPTS[*]}"
113 | echo "PKGSERVER: $PKGSERVER"
114 | echo "---"
115 | }
116 |
117 | show
118 | skipIfAlreadyPublished
119 | init
120 | generateSite
121 | uploadPackage
122 | uploadSite
123 | clean
124 |
--------------------------------------------------------------------------------