aboutsummaryrefslogtreecommitdiff
path: root/infra/ci/build.py
diff options
context:
space:
mode:
authorjonathanmetzman <31354670+jonathanmetzman@users.noreply.github.com>2020-11-20 08:40:47 -0800
committerGitHub <noreply@github.com>2020-11-20 08:40:47 -0800
commit486c1c3e9da760409d646d367dfbd834548c16ba (patch)
tree4c0253e946e07ed96fb0f36c48f13fda390f37a4 /infra/ci/build.py
parent5fdc24206ebcef2eed894831dfd1ba709a74c566 (diff)
downloadoss-fuzz-486c1c3e9da760409d646d367dfbd834548c16ba.tar.gz
[CI] Build a canary project on infra/ changes. (#4675)
[CI] Build a canary project on infra/ changes. Build a specific project, sckms, that does msan, ubsan, asan, i386 builds quickly, when infra/ code is changed. This can let us know when infra/ changes break proper functioning of OSS-Fuzz. For this to work more thoroughly we also need to rebuild images.
Diffstat (limited to 'infra/ci/build.py')
-rwxr-xr-xinfra/ci/build.py67
1 files changed, 62 insertions, 5 deletions
diff --git a/infra/ci/build.py b/infra/ci/build.py
index 9bdbb9699..9fde53fe0 100755
--- a/infra/ci/build.py
+++ b/infra/ci/build.py
@@ -18,12 +18,15 @@
from __future__ import print_function
+import enum
import os
import re
import sys
import subprocess
import yaml
+CANARY_PROJECT = 'skcms'
+
DEFAULT_ARCHITECTURES = ['x86_64']
DEFAULT_ENGINES = ['afl', 'honggfuzz', 'libfuzzer']
DEFAULT_SANITIZERS = ['address', 'undefined']
@@ -32,13 +35,18 @@ DEFAULT_SANITIZERS = ['address', 'undefined']
LANGUAGES_WITH_COVERAGE_SUPPORT = ['c', 'c++']
+def get_changed_files():
+ """Returns the output of a git command that discovers changed files."""
+ return subprocess.check_output(['git', 'diff', '--name-only',
+ 'FETCH_HEAD']).decode()
+
+
def get_modified_buildable_projects():
"""Returns a list of all the projects modified in this commit that have a
build.sh file."""
- output = subprocess.check_output(['git', 'diff', '--name-only',
- 'FETCH_HEAD']).decode()
+ git_output = get_changed_files()
projects_regex = '.*projects/(?P<name>.*)/.*\n'
- modified_projects = set(re.findall(projects_regex, output))
+ modified_projects = set(re.findall(projects_regex, git_output))
projects_dir = os.path.join(get_oss_fuzz_root(), 'projects')
# Filter out projects without Dockerfile files since new projects and reverted
# projects frequently don't have them. In these cases we don't want Travis's
@@ -156,9 +164,22 @@ def build_project(project):
check_build(project, engine, sanitizer, architecture)
-def main():
- """Build modified projects."""
+class BuildModifiedProjectsResult(enum.Enum):
+ """Enum containing the return values of build_modified_projects()."""
+ NONE_BUILT = 0
+ BUILD_SUCCESS = 1
+ BUILD_FAIL = 2
+
+
+def build_modified_projects():
+ """Build modified projects. Returns BuildModifiedProjectsResult.NONE_BUILT if
+ no builds were attempted. Returns BuildModifiedProjectsResult.BUILD_SUCCESS if
+ all attempts succeed, otherwise returns
+ BuildModifiedProjectsResult.BUILD_FAIL."""
projects = get_modified_buildable_projects()
+ if not projects:
+ return BuildModifiedProjectsResult.NONE_BUILT
+
failed_projects = []
for project in projects:
try:
@@ -168,6 +189,42 @@ def main():
if failed_projects:
print('Failed projects:', ' '.join(failed_projects))
+ return BuildModifiedProjectsResult.BUILD_FAIL
+
+ return BuildModifiedProjectsResult.BUILD_SUCCESS
+
+
+def should_build_canary_project():
+ """Returns True if we should build the canary project."""
+ git_output = get_changed_files()
+ infra_code_regex = '.*infra/.*\n'
+ return re.search(infra_code_regex, git_output) is not None
+
+
+def build_canary_project():
+ """Builds a specific project when infra/ is changed to verify that infra/
+ changes don't break things. Returns False if build was attempted but
+ failed."""
+ if not should_build_canary_project():
+ return True
+
+ try:
+ build_project('skcms')
+ except subprocess.CalledProcessError:
+ return False
+
+ return True
+
+
+def main():
+ """Build modified projects or canary project."""
+ result = build_modified_projects()
+ if result == BuildModifiedProjectsResult.BUILD_FAIL:
+ return 1
+
+ # It's unnecessary to build the canary if we've built any projects already.
+ no_projects_built = result == BuildModifiedProjectsResult.NONE_BUILT
+ if no_projects_built and not build_canary_project():
return 1
return 0