[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.
This commit is contained in:
jonathanmetzman 2020-11-20 08:40:47 -08:00 committed by GitHub
parent 5fdc24206e
commit 486c1c3e9d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 62 additions and 5 deletions

View File

@ -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