Moved jenkins.bzl to a subdirectory and split it
Change-Id: I2cfa48cbf6824b3dbd4f7c538fe4b523f5f73a33
diff --git a/jenkins/BUILD b/jenkins/BUILD
index 4124a2e..1fd6b5e 100644
--- a/jenkins/BUILD
+++ b/jenkins/BUILD
@@ -14,12 +14,9 @@
# Configuration for our Jenkins instance
load("@bazel_tools//tools/build_defs/docker:docker.bzl", "docker_build")
-load(":jenkins.bzl", "jenkins_node", "jenkins_build", "jenkins_job")
-load(":nodes.bzl", "jenkins_nodes", "jenkins_node_names")
+load("//jenkins/build_defs:jenkins.bzl", "jenkins_node", "jenkins_docker_build", "jenkins_job", "jenkins_nodes", "jenkins_node_names")
load("//jenkins/jobs:jobs.bzl", "JOBS_SUBSTITUTIONS", "STAGING_JOBS_SUBSTITUTIONS")
-exports_files(glob(["github-jobs*.tpl"]))
-
#
# Nodes
#
@@ -279,7 +276,7 @@
#
# Finally the Jenkins image
#
-jenkins_build(
+jenkins_docker_build(
name = "jenkins",
configs = [
":deploy",
@@ -305,7 +302,7 @@
visibility = ["//visibility:public"],
)
-jenkins_build(
+jenkins_docker_build(
name = "jenkins-staging",
configs = [
":darwin-x86_64-staging",
@@ -332,7 +329,7 @@
#
# A jenkins image for testing purpose
-jenkins_build(
+jenkins_docker_build(
name = "jenkins-test",
configs = [
":deploy",
diff --git a/jenkins/build_defs/BUILD b/jenkins/build_defs/BUILD
new file mode 100644
index 0000000..9d03353
--- /dev/null
+++ b/jenkins/build_defs/BUILD
@@ -0,0 +1 @@
+exports_files(glob(["github-jobs*.tpl"]))
diff --git a/jenkins/github-jobs-Gerrit.xml.tpl b/jenkins/build_defs/github-jobs-Gerrit.xml.tpl
similarity index 100%
rename from jenkins/github-jobs-Gerrit.xml.tpl
rename to jenkins/build_defs/github-jobs-Gerrit.xml.tpl
diff --git a/jenkins/github-jobs-PR.xml.tpl b/jenkins/build_defs/github-jobs-PR.xml.tpl
similarity index 100%
rename from jenkins/github-jobs-PR.xml.tpl
rename to jenkins/build_defs/github-jobs-PR.xml.tpl
diff --git a/jenkins/github-jobs.bat.tpl b/jenkins/build_defs/github-jobs.bat.tpl
similarity index 100%
rename from jenkins/github-jobs.bat.tpl
rename to jenkins/build_defs/github-jobs.bat.tpl
diff --git a/jenkins/github-jobs.sh.tpl b/jenkins/build_defs/github-jobs.sh.tpl
similarity index 100%
rename from jenkins/github-jobs.sh.tpl
rename to jenkins/build_defs/github-jobs.sh.tpl
diff --git a/jenkins/github-jobs.test-logs.bat.tpl b/jenkins/build_defs/github-jobs.test-logs.bat.tpl
similarity index 100%
rename from jenkins/github-jobs.test-logs.bat.tpl
rename to jenkins/build_defs/github-jobs.test-logs.bat.tpl
diff --git a/jenkins/github-jobs.test-logs.sh.tpl b/jenkins/build_defs/github-jobs.test-logs.sh.tpl
similarity index 100%
rename from jenkins/github-jobs.test-logs.sh.tpl
rename to jenkins/build_defs/github-jobs.test-logs.sh.tpl
diff --git a/jenkins/github-jobs.xml.tpl b/jenkins/build_defs/github-jobs.xml.tpl
similarity index 100%
rename from jenkins/github-jobs.xml.tpl
rename to jenkins/build_defs/github-jobs.xml.tpl
diff --git a/jenkins/build_defs/jenkins.bzl b/jenkins/build_defs/jenkins.bzl
new file mode 100644
index 0000000..53d45f7
--- /dev/null
+++ b/jenkins/build_defs/jenkins.bzl
@@ -0,0 +1,20 @@
+# Copyright 2017 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Some definition to setup jenkins and build the corresponding docker images
+load(":jenkins_docker_build.bzl", "jenkins_docker_build")
+load(":jenkins_node.bzl", "jenkins_node")
+load(":jenkins_nodes.bzl", "jenkins_nodes", "jenkins_node_names")
+load(":jenkins_job.bzl", "jenkins_job", "bazel_git_job", "bazel_github_job")
+
diff --git a/jenkins/build_defs/jenkins_docker_build.bzl b/jenkins/build_defs/jenkins_docker_build.bzl
new file mode 100644
index 0000000..788b0db
--- /dev/null
+++ b/jenkins/build_defs/jenkins_docker_build.bzl
@@ -0,0 +1,65 @@
+# Copyright 2015 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Creation of the docker container for the jenkins master.
+
+load("@bazel_tools//tools/build_defs/docker:docker.bzl", "docker_build")
+load(":templates.bzl", "merge_files")
+load(":vars.bzl", "MAIL_SUBSTITUTIONS")
+
+def jenkins_docker_build(name, plugins = None, base = "//jenkins/base", configs = [],
+ jobs = [], substitutions = {}, visibility = None, tars = []):
+ """Build the docker image for the Jenkins instance."""
+ substitutions = substitutions + MAIL_SUBSTITUTIONS
+ # Expands config files in a tar ball
+ merge_files(
+ name = "%s-configs" % name,
+ srcs = configs,
+ directory = "/usr/share/jenkins/ref",
+ strip_prefixes = [
+ "jenkins/config",
+ "jenkins",
+ ],
+ substitutions = substitutions)
+
+ # Create the structures for jobs
+ merge_files(
+ name = "%s-jobs" % name,
+ srcs = jobs,
+ path_format = "jobs/{basename}/config.xml",
+ directory = "/usr/share/jenkins/ref",
+ )
+
+ ### FINAL IMAGE ###
+ docker_build(
+ name = name,
+ tars = [
+ ":%s-jobs" % name,
+ ":%s-configs" % name,
+ ] + tars,
+ # Workaround no way to specify owner in pkg_tar
+ # TODO(dmarting): use https://cr.bazel.build/10255 when it hits a release.
+ user = "root",
+ entrypoint = [
+ "/bin/tini",
+ "--",
+ "/bin/bash",
+ "-c",
+ "[ -d /opt/lib ] && chown -R jenkins /opt/lib; su jenkins -c /usr/local/bin/jenkins.sh",
+ ],
+ # End of workaround
+ base = base,
+ directory = "/",
+ visibility = visibility,
+ )
diff --git a/jenkins/build_defs/jenkins_job.bzl b/jenkins/build_defs/jenkins_job.bzl
new file mode 100644
index 0000000..4af6990
--- /dev/null
+++ b/jenkins/build_defs/jenkins_job.bzl
@@ -0,0 +1,182 @@
+# Copyright 2017 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Jenkins job creation
+
+load(":templates.bzl", "expand_template")
+load(":vars.bzl", "MAIL_SUBSTITUTIONS")
+
+def jenkins_job(name, config, substitutions = {}, deps = [],
+ project='bazel', org='bazelbuild', git_url=None, project_url=None,
+ folder=None, platforms=[], test_platforms=["linux-x86_64"]):
+ """Create a job configuration on Jenkins.
+
+ Args:
+ name: the name of the job to create
+ config: the configuration file for the job
+ substitutions: additional substitutions to pass to the template generation
+ deps: list of dependencies (templates included by the config file)
+ project: the project name on github
+ org: the project organization on github, default 'bazelbuild'
+ git_url: the URL to the git project, defaulted to the Github URL
+ project_url: the project url, defaulted to the Git URL
+ platforms: platforms on which to run that job, default None,
+ test_platforms: platforms on which to run that job when inside of a
+ dockerized test, by default only 'linux-x86_64'
+ """
+ github_project = "%s/%s" % (org, project.lower())
+ github_url = "https://github.com/" + github_project
+ if not git_url:
+ git_url = github_url
+ if not project_url:
+ project_url = git_url
+ substitutions = substitutions + {
+ "GITHUB_URL": github_url,
+ "GIT_URL": git_url,
+ "GITHUB_PROJECT": github_project,
+ "PROJECT_URL": project_url,
+ "PLATFORMS": "\n".join(platforms),
+ } + MAIL_SUBSTITUTIONS
+ substitutions["SEND_EMAIL"] = "1"
+ expand_template(
+ name = name,
+ template = config,
+ out = "%s.xml" % name,
+ deps = deps,
+ substitutions = substitutions,
+ )
+ substitutions["SEND_EMAIL"] = "0"
+ expand_template(
+ name = name + "-staging",
+ template = config,
+ out = "%s-staging.xml" % name,
+ deps = deps,
+ substitutions = substitutions,
+ )
+
+ if test_platforms:
+ substitutions["PLATFORMS"] = "\n".join(test_platforms)
+ expand_template(
+ name = name + "-test",
+ template = config,
+ out = "%s-test.xml" % name,
+ deps = deps,
+ substitutions = substitutions,
+ )
+
+def bazel_git_job(**kwargs):
+ """Override bazel_github_job to test a project that is not on GitHub."""
+ kwargs["github_enabled"] = False
+ if not "git_url" in kwargs:
+ if not "project_url" in kwargs:
+ fail("Neither project_url nor git_url was specified")
+ kwargs["git_url"] = kwargs
+ bazel_github_job(**kwargs)
+
+def bazel_github_job(name, platforms=[], branch="master", project=None, org="google",
+ project_url=None, workspace=".", configure=[], git_url=None,
+ bazel_versions=["HEAD", "latest"],
+ tests=["//..."], targets=["//..."], substitutions={},
+ windows_configure=[],
+ windows_tests=["//..."], windows_targets=["//..."],
+ windows_tests_msys=["//..."], windows_targets_msys=["//..."],
+ test_opts=["--test_output=errors", "--build_tests_only"],
+ test_tag_filters=["-noci", "-manual"],
+ build_opts=["--verbose_failures"],
+ test_platforms=["linux-x86_64"],
+ enable_trigger=True,
+ gerrit_project=None,
+ enabled=True,
+ pr_enabled=True,
+ github_enabled=True,
+ run_sequential=False,
+ sauce_enabled=False):
+ """Create a generic github job configuration to build against Bazel head."""
+ if not project:
+ project = name
+ substitutions = substitutions + {
+ "WORKSPACE": workspace,
+ "PROJECT_NAME": project,
+ "BRANCH": branch,
+ "CONFIGURE": "\n".join(configure),
+ "WINDOWS_CONFIGURE": "\n".join(windows_configure),
+ "TEST_OPTS": " ".join(test_opts),
+ "TEST_TAG_FILTERS": ",".join(test_tag_filters),
+ "BUILD_OPTS": " ".join(build_opts),
+ "TESTS": " + ".join(tests),
+ "WINDOWS_TESTS": " ".join(windows_tests),
+ # TODO(pcloudy): remove *_MSYS attributes when we don't need MSYS anymore
+ "WINDOWS_TESTS_MSYS": " ".join(windows_tests_msys),
+ "BUILDS": " ".join(targets),
+ "WINDOWS_BUILDS": " ".join(windows_targets),
+ "WINDOWS_BUILDS_MSYS": " ".join(windows_targets_msys),
+ "BAZEL_VERSIONS": "\n".join(bazel_versions),
+ "disabled": str(not enabled).lower(),
+ "enable_trigger": str(enable_trigger and github_enabled).lower(),
+ "github": str(github_enabled),
+ "GERRIT_PROJECT": str(gerrit_project),
+ "RUN_SEQUENTIAL": str(run_sequential).lower(),
+ "SAUCE_ENABLED": str(sauce_enabled).lower(),
+ }
+
+ jenkins_job(
+ name = name,
+ config = "//jenkins/build_defs:github-jobs.xml.tpl",
+ deps = [
+ "//jenkins/build_defs:github-jobs.sh.tpl",
+ "//jenkins/build_defs:github-jobs.bat.tpl",
+ "//jenkins/build_defs:github-jobs.test-logs.sh.tpl",
+ "//jenkins/build_defs:github-jobs.test-logs.bat.tpl",
+ ],
+ substitutions=substitutions,
+ git_url=git_url,
+ project=project,
+ org=org,
+ project_url=project_url,
+ platforms=platforms,
+ test_platforms=test_platforms)
+ substitutions["BAZEL_VERSIONS"] = "\n".join([
+ v for v in bazel_versions if not v.startswith("HEAD")])
+ if pr_enabled:
+ jenkins_job(
+ name = "PR-" + name,
+ config = "//jenkins/build_defs:github-jobs-PR.xml.tpl",
+ deps = [
+ "//jenkins/build_defs:github-jobs.sh.tpl",
+ "//jenkins/build_defs:github-jobs.bat.tpl",
+ "//jenkins/build_defs:github-jobs.test-logs.sh.tpl",
+ "//jenkins/build_defs:github-jobs.test-logs.bat.tpl",
+ ],
+ substitutions=substitutions,
+ project=project,
+ org=org,
+ project_url=project_url,
+ platforms=platforms,
+ test_platforms=test_platforms)
+ if gerrit_project != None:
+ jenkins_job(
+ name = "Gerrit-" + name,
+ config = "//jenkins/build_defs:github-jobs-Gerrit.xml.tpl",
+ deps = [
+ "//jenkins/build_defs:github-jobs.sh.tpl",
+ "//jenkins/build_defs:github-jobs.bat.tpl",
+ "//jenkins/build_defs:github-jobs.test-logs.sh.tpl",
+ "//jenkins/build_defs:github-jobs.test-logs.bat.tpl",
+ ],
+ substitutions=substitutions,
+ project=project,
+ org=org,
+ project_url=project_url,
+ platforms=platforms,
+ test_platforms=test_platforms)
diff --git a/jenkins/build_defs/jenkins_node.bzl b/jenkins/build_defs/jenkins_node.bzl
new file mode 100644
index 0000000..9c4c8fa
--- /dev/null
+++ b/jenkins/build_defs/jenkins_node.bzl
@@ -0,0 +1,90 @@
+# Copyright 2017 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Setup jenkins and build the corresponding docker images
+
+load("@bazel_tools//tools/build_defs/docker:docker.bzl", "docker_build")
+load(":templates.bzl", "expand_template")
+
+JENKINS_SERVER = "http://jenkins:80"
+
+def jenkins_node(name, remote_fs = "/home/ci", num_executors = 1, mode = "NORMAL",
+ labels = [], docker_base = None, preference = 1,
+ visibility = None):
+ """Create a node configuration on Jenkins, with possible docker image.
+
+ Args:
+ name: Name of the node on Jenkins.
+ remote_fs: path to the home of the Jenkins user.
+ num_executors: number of executors (i.e. concurrent build) this machine can have.
+ mode: NORMAL for "Utilize this node as much as possible"
+ EXCLUSIVE for "Only build jobs with label restrictions matching this node"
+ labels: list of Jenkins labels for this node (the node name is always added).
+ docker_base: base for the corresponding docker image to create if we should create one
+ (if docker_base is not specified, then a corresponding machine should be configured
+ to connect to the Jenkins master).
+ preference: A preference factor, if a node as a factor of 1 and another a factor of
+ 4, then the second one will be scheduled 4 time more jobs than the first one.
+ visibility: rule visibility.
+ """
+ native.genrule(
+ name = name,
+ cmd = """cat >$@ <<'EOF'
+<?xml version='1.0' encoding='UTF-8'?>
+<slave>
+ <name>%s</name>
+ <description></description>
+ <remoteFS>%s</remoteFS>
+ <numExecutors>%s</numExecutors>
+ <mode>%s</mode>
+ <retentionStrategy class="hudson.slaves.RetentionStrategy$$Always"/>
+ <launcher class="hudson.slaves.JNLPLauncher"/>
+ <label>%s</label>
+ <nodeProperties>
+ <jp.ikedam.jenkins.plugins.scoringloadbalancer.preferences.BuildPreferenceNodeProperty plugin="scoring-load-balancer@1.0.1">
+ <preference>%s</preference>
+ </jp.ikedam.jenkins.plugins.scoringloadbalancer.preferences.BuildPreferenceNodeProperty>
+ </nodeProperties>
+</slave>
+EOF
+""" % (name, remote_fs, num_executors, mode, " ".join([name] + labels), preference),
+ outs = ["nodes/%s/config.xml" % name],
+ visibility = visibility,
+ )
+ if docker_base:
+ # Generate docker image startup script
+ expand_template(
+ name = name + ".docker-launcher",
+ out = name + ".docker-launcher.sh",
+ template = "slave_setup.sh",
+ substitutions = {
+ "NODE_NAME": name,
+ "HOME_FS": remote_fs,
+ "JENKINS_SERVER": JENKINS_SERVER,
+ },
+ executable = True,
+ )
+ # Generate docker image
+ docker_build(
+ name = name + ".docker",
+ base = docker_base,
+ volumes = [remote_fs],
+ files = [":%s.docker-launcher.sh" % name],
+ data_path = ".",
+ entrypoint = [
+ "/bin/bash",
+ "/%s.docker-launcher.sh" % name,
+ ],
+ visibility = visibility,
+ )
diff --git a/jenkins/nodes.bzl b/jenkins/build_defs/jenkins_nodes.bzl
similarity index 97%
rename from jenkins/nodes.bzl
rename to jenkins/build_defs/jenkins_nodes.bzl
index 7704d87..80a805f 100644
--- a/jenkins/nodes.bzl
+++ b/jenkins/build_defs/jenkins_nodes.bzl
@@ -13,7 +13,7 @@
# limitations under the License.
# Macros to ease the creation of machines
-load(":jenkins.bzl", "jenkins_node")
+load(":jenkins_node.bzl", "jenkins_node")
def jenkins_node_names(name, count):
"""Returns the names for `count` production jenkins node prefixed by `name`."""
diff --git a/jenkins/build_defs/templates.bzl b/jenkins/build_defs/templates.bzl
new file mode 100644
index 0000000..a25d84b
--- /dev/null
+++ b/jenkins/build_defs/templates.bzl
@@ -0,0 +1,202 @@
+# Copyright 2017 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Rules for templating / files layout
+
+def _expand_template_impl(ctx):
+ """Simply spawn the template-engine in a rule."""
+ variables = [
+ "--variable=%s=%s" % (k, ctx.attr.substitutions[k])
+ for k in ctx.attr.substitutions
+ ]
+ imports = [
+ "--imports=%s=%s" % (ctx.attr.deps[i].label, ctx.files.deps[i].path)
+ for i in range(0, len(ctx.attr.deps))
+ ]
+ ctx.action(
+ executable = ctx.executable._engine,
+ arguments = [
+ "--executable" if ctx.attr.executable else "--noexecutable",
+ "--template=%s" % ctx.file.template.path,
+ "--output=%s" % ctx.outputs.out.path,
+ ] + variables + imports,
+ inputs = [ctx.file.template] + ctx.files.deps,
+ outputs = [ctx.outputs.out],
+ )
+
+expand_template = rule(
+ attrs = {
+ "template": attr.label(
+ mandatory = True,
+ allow_files = True,
+ single_file = True,
+ ),
+ "deps": attr.label_list(default = [], allow_files = True),
+ "substitutions": attr.string_dict(mandatory = True),
+ "out": attr.output(mandatory = True),
+ "executable": attr.bool(default = True),
+ "_engine": attr.label(
+ default = Label("//templating:template_engine"),
+ executable = True,
+ cfg="host"),
+ },
+ implementation = _expand_template_impl,
+)
+"""Expand a jinja2 template file.
+
+This rules expands the file given in template, into the file given by out.
+
+Args:
+ template: The template file to expand.
+ deps: additional files to expand, they will be accessible as imports[label]
+ in the template environment. If a file ends with .tpl, it is considered
+ a template itself and will be expanded.
+ deps_aliases: a dictionary of name to label. Each label in that dictionary
+ should be present in the deps attribute, and will be make accessible as
+ imports[name] in the template environment.
+ substitutions: a dictionary of key => values that will appear as variables.key
+ in the template environment.
+ out: the name of the output file to generate.
+ executable: mark the result as excutable if set to True.
+"""
+
+def _strip_prefix(path, prefixes):
+ for prefix in prefixes:
+ if path.startswith(prefix):
+ return path[len(prefix):]
+ return path
+
+def _strip_suffix(path, suffixes):
+ for suffix in suffixes:
+ if path.endswith(suffix):
+ return path[:-len(suffix)]
+ return path
+
+def _dest_path(f, strip_prefixes, strip_suffixes):
+ """Returns the short path of f, stripped of strip_prefixes and strip_suffixes."""
+ return _strip_suffix(_strip_prefix(f.short_path, strip_prefixes), strip_suffixes)
+
+def _format_path(path_format, path):
+ dirsep = path.rfind("/")
+ dirname = path[:dirsep] if dirsep > 0 else ""
+ basename = path[dirsep+1:] if dirsep > 0 else path
+ extsep = basename.rfind(".")
+ extension = basename[extsep+1:] if extsep > 0 else ""
+ basename = basename[:extsep] if extsep > 0 else basename
+ return path_format.format(
+ path=path,
+ dirname=dirname,
+ basename=basename,
+ extension=extension
+ )
+
+def _append_inputs(args, inputs, f, path, path_format):
+ args.append("--file=%s=%s" % (
+ f.path,
+ _format_path(path_format, path)
+ ))
+ inputs.append(f)
+
+def _merge_files_impl(ctx):
+ """Merge a list of config files in a tar ball with the correct layout."""
+ output = ctx.outputs.out
+ build_tar = ctx.executable._build_tar
+ inputs = []
+ args = [
+ "--output=" + output.path,
+ "--directory=" + ctx.attr.directory,
+ "--mode=0644",
+ ]
+ variables = [
+ "--variable=%s=%s" % (k, ctx.attr.substitutions[k])
+ for k in ctx.attr.substitutions
+ ]
+ for f in ctx.files.srcs:
+ path = _dest_path(f, ctx.attr.strip_prefixes, ctx.attr.strip_suffixes)
+ if path.endswith(ctx.attr.template_extension):
+ path = path[:-4]
+ f2 = ctx.new_file(ctx.label.name + "/" + path)
+ ctx.action(
+ executable = ctx.executable._engine,
+ arguments = [
+ "--template=%s" % f.path,
+ "--output=%s" % f2.path,
+ "--noescape_xml",
+ ] + variables,
+ inputs = [f],
+ outputs = [f2],
+ )
+ _append_inputs(args, inputs, f2, path, ctx.attr.path_format)
+ else:
+ _append_inputs(args, inputs, f, path, ctx.attr.path_format)
+ ctx.action(
+ executable = build_tar,
+ arguments = args,
+ inputs = inputs,
+ outputs = [output],
+ mnemonic="MergeFiles"
+ )
+
+merge_files = rule(
+ attrs = {
+ "srcs": attr.label_list(allow_files=True),
+ "template_extension": attr.string(default=".tpl"),
+ "directory": attr.string(default="/"),
+ "strip_prefixes": attr.string_list(default=[]),
+ "strip_suffixes": attr.string_list(default=["-staging", "-test"]),
+ "substitutions": attr.string_dict(default={}),
+ "path_format": attr.string(default="{path}"),
+ "_build_tar": attr.label(
+ default=Label("@bazel_tools//tools/build_defs/pkg:build_tar"),
+ cfg="host",
+ executable=True,
+ allow_files=True),
+ "_engine": attr.label(
+ cfg="host",
+ default = Label("//templating:template_engine"),
+ executable = True),
+ },
+ outputs = {"out": "%{name}.tar"},
+ implementation = _merge_files_impl,
+)
+"""Merge a set of files in a single tarball.
+
+This rule merge a set of files into one tarball, each file will appear in the
+tarball as a file determined by path_format, strip_prefixes and directory.
+
+Outputs:
+ <name>.tar: the tarball containing all the files in srcs.
+
+Args:
+ srcs: The list of files to merge. If a file is ending with ".tpl" (see
+ template_extension), it will get expanded like a template passed to
+ expand_template.
+ template_extension: extension of files to be considered as template, ".tpl"
+ by default.
+ directory: base directory for all the files in the resulting tarball.
+ strip_prefixes: list of prefixes to strip from the path of the srcs to obtain
+ the final path (see path_format).
+ strip_suffixes: list of suffixes to strip from the path of the srcs to obtain
+ the final path (see path_format).
+ substitutions: map of substitutions to make available during template
+ expansion. Values of that map will be available as "variables.name" in
+ the template environment.
+ path_format: format of the final files. Each file will appear in the final
+ tarball under "{directory}/{path_format}" where the following string of
+ path_format are replaced:
+ {path}: path of the input file, removed from prefixes and suffixes,
+ {dirname}: directory name of path,
+ {basename}: base filename of path,
+ {extension}: extension of path
+"""
diff --git a/jenkins/build_defs/vars.bzl b/jenkins/build_defs/vars.bzl
new file mode 100644
index 0000000..3892447
--- /dev/null
+++ b/jenkins/build_defs/vars.bzl
@@ -0,0 +1,21 @@
+# Copyright 2017 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Global constants for jenkins jobs substitutions
+
+MAIL_SUBSTITUTIONS = {
+ "BAZEL_BUILD_RECIPIENT": "bazel-ci@googlegroups.com",
+ "BAZEL_RELEASE_RECIPIENT": "bazel-discuss+release@googlegroups.com",
+ "SENDER_EMAIL": "noreply@bazel.io",
+}
diff --git a/jenkins/jenkins.bzl b/jenkins/jenkins.bzl
deleted file mode 100644
index 6410d31..0000000
--- a/jenkins/jenkins.bzl
+++ /dev/null
@@ -1,446 +0,0 @@
-# Copyright 2015 The Bazel Authors. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Some definition to setup jenkins and build the corresponding docker images
-
-load("@bazel_tools//tools/build_defs/docker:docker.bzl", "docker_build")
-load("@bazel_tools//tools/build_defs/pkg:pkg.bzl", "pkg_tar")
-
-JENKINS_PORT = 80
-JENKINS_HOST = "jenkins"
-
-MAILS_SUBSTITUTIONS = {
- "BAZEL_BUILD_RECIPIENT": "bazel-ci@googlegroups.com",
- "BAZEL_RELEASE_RECIPIENT": "bazel-discuss+release@googlegroups.com",
- "SENDER_EMAIL": "noreply@bazel.io",
-}
-
-def expand_template_impl(ctx):
- """Simply spawn the template-engine in a rule."""
- variables = [
- "--variable=%s=%s" % (k, ctx.attr.substitutions[k])
- for k in ctx.attr.substitutions
- ]
- imports = [
- "--imports=%s=%s" % (ctx.attr.deps[i].label, ctx.files.deps[i].path)
- for i in range(0, len(ctx.attr.deps))
- ]
- ctx.action(
- executable = ctx.executable._engine,
- arguments = [
- "--executable" if ctx.attr.executable else "--noexecutable",
- "--template=%s" % ctx.file.template.path,
- "--output=%s" % ctx.outputs.out.path,
- ] + variables + imports,
- inputs = [ctx.file.template] + ctx.files.deps,
- outputs = [ctx.outputs.out],
- )
-
-expand_template = rule(
- attrs = {
- "template": attr.label(
- mandatory = True,
- allow_files = True,
- single_file = True,
- ),
- "deps": attr.label_list(default = [], allow_files = True),
- "substitutions": attr.string_dict(mandatory = True),
- "out": attr.output(mandatory = True),
- "executable": attr.bool(default = True),
- "_engine": attr.label(
- default = Label("//templating:template_engine"),
- executable = True,
- cfg="host"),
- },
- implementation = expand_template_impl,
-)
-
-def _dest_path(f, strip_prefixes):
- """Returns the short path of f, stripped of strip_prefix."""
- for strip_prefix in strip_prefixes:
- if f.short_path.startswith(strip_prefix):
- return f.short_path[len(strip_prefix):]
- return f.short_path
-
-def _format_path(path_format, path):
- dirsep = path.rfind("/")
- dirname = path[:dirsep] if dirsep > 0 else ""
- basename = path[dirsep+1:] if dirsep > 0 else path
- extsep = basename.rfind(".")
- extension = basename[extsep+1:] if extsep > 0 else ""
- basename = basename[:extsep] if extsep > 0 else basename
- flavor = ""
- if basename.endswith("-staging"):
- basename = basename[:-8]
- flavor = "staging"
- elif basename.endswith("-test"):
- basename = basename[:-5]
- flavor = "test"
- return path_format.format(
- path=path,
- dirname=dirname,
- basename=basename,
- flavor=flavor,
- extension=extension
- )
-
-def _append_inputs(args, inputs, f, path, path_format):
- args.append("--file=%s=%s" % (
- f.path,
- _format_path(path_format, path)
- ))
- inputs.append(f)
-
-def _merge_files_impl(ctx):
- """Merge a list of config files in a tar ball with the correct layout."""
- output = ctx.outputs.out
- build_tar = ctx.executable._build_tar
- inputs = []
- args = [
- "--output=" + output.path,
- "--directory=" + ctx.attr.directory,
- "--mode=0644",
- ]
- variables = [
- "--variable=%s=%s" % (k, ctx.attr.substitutions[k])
- for k in ctx.attr.substitutions
- ]
- for f in ctx.files.srcs:
- path = _dest_path(f, ctx.attr.strip_prefixes)
- if path.endswith(".tpl"):
- path = path[:-4]
- f2 = ctx.new_file(ctx.label.name + "/" + path)
- ctx.action(
- executable = ctx.executable._engine,
- arguments = [
- "--template=%s" % f.path,
- "--output=%s" % f2.path,
- "--noescape_xml",
- ] + variables,
- inputs = [f],
- outputs = [f2],
- )
- _append_inputs(args, inputs, f2, path, ctx.attr.path_format)
- else:
- _append_inputs(args, inputs, f, path, ctx.attr.path_format)
- ctx.action(
- executable = build_tar,
- arguments = args,
- inputs = inputs,
- outputs = [output],
- mnemonic="MergeFiles"
- )
-
-_merge_files = rule(
- attrs = {
- "srcs": attr.label_list(allow_files=True),
- "template_extension": attr.string(default=".tpl"),
- "directory": attr.string(default="/"),
- "strip_prefixes": attr.string_list(default=[]),
- "substitutions": attr.string_dict(default={}),
- "path_format": attr.string(default="{path}"),
- "_build_tar": attr.label(
- default=Label("@bazel_tools//tools/build_defs/pkg:build_tar"),
- cfg="host",
- executable=True,
- allow_files=True),
- "_engine": attr.label(
- cfg="host",
- default = Label("//templating:template_engine"),
- executable = True),
- },
- outputs = {"out": "%{name}.tar"},
- implementation = _merge_files_impl,
-)
-
-def jenkins_job(name, config, substitutions = {}, deps = [],
- project='bazel', org='bazelbuild', git_url=None, project_url=None,
- platforms=[], test_platforms=["linux-x86_64"]):
- """Create a job configuration on Jenkins.
-
- Args:
- name: the name of the job to create
- config: the configuration file for the job
- substitutions: additional substitutions to pass to the template generation
- deps: list of dependencies (templates included by the config file)
- project: the project name on github
- org: the project organization on github, default 'bazelbuild'
- git_url: the URL to the git project, defaulted to the Github URL
- project_url: the project url, defaulted to the Git URL
- platforms: platforms on which to run that job, default None,
- test_platforms: platforms on which to run that job when inside of a
- dockerized test, by default only 'linux-x86_64'
- """
- github_project = "%s/%s" % (org, project.lower())
- github_url = "https://github.com/" + github_project
- if not git_url:
- git_url = github_url
- if not project_url:
- project_url = git_url
- substitutions = substitutions + {
- "GITHUB_URL": github_url,
- "GIT_URL": git_url,
- "GITHUB_PROJECT": github_project,
- "PROJECT_URL": project_url,
- "PLATFORMS": "\n".join(platforms),
- } + MAILS_SUBSTITUTIONS
- substitutions["SEND_EMAIL"] = "1"
- expand_template(
- name = name,
- template = config,
- out = "%s.xml" % name,
- deps = deps,
- substitutions = substitutions,
- )
- substitutions["SEND_EMAIL"] = "0"
- expand_template(
- name = name + "-staging",
- template = config,
- out = "%s-staging.xml" % name,
- deps = deps,
- substitutions = substitutions,
- )
-
- if test_platforms:
- substitutions["PLATFORMS"] = "\n".join(test_platforms)
- expand_template(
- name = name + "-test",
- template = config,
- out = "%s-test.xml" % name,
- deps = deps,
- substitutions = substitutions,
- )
-
-def bazel_git_job(**kwargs):
- """Override bazel_github_job to test a project that is not on GitHub."""
- kwargs["github_enabled"] = False
- if not "git_url" in kwargs:
- if not "project_url" in kwargs:
- fail("Neither project_url nor git_url was specified")
- kwargs["git_url"] = kwargs
- bazel_github_job(**kwargs)
-
-def bazel_github_job(name, platforms=[], branch="master", project=None, org="google",
- project_url=None, workspace=".", configure=[], git_url=None,
- bazel_versions=["HEAD", "latest"],
- tests=["//..."], targets=["//..."], substitutions={},
- windows_configure=[],
- windows_tests=["//..."], windows_targets=["//..."],
- windows_tests_msys=["//..."], windows_targets_msys=["//..."],
- test_opts=["--test_output=errors", "--build_tests_only"],
- test_tag_filters=["-noci", "-manual"],
- build_opts=["--verbose_failures"],
- test_platforms=["linux-x86_64"],
- enable_trigger=True,
- gerrit_project=None,
- enabled=True,
- pr_enabled=True,
- github_enabled=True,
- run_sequential=False,
- sauce_enabled=False):
- """Create a generic github job configuration to build against Bazel head."""
- if not project:
- project = name
- substitutions = substitutions + {
- "WORKSPACE": workspace,
- "PROJECT_NAME": project,
- "BRANCH": branch,
- "CONFIGURE": "\n".join(configure),
- "WINDOWS_CONFIGURE": "\n".join(windows_configure),
- "TEST_OPTS": " ".join(test_opts),
- "TEST_TAG_FILTERS": ",".join(test_tag_filters),
- "BUILD_OPTS": " ".join(build_opts),
- "TESTS": " + ".join(tests),
- "WINDOWS_TESTS": " ".join(windows_tests),
- # TODO(pcloudy): remove *_MSYS attributes when we don't need MSYS anymore
- "WINDOWS_TESTS_MSYS": " ".join(windows_tests_msys),
- "BUILDS": " ".join(targets),
- "WINDOWS_BUILDS": " ".join(windows_targets),
- "WINDOWS_BUILDS_MSYS": " ".join(windows_targets_msys),
- "BAZEL_VERSIONS": "\n".join(bazel_versions),
- "disabled": str(not enabled).lower(),
- "enable_trigger": str(enable_trigger and github_enabled).lower(),
- "github": str(github_enabled),
- "GERRIT_PROJECT": str(gerrit_project),
- "RUN_SEQUENTIAL": str(run_sequential).lower(),
- "SAUCE_ENABLED": str(sauce_enabled).lower(),
- }
-
- jenkins_job(
- name = name,
- config = "//jenkins:github-jobs.xml.tpl",
- deps = [
- "//jenkins:github-jobs.sh.tpl",
- "//jenkins:github-jobs.bat.tpl",
- "//jenkins:github-jobs.test-logs.sh.tpl",
- "//jenkins:github-jobs.test-logs.bat.tpl",
- ],
- substitutions=substitutions,
- git_url=git_url,
- project=project,
- org=org,
- project_url=project_url,
- platforms=platforms,
- test_platforms=test_platforms)
- substitutions["BAZEL_VERSIONS"] = "\n".join([
- v for v in bazel_versions if not v.startswith("HEAD")])
- if pr_enabled:
- jenkins_job(
- name = "PR-" + name,
- config = "//jenkins:github-jobs-PR.xml.tpl",
- deps = [
- "//jenkins:github-jobs.sh.tpl",
- "//jenkins:github-jobs.bat.tpl",
- "//jenkins:github-jobs.test-logs.sh.tpl",
- "//jenkins:github-jobs.test-logs.bat.tpl",
- ],
- substitutions=substitutions,
- project=project,
- org=org,
- project_url=project_url,
- platforms=platforms,
- test_platforms=test_platforms)
- if gerrit_project != None:
- jenkins_job(
- name = "Gerrit-" + name,
- config = "//jenkins:github-jobs-Gerrit.xml.tpl",
- deps = [
- "//jenkins:github-jobs.sh.tpl",
- "//jenkins:github-jobs.bat.tpl",
- "//jenkins:github-jobs.test-logs.sh.tpl",
- "//jenkins:github-jobs.test-logs.bat.tpl",
- ],
- substitutions=substitutions,
- project=project,
- org=org,
- project_url=project_url,
- platforms=platforms,
- test_platforms=test_platforms)
-
-
-def jenkins_node(name, remote_fs = "/home/ci", num_executors = 1, mode = "NORMAL",
- labels = [], docker_base = None, preference = 1,
- visibility = None):
- """Create a node configuration on Jenkins, with possible docker image.
-
- Args:
- name: Name of the node on Jenkins.
- remote_fs: path to the home of the Jenkins user.
- num_executors: number of executors (i.e. concurrent build) this machine can have.
- mode: NORMAL for "Utilize this node as much as possible"
- EXCLUSIVE for "Only build jobs with label restrictions matching this node"
- labels: list of Jenkins labels for this node (the node name is always added).
- docker_base: base for the corresponding docker image to create if we should create one
- (if docker_base is not specified, then a corresponding machine should be configured
- to connect to the Jenkins master).
- preference: A preference factor, if a node as a factor of 1 and another a factor of
- 4, then the second one will be scheduled 4 time more jobs than the first one.
- visibility: rule visibility.
- """
- native.genrule(
- name = name,
- cmd = """cat >$@ <<'EOF'
-<?xml version='1.0' encoding='UTF-8'?>
-<slave>
- <name>%s</name>
- <description></description>
- <remoteFS>%s</remoteFS>
- <numExecutors>%s</numExecutors>
- <mode>%s</mode>
- <retentionStrategy class="hudson.slaves.RetentionStrategy$$Always"/>
- <launcher class="hudson.slaves.JNLPLauncher"/>
- <label>%s</label>
- <nodeProperties>
- <jp.ikedam.jenkins.plugins.scoringloadbalancer.preferences.BuildPreferenceNodeProperty plugin="scoring-load-balancer@1.0.1">
- <preference>%s</preference>
- </jp.ikedam.jenkins.plugins.scoringloadbalancer.preferences.BuildPreferenceNodeProperty>
- </nodeProperties>
-</slave>
-EOF
-""" % (name, remote_fs, num_executors, mode, " ".join([name] + labels), preference),
- outs = ["nodes/%s/config.xml" % name],
- visibility = visibility,
- )
- if docker_base:
- # Generate docker image startup script
- expand_template(
- name = name + ".docker-launcher",
- out = name + ".docker-launcher.sh",
- template = "slave_setup.sh",
- substitutions = {
- "NODE_NAME": name,
- "HOME_FS": remote_fs,
- "JENKINS_SERVER": "http://%s:%s" % (JENKINS_HOST, JENKINS_PORT),
- },
- executable = True,
- )
- # Generate docker image
- docker_build(
- name = name + ".docker",
- base = docker_base,
- volumes = [remote_fs],
- files = [":%s.docker-launcher.sh" % name],
- data_path = ".",
- entrypoint = [
- "/bin/bash",
- "/%s.docker-launcher.sh" % name,
- ],
- visibility = visibility,
- )
-
-def jenkins_build(name, plugins = None, base = "//jenkins/base", configs = [],
- jobs = [], substitutions = {}, visibility = None, tars = []):
- """Build the docker image for the Jenkins instance."""
- substitutions = substitutions + MAILS_SUBSTITUTIONS
- # Expands config files in a tar ball
- _merge_files(
- name = "%s-configs" % name,
- srcs = configs,
- directory = "/usr/share/jenkins/ref",
- strip_prefixes = [
- "jenkins/config",
- "jenkins",
- ],
- substitutions = substitutions)
-
- # Create the structures for jobs
- _merge_files(
- name = "%s-jobs" % name,
- srcs = jobs,
- path_format = "jobs/{basename}/config.xml",
- directory = "/usr/share/jenkins/ref",
- )
-
- ### FINAL IMAGE ###
- docker_build(
- name = name,
- tars = [
- ":%s-jobs" % name,
- ":%s-configs" % name,
- ] + tars,
- # Workaround no way to specify owner in pkg_tar
- # TODO(dmarting): use https://cr.bazel.build/10255 when it hits a release.
- user = "root",
- entrypoint = [
- "/bin/tini",
- "--",
- "/bin/bash",
- "-c",
- "[ -d /opt/lib ] && chown -R jenkins /opt/lib; su jenkins -c /usr/local/bin/jenkins.sh",
- ],
- # End of workaround
- base = base,
- directory = "/",
- visibility = visibility,
- )
diff --git a/jenkins/jobs/BUILD b/jenkins/jobs/BUILD
index d53d133..ca5a5ef 100644
--- a/jenkins/jobs/BUILD
+++ b/jenkins/jobs/BUILD
@@ -1,4 +1,4 @@
-load("//jenkins:jenkins.bzl", "jenkins_job", "bazel_github_job", "bazel_git_job")
+load("//jenkins/build_defs:jenkins.bzl", "jenkins_job", "bazel_github_job", "bazel_git_job")
load(
":jobs.bzl",
"LINUX_PLATFORMS",