├── .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 | [![logo](https://img.shields.io/docker/pulls/jenkinsciinfra/packaging?label=jenkinsciinfra%2Fpackaging&logo=docker&logoColor=white)](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 |

103 | Long Term Support (LTS) Release Line 104 |

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 | --------------------------------------------------------------------------------