├── .dockerignore ├── .github ├── dependabot.yml ├── release-drafter.yml └── workflows │ └── changelog.yml ├── .gitignore ├── Dockerfile ├── Jenkinsfile ├── LICENSE.md ├── Makefile ├── README.md ├── demo ├── locale-plugin │ ├── .gitignore │ └── repo │ │ ├── Jenkinsfile │ │ ├── README.md │ │ ├── pom.xml │ │ └── src │ │ ├── main │ │ ├── java │ │ │ └── hudson │ │ │ │ └── plugins │ │ │ │ └── locale │ │ │ │ ├── LocaleFilter.java │ │ │ │ └── PluginImpl.java │ │ ├── resources │ │ │ ├── hudson │ │ │ │ └── plugins │ │ │ │ │ └── locale │ │ │ │ │ └── PluginImpl │ │ │ │ │ ├── config.jelly │ │ │ │ │ ├── config.properties │ │ │ │ │ └── config_zh_TW.properties │ │ │ └── index.jelly │ │ └── webapp │ │ │ └── help │ │ │ └── default-language.html │ │ └── test │ │ ├── java │ │ └── hudson │ │ │ └── plugins │ │ │ └── locale │ │ │ └── MigrationTest.java │ │ └── resources │ │ └── hudson │ │ └── plugins │ │ └── locale │ │ └── MigrationTest │ │ └── dataMigration_13 │ │ └── locale.xml └── simple │ └── Jenkinsfile ├── init_scripts ├── pom.xml └── src │ └── main │ └── groovy │ ├── PipelineLibrary.groovy │ ├── System.groovy │ └── Tools.groovy ├── jenkins-dev.yaml ├── jenkins.yaml └── pom.xml /.dockerignore: -------------------------------------------------------------------------------- 1 | # Repository 2 | .git 3 | .github 4 | .demo 5 | Makefile 6 | README.md 7 | 8 | # Custom WAR Packager 9 | .build 10 | tmp 11 | 12 | # Maven Packaging flow 13 | target 14 | 15 | # IDE 16 | .settings 17 | .idea 18 | .classpath 19 | .factoryclass 20 | .project 21 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "maven" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | - package-ecosystem: "docker" 8 | directory: "/" 9 | schedule: 10 | interval: "weekly" 11 | -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | _extends: .github 2 | # We are using semver here 3 | version-template: $MAJOR.$MINOR.$PATCH 4 | -------------------------------------------------------------------------------- /.github/workflows/changelog.yml: -------------------------------------------------------------------------------- 1 | 2 | # Automates creation of Release Drafts using Release Drafter 3 | # More Info: https://github.com/jenkinsci/.github/blob/master/.github/release-drafter.adoc 4 | 5 | on: 6 | push: 7 | branches: 8 | - master 9 | 10 | jobs: 11 | update_release_draft: 12 | runs-on: ubuntu-latest 13 | steps: 14 | # Drafts your next Release notes as Pull Requests are merged into "master" 15 | - uses: release-drafter/release-drafter@v5.11.0 16 | env: 17 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Jenkins Config As Code Example.iml 2 | .build 3 | tmp/ 4 | target 5 | 6 | # VS Code 7 | .factorypath 8 | .settings 9 | .project 10 | .classpath 11 | 12 | # IDEA 13 | .idea 14 | *.iml 15 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jenkins/jenkinsfile-runner:build-mvncache as jfr-mvncache 2 | 3 | FROM jenkins/jenkinsfile-runner:1.0-beta-19 as jfr-base 4 | 5 | ### 6 | # Build stage 7 | ### 8 | FROM maven:3.5.4 as jfr-build 9 | ENV MAVEN_OPTS=-Dmaven.repo.local=/mavenrepo 10 | COPY --from=jfr-mvncache /mavenrepo /mavenrepo 11 | ADD pom.xml /jenkinsfile-runner/pom.xml 12 | RUN cd /jenkinsfile-runner && mvn clean package 13 | # TODO: Should be automated in Parent POM 14 | # Prepare the Jenkins core 15 | RUN mkdir /app && unzip /jenkinsfile-runner/target/war/jenkins.war -d /app/jenkins && \ 16 | rm -rf /app/jenkins/scripts /app/jenkins/jsbundles /app/jenkins/css /app/jenkins/images /app/jenkins/help /app/jenkins/WEB-INF/detached-plugins /app/jenkins/winstone.jar /app/jenkins/WEB-INF/jenkins-cli.jar /app/jenkins/WEB-INF/lib/jna-4.5.2.jar 17 | # Delete HPI files and use the archive directories instead 18 | #RUN echo "Optimizing plugins..." && \ 19 | # cd /jenkinsfile-runner/target/plugins && \ 20 | # rm -rf *.hpi && \ 21 | # for f in * ; do echo "Exploding $f..." && mv "$f" "$f.hpi" ; done; 22 | 23 | #### 24 | # Production image 25 | #### 26 | FROM adoptopenjdk:8u262-b10-jdk-hotspot 27 | 28 | LABEL Description="This is a base image for a single-shot ci.jenkins.io demo" Vendor="Oleg Nenashev" Version="0.3" 29 | 30 | # Packages 31 | RUN apt-get update && apt-get install -y wget git && rm -rf /var/lib/apt/lists/* 32 | 33 | # Maven 34 | ENV MAVEN_VERSION 3.6.3 35 | RUN curl -Lf https://downloads.apache.org/maven/maven-3/$MAVEN_VERSION/binaries/apache-maven-$MAVEN_VERSION-bin.tar.gz | tar -C /opt -xzv 36 | ENV M2_HOME /opt/apache-maven-$MAVEN_VERSION 37 | ENV maven.home $M2_HOME 38 | ENV M2 $M2_HOME/bin 39 | ENV PATH $M2:$PATH 40 | 41 | # JDK11 42 | RUN curl -L --show-error "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.8%2B10/OpenJDK11U-jdk_x64_linux_hotspot_11.0.8_10.tar.gz" --output adoptopenjdk.tar.gz && \ 43 | echo "6e4cead158037cb7747ca47416474d4f408c9126be5b96f9befd532e0a762b47 adoptopenjdk.tar.gz" | sha256sum -c && \ 44 | tar xvzf adoptopenjdk.tar.gz && \ 45 | mkdir -p /usr/lib/jvm && \ 46 | mv "jdk-11.0.8+10/" /usr/lib/jvm/jdk-11 && \ 47 | rm adoptopenjdk.tar.gz 48 | 49 | COPY --from=jfr-build /jenkinsfile-runner/target/appassembler /app 50 | COPY --from=jfr-build /jenkinsfile-runner/target/plugins /usr/share/jenkins/ref/plugins 51 | COPY --from=jenkins/jenkinsfile-runner:1.0-beta-15 /app/bin/jenkinsfile-runner-launcher /app/bin/jenkinsfile-runner-launcher 52 | # /app/jenkins is a location of the WAR file. It can be empty in the current packaging 53 | RUN mkdir /app/jenkins 54 | 55 | VOLUME /usr/share/jenkins/ref/casc 56 | 57 | ENV JENKINS_HOME="/usr/share/jenkins/ref/" 58 | ENV JAVA_OPTS="-Djenkins.model.Jenkins.slaveAgentPort=50000 -Djenkins.model.Jenkins.slaveAgentPortEnforce=true -Dhudson.model.LoadStatistics.clock=1000" 59 | ENV CASC_JENKINS_CONFIG /usr/share/jenkins/ref/jenkins.yaml 60 | COPY jenkins.yaml /usr/share/jenkins/ref/jenkins.yaml 61 | COPY init_scripts/src/main/groovy/* /usr/share/jenkins/ref/init.groovy.d/ 62 | 63 | ENTRYPOINT ["/app/bin/jenkinsfile-runner",\ 64 | "-w", "/app/jenkins",\ 65 | "-p", "/usr/share/jenkins/ref/plugins",\ 66 | "-f", "/workspace/Jenkinsfile"] 67 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | properties([ 2 | durabilityHint('PERFORMANCE_OPTIMIZED'), 3 | buildDiscarder(logRotator(numToKeepStr: '5')), 4 | ]) 5 | 6 | timeout(time: 2, unit: 'HOURS') { 7 | node ("linux") { 8 | stage("Checkout") { 9 | checkout scm 10 | } 11 | 12 | stage ("Build") { 13 | def makeCommand = "make clean build" 14 | infra.runWithMaven(makeCommand) 15 | } 16 | 17 | stage("Run demo jobs") { 18 | stage("Smoke test") { 19 | sh "make run" 20 | } 21 | stage("Plugin build") { 22 | sh "make demo-plugin" 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Oleg Nenashev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Just a Makefile for manual testing 2 | .PHONY: all 3 | 4 | DOCKER_TAG=jenkins4eval/ci.jenkins.io-runner:local-test 5 | PIPELINE_LIBRARY_DIR=/Users/nenashev/Documents/jenkins/infra/pipeline-library/ 6 | DOCKER_RUN_OPTS=-v maven-repo:/root/.m2 7 | 8 | all: clean build 9 | 10 | clean: 11 | rm -rf tmp 12 | 13 | .PHONY: docker 14 | docker: 15 | docker build -t $(DOCKER_TAG) . 16 | 17 | build: docker 18 | 19 | .PHONY: run 20 | run: 21 | docker run --rm ${DOCKER_RUN_OPTS} \ 22 | -v $(CURDIR)/demo/simple/:/workspace/ \ 23 | $(DOCKER_TAG) 24 | 25 | .PHONY: demo-plugin 26 | demo-plugin: 27 | docker run --rm ${DOCKER_RUN_OPTS} \ 28 | -v $(CURDIR)/demo/locale-plugin/repo/:/workspace/ \ 29 | $(DOCKER_TAG) 30 | 31 | .PHONY: demo-plugin-local-lib 32 | demo-plugin-local-lib: 33 | docker run --rm ${DOCKER_RUN_OPTS} \ 34 | -v ${PIPELINE_LIBRARY_DIR}:/var/jenkins_home/pipeline-library \ 35 | -v $(CURDIR)/demo/locale-plugin/repo:/workspace/ \ 36 | $(DOCKER_TAG) 37 | 38 | .PHONY: jfr-profile 39 | jfr-profile: 40 | mkdir -p war-empty && \ 41 | mkdir -p demo/locale-plugin/work && \ 42 | cd demo/locale-plugin/work && \ 43 | CASC_JENKINS_CONFIG=../../../jenkins-dev.yaml \ 44 | JAVA_OPTS=-XX:StartFlightRecording=disk=true,dumponexit=true,filename=recording.jfr,maxsize=1024m,maxage=1d,settings=profile,path-to-gc-roots=true \ 45 | ../../../target/appassembler/bin/jenkinsfile-runner \ 46 | -p ../../../target/plugins/ -w war-empty -f ../repo/Jenkinsfile 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ci.jenkins.io-runner 2 | === 3 | 4 | [![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/jenkinsci/ci.jenkins.io-runner?include_prereleases&label=changelog)](https://github.com/jenkinsci/ci.jenkins.io-runner/releases/latest) 5 | [![](https://images.microbadger.com/badges/image/onenashev/ci.jenkins.io-runner.svg)](https://microbadger.com/images/onenashev/ci.jenkins.io-runner "Get your own image badge on microbadger.com") 6 | [![Gitter](https://badges.gitter.im/jenkinsci/jenkinsfile-runner.svg)](https://gitter.im/jenkinsci/jenkinsfile-runner) 7 | 8 | This project offers environment for running Jenkinsfile instances from ci.jenkins.io locally. 9 | It is powered by [Jenkinsfile Runner](https://github.com/jenkinsci/jenkinsfile-runner) and the experimental [JFR Maven packaging flow](https://github.com/jenkinsci/jenkinsfile-runner/tree/master/packaging-parent-pom) introduced in 1.0-beta-16. 10 | If you want a classic runtime Jenkins master with agents, 11 | checkout [my Jenkins Configuration-as-code demo](https://github.com/oleg-nenashev/demo-jenkins-config-as-code). 12 | 13 | The runner can execute `buildPlugin()` builds and some other commands from 14 | the [Jenkins Pipeline Library](https://github.com/jenkins-infra/pipeline-library). 15 | In particular, it is possible to run builds against multiple JDK and Jenkins core version combinations. 16 | 17 | See the _Limitations_ section below for some of known limitations. 18 | 19 | ### Quickstart 20 | 21 | 1. Checkout this repo 22 | 2. Run `make docker` to build the base image 23 | 3. Run `make run` to run a simple demo 24 | 4. Run `make demo-plugin` to run a demo of the plugin build 25 | 26 | ### Usage 27 | 28 | The runner can be invoked against a workspace which contains a `Jenkinsfile` 29 | and, if needed, the project's sourcecode. 30 | 31 | ``` 32 | docker run --rm -v maven-repo:/root/.m2 \ 33 | -v $(pwd)/demo/locale-plugin/:/workspace/ \ 34 | onenashev/ci.jenkins.io-runner 35 | ``` 36 | 37 | ### Developing Jenkins Pipeline Library 38 | 39 | Jenkins Pipeline library may be passed from a volume so that it is possible to test a local snapshot. 40 | 41 | ``` 42 | docker run --rm -v maven-repo:/root/.m2 \ 43 | -v ${MY_PIPELINE_LIBRARY_DIR}:/var/jenkins_home/pipeline-library \ 44 | -v $(pwd)/demo/locale-plugin/:/workspace/ \ 45 | onenashev/ci.jenkins.io-runner 46 | ``` 47 | 48 | ### Developer notes 49 | 50 | #### Upgrade management 51 | 52 | This repository uses [Dependabot](https://dependabot.com/) to track dependencies and to propose updates. 53 | Many plugin and library dependencies actually come from Bills of Materials supplied by the JFR packaging parent POM: 54 | [Jenkins Core BOM](https://github.com/jenkinsci/jenkins/tree/master/bom) and 55 | [Jenkins Plugin BOM](https://github.com/jenkinsci/bom). 56 | It reduces the number of moving parts by consuming the cross-verified plugin versions. 57 | 58 | #### Debugging Jenkinsfile Runner 59 | 60 | To debug the execution, you can pass the `JFR_LOCAL_WORKSPACE=true` environment variable to the image. 61 | It will make the builder to execute Pipeline directly. 62 | It is also possible to debug Jenkinsfile Runner and Groovy init hooks by passing the remote debug options and exposing the debug port: 63 | 64 | ``` 65 | docker run --rm -v maven-repo:/root/.m2 \ 66 | -v $(pwd)/demo/locale-plugin/:/workspace/ \ 67 | -p 5005:5005 -e JAVA_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,address=5005,suspend=y" \ 68 | onenashev/ci.jenkins.io-runner 69 | ``` 70 | 71 | #### Profiling Jenkinsfile Runner 72 | 73 | This repository supports profiling of Jenkinsfile Runner with Java Flight Recorder. 74 | Due to performance reasons, profiling happens on a local machine instead of the Docker containers. 75 | 76 | To run profiling on a Unix machine: 77 | 78 | * Build ci.jenkins.io-runner locally via `mvn clean package` 79 | * Run `make jfr-profile` and wait till completion 80 | * Retrieve the `demo/locale-plugin/work/recording.jfr` file with Java Flight Recorder dump 81 | * Use performance analysis tools to analyze the Java Flight Recorder dump (e.g. IntelligIDEA, JDK Mission Control in AdoptOpenJDK). 82 | CPU and memory usage analysis can be done with the existing tools. 83 | 84 | ### Limitations 85 | 86 | This project has just started, so it has some downsides being compared 87 | to the runtime Pipeline Development instance [here](https://github.com/oleg-nenashev/demo-jenkins-config-as-code). 88 | All of the limitations below can be improved in the future. 89 | 90 | * A custom fork of Jenkins Pipeline Library is needed to run it 91 | * Follow https://github.com/jenkins-infra/pipeline-library/pull/78 92 | * `ci.jenkins.io-runner` is a single-container package with only 1 executor 93 | * Only JDK8 and JDK11 are provided in the image 94 | * Windows steps are not supported 95 | * Docker image is pretty big, because it bundles two versions of JDK 96 | -------------------------------------------------------------------------------- /demo/locale-plugin/.gitignore: -------------------------------------------------------------------------------- 1 | # mvn 2 | /target/ 3 | 4 | # jenkins 5 | work 6 | 7 | # idea 8 | .idea 9 | *.iml 10 | 11 | # vim 12 | .swp 13 | -------------------------------------------------------------------------------- /demo/locale-plugin/repo/Jenkinsfile: -------------------------------------------------------------------------------- 1 | // Build the plugin using https://github.com/jenkins-infra/pipeline-library 2 | buildPlugin(jenkinsVersions: [null, '2.107.2']) 3 | -------------------------------------------------------------------------------- /demo/locale-plugin/repo/README.md: -------------------------------------------------------------------------------- 1 | Locale Plugin for Jenkins 2 | ========================= 3 | 4 | This plugin controls the language of Jenkins 5 | 6 | Normally, Jenkins honors the browser's language preference 7 | if a translation is available for the preferred language, 8 | and uses the system default locale for messages during a build. 9 | 10 | This plugin allows you to: 11 | 12 | * override the system default locale to the language of your choice 13 | * ignore browser's language preference completely 14 | 15 | This feature is sometimes convenient for multi-lingual environment. 16 | 17 | ### Usage 18 | Under _Manage Jenkins > Configure System_ there should be a "Locale" section. 19 | 20 | Here you can enter the _Default Language_: this should be a language code 21 | or locale code like "fr" (for French), or "de_AT" (German, in Austria). 22 | 23 | This value will be used by the system, for example, for messages that are printed 24 | to the log during a build (assuming that the Jenkins features and plugins that 25 | you're using have been translated into the specified language). 26 | 27 | To additionally force this language on all users, overriding their browser language, 28 | you can check the "Ignore browser preference and force this language to all users" option. 29 | -------------------------------------------------------------------------------- /demo/locale-plugin/repo/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | Locale plugin 5 | https://wiki.jenkins.io/display/JENKINS/Locale+Plugin 6 | 7 | 8 | org.jenkins-ci.plugins 9 | plugin 10 | 3.28 11 | 12 | 13 | 14 | 1.625.3 15 | 7 16 | 17 | 18 | io.jenkins.plugins 19 | locale 20 | 1.5-SNAPSHOT 21 | hpi 22 | 23 | 24 | 25 | kohsuke 26 | Kohsuke Kawaguchi 27 | 28 | 29 | oleg_nenashev 30 | Oleg Nenashev 31 | 32 | 33 | 34 | 35 | 36 | repo.jenkins-ci.org 37 | https://repo.jenkins-ci.org/public/ 38 | 39 | 40 | 41 | 42 | 43 | repo.jenkins-ci.org 44 | https://repo.jenkins-ci.org/public/ 45 | 46 | 47 | 48 | 49 | 50 | MIT License 51 | http://opensource.org/licenses/MIT 52 | 53 | 54 | 55 | 56 | scm:git:ssh://github.com/jenkinsci/locale-plugin.git 57 | scm:git:ssh://git@github.com/jenkinsci/locale-plugin.git 58 | https://github.com/jenkinsci/locale-plugin 59 | HEAD 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /demo/locale-plugin/repo/src/main/java/hudson/plugins/locale/LocaleFilter.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.locale; 2 | 3 | import jenkins.model.Jenkins; 4 | 5 | import javax.servlet.Filter; 6 | import javax.servlet.FilterChain; 7 | import javax.servlet.FilterConfig; 8 | import javax.servlet.ServletException; 9 | import javax.servlet.ServletRequest; 10 | import javax.servlet.ServletResponse; 11 | import javax.servlet.http.HttpServletRequest; 12 | import javax.servlet.http.HttpServletRequestWrapper; 13 | import java.io.IOException; 14 | import java.util.Locale; 15 | 16 | /** 17 | * @author Nicolas De Loof 18 | */ 19 | public class LocaleFilter implements Filter { 20 | 21 | @Override 22 | public void init(FilterConfig filterConfig) 23 | throws ServletException { 24 | // nop 25 | } 26 | 27 | @Override 28 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 29 | throws IOException, ServletException { 30 | if (request instanceof HttpServletRequest) { 31 | PluginImpl plugin = (PluginImpl) Jenkins.getActiveInstance().getPlugin("locale"); 32 | if (plugin != null && plugin.isIgnoreAcceptLanguage()) { 33 | request = new HttpServletRequestWrapper((HttpServletRequest) request) { 34 | @Override 35 | public Locale getLocale() { 36 | // Force locale to configured default, ignore request' Accept-Language header 37 | return Locale.getDefault(); 38 | } 39 | }; 40 | } 41 | } 42 | chain.doFilter(request, response); 43 | } 44 | 45 | @Override 46 | public void destroy() { 47 | // nop 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /demo/locale-plugin/repo/src/main/java/hudson/plugins/locale/PluginImpl.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.locale; 2 | 3 | import com.thoughtworks.xstream.XStream; 4 | import hudson.Plugin; 5 | import hudson.Util; 6 | import hudson.XmlFile; 7 | import hudson.model.Descriptor.FormException; 8 | import hudson.util.PluginServletFilter; 9 | import hudson.util.XStream2; 10 | import net.sf.json.JSONObject; 11 | import org.jvnet.localizer.LocaleProvider; 12 | import org.kohsuke.stapler.StaplerRequest; 13 | 14 | import javax.servlet.ServletException; 15 | import java.io.File; 16 | import java.io.IOException; 17 | import java.util.Locale; 18 | import jenkins.model.Jenkins; 19 | 20 | /** 21 | * @author Kohsuke Kawaguchi 22 | */ 23 | public class PluginImpl extends Plugin { 24 | 25 | private String systemLocale; 26 | private boolean ignoreAcceptLanguage; 27 | 28 | /** 29 | * The value of {@link Locale#getDefault()} before we replace it. 30 | */ 31 | private transient final Locale originalLocale = Locale.getDefault(); 32 | 33 | @Override 34 | public void start() 35 | throws Exception { 36 | load(); 37 | LocaleProvider.setProvider(new LocaleProvider() { 38 | LocaleProvider original = LocaleProvider.getProvider(); 39 | 40 | @Override 41 | public Locale get() { 42 | if (ignoreAcceptLanguage) { 43 | return Locale.getDefault(); 44 | } 45 | return original.get(); 46 | } 47 | }); 48 | 49 | PluginServletFilter.addFilter(new LocaleFilter()); 50 | } 51 | 52 | @Override 53 | protected void load() 54 | throws IOException { 55 | super.load(); 56 | setSystemLocale(systemLocale); // make the loaded value take effect 57 | } 58 | 59 | @Override 60 | protected XmlFile getConfigXml() { 61 | return new XmlFile(XSTREAM, new File(Jenkins.getActiveInstance().getRootDir(), "locale.xml")); 62 | } 63 | 64 | @Override 65 | public void configure(StaplerRequest req, JSONObject jsonObject) 66 | throws IOException, ServletException, FormException { 67 | setSystemLocale(jsonObject.getString("systemLocale")); 68 | ignoreAcceptLanguage = jsonObject.getBoolean("ignoreAcceptLanguage"); 69 | save(); 70 | } 71 | 72 | public boolean isIgnoreAcceptLanguage() { 73 | return ignoreAcceptLanguage; 74 | } 75 | 76 | public String getSystemLocale() { 77 | return systemLocale; 78 | } 79 | 80 | public void setSystemLocale(String systemLocale) 81 | throws IOException { 82 | systemLocale = Util.fixEmptyAndTrim(systemLocale); 83 | Locale.setDefault(systemLocale == null ? originalLocale : parse(systemLocale)); 84 | this.systemLocale = systemLocale; 85 | } 86 | 87 | /** 88 | * Sets whether the plugin should take user preferences into account. 89 | * @param ignoreAcceptLanguage If {@code true}, 90 | * Ignore browser preference and force this language to all users 91 | * @since 1.3 92 | */ 93 | public void setIgnoreAcceptLanguage(boolean ignoreAcceptLanguage) { 94 | this.ignoreAcceptLanguage = ignoreAcceptLanguage; 95 | } 96 | 97 | /** 98 | * Parses a string like "ja_JP" into a {@link Locale} object. 99 | * 100 | * @param s the locale string using underscores as delimiters 101 | * @return the Locale object 102 | */ 103 | public static Locale parse(String s) { 104 | String[] tokens = s.trim().split("_"); 105 | switch (tokens.length) { 106 | case 1: 107 | return new Locale(tokens[0]); 108 | case 2: 109 | return new Locale(tokens[0], tokens[1]); 110 | case 3: 111 | return new Locale(tokens[0], tokens[1], tokens[2]); 112 | default: 113 | throw new IllegalArgumentException(s + " is not a valid locale"); 114 | } 115 | } 116 | 117 | private static final XStream XSTREAM = new XStream2(); 118 | 119 | static { 120 | XSTREAM.alias("locale", PluginImpl.class); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /demo/locale-plugin/repo/src/main/resources/hudson/plugins/locale/PluginImpl/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /demo/locale-plugin/repo/src/main/resources/hudson/plugins/locale/PluginImpl/config.properties: -------------------------------------------------------------------------------- 1 | description=Ignore browser preference and force this language to all users -------------------------------------------------------------------------------- /demo/locale-plugin/repo/src/main/resources/hudson/plugins/locale/PluginImpl/config_zh_TW.properties: -------------------------------------------------------------------------------- 1 | # The MIT License 2 | # 3 | # Copyright (c) 2004-2010, Sun Microsystems, Inc. 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | 23 | Default\ Language=\u9810\u8A2D\u8A9E\u8A00 24 | -------------------------------------------------------------------------------- /demo/locale-plugin/repo/src/main/resources/index.jelly: -------------------------------------------------------------------------------- 1 | 2 |
3 | This plugin lets you control the language of Jenkins. 4 |
5 | -------------------------------------------------------------------------------- /demo/locale-plugin/repo/src/main/webapp/help/default-language.html: -------------------------------------------------------------------------------- 1 |
2 | Specifies the default language of Jenkins. This is used for messages 3 | that Jenkins produces during builds, as well as the default choice 4 | of the UI language when the browser didn't specify its preference. 5 | 6 |

7 | Internally, this uses Locale.setDefault(), so this affects 8 | all the other web applications that are running in the same container. 9 |

10 | -------------------------------------------------------------------------------- /demo/locale-plugin/repo/src/test/java/hudson/plugins/locale/MigrationTest.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.locale; 2 | 3 | import jenkins.model.Jenkins; 4 | import org.junit.Rule; 5 | import org.junit.Test; 6 | import org.jvnet.hudson.test.JenkinsRule; 7 | import org.jvnet.hudson.test.recipes.LocalData; 8 | 9 | import static org.junit.Assert.assertEquals; 10 | 11 | /** 12 | * Tests data loading from Locale Plugin 1.3. 13 | * @author Oleg Nenashev 14 | */ 15 | public class MigrationTest { 16 | 17 | @Rule 18 | public JenkinsRule j = new JenkinsRule(); 19 | 20 | @LocalData 21 | @Test 22 | public void dataMigration_13() { 23 | PluginImpl plugin = (PluginImpl) Jenkins.getActiveInstance().getPlugin("locale"); 24 | assertEquals("en-US", plugin.getSystemLocale()); 25 | assertEquals(true, plugin.isIgnoreAcceptLanguage()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /demo/locale-plugin/repo/src/test/resources/hudson/plugins/locale/MigrationTest/dataMigration_13/locale.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | en-US 4 | true 5 | 6 | -------------------------------------------------------------------------------- /demo/simple/Jenkinsfile: -------------------------------------------------------------------------------- 1 | stage('Read Evergreen YAML') { 2 | node { 3 | // Discover core version using Pipeline utility steps 4 | sh 'wget https://raw.githubusercontent.com/jenkins-infra/evergreen/master/services/essentials.yaml' 5 | def essentialsYaml = readYaml(file: "essentials.yaml") 6 | echo "Jenkins Evergreen uses the following Core version: ${essentialsYaml.spec.core.version}" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /init_scripts/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.jenkins-ci.plugins 8 | plugin 9 | 2.28 10 | 11 | 12 | io.jenkins.systemgroovy.demo 13 | initscripts 14 | Jenkins Config-as-Code Demo Scripts 15 | Initialization scripts for Jenkins Config-as-Code demo 16 | 1.0-SNAPSHOT 17 | 18 | 19 | 20 | 21 | org.codehaus.gmaven 22 | gmaven-plugin 23 | 1.5-jenkins-3 24 | 25 | 26 | org.codehaus.gmaven.runtime 27 | gmaven-runtime-1.8 28 | 1.5-jenkins-3 29 | 30 | 31 | 32 | 33 | 34 | compile 35 | testCompile 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | repo.jenkins-ci.org 46 | https://repo.jenkins-ci.org/public/ 47 | 48 | 49 | 50 | 51 | repo.jenkins-ci.org 52 | https://repo.jenkins-ci.org/public/ 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /init_scripts/src/main/groovy/PipelineLibrary.groovy: -------------------------------------------------------------------------------- 1 | import hudson.plugins.filesystem_scm.FSSCM 2 | import jenkins.plugins.git.GitSCMSource 3 | import org.jenkinsci.plugins.workflow.libs.GlobalLibraries 4 | import org.jenkinsci.plugins.workflow.libs.LibraryConfiguration 5 | import org.jenkinsci.plugins.workflow.libs.SCMRetriever 6 | import org.jenkinsci.plugins.workflow.libs.SCMSourceRetriever 7 | 8 | println("== Configuring the Jenkins Pipeline library") 9 | 10 | final LibraryConfiguration lc 11 | File file = new File("/var/jenkins_home/pipeline-library/vars") 12 | if (!file.exists()) { 13 | // TODO: change defaults once https://github.com/jenkins-infra/pipeline-library/pull/78 is merged 14 | def defaultPipelineLibRepo = "https://github.com/oleg-nenashev/pipeline-library" 15 | def defaultPipelineLibBranch = "jenkinsfile-runner-support" 16 | println("===== Using the Pipeline library from ${defaultPipelineLibRepo} ") 17 | // Include https://github.com/jenkins-infra/pipeline-library 18 | def pipelineLibrarySource = new GitSCMSource("pipeline-library", "${defaultPipelineLibRepo}.git", null, null, null, false) 19 | lc = new LibraryConfiguration("pipeline-library", new SCMSourceRetriever(pipelineLibrarySource)) 20 | lc.with { 21 | implicit = true 22 | defaultVersion = defaultPipelineLibBranch 23 | } 24 | GlobalLibraries.get().libraries.add(lc) 25 | } else { 26 | println("===== Adding local Pipeline libs") 27 | def scm = new FSSCM("/var/jenkins_home/pipeline-library", false, false, null) 28 | lc = new LibraryConfiguration("pipeline-library", new SCMRetriever(scm)) 29 | lc.with { 30 | implicit = true 31 | defaultVersion = "master" 32 | } 33 | } 34 | 35 | GlobalLibraries.get().libraries.add(lc) 36 | -------------------------------------------------------------------------------- /init_scripts/src/main/groovy/System.groovy: -------------------------------------------------------------------------------- 1 | import jenkins.model.Jenkins 2 | import jenkins.model.JenkinsLocationConfiguration 3 | import hudson.tasks.Mailer 4 | 5 | println("== Configuring the system...") 6 | 7 | // We do not wait for anything 8 | Jenkins.instance.quietPeriod = 0 9 | 10 | JenkinsLocationConfiguration.get().adminAddress = "admin@non.existent.email" 11 | Mailer.descriptor().defaultSuffix = "@non.existent.email" 12 | -------------------------------------------------------------------------------- /init_scripts/src/main/groovy/Tools.groovy: -------------------------------------------------------------------------------- 1 | 2 | import jenkins.model.Jenkins 3 | import hudson.model.JDK 4 | import hudson.tasks.Maven.MavenInstallation; 5 | import hudson.tasks.Maven 6 | 7 | println("== Configuring tools...") 8 | // By default we offer no JDK7, Nodes should override 9 | JDK jdk7 = new JDK("jdk7", "/non/existent/JVM") 10 | // Java 8 should be a default Java, because we require it for Jenkins 2.60.1+ 11 | JDK jdk8 = new JDK("jdk8", "") 12 | JDK jdk11 = new JDK("jdk11", "/usr/lib/jvm/jdk-11") 13 | Jenkins.instance.getDescriptorByType(JDK.DescriptorImpl.class).setInstallations(jdk7, jdk8, jdk11) 14 | 15 | MavenInstallation mvn = new MavenInstallation("mvn", null) 16 | Jenkins.instance.getDescriptorByType(Maven.DescriptorImpl.class).setInstallations(mvn) 17 | -------------------------------------------------------------------------------- /jenkins-dev.yaml: -------------------------------------------------------------------------------- 1 | jenkins: 2 | mode: NORMAL 3 | numExecutors: 1 4 | labelString: "linux" 5 | scmCheckoutRetryCount: 0 6 | myViewsTabBar: "standard" 7 | viewsTabBar: "standard" 8 | globalNodeProperties: 9 | - envVars: 10 | env: 11 | #TODO: Copies work 12 | - key: JFR_LOCAL_WORKSPACE 13 | value: /c/Users/Oleg/Documents/jenkins/jfr/ci.jenkins.io-runner/demo/locale-plugin/repo 14 | - key: PIPELINE_LIBRARY_SKIP_WINDOWS 15 | value: true 16 | - key: PIPELINE_LIBRARY_USE_DEFAULT_MAVEN_REPO 17 | value: true 18 | 19 | tool: 20 | git: 21 | installations: 22 | - home: "git" 23 | name: "Default" 24 | groovy: 25 | - file: "../../../init_scripts/src/main/groovy/System.groovy" 26 | - file: "../../../init_scripts/src/main/groovy/Tools.groovy" 27 | - file: "../../../init_scripts/src/main/groovy/PipelineLibrary.groovy" 28 | -------------------------------------------------------------------------------- /jenkins.yaml: -------------------------------------------------------------------------------- 1 | jenkins: 2 | mode: NORMAL 3 | numExecutors: 1 4 | labelString: "linux" 5 | scmCheckoutRetryCount: 0 6 | myViewsTabBar: "standard" 7 | viewsTabBar: "standard" 8 | globalNodeProperties: 9 | - envVars: 10 | env: 11 | - key: JFR_LOCAL_WORKSPACE 12 | value: /workspace 13 | - key: PIPELINE_LIBRARY_SKIP_WINDOWS 14 | value: true 15 | - key: PIPELINE_LIBRARY_USE_DEFAULT_MAVEN_REPO 16 | value: true 17 | tool: 18 | git: 19 | installations: 20 | - home: "git" 21 | name: "Default" 22 | # Works around https://github.com/jenkinsci/jenkinsfile-runner/issues/359 23 | groovy: 24 | - file: "/usr/share/jenkins/ref/init.groovy.d/System.groovy" 25 | - file: "/usr/share/jenkins/ref/init.groovy.d/Tools.groovy" 26 | - file: "/usr/share/jenkins/ref/init.groovy.d/PipelineLibrary.groovy" 27 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | io.jenkins.jenkinsfile-runner 9 | packaging-parent-pom 10 | 1.0-beta-19 11 | 12 | 13 | 14 | ci.jenkins.io.runner 15 | ci.jenkins.io Runner Plugins 16 | Jenkinsfile Runner reference implementation which emulates ci.jenkins.io 17 | 1.0-beta-19 18 | 19 | 20 | ci.jenkins.io-runner 21 | true 22 | 23 | 24 | 25 | 26 | Oleg Nenashev 27 | Jenkins project 28 | https://www.jenkins.io 29 | 30 | 31 | 32 | 33 | 34 | 35 | org.jenkinsci.plugins 36 | pipeline-model-definition 37 | 38 | 39 | org.jenkins-ci.plugins.workflow 40 | workflow-multibranch 41 | 42 | 43 | 44 | org.jenkins-ci.plugins 45 | cloudbees-folder 46 | 47 | 48 | org.jenkins-ci.plugins 49 | jsch 50 | 51 | 52 | org.jenkins-ci.plugins 53 | apache-httpcomponents-client-4-api 54 | 55 | 56 | org.jenkins-ci.plugins 57 | git 58 | 59 | 60 | com.github.kostyasha.yet-another-docker 61 | yet-another-docker-plugin 62 | 0.2.0 63 | 64 | 65 | org.jenkins-ci.plugins 66 | mailer 67 | 68 | 69 | hudson.plugins.filesystem_scm 70 | filesystem_scm 71 | 2.1 72 | 73 | 74 | org.jenkins-ci.plugins 75 | pipeline-utility-steps 76 | 2.6.1 77 | 78 | 79 | org.jenkins-ci.plugins 80 | pipeline-stage-step 81 | 82 | 83 | org.jenkins-ci.plugins 84 | junit 85 | 86 | 87 | org.jenkins-ci.plugins 88 | scm-api 89 | 90 | 91 | org.jenkins-ci.plugins 92 | ssh-credentials 93 | 94 | 95 | org.jenkins-ci.plugins 96 | credentials-binding 97 | 98 | 99 | org.jenkins-ci.plugins 100 | git 101 | 102 | 103 | org.jenkins-ci.plugins 104 | parameterized-trigger 105 | 2.35.1 106 | 107 | 108 | org.jenkins-ci.plugins 109 | timestamper 110 | 1.11.5 111 | 112 | 113 | org.jenkins-ci.plugins 114 | parallel-test-executor 115 | 1.13 116 | 117 | 118 | org.jenkins-ci.plugins 119 | email-ext 120 | 2.79 121 | 122 | 123 | org.jenkins-ci.plugins 124 | cobertura 125 | 1.16 126 | 127 | 128 | org.jenkins-ci.plugins 129 | jdk-tool 130 | 131 | 132 | io.jenkins 133 | configuration-as-code 134 | 135 | 136 | io.jenkins.plugins 137 | configuration-as-code-groovy 138 | 1.1 139 | 140 | 141 | org.jenkins-ci.main 142 | maven-plugin 143 | 3.6 144 | 145 | 146 | org.jenkins-ci.plugins 147 | docker-commons 148 | 1.17 149 | 150 | 151 | io.jenkins.plugins 152 | warnings-ng 153 | 8.2.0 154 | 155 | 156 | 157 | org.slf4j 158 | slf4j-api 159 | 1.7.30 160 | 161 | 162 | com.google.code.gson 163 | gson 164 | 2.8.6 165 | 166 | 167 | org.antlr 168 | antlr4-runtime 169 | 4.8-1 170 | 171 | 172 | commons-io 173 | commons-io 174 | 2.7 175 | 176 | 177 | org.apache.commons 178 | commons-lang3 179 | 3.11 180 | 181 | 182 | com.github.spotbugs 183 | spotbugs-annotations 184 | 4.1.3 185 | 186 | 187 | 188 | 189 | 190 | 191 | The MIT License (MIT) 192 | http://opensource.org/licenses/MIT 193 | repo 194 | 195 | 196 | 197 | 198 | 199 | repo.jenkins-ci.org 200 | https://repo.jenkins-ci.org/public/ 201 | 202 | 203 | 204 | 205 | repo.jenkins-ci.org 206 | https://repo.jenkins-ci.org/public/ 207 | 208 | 209 | 210 | 211 | --------------------------------------------------------------------------------