├── jenkins ├── workflow-version.txt ├── jenkins_home │ ├── org.jenkinsci.plugins.workflow.flow.FlowExecutionList.xml │ ├── org.jenkinsci.plugins.workflow.support.steps.StageStep.xml │ ├── hudson.model.UpdateCenter.xml │ ├── hudson.tasks.Maven.xml │ ├── hudson.plugins.git.GitTool.xml │ ├── scriptApproval.xml │ ├── nodeMonitors.xml │ ├── config.xml │ ├── jobs │ │ ├── freestylebuild │ │ │ └── config.xml │ │ └── wf-build │ │ │ └── config.xml │ └── gerrit-trigger.xml ├── demo_key_rsa.pub ├── plugins.txt ├── Dockerfile └── demo_key_rsa ├── gerrit ├── repos │ ├── primary │ │ ├── output.txt │ │ ├── src │ │ │ ├── test │ │ │ │ └── java │ │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── app │ │ │ │ │ └── AppTest.java │ │ │ └── main │ │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── app │ │ │ │ └── App.java │ │ └── pom.xml │ ├── secondary │ │ ├── test.txt │ │ ├── src │ │ │ ├── test │ │ │ │ └── java │ │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── app │ │ │ │ │ └── AppTest.java │ │ │ └── main │ │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── app │ │ │ │ └── App.java │ │ └── pom.xml │ ├── umbrella │ │ ├── default.xml │ │ └── jenkins.xml │ └── workflow │ │ └── demoscript.groovy ├── ReviewDB.h2.db └── Dockerfile ├── util └── copy_docker_db.sh ├── start.sh ├── docker-compose.yml ├── testme.sh ├── config-gerrit-mac.sh ├── config-gerrit.sh ├── .gitignore ├── demoscript-rawgerrit.groovy ├── demoscript.groovy ├── lessons.md ├── README.md └── LICENSE /jenkins/workflow-version.txt: -------------------------------------------------------------------------------- 1 | 1.10 -------------------------------------------------------------------------------- /gerrit/repos/primary/output.txt: -------------------------------------------------------------------------------- 1 | sample text 2 | -------------------------------------------------------------------------------- /gerrit/repos/secondary/test.txt: -------------------------------------------------------------------------------- 1 | SDUO$!@#" 2 | -------------------------------------------------------------------------------- /gerrit/ReviewDB.h2.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svanoort/gerrit-workflow-demo/HEAD/gerrit/ReviewDB.h2.db -------------------------------------------------------------------------------- /jenkins/jenkins_home/org.jenkinsci.plugins.workflow.flow.FlowExecutionList.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /jenkins/jenkins_home/org.jenkinsci.plugins.workflow.support.steps.StageStep.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /jenkins/jenkins_home/hudson.model.UpdateCenter.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | default 5 | http://updates.jenkins-ci.org/update-center.json 6 | 7 | -------------------------------------------------------------------------------- /util/copy_docker_db.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Assuming you're running docker natively, copy the review db to local copy 4 | sudo docker cp gerrit:/var/gerrit/db/ReviewDB.h2.db gerrit/ReviewDB.h2.db 5 | sudo chown "$USER":"$USER" gerrit/ReviewDB.h2.db -------------------------------------------------------------------------------- /start.sh: -------------------------------------------------------------------------------- 1 | # Starts both containers in daemon mode 2 | docker rm -f gerrit && docker rm -f jenkins 3 | docker run -d -h gerrit -p 8080:8080 -p 29418:29418 --name gerrit jenkins-gerrit-wfdemo-gerrit:1.0 4 | docker run -d -h jenkins -p 8081:8080 --name jenkins --link gerrit:gerrit jenkins-gerrit-wfdemo-jenkins:1.0 5 | -------------------------------------------------------------------------------- /jenkins/jenkins_home/hudson.tasks.Maven.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Maven 3.x 6 | /usr/local/maven 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /jenkins/demo_key_rsa.pub: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDVAg824XdUvLJimi6a3ey6+lDxYJy0HC3+/3V+IVj30vuNvMwqSMsRb/7aTmcxtetLe0vJhBbUsVoJxK4M8MW9CFMiYP7gKnMcoVoZxrGbQTwt0eAdKZCMIXXWmacQ7Lpy277dNj1dsxSNVde+2fEKeiSlBKjI54StioSuxEQngy5/mQzX35xAvya+XH+UApkERbinR6xZtbl7AdKZgEGnNrW54e3UrVJMw5ry3X9+n2e77BJzA2Q7ZiPOcmARXUbRAP+3YL9yvQaITu33w8cH4+oKO4GB9+SeLfuQS0jElObHC3+HPViGcpah2H1cZkniJZ/j7IWMi8IssBhsuvSp demouser@example.com 2 | -------------------------------------------------------------------------------- /jenkins/jenkins_home/hudson.plugins.git.GitTool.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Default 6 | git 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /gerrit/repos/umbrella/default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /gerrit/repos/umbrella/jenkins.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /gerrit/repos/secondary/src/test/java/com/example/app/AppTest.java: -------------------------------------------------------------------------------- 1 | package com.example.app; 2 | 3 | 4 | import org.junit.Test; 5 | 6 | import static org.junit.Assert.fail; 7 | 8 | /** 9 | * Testcase that always fail after 15 sec so this build will crash unless tests are skipped 10 | */ 11 | public class AppTest { 12 | 13 | @Test 14 | public void fails() throws Exception { 15 | Thread.sleep(15000); 16 | fail("Always fails"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /jenkins/jenkins_home/scriptApproval.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | method groovy.lang.GroovyObject invokeMethod java.lang.String java.lang.Object 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | gerrit: 2 | container_name: gerrit 3 | hostname: gerrit 4 | build: ./gerrit 5 | ports: 6 | - "8080:8080" 7 | - "29418:29418" 8 | 9 | jenkins: 10 | container_name: jenkins 11 | build: ./jenkins 12 | hostname: jenkins 13 | links: 14 | - gerrit 15 | ports: 16 | - "8081:8080" 17 | # Use caution when mountaining the home directory as a volume 18 | # Repo will fail to init, and performance issues may occur 19 | # volumes: 20 | # - ./jenkins/jenkins_home:/var/jenkins_home 21 | -------------------------------------------------------------------------------- /gerrit/repos/secondary/src/main/java/com/example/app/App.java: -------------------------------------------------------------------------------- 1 | package com.example.app; 2 | 3 | /** 4 | * Generates arguments for invoking the string generator in primary project 5 | */ 6 | public class App 7 | { 8 | public static void main( String[] args ) { 9 | // TWO MODES: normal and legacy 10 | StringBuilder output = new StringBuilder() 11 | .append(" -d 10") 12 | // .append("-n") //Unsupported 13 | .append(" -l 50"); 14 | System.out.println(output); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /testme.sh: -------------------------------------------------------------------------------- 1 | # Debugging use, runs removable containers in interactive mode if needed 2 | 3 | sudo docker run -h gerrit -i -t --rm=true --name gerrit -p 8080:8080 -p 29418:29418 jenkins-gerrit-wfdemo-gerrit:1.0 /bin/bash 4 | 5 | # Note when you run jenkins this way, something in the volumes means you have to run /usr/local/bin/jenkins.sh 6 | # Twice (killing java in between) 7 | # NOTE: using Jenkins home in a volume will interact poorly with gerrit 8 | sudo docker run -h jenkins -i -t --rm=true -v `pwd`/jenkins/jenkins_home:/var/jenkins_home -p 8081:8080 --name jenkins --link gerrit:gerrit jenkins-gerrit-wfdemo-jenkins:1.0 /bin/bash 9 | -------------------------------------------------------------------------------- /config-gerrit-mac.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | USERNAME="`git config user.name`" 3 | EMAIL="`git config user.email`" 4 | USERNAME="$USER" 5 | HTTP_PASS=goober 6 | FULLNAME="`git config user.name`" 7 | 8 | # Fixes issues with repo url getting wrong username, since it uses local part of 9 | # email for SSH username 10 | git config --global review.http://gerrit:8080/.username $USER 11 | chmod 400 jenkins/demo_key_rsa 12 | cat ~/.ssh/id_rsa.pub | ssh -i jenkins/demo_key_rsa -p 29418 demouser@gerrit \ 13 | gerrit create-account --group Workers --group \"Non-Interactive Users\" --full-name \"$FULLNAME\" --email \"$EMAIL\" --http-password \"$HTTP_PASS\" --ssh-key - $USERNAME -------------------------------------------------------------------------------- /config-gerrit.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | USERNAME="`git config user.name`" 3 | EMAIL="`git config user.email`" 4 | USERNAME="$USER" 5 | HTTP_PASS=goober 6 | FULLNAME="`git config user.name`" 7 | 8 | # Fixes issues with repo url getting wrong username, since it uses local part of 9 | # email for SSH username 10 | git config --global review.http://localhost:8080/.username $USER 11 | chmod 400 jenkins/demo_key_rsa 12 | cat ~/.ssh/id_rsa.pub | ssh -i jenkins/demo_key_rsa -p 29418 demouser@localhost \ 13 | gerrit create-account --group Workers --group \"Non-Interactive Users\" --full-name \"$FULLNAME\" --email \"$EMAIL\" --http-password \"$HTTP_PASS\" --ssh-key - $USERNAME -------------------------------------------------------------------------------- /jenkins/plugins.txt: -------------------------------------------------------------------------------- 1 | branch-api:0.2-beta-4 2 | durable-task:1.6 3 | gerrit-trigger:2.15.1 4 | git:2.3.5 5 | git-client:1.17.0 6 | git-server:1.6 7 | javadoc:1.3 8 | junit:1.5 9 | mailer:1.15 10 | mapdb-api:1.0.6.0 11 | mercurial:1.54 12 | scm-api:0.2 13 | script-security:1.15 14 | subversion:2.5 15 | workflow-aggregator:@VERSION@ 16 | workflow-api:@VERSION@ 17 | workflow-basic-steps:@VERSION@ 18 | workflow-cps:@VERSION@ 19 | workflow-cps-global-lib:@VERSION@ 20 | workflow-durable-task-step:@VERSION@ 21 | workflow-job:@VERSION@ 22 | workflow-multibranch:1.9-beta-2 23 | workflow-scm-step:@VERSION@ 24 | workflow-step-api:@VERSION@ 25 | workflow-support:@VERSION@ 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | 4 | # Mobile Tools for Java (J2ME) 5 | .mtj.tmp/ 6 | 7 | # Package Files # 8 | *.jar 9 | *.war 10 | *.ear 11 | 12 | # Java build and projects 13 | target/ 14 | *.iml 15 | .eclipse 16 | .idea/ 17 | 18 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 19 | hs_err_pid* 20 | 21 | # Jenkins unneeded data 22 | plugins/ 23 | .java/ 24 | war/ 25 | userContent/ 26 | updates/ 27 | secrets/ 28 | nodes/ 29 | builds/ 30 | jenkins/jenkins_home/init.groovy.d/ 31 | .bashrc 32 | .* 33 | *.bak 34 | *.log 35 | *.key* 36 | jobs/*/last* 37 | nextBuildNumber 38 | lastStable 39 | lastSuccessful 40 | workspace/ 41 | workspace*/ 42 | queue.xml -------------------------------------------------------------------------------- /gerrit/repos/primary/src/test/java/com/example/app/AppTest.java: -------------------------------------------------------------------------------- 1 | package com.example.app; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.Arrays; 6 | import java.util.HashSet; 7 | 8 | import static org.junit.Assert.*; 9 | 10 | /** 11 | * Basic unit tests for command generation 12 | */ 13 | public class AppTest { 14 | 15 | @Test 16 | public void testRandomStrings() throws Exception { 17 | String chars = "ABCDEDF"; 18 | String output = App.randomString(chars, 10); 19 | assertEquals(10, output.length()); 20 | 21 | // Check output 22 | HashSet validChars = new HashSet(); 23 | for (char v : chars.toCharArray()) { 24 | validChars.add(v); 25 | } 26 | 27 | for (char v : output.toCharArray()) { 28 | assertTrue(validChars.contains(new Character(v))); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /jenkins/jenkins_home/nodeMonitors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | 7 | false 8 | 9 | 10 | false 11 | 1GB 12 | 13 | 14 | false 15 | 16 | 17 | false 18 | 1GB 19 | 20 | 21 | false 22 | 23 | -------------------------------------------------------------------------------- /gerrit/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM gerritforge/gerrit-ubuntu15.04:2.11.3 2 | MAINTAINER svanoort 3 | 4 | USER root 5 | RUN apt-get update && \ 6 | apt-get install -y curl python net-tools && \ 7 | rm -rf /var/lib/apt/lists/* 8 | RUN curl https://storage.googleapis.com/git-repo-downloads/repo > /bin/repo \ 9 | && chmod a+x /bin/repo 10 | 11 | COPY ReviewDB.h2.db /var/gerrit/db/ReviewDB.h2.db 12 | COPY repos /tmp/repos-wc 13 | RUN chown -R gerrit:gerrit /tmp/repos-wc var/gerrit/db/ReviewDB.h2.db 14 | 15 | USER gerrit 16 | RUN git config --global user.email "demouser@example.com" && \ 17 | git config --global user.name "Demo User" 18 | 19 | # This is how we save gerrit user/project configuration 20 | 21 | # Create repo working copies & then do bare clones to expose for work 22 | RUN cd /tmp/repos-wc && mkdir /tmp/repos && \ 23 | for r in primary secondary umbrella workflow; do ( \ 24 | cd $r; git init && git add . && git commit -am "Initial commit"; \ 25 | git clone --bare /tmp/repos-wc/$r /var/gerrit/git/$r.git; \ 26 | ); done; 27 | 28 | CMD /var/gerrit/bin/gerrit.sh start && tail -f /var/gerrit/logs/error_log 29 | 30 | # Docker doesn't set this to user home by default 31 | ENV HOME /var/gerrit 32 | -------------------------------------------------------------------------------- /jenkins/jenkins_home/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1.609.2 5 | 4 6 | NORMAL 7 | true 8 | 9 | 10 | false 11 | 12 | ${ITEM_ROOTDIR}/workspace 13 | ${ITEM_ROOTDIR}/builds 14 | 15 | 16 | 17 | 18 | 1 19 | 0 20 | 21 | 22 | 23 | All 24 | false 25 | false 26 | 27 | 28 | 29 | All 30 | 50000 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /jenkins/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jenkins:1.609.2 2 | MAINTAINER svanoort 3 | 4 | # Workflow demo, jenkins host setup 5 | 6 | USER root 7 | ENV JENKINS_UC http://jenkins-updates.cloudbees.com 8 | 9 | # Google repo install 10 | RUN apt-get install -y curl python && \ 11 | rm -rf /var/lib/apt/lists/* 12 | RUN curl https://storage.googleapis.com/git-repo-downloads/repo > /bin/repo \ 13 | && chmod a+x /bin/repo 14 | 15 | # Maven install 16 | ENV MAVEN_VERSION 3.3.9 17 | RUN cd /usr/local; wget -O - http://mirrors.ibiblio.org/apache/maven/maven-3/$MAVEN_VERSION/binaries/apache-maven-$MAVEN_VERSION-bin.tar.gz | tar xvzf - 18 | RUN ln -sv /usr/local/apache-maven-$MAVEN_VERSION /usr/local/maven 19 | 20 | # Keys for gerrit user, passphrase is EMPTY 21 | COPY demo_key_rsa /tmp/ 22 | COPY workflow-version.txt /tmp/ 23 | COPY plugins.txt /tmp/ 24 | RUN sed -i "s/@VERSION@/`cat /tmp/workflow-version.txt`/g" /tmp/plugins.txt 25 | RUN chown jenkins:jenkins /tmp/demo_key_rsa 26 | 27 | # Set up jenkins home folder for starting point 28 | ADD jenkins_home /usr/share/jenkins/ref 29 | RUN chown -R jenkins.jenkins /usr/share/jenkins/ref 30 | 31 | USER jenkins 32 | RUN /usr/local/bin/plugins.sh /tmp/plugins.txt 33 | CMD /usr/local/bin/jenkins.sh 34 | 35 | # Fix for issues with the 'repo' tool needing an ident 36 | RUN git config --global user.email "demouser@example.com" && \ 37 | git config --global user.name "Demo User" 38 | 39 | # COPY KEYS FOR USER TO JENKINS DIR 40 | EXPOSE 8080 -------------------------------------------------------------------------------- /jenkins/jenkins_home/jobs/freestylebuild/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | freestyle parallel build 5 | false 6 | 7 | 8 | 9 | 10 | sample 11 | 12 | noparam 13 | 14 | 15 | 16 | 17 | hour 18 | 0 19 | 20 | 21 | 22 | true 23 | false 24 | false 25 | false 26 | 27 | false 28 | 29 | 30 | echo "$sample" 31 | rm -rf sources 32 | mkdir sources 33 | cd sources 34 | sleep 30 35 | repo init -u http://gerrit:8080/umbrella -m jenkins.xml 36 | repo sync 37 | /usr/local/maven/bin/mvn clean compile install -Dmaven.test.skip -f primary/pom.xml 38 | /usr/local/maven/bin/mvn clean compile install -Dmaven.test.skip -f secondary/pom.xml 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /jenkins/demo_key_rsa: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEogIBAAKCAQEA1QIPNuF3VLyyYpoumt3suvpQ8WCctBwt/v91fiFY99L7jbzM 3 | KkjLEW/+2k5nMbXrS3tLyYQW1LFaCcSuDPDFvQhTImD+4CpzHKFaGcaxm0E8LdHg 4 | HSmQjCF11pmnEOy6ctu+3TY9XbMUjVXXvtnxCnokpQSoyOeErYqErsREJ4Muf5kM 5 | 19+cQL8mvlx/lAKZBEW4p0esWbW5ewHSmYBBpza1ueHt1K1STMOa8t1/fp9nu+wS 6 | cwNkO2YjznJgEV1G0QD/t2C/cr0GiE7t98PHB+PqCjuBgffkni37kEtIxJTmxwt/ 7 | hz1YhnKWodh9XGZJ4iWf4+yFjIvCLLAYbLr0qQIDAQABAoIBAAK67AcADM+BO6gX 8 | 4dEKVyZuXus5GckVM2G5VIAxXTqP8bl3WgaQuEmY7eNObfQtKL7m7am/j6taOpU1 9 | eCWiUGaD3MzsAVhOMvuC9eyup0geJe9QaVb2WWvyYdhGT+XfouQl/ORI9bBlwzWs 10 | i/9eO8CuoBmdXax1izXOOLUkvtrixZFY/3AuaFZ446yGF3ZX9Y9LwseenkwxRBr5 11 | gn/u0lcJkjnCTApRC9K8rN58bPH1PzMNdJmYvf4xtKM6hqkbfVxi4f7jinf97lyo 12 | oewGJa6e+rqCS6E7wUwIzyehmGiV73kkOXM584DTIgaXqhtUj3EPQBkvLZx/jYAz 13 | rK6I86ECgYEA6ZhOXyY3/buaYAcWUm1KTlH1hrWJjgVn5xvZ4QWD/VoycmfA54N4 14 | YrGnPUSgdBey5jNrp3w7ZYEz6e3u0Qk/l8uaaDL6yFrjY1ISaXubVhfsds3rY4P+ 15 | ykUmOVb8W6i++i1Guy8kXTrc19M3eiKaRxJ6Rbj8OIWZEMCJGmToVfcCgYEA6XBD 16 | H+zTWMQo/5SaS36q6WZUcE321FRv3UUQVRmtjhif6ojTrSPFWbqndRkeveApGwq9 17 | eeGl/J0H6lqsbjqpHzYWoLrJg20Pxv53duAZSumrdThX/6jTwqP4KH1Yqp2PM5Y0 18 | ISi8uJ7lVXF3WhWht/Sjr15b8bJ6nf4Ub/KZ4l8CgYBisF4sBNGS+Td3aocbu+Cw 19 | xh+dEgVTYyVKlpGuZ84js3+spfjx1rF9wOCPGfdQFNMYPpE06V+Ous9b/ZHv7qBX 20 | WUWa0C7zhrKau4nb1sUB0omsh8LzAEkc26oSf5WOg/RrbcV8P6Z1XPEAndPKXeQg 21 | MsZFvqmQl6DbWvyRkiA2cQKBgCKrFnz2SgkD0ObsJeISZMWW+fFX0tGD3L0q1Zsd 22 | 3iWdSJqnSXCMQHHsA5Sjb2pZkSE//hXMyj7y/0rxvmv8cEN/X+rs8qJ/Hvm5rvpL 23 | m9YBUAJvpLoGU7Szb1ZsDy//iFXr97/48dYlWv/OgyAw2Dyeq3SO+e6yR/2Qz240 24 | xF/XAoGAJJ5fofDlo/tBqDxcSQqYTmj1JnoBilzuzWF49+ilIL/vd6WA5Rn/P5+q 25 | 4+o2Z9VHw5J9VejKPbl7F8qTeQh0as0eTXUXeMBxYbnmdoyZwcv7rlj0riVndzqN 26 | 3F7KhwevTZWeDzS95yAm+WNPnVohRB5xrfWMfXmbQultC9V4uPM= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /gerrit/repos/secondary/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | com.example.app 5 | secondary 6 | jar 7 | 1.0-SNAPSHOT 8 | secondary 9 | http://maven.apache.org 10 | 11 | 12 | junit 13 | junit 14 | 4.11 15 | test 16 | 17 | 18 | commons-cli 19 | commons-cli 20 | 1.3.1 21 | 22 | 23 | 24 | 25 | 26 | org.apache.maven.plugins 27 | maven-assembly-plugin 28 | 2.4.1 29 | 30 | 31 | jar-with-dependencies 32 | 33 | 34 | 35 | com.example.app.App 36 | 37 | 38 | false 39 | 40 | 41 | 42 | make-assembly 43 | 44 | package 45 | 46 | single 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /gerrit/repos/primary/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | com.example.app 5 | primary 6 | jar 7 | 1.0-SNAPSHOT 8 | primary 9 | http://maven.apache.org 10 | 11 | 12 | junit 13 | junit 14 | 4.11 15 | test 16 | 17 | 18 | commons-cli 19 | commons-cli 20 | 1.3.1 21 | compile 22 | 23 | 24 | 25 | 26 | 27 | 28 | org.apache.maven.plugins 29 | maven-assembly-plugin 30 | 2.4.1 31 | 32 | 33 | jar-with-dependencies 34 | 35 | 36 | 37 | com.example.app.App 38 | 39 | 40 | false 41 | 42 | 43 | 44 | make-assembly 45 | 46 | package 47 | 48 | single 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /demoscript-rawgerrit.groovy: -------------------------------------------------------------------------------- 1 | // Run this with mvn args on each node 2 | def mvn(args) { 3 | sh "${tool 'Maven 3.x'}/bin/mvn ${args}" 4 | } 5 | 6 | def fetch_repo() { 7 | // def changeBranch = "change-${GERRIT_CHANGE_NUMBER}-${GERRIT_PATCHSET_NUMBER}" 8 | // sh 'git clone http://gerrit:8080/primary' 9 | // sh 'git clone http://gerrit:8080/secondary' 10 | sh 'repo init stuff' 11 | sh "cd $GERRIT_PROJECT" 12 | sh "git checkout git fetch origin ${GERRIT_REFSPEC}:${changeBranch}" 13 | sh "git checkout ${changeBranch}" 14 | sh "cd .." 15 | } 16 | 17 | // TOOD patchset use 18 | // TODO supply branch name to script for easy customization 19 | 20 | def builds = [:] 21 | builds['workflowrun'] = { 22 | node { 23 | sh 'rm -rf source' 24 | // Remove dir component in 1.11, replaced with deletedir 25 | dir ('source') { 26 | fetch_repo() 27 | mvn("clean compile install -f primary/pom.xml") 28 | mvn("clean compile install -Dmaven.test.skip -f secondary/pom.xml") 29 | sh "mv */target/*.jar ." 30 | stash includes: '*.jar', name: 'jars' 31 | } 32 | } 33 | 34 | def slowtests = [:] 35 | slowtests['Functional Tests'] = { 36 | node { 37 | // Fetch both artifacts 38 | unstash name:'jars' 39 | sleep 2 40 | 41 | // Verify both jars can run successfully 42 | sh 'java -jar primary*.jar -delay 1 --length 100' 43 | sh 'java -jar secondary*.jar' 44 | } 45 | } 46 | slowtests['Integration tests'] = { 47 | node { 48 | sleep 30 49 | unstash name:'jars' 50 | sh 'java -jar primary*.jar `java -jar secondary*.jar`' 51 | } 52 | } 53 | slowtests['failFast'] = true 54 | parallel slowtests 55 | } 56 | 57 | // PARALLEL BUILD STEP 58 | builds['parallelbuild'] = { 59 | build job: 'freestylebuild-sample', parameters: [[$class: 'StringParameterValue', name: 'sample', value: 'val']] 60 | } 61 | 62 | builds['failFast'] = true 63 | parallel builds -------------------------------------------------------------------------------- /demoscript.groovy: -------------------------------------------------------------------------------- 1 | // Run this with mvn args on each node 2 | def mvn(args) { 3 | sh "${tool 'Maven 3.x'}/bin/mvn ${args}" 4 | } 5 | 6 | def fetch_repo() { 7 | sh 'repo init -u http://gerrit:8080/umbrella -m jenkins.xml' 8 | sh 'repo sync' 9 | sh "repo download $GERRIT_PROJECT $GERRIT_CHANGE_NUMBER/$GERRIT_PATCHSET_NUMBER" 10 | } 11 | 12 | // Builds are defined before being run! 13 | // We are building up a set of parallel pipelines, one using workflow for build + 14 | //builds... they're defined first as a name : {block} pairs, then run by 'parallel' DSL step 15 | def builds = [:] 16 | // Core build/run inlined with workflow 17 | builds['workflowrun'] = { 18 | node { 19 | sh 'rm -rf source' 20 | // Remove dir component in 1.11, replaced with deletedir 21 | dir ('source') { 22 | fetch_repo() 23 | mvn("clean compile install -f primary/pom.xml") 24 | mvn("clean compile install -Dmaven.test.skip -f secondary/pom.xml") 25 | sh "mv */target/*.jar ." 26 | stash includes: '*.jar', name: 'jars' 27 | } 28 | } 29 | 30 | // Set of tests that run slowly and are run in parallel for speed 31 | def slowtests = [:] 32 | 33 | // Fast functional tests run in parallel with slower integration tests 34 | slowtests['Functional Tests'] = { 35 | node { 36 | // Fetch both artifacts 37 | unstash name:'jars' 38 | sleep 2 39 | 40 | // Verify both jars can run successfully 41 | sh 'java -jar primary*.jar -delay 1 --length 100' 42 | sh 'java -jar secondary*.jar' 43 | } 44 | } 45 | 46 | // Slower integration tests that are run 47 | slowtests['Integration tests'] = { 48 | node { 49 | sleep 15 50 | unstash name:'jars' 51 | sh 'java -jar primary*.jar `java -jar secondary*.jar`' 52 | } 53 | } 54 | slowtests['failFast'] = true 55 | parallel slowtests // This is where it actually will run this step when block is executed 56 | } 57 | 58 | // PARALLEL NESTED PIPE 59 | builds['parallelbuild'] = { 60 | build job: 'freestylebuild', parameters: [[$class: 'StringParameterValue', name: 'sample', value: 'val']] 61 | } 62 | 63 | builds['failFast'] = true 64 | parallel builds // This is where the block is finally run -------------------------------------------------------------------------------- /gerrit/repos/workflow/demoscript.groovy: -------------------------------------------------------------------------------- 1 | // Run this with mvn args on each node 2 | def mvn(args) { 3 | sh "${tool 'Maven 3.x'}/bin/mvn ${args}" 4 | } 5 | 6 | def fetch_repo() { 7 | sh 'repo init -u http://gerrit:8080/umbrella -m jenkins.xml' 8 | sh 'repo sync' 9 | sh "repo download $GERRIT_PROJECT $GERRIT_CHANGE_NUMBER/$GERRIT_PATCHSET_NUMBER" 10 | } 11 | 12 | // Builds are defined before being run! 13 | // We are building up a set of parallel pipelines, one using workflow for build + 14 | //builds... they're defined first as a name : {block} pairs, then run by 'parallel' DSL step 15 | def builds = [:] 16 | // Core build/run inlined with workflow 17 | builds['workflowrun'] = { 18 | node { 19 | sh 'rm -rf source' 20 | // Remove dir component in 1.11, replaced with deletedir 21 | dir ('source') { 22 | fetch_repo() 23 | mvn("clean compile install -f primary/pom.xml") 24 | mvn("clean compile install -Dmaven.test.skip -f secondary/pom.xml") 25 | sh "mv */target/*.jar ." 26 | stash includes: '*.jar', name: 'jars' 27 | } 28 | } 29 | 30 | // Set of tests that run slowly and are run in parallel for speed 31 | def slowtests = [:] 32 | 33 | // Fast functional tests run in parallel with slower integration tests 34 | slowtests['Functional Tests'] = { 35 | node { 36 | // Fetch both artifacts 37 | unstash name:'jars' 38 | sleep 2 39 | 40 | // Verify both jars can run successfully 41 | sh 'java -jar primary*.jar -delay 1 --length 100' 42 | sh 'java -jar secondary*.jar' 43 | } 44 | } 45 | 46 | // Slower integration tests that are run 47 | slowtests['Integration tests'] = { 48 | node { 49 | sleep 15 50 | unstash name:'jars' 51 | sh 'java -jar primary*.jar `java -jar secondary*.jar`' 52 | } 53 | } 54 | slowtests['failFast'] = true 55 | parallel slowtests // This is where it actually will run this step when block is executed 56 | } 57 | 58 | // PARALLEL NESTED PIPE 59 | builds['parallelbuild'] = { 60 | build job: 'freestylebuild', parameters: [[$class: 'StringParameterValue', name: 'sample', value: 'val']] 61 | } 62 | 63 | builds['failFast'] = true 64 | parallel builds // This is where the block is finally run -------------------------------------------------------------------------------- /gerrit/repos/primary/src/main/java/com/example/app/App.java: -------------------------------------------------------------------------------- 1 | package com.example.app; 2 | 3 | import org.apache.commons.cli.CommandLine; 4 | import org.apache.commons.cli.CommandLineParser; 5 | import org.apache.commons.cli.DefaultParser; 6 | import org.apache.commons.cli.HelpFormatter; 7 | import org.apache.commons.cli.Options; 8 | 9 | import java.lang.Character; 10 | import java.nio.charset.Charset; 11 | import java.util.Random; 12 | 13 | /** 14 | * Generate random string content from command line and return output 15 | * Adds a configurable delay (default 1 sec) 16 | */ 17 | public class App { 18 | 19 | public static String randomString(String chars, int length) { 20 | Random rand = new Random(); 21 | StringBuilder buf = new StringBuilder(); 22 | for (int i=0; i Gerrit Trigger > edit next to server name > Advanced button at bottom 16 | - Under "Gerrit Verified Commands" remove the "--verified " section from each and it won't send this (just normal code review vote) 17 | 18 | # Repo problems 19 | 20 | ## Problem: repo behaves eratically if the old .repo folder is not removed 21 | * Solution: rm and recreate the folder every time (using sh rm and the workflow dir step, or shell) 22 | 23 | ## Problem: repo needs a git user configured to init a repo 24 | * Solution: configure a local git user for jenkins user, in the Dockerfile 25 | 26 | ## Problem: By default repo sets the SSH user name used to upload to gerrit using committer email and not username 27 | * Solution: Explicitly Set the Reviewer username for the review URL 28 | - 'git config --global review.http://reviewhost:8080/.username $USER' 29 | - http://stackoverflow.com/questions/11804469/debugging-repo-upload-problems-permission-denied-publickey 30 | - See: config-gerrit.sh 31 | 32 | ## Problem: On Init, repo will try to fetch content from googlesource if this fails it will not work 33 | * Solution: ensure you have external connectivity to https://gerrit.googlesource.com/git-repo/clone.bundle 34 | * Possible other solution: use the --repo-url argument to point it at a local repo, and clone from there 35 | - See: http://stackoverflow.com/questions/18895382/how-to-repo-init-on-a-disconnected-system 36 | 37 | ## Problem: repo init will fail if Jenkins Home is mounted as a Docker volume 38 | * Solution: don't mount it as a volume, repo installs hooks using symlinks in a way that is not compatible with Docker volumes 39 | 40 | 41 | # Dockerizing problems 42 | 43 | ## Problem: gerrit needs to have a user configured for jenkins & baked into the image in order for the jenkins gerrit trigger to work 44 | * Solution: create the user in a Gerrit container and copy in the DB into your container 45 | - This is conveniently set up in: util/copy_docker_db.sh - see gerrit/Dockerfile for the COPY 46 | 47 | ## Problem: Jenkins Gerrit Trigger Needs a User With Stream Event Permissions, which are not on by default 48 | * For an unDockerized Gerrit config, you'd simply create a new group "Streaming Events Users", add the jenkins user to it, and add give that group permission for streaming events in Projects > All Projects > Access within Gerrit UI 49 | * For Dockerized configs, the "All Projects" access configuration is in a git repo in gerrit, and landing the configuration for this repo within your gerrit container is a problem 50 | 51 | * Solution: Add the jenkins user to group "Non-Interactive Users" which has the Stream Events permission by default 52 | 53 | ## Problem: Jenkins needs consistent hostname for the gerrit container to speak to it 54 | * Solution: Explicitly set names for containers 55 | 56 | ## Problem: How do I preload git repos into my gerrit container? It has its own git stores under $GERRIT_BASE/git/ 57 | * Solution: you can simply do `git clone --bare` for your repos while gerrit isn't running, when gerrit starts it'll pick them up -------------------------------------------------------------------------------- /jenkins/jenkins_home/jobs/wf-build/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Main workflow build! 5 | 6 | -1 7 | 4 8 | -1 9 | -1 10 | 11 | false 12 | 13 | 14 | hour 15 | 0 16 | 17 | 18 | 19 | 20 | 2 21 | 22 | 23 | http://gerrit:8080/workflow.git 24 | 25 | 26 | 27 | 28 | */master 29 | 30 | 31 | false 32 | 33 | 34 | 35 | demoscript.groovy 36 | 37 | 38 | 39 | 40 | 41 | 42 | REG_EXP 43 | .* 44 | 45 | 46 | REG_EXP 47 | .* 48 | 49 | 50 | 51 | 52 | 53 | false 54 | false 55 | false 56 | false 57 | 58 | false 59 | 60 | false 61 | true 62 | false 63 | 64 | false 65 | 66 | 67 | 68 | 69 | 70 | 71 | local 72 | 73 | 74 | false 75 | false 76 | false 77 | 78 | 79 | false 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /jenkins/jenkins_home/gerrit-trigger.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | local 6 | false 7 | 8 | gerrit 9 | 29418 10 | 11 | demouser 12 | demouser@example.com 13 | /tmp/demo_key_rsa 14 | geQ0/Xw/RKYdz242QyVsRg== 15 | false 16 | false 17 | false 18 | gerrit review <CHANGE>,<PATCHSET> --message 'Build Successful <BUILDS_STATS>' --code-review <CODE_REVIEW> 19 | gerrit review <CHANGE>,<PATCHSET> --message 'Build Unstable <BUILDS_STATS>' --code-review <CODE_REVIEW> 20 | gerrit review <CHANGE>,<PATCHSET> --message 'Build Failed <BUILDS_STATS>' --code-review <CODE_REVIEW> 21 | gerrit review <CHANGE>,<PATCHSET> --message 'Build Started <BUILDURL> <STARTED_STATS>' --code-review <CODE_REVIEW> 22 | gerrit review <CHANGE>,<PATCHSET> --message 'No Builds Executed <BUILDS_STATS>' --code-review <CODE_REVIEW> 23 | http://gerrit:8080/ 24 | 0 25 | 0 26 | 1 27 | 1 28 | -1 29 | -1 30 | 0 31 | -1 32 | 0 33 | 0 34 | true 35 | true 36 | 3 37 | 30 38 | true 39 | 3600 40 | 0 41 | 42 | 43 | CRVW 44 | Code Review 45 | 46 | 47 | VRIF 48 | Verified 49 | 50 | 51 | 52 | false 53 | 54 | false 55 | 56 | 2 57 | 58 | 59 | 60 | 61 | ALL 62 | 63 | true 64 | false 65 | false 66 | 67 | 68 | 69 | 70 | 71 | 3 72 | 1 73 | 360 74 | 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gerrit-workflow-demo 2 | Demo of Dockerized gerrit/jenkins workflow functionality 3 | 4 | # What? 5 | * Dockerized demonstration of an integrated Jenkins/Gerrit environment, using Jenkins workflow to construct a build/test pipeline that is triggered when patchsets are submitted for review 6 | * Mimics the work environment of a real world user doing mobile development 7 | 8 | # Why? 9 | * To demonstrate how Jenkins workflow facilitates complex build/testing schemes 10 | * Show how one can construct a Dockerized code review/automation environment with full integration 11 | * Demonstrate an integrated, containerized setup of Jenkins + Gerrit 12 | 13 | This comprises 3 parts: 14 | * Jenkins server using workflow and the gerrit trigger plugin to work with gerrit patchsets 15 | * Gerrit server: acts as a central git repository and provides code review 16 | * Installation of git-repo tool (in both Jenkins and Gerrit), to support projects spanning multiple repositories 17 | * Code repos in gerrit for repo (umbrella manifest) and two sample Java projects 18 | 19 | In fitting with Docker best practices, this is split into two Docker containers: 20 | 21 | * jenkins-gerrit-wfdemo-jenkins - the jenkins host, complete with its own home directory (runs on port 8081) 22 | * jenkins-gerrit-wfdemo-gerrit - gerrit server on port 8080, with local git repos and repo running in server mode 23 | 24 | 25 | # Setup 26 | * Prerequisite: Linux or Mac with a working Docker installation (Boot2Docker or Docker machine will work), and *optionally* Docker Compose 27 | * Prerequisite for use of repo tool: installation 28 | - Linux: `sudo curl https://storage.googleapis.com/git-repo-downloads/repo > /bin/repo && sudo chmod a+x /bin/repo` 29 | - Mac: `curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo && chmod a+x ~/bin/repo` 30 | * Create Host Mappings (optional for linux, **required on Mac for Docker Machine / Boot2Docker** ): 31 | - Find your Docker host's IP and write it down 32 | - In linux on native docker, use 127.0.0.1 33 | - For boot2docker, run `boot2docker ip` 34 | - For Docker Machine, run `docker-machine ls` and finding the matching host 35 | - In your favorite text editor (in sudo mode) open /etc/hosts for editing, ex `sudo vi /etc/hosts` 36 | - Add two new lines mapping this IP to hostname 'jenkins' and 'gerrit' and save the file, ex: 37 | 38 | ``` 39 | 192.168.99.100 gerrit 40 | 192.168.99.100 jenkins 41 | ``` 42 | 43 | # To run: 44 | 45 | * Using Docker Compose: simply run 'docker-compose up' 46 | * Vanilla Docker: 47 | - To build: run build.sh (using sudo if needed) - it will need a couple minutes 48 | - To run: run start.sh 49 | 50 | # Using it: 51 | * Jenkins is available at localhost:8081 (Linux) or jenkins:8081 (Mac or with hosts entry) 52 | * Gerrit is available at localhost:8080 (Linux) or gerrit:8080 (Mac or with hosts entry) 53 | * To set up the local user with push permissions for gerrit: 54 | - **Linux:** `sh config-gerrit.sh` 55 | - **Mac or with hosts entry:** `sh config-gerrit-mac.sh` 56 | 57 | By default, this will use your git name & email, set the gerrit username as local username, and your HTTP gerrit password as 'goober' (and add your local SSH public RSA key). You can always set this up manually and change it from the gerrit interface. 58 | 59 | # Sample project 60 | * By default, there are three repositories, each with a gerrit project 61 | - 'umbrella' - this contains a manifest for repo 62 | - 'primary' - Java command line tool to generate random text, after a delay. Mimics an API provider, built with maven. 63 | - 'secondary' - Very basic java program to generate arguments to the program in 'primary.' Mimics an API consumer, also built in maven 64 | 65 | # Creating commits and pushing to gerrit directly 66 | 1. You must have a gerrit user configured (see "using it") 67 | 2. Git clone repositories (replace 'gerrit' with localhost if using native Docker) 68 | - http://gerrit:8080/primary 69 | - http://gerrit:8080/secondary 70 | 3. Go into each repository and do the following to install Gerrit hooks: 71 | - *Linux*: `curl -Lo .git/hooks/commit-msg http://localhost:8080/tools/hooks/commit-msg && chmod u+x .git/hooks/commit-msg` 72 | - *Mac*: `curl -Lo .git/hooks/commit-msg http://gerrit:8080/tools/hooks/commit-msg && chmod u+x .git/hooks/commit-msg` 73 | 4. Create a test commit 74 | - `echo 'blahblahblah' > newfile.txt && git add newfile.txt` 75 | - `git commit -a -m "Test"` 76 | 5. Push by SSH 77 | - *Linux:* `git push ssh://$USER@localhost:29418/primary HEAD:refs/for/master` 78 | - *Mac:* `git push ssh://$USER@gerrit:29418/primary HEAD:refs/for/master` 79 | 6. You should see new changes for review in Gerrit... and responses back from Jenkins after running 'wf-build' 80 | 81 | 82 | # Creating and uploading changes by repo 83 | 1. You must have a gerrit user configured (see "using it") and repo installed 84 | 2. Pull down the project structure via repo (must be installed, see prerequisites) 85 | - *Linux, native docker:* `repo init -u http://localhost:8080/umbrella && repo sync` 86 | - *Mac or linux with hosts entry*: `repo init -u http://gerrit:8080/umbrella -m jenkins.xml && repo sync` 87 | 3. Start a new working branch in repo 88 | - `repo start feature-testing --all` 89 | 4. Push back changes for review: 90 | - `repo upload` 91 | 5. You should see changes ready for review, and Jenkins test results from 'wf-build' 92 | 6. Feel free to go back to the master branch: 93 | - `repo sync -d` 94 | 95 | # To stop: 96 | * Using Docker Compose: 'docker-compose kill && docker-compose rm' 97 | * Vanilla Docker: 'docker rm -f gerrit && docker rm -f jenkins' 98 | 99 | # Troubleshooting 100 | 101 | 1. Verifying Gerrit access by SSH for jenkins 102 | * go to the gerrit-workflow-demo/jenkins 103 | * run the following: 104 | - Linux: `ssh -i demo_key_rsa -p 29418 demouser@localhost` 105 | - Mac: `ssh -i demo_key_rsa -p 29418 demouser@gerrit` 106 | * you should see the following: 107 | ``` 108 | Enter passphrase for key 'demo_key_rsa': 109 | 110 | **** Welcome to Gerrit Code Review **** 111 | 112 | Hi demouser, you have successfully connected over SSH. 113 | 114 | Unfortunately, interactive shells are disabled. 115 | To clone a hosted Git repository, use: 116 | 117 | git clone ssh://demouser@gerrit:29418/REPOSITORY_NAME.git 118 | 119 | Connection to localhost closed. 120 | ``` -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | --------------------------------------------------------------------------------