diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f26214f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,97 @@ +FROM nginx:alpine +USER root + +# Prepare the alpine image with some Jenkins dependencies +################################################################################ +RUN apk add --no-cache git \ + openssh-client \ + curl \ + unzip \ + bash \ + ttf-dejavu \ + coreutils \ + supervisor \ + openjdk8-jre && \ + mkdir -p /usr/share/jenkins && \ + curl -sSL https://ci.jenkins.io/job/Core/job/jenkins/job/master/lastSuccessfulBuild/artifact/war/target/linux-jenkins.war > /usr/share/jenkins/jenkins.war +################################################################################ + + +# Snippet taken from Dockerfile.alpine +################################################################################ +ARG user=jenkins +ARG group=jenkins +ARG uid=1000 +ARG gid=1000 +ARG http_port=8080 +ARG agent_port=50000 + +ENV JENKINS_HOME /var/jenkins_home +ENV JENKINS_SLAVE_AGENT_PORT ${agent_port} +# Jenkins is run with user `jenkins`, uid = 1000 +# If you bind mount a volume from the host or a data container, +# ensure you use the same uid +RUN addgroup -g ${gid} ${group} \ + && adduser -h "$JENKINS_HOME" -u ${uid} -G ${group} -s /bin/bash -D ${user} + +# Jenkins home directory is a volume, so configuration and build history +# can be persisted and survive image upgrades +VOLUME /var/jenkins_home + +# `/usr/share/jenkins/ref/` contains all reference configuration we want +# to set on a fresh new installation. Use it to bundle additional plugins +# or config file with your custom jenkins Docker image. +RUN mkdir -p /usr/share/jenkins/ref/init.groovy.d + +ENV TINI_VERSION 0.14.0 +ENV TINI_SHA 6c41ec7d33e857d4779f14d9c74924cab0c7973485d2972419a3b7c7620ff5fd + +# Use tini as subreaper in Docker container to adopt zombie processes +RUN curl -fsSL https://github.com/krallin/tini/releases/download/v${TINI_VERSION}/tini-static-amd64 -o /bin/tini && chmod +x /bin/tini \ + && echo "$TINI_SHA /bin/tini" | sha256sum -c - + +ENV JENKINS_UC https://updates.jenkins.io +RUN chown -R ${user} "$JENKINS_HOME" /usr/share/jenkins/ref + +# for main web interface: +EXPOSE ${http_port} + +# will be used by attached agents: +EXPOSE ${agent_port} +################################################################################ + + +# Grab the latest jenkins.sh from the Jenkins on Docker project +RUN curl -fsSL https://github.com/jenkinsci/docker/raw/master/jenkins.sh > /usr/local/bin/jenkins.sh && \ + chmod +x /usr/local/bin/jenkins.sh +RUN curl -fsSL https://github.com/jenkinsci/docker/raw/master/jenkins-support > /usr/local/bin/jenkins-support + + +# Ensure that all our plugins are bundled properly, along with Groovy bootstrap +# scripts and other build-related content. +################################################################################ +ADD build/plugins/*.hpi /usr/share/jenkins/ref/plugins/ +RUN for f in /usr/share/jenkins/ref/plugins/*.hpi; do mv $f $f.override ; done +ADD init.groovy.d/*.groovy /usr/share/jenkins/ref/init.groovy.d/ +# Link all our files with .override as the suffix to ensure copy_reference_file +# overrides any existing versions on the persistent volume. Basically, we +# always want the init.groovy.d/ in the container to win. +RUN for f in /usr/share/jenkins/ref/init.groovy.d/*.groovy; do mv $f $f.override ; done + +RUN mkdir /usr/share/jenkins/ref/userContent +RUN date > /usr/share/jenkins/ref/userContent/builtOn.txt +ADD build/git-refs.txt /usr/share/jenkins/ref/userContent +RUN for f in /usr/share/jenkins/ref/userContent/*.txt; do mv $f $f.override ; done +################################################################################ + + +# Prepare the nginx instance itself +################################################################################ +COPY nginx.master.conf /etc/nginx/conf.d/default.conf +################################################################################ + +# Prepare the supervisor script to run nginx and Jenkins inside the container +################################################################################ +COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf +CMD /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf +################################################################################ diff --git a/Dockerfile.builder b/Dockerfile.builder new file mode 100644 index 0000000..d2ac21c --- /dev/null +++ b/Dockerfile.builder @@ -0,0 +1,3 @@ +FROM maven:3 + +RUN apt-get update && apt-get install -qy git nodejs node-gyp diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..dedf78c --- /dev/null +++ b/Makefile @@ -0,0 +1,35 @@ +IMAGE_PREFIX="rtyler/codevalet" + +all: check plugins master + +check: agent-templates + +clean: + rm -rf build/ + +## Build the Jenkins master image +############################################################### +builder: Dockerfile.builder + docker build -t ${IMAGE_PREFIX}-$@ -f Dockerfile.$@ . + +master: Dockerfile build/git-refs.txt agent-templates + docker build -t ${IMAGE_PREFIX}-$@ . + +plugins: ./scripts/build-plugins plugins.txt builder + ./scripts/build-plugins + +build/git-refs.txt: + ./scripts/record-sha1sums +############################################################### + + +## Handling for agent-templates which is an external repository +############################################################### +agent-templates: build/agent-templates + ./scripts/ruby ./scripts/render-agent-templates build/agent-templates + +build/agent-templates: + git clone --depth 1 https://github.com/codevalet/agent-templates.git build/agent-templates +############################################################### + +.PHONY: clean plugins master builder all check diff --git a/init.groovy.d/.gitignore b/init.groovy.d/.gitignore new file mode 100644 index 0000000..e735110 --- /dev/null +++ b/init.groovy.d/.gitignore @@ -0,0 +1,2 @@ +setup-azure-cloud.groovy +*.class diff --git a/init.groovy.d/README.adoc b/init.groovy.d/README.adoc new file mode 100644 index 0000000..e2e89fb --- /dev/null +++ b/init.groovy.d/README.adoc @@ -0,0 +1,29 @@ += Groovy bootstrap scripts for Jenkins + +This directory contains a number Groovy-based scripts which will execute when +the Jenkins instances boot up, providing the baseline configuration required +per instance. + +== Environment Variables + +The environment variables that these scripts need to be present when Jenkins +executes are: + +=== GITHUB_USER + +The user on link:https://github.com[github.com] who should "own" this instance. +This will automatically set up some permissions for the set `GITHUB_USER` + +=== CLIENT_SECRET + +The GitHub OAuth "Client Secret" for the OAuth Application which should be used +for authentication against these Jenkins instances. + + +=== AZURE_TENANT_ID + +=== AZURE_SUBSCRIPTION_ID + +=== AZURE_CLIENT_ID + +=== AZURE_CLIENT_SECRET diff --git a/init.groovy.d/configure-datadog.groovy b/init.groovy.d/configure-datadog.groovy new file mode 100644 index 0000000..586e593 --- /dev/null +++ b/init.groovy.d/configure-datadog.groovy @@ -0,0 +1,17 @@ +#!/usr/bin/env groovy + +/* Configure the Datadog plugin for this instance */ + +import jenkins.model.* +import org.datadog.jenkins.plugins.datadog.DatadogBuildListener + +def dog = Jenkins.instance.getDescriptor('org.datadog.jenkins.plugins.datadog.DatadogBuildListener') + +if (System.env.get('GITHUB_USER')) { + dog.hostname = "${System.env.get('GITHUB_USER')}.codevalet.io" +} + +dog.tagNode = true +dog.apiKey = System.env.get('DATADOG_API_KEY') ?: 'dummy-datadog-api-key' + +dog.save() diff --git a/init.groovy.d/configure-quiet-period.groovy b/init.groovy.d/configure-quiet-period.groovy new file mode 100644 index 0000000..0754c1d --- /dev/null +++ b/init.groovy.d/configure-quiet-period.groovy @@ -0,0 +1,9 @@ +#!/usr/bin/env groovy +/* + * Set the global quiet period to zero to avoid any delays in provisioning + * infrastructure or executing Pipelines + */ + +import jenkins.model.Jenkins + +Jenkins.instance.quietPeriod = 0 diff --git a/init.groovy.d/configure-sentry.groovy b/init.groovy.d/configure-sentry.groovy new file mode 100644 index 0000000..e69de29 diff --git a/init.groovy.d/disable-cli.groovy b/init.groovy.d/disable-cli.groovy new file mode 100644 index 0000000..ec36dfc --- /dev/null +++ b/init.groovy.d/disable-cli.groovy @@ -0,0 +1,6 @@ +#!/usr/bin/env groovy +/* + * Disable the CLI by default + */ + +jenkins.CLI.get().setEnabled(false) diff --git a/init.groovy.d/enable-csrf-protection.groovy b/init.groovy.d/enable-csrf-protection.groovy new file mode 100644 index 0000000..e7ce0eb --- /dev/null +++ b/init.groovy.d/enable-csrf-protection.groovy @@ -0,0 +1,14 @@ +#!/usr/bin/env groovy +/* + * Set up the CSRF protection which would normally be defaulted in 2.0 , but + * are not in our instances because we're * skipping the setup wizard + */ + +import jenkins.model.* +import hudson.security.csrf.* + +println "Checking CSRF protection..." +if (Jenkins.instance.crumbIssuer == null) { + println "Enabling CSRF protection" + Jenkins.instance.crumbIssuer = new DefaultCrumbIssuer(true) +} diff --git a/init.groovy.d/limit-jnlp-protocols.groovy b/init.groovy.d/limit-jnlp-protocols.groovy new file mode 100644 index 0000000..d1af963 --- /dev/null +++ b/init.groovy.d/limit-jnlp-protocols.groovy @@ -0,0 +1,14 @@ +#!/usr/bin/env groovy +/* + * Restrict the JNLP protocols to only those which should be enabled (modern + * and secure ones) + */ + +import jenkins.model.* +import org.kohsuke.stapler.StaplerProxy +import jenkins.security.s2m.AdminWhitelistRule + +Jenkins.instance.agentProtocols = ['JNLP4-connect', 'Ping'] +Jenkins.instance.save() + +Jenkins.instance.getExtensionList(StaplerProxy).get(AdminWhitelistRule).masterKillSwitch = false diff --git a/init.groovy.d/limit-master-executors.groovy b/init.groovy.d/limit-master-executors.groovy new file mode 100644 index 0000000..c18466e --- /dev/null +++ b/init.groovy.d/limit-master-executors.groovy @@ -0,0 +1,8 @@ +#!/usr/bin/env groovy +/* + * Make sure the number of executors available on the master is set to zero for + * security purposes + */ + +import jenkins.model.* +Jenkins.instance.setNumExecutors(0) diff --git a/init.groovy.d/pipeline-global-configuration.groovy b/init.groovy.d/pipeline-global-configuration.groovy new file mode 100644 index 0000000..3e54e0e --- /dev/null +++ b/init.groovy.d/pipeline-global-configuration.groovy @@ -0,0 +1,34 @@ +#!/usr/bin/env groovy + +/* + * This file is responsible for setting Global Pipeline configurations to the + * sensible defaults which are necessary + */ + + +import jenkins.model.* +import jenkins.plugins.git.GitSCMSource +import org.jenkinsci.plugins.workflow.libs.* +import jenkins.model.GlobalConfiguration +import org.jenkinsci.plugins.pipeline.modeldefinition.config.GlobalConfig + + +/* Set the default Docker label for Declarative Pipeline to .. wait for it .. docker */ +GlobalConfig c = GlobalConfiguration.all().find { it instanceof GlobalConfig } +c?.dockerLabel = 'docker' + + +/* Add our global library properly */ +List libs = [] + +['pipeline-library', 'inline-pipeline-secrets'].each { + GitSCMSource source= new GitSCMSource(it, "https://github.com/codevalet/${it}.git", + null, null, null, false) + + LibraryConfiguration lib = new LibraryConfiguration(it, new SCMSourceRetriever(source)) + lib.implicit = true + lib.defaultVersion = 'master' + libs.add (lib) +} + +GlobalLibraries.get().libraries = libs diff --git a/init.groovy.d/set-instance-url.groovy b/init.groovy.d/set-instance-url.groovy new file mode 100644 index 0000000..1bd4926 --- /dev/null +++ b/init.groovy.d/set-instance-url.groovy @@ -0,0 +1,9 @@ +#!/usr/bin/env groovy + +/* Configure the instance's URL based on the GITHUB_USER */ + +import jenkins.model.* + +if (System.env.get('GITHUB_USER')) { + JenkinsLocationConfiguration.get().setUrl("https://${System.env.get('GITHUB_USER')}.codevalet.io/") +} diff --git a/init.groovy.d/setup-azure-cloud.groovy.erb b/init.groovy.d/setup-azure-cloud.groovy.erb new file mode 100644 index 0000000..0d079ca --- /dev/null +++ b/init.groovy.d/setup-azure-cloud.groovy.erb @@ -0,0 +1,126 @@ +#!/usr/bin/env groovy + +/* + * Set up the Azure VM Cloud plugin. + * + * This file is generated from an ERB template! + */ + +import jenkins.model.* +import com.microsoft.azure.vmagent.* +import com.microsoft.azure.util.* + +import com.cloudbees.plugins.credentials.* +import com.cloudbees.plugins.credentials.impl.* +import com.cloudbees.plugins.credentials.domains.Domain + +final String maxAgents = System.env.get('MAX_AGENTS') ?: '2' +final String cloudName = 'Azure' +final String githubUser = System.env.get('GITHUB_USER') ?: 'max-the-code-monkey' +final String resourceGroup = "azureagents-for-codevalet" +final String credentialsId = 'azure-agents-credential' +final String adminCredentialsId = 'azure-agent-admin-credential' +final String tenantId = System.env.get('AZURE_TENANT_ID') ?: 'dummy-tenant-id' +final String subscriptionId = System.env.get('AZURE_SUBSCRIPTION_ID') ?: 'dummy-subscription-id' +final String clientId = System.env.get('AZURE_CLIENT_ID') ?: 'dummy-client-id' +final String clientSecret = System.env.get('AZURE_CLIENT_SECRET') ?: 'dummy-secret' +CredentialsScope scope = CredentialsScope.valueOf('SYSTEM') +AzureCredentials.ServicePrincipal principle = AzureCredentials.getServicePrincipal(credentialsId) +final String id = java.util.UUID.randomUUID().toString() +final Credentials c = new UsernamePasswordCredentialsImpl(scope, + adminCredentialsId, + adminCredentialsId, + 'azureuser', + id) + +SystemCredentialsProvider.instance.store.addCredentials(Domain.global(), c) + +println ">> Credential: ${id}" + +/* If the credentials hasn't already been defined, let's create one! */ +if (principle.isBlank()) { + AzureCredentials credential = new AzureCredentials(scope, /* Scope for the credential */ + credentialsId, /* */ + 'Azure credentials for provisioning agent', /* description */ + subscriptionId, /* subscriptionId */ + clientId, /* clientId */ + clientSecret) /* clientSecret */ + credential.tenant = tenantId + + SystemCredentialsProvider.instance.store.addCredentials(Domain.global(), credential) +} + + +Jenkins.instance.clouds.clear() +def cloud = Jenkins.instance.clouds.find { it.name == cloudName } + +/* Avoid adding the AzureVMCloud over and over and over again */ +if (cloud == null) { + cloud = new AzureVMCloud(cloudName, /* Cloud Name */ + credentialsId, /* credentials id */ + maxAgents, /* Max Agents */ + '1200', /* Deployment Timeout (s) */ + 'existing', /* Resource group reference type */ + '', /* New resource group name */ + resourceGroup, /* Existing resource group name */ + null) /* VM Templates */ + Jenkins.instance.clouds.add(cloud) +} + + +/* Nuke all our templates */ +cloud.clearVmTemplates() + +final String agentWorkspace = '/home/azureuser/workspace' +def retentionTime = null +def imageReference = null +def vmTemplate = null +def vhd = null + +<% agents.each_pair do |name, d| %> + + vhd = '<%= d['image']['vhd'] %>' + retentionTime = new AzureVMCloudRetensionStrategy(<%= d['retention'] %>) + imageReference = new AzureVMAgentTemplate.ImageReferenceTypeClass(vhd, vhd, vhd, vhd, vhd) + vmTemplate = new AzureVMAgentTemplate('<%= name %>', + '<%= d['description'] %>', /* description */ + '<%= d['labels'].join(' ') %>', /* labels */ + 'West US', /* location */ + '<%= d['size'] %>', /* VM Size */ + 'existing', /* Storage account Name reference type */ + 'Standard_LRS', /* Storage account type */ + '', /* new storage account name */ + 'codevaletimages', /* existing storage account name */ + 'unmanaged', /* disk type */ + '<%= d['executors'] %>', /* number of executors */ + 'NORMAL', /* Usage mode */ + '', /* built-in image */ + false, /* install git */ + false, /* install maven */ + false, /* install docker */ + 'Linux', /* OS type */ + 'custom', /* image top level type */ + false, /* image reference? */ + imageReference, /* image reference class */ + 'SSH', /* agent launch method */ + false, /* pre install SSH */ + '<%= d['initscript']%>', /* init script */ + adminCredentialsId, /* admin credential Id */ + '', /* virtual network name */ + '', /* virtual network resource group name */ + '', /* subnet name */ + false, /* use private IP */ + '', /* Network security group name */ + agentWorkspace, /* agent workspace */ + '', /* JVM options */ + retentionTime, /* retention time */ + false, /* shutdown on idle */ + false, /* template disabled */ + '', /* template status details */ + true, /* execute init script as root */ + true /* do not use machine if init fails */ + ) + vmTemplate.azureCloud = cloud + cloud.addVmTemplate(vmTemplate) + +<% end %> diff --git a/init.groovy.d/setup-git.groovy b/init.groovy.d/setup-git.groovy new file mode 100644 index 0000000..9d30f98 --- /dev/null +++ b/init.groovy.d/setup-git.groovy @@ -0,0 +1,19 @@ +#!/usr/bin/env groovy +/* + * Pre-configure the Git plugin and the default git tooling in Jenkins + */ +import org.jenkinsci.plugins.gitclient.* +import hudson.plugins.git.* +import jenkins.model.Jenkins + +def gitConfig = Jenkins.instance.getDescriptor('hudson.plugins.git.GitSCM') +def tools = Jenkins.instance.getDescriptor('hudson.plugins.git.GitTool') + +GitTool[] gitTools = new GitTool[1] +gitTools[0] = new JGitTool() + +tools.installations = gitTools +tools.save() + +gitConfig.globalConfigName = 'max' +gitConfig.globalConfigEmail = 'max@example.com' diff --git a/init.groovy.d/setup-github-oauth.groovy b/init.groovy.d/setup-github-oauth.groovy new file mode 100644 index 0000000..f33c6c7 --- /dev/null +++ b/init.groovy.d/setup-github-oauth.groovy @@ -0,0 +1,45 @@ +#!/usr/bin/env groovy +/* + * Set up the basic GitHub OAuth permissions for this instance + */ + +if (System.env.get('SUPER_DANGEROUS_LOCAL_ONLY_DISABLE_AUTH')) { + return +} + +import jenkins.model.* +import hudson.security.* +import hudson.model.Item +import org.jenkinsci.plugins.workflow.cps.replay.ReplayAction +import org.jenkinsci.plugins.GithubAuthorizationStrategy +import org.jenkinsci.plugins.GithubSecurityRealm + +def authorization = new GlobalMatrixAuthorizationStrategy() +authorization.add(Jenkins.READ, 'Anonymous') +authorization.add(Item.READ, 'Anonymous') +authorization.add(Jenkins.ADMINISTER, 'rtyler') + +[ + Jenkins.READ, + Item.BUILD, + Item.CANCEL, + Item.CONFIGURE, + Item.CREATE, + Item.DELETE, + Item.DISCOVER, + Item.READ, + ReplayAction.REPLAY, +].each { permission -> + authorization.add(permission, System.env.get('GITHUB_USER') ?: 'rtyler') +} + + +def realm = new GithubSecurityRealm('https://github.com', /* GitHub web URI */ + 'https://api.github.com', /* GitHub API URI */ + System.env.get('CLIENT_ID') ?: 'f19661554c93f3b11cfe', /* OAuth Client ID */ + System.env.get('CLIENT_SECRET') ?: '0672e14addb9f41dec11b5da1219017edfc82a58',/* OAuth Client Secret */ + 'read:public_repo,user:email' /* OAuth permission scopes */ + ) +Jenkins.instance.authorizationStrategy = authorization +Jenkins.instance.securityRealm = realm +Jenkins.instance.save() diff --git a/plugins.txt b/plugins.txt new file mode 100644 index 0000000..e6d9d43 --- /dev/null +++ b/plugins.txt @@ -0,0 +1,7 @@ +workflow-aggregator-plugin +blueocean-plugin +github-oauth-plugin +azure-vm-agents-plugin +matrix-auth-plugin +embeddable-build-status-plugin +sentry-plugin diff --git a/scripts/build-plugins b/scripts/build-plugins new file mode 100755 index 0000000..28b3d1d --- /dev/null +++ b/scripts/build-plugins @@ -0,0 +1,85 @@ +#!/bin/bash + +BUILD_DIR=$PWD/build +REPOS_DIR=$BUILD_DIR/repos +SCRIPTS_DIR=$(realpath $(dirname $0)) +PLUGINS_OUTPUT_DIR=$BUILD_DIR/plugins +BUILDER_CONTAINER="rtyler/codevalet-builder" + +mkdir -p $REPOS_DIR +mkdir -p $PLUGINS_OUTPUT_DIR + +declare -A PROCESSED + +function cloneWithDependencies() { + if [ ! ${PROCESSED[$1]} ]; then + PROCESSED[$1]="$1" + if [ ! -d $1 ]; then + git clone --depth 1 git://github.com/jenkinsci/$1.git + fi; + + for pom in $(find $1 -iname 'pom.xml' -maxdepth 2 -type f); do + (cd $(dirname $pom) && ${SCRIPTS_DIR}/plugins-from-pom 'pom.xml') + done; + + for dep in $(find $1 -iname '.plugins.txt' -type f -exec cat {} \; | sort -u); do + cloneWithDependencies "${dep}-plugin" + done; + fi; +} + +tty --quiet +if [ $? -eq 0 ]; then + echo "We're interactive, adjusting the Docker arguments accordingly"; + TTY_ARGS="-ti"; +fi; + +pushd $REPOS_DIR + + # See https://github.com/jenkinsci/azure-commons-plugin/pull/15 + git clone --depth 1 -b jenkins-48636 git://github.com/abayer/azure-commons-plugin.git + + # Grab the latest datadog plugin from their org (it's not in jenkinsci) + git clone --depth 1 git://github.com/datadog/jenkins-datadog-plugin.git datadog-plugin + + # pubsub-light-module is a plugin but not called a plugin + git clone --depth 1 git://github.com/jenkinsci/pubsub-light-module.git pubsub-light-plugin + + # the artifact is called cloudbees-bitbucket-branch-source but the repo isn't + git clone --depth 1 git://github.com/jenkinsci/bitbucket-branch-source-plugin.git cloudbees-bitbucket-branch-source-plugin + + git clone --depth 1 git://github.com/jenkinsci/js-libs.git js-libs-plugin + # https://issues.jenkins-ci.org/browse/JENKINS-45668 + (cd js-libs-plugin && find . -maxdepth 1 -type d -exec mkdir -p {}/src/main/webapp/jsmodules \;) + + + for plugin in $(cat $SCRIPTS_DIR/../plugins.txt); do + cloneWithDependencies $plugin + done; + + # This was merged into the blueocean-plugin repository but still exists as a tombstone + rm -rf blueocean-pipeline-editor-plugin + + set -e + for d in *-plugin; do + pushd $d + + if [ -f pom.xml ]; then + echo ">> Building $d" + git pull --rebase + docker run --rm ${TTY_ARGS} -v $HOME/.m2:/root/.m2 \ + -v $PWD:/data -w /data ${BUILDER_CONTAINER} mvn install -e -B -DskipTests + fi; + popd + done; + set +e + + # Handle an old tombstoned dependency which will not build from source + # anymore :( + # https://github.com/jenkinsci/pipeline-model-definition-plugin/blob/master/pipeline-model-definition/pom.xml#L117-L123 + curl https://repo.jenkins-ci.org/releases/org/jenkinsci/plugins/pipeline-model-declarative-agent/1.1.1/pipeline-model-declarative-agent-1.1.1.hpi > $PLUGINS_OUTPUT_DIR/pipeline-model-declarative-agent.hpi + + for hpi in $(find . -iname "*.hpi" | grep -v "test-classes" | grep -v "target/plugins/"); do + cp $hpi $PLUGINS_OUTPUT_DIR + done; +popd diff --git a/scripts/plugins-from-pom b/scripts/plugins-from-pom new file mode 100755 index 0000000..1cb52e7 --- /dev/null +++ b/scripts/plugins-from-pom @@ -0,0 +1,47 @@ +#!/usr/bin/env python + +import sys + +from xml.etree.ElementTree import ElementTree + + +def main(): + document = ElementTree(file=sys.argv[1]) + plugins = [] + ns = {'mvn' : 'http://maven.apache.org/POM/4.0.0'} + packaging = document.find('mvn:packaging', ns) + + if (packaging is not None) and (packaging.text == 'hpi'): + for e in document.findall('mvn:dependencies', ns): + for dep in list(e): + scope = dep.find('mvn:scope', ns) + if scope is None: + optional = dep.find('mvn:optional', ns) + if optional is None: + group = dep.find('mvn:groupId', ns).text + plugin = dep.find('mvn:artifactId', ns).text + # Avoid the github-organization-folder since it's + # tombstoned + if plugin == 'github-organization-folder': + next + try: + ['org.jvnet.hudson.plugins', 'org.jenkins-ci.plugins', + 'org.jenkinsci.plugins', 'org.jenkins-ci.plugins.icon-shim', + '${project.groupId}', 'io.jenkins.plugins', + 'io.jenkins.blueocean', + 'org.jenkins-ci.main', 'com.coravy.hudson.plugins.github', + 'org.6wind.jenkins', 'org.jenkins-ci.plugins.pipeline-stage-view', + 'org.jenkins-ci.ui', 'org.jenkins-ci.plugins.workflow'].index(group) + # Let's only bother with dependencies that are actually Jenkins + # plugins :) + plugins.append(plugin) + except ValueError: + pass + + with open('.plugins.txt', 'w+') as fd: + for plugin in plugins: + fd.write(plugin) + fd.write('\n') + +if __name__ == '__main__': + main() diff --git a/scripts/record-sha1sums b/scripts/record-sha1sums new file mode 100755 index 0000000..f098f20 --- /dev/null +++ b/scripts/record-sha1sums @@ -0,0 +1,13 @@ +#!/bin/bash + +mkdir build + +OUTPUT_FILE=build/git-refs.txt + +echo > $OUTPUT_FILE + +for plugin in build/repos/*-plugin; do + echo ">> Record HEAD for ${plugin}"; + SHA=$(cd $plugin && git rev-parse HEAD) + echo "${plugin},${SHA}" >> $OUTPUT_FILE +done; diff --git a/scripts/render-agent-templates b/scripts/render-agent-templates new file mode 100755 index 0000000..b2ef864 --- /dev/null +++ b/scripts/render-agent-templates @@ -0,0 +1,22 @@ +#!/usr/bin/env ruby + +require 'erb' +require 'yaml' + +repo_dir = ARGV.first + +puts ">> Using #{repo_dir} as the agent templates directory" + +agents = {} + +Dir.glob("#{repo_dir}/**/*.yml").each do |agent| + data = YAML.load(File.read(agent)) + name = File.basename(agent, File.extname(agent)) + agents[name] = data +end + + +template = ERB.new(File.read('init.groovy.d/setup-azure-cloud.groovy.erb')) +File.open('init.groovy.d/setup-azure-cloud.groovy', 'w+') do |f| + f.write(template.result) +end diff --git a/scripts/ruby b/scripts/ruby new file mode 100755 index 0000000..4c268f9 --- /dev/null +++ b/scripts/ruby @@ -0,0 +1,6 @@ +#!/bin/sh + +exec docker run --rm \ + -v ${PWD}:${PWD} \ + -w ${PWD} \ + ruby:2-alpine $@