-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds scan build to Github Actions (#324)
- Loading branch information
1 parent
157afcd
commit 5c4bd25
Showing
2 changed files
with
240 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
#!/usr/bin/python3 | ||
# Copyright 2020 Toyota Research Institute | ||
|
||
import os | ||
import sys | ||
|
||
EXTRA_EXCLUDE_ARGS = " --exclude src/pybind11 --exclude /usr/include/eigen3 " | ||
|
||
def get_package_dependencies_names(packages_up_to = None): | ||
''' | ||
Returns a set of dependencies by name of all the `packages-up-to` argument. | ||
When None is provided, all the packages are returned. | ||
''' | ||
stream = os.popen('colcon graph') if not packages_up_to else os.popen('colcon graph --packages-up-to ' + packages_up_to) | ||
|
||
colcon_graph = stream.read().splitlines() | ||
result = set() | ||
for line in colcon_graph: | ||
result.add(line[:line.find(' ')]) | ||
return result | ||
|
||
def get_exclusion_paths_from_file(filepath, store): | ||
''' | ||
Get the paths located in the `filepath` and save them in the `store` set. | ||
''' | ||
if(os.path.exists(filepath)): | ||
with open(filepath) as fp: | ||
for line in fp.readlines(): | ||
store.add(line.replace('\n', ' ')) | ||
|
||
def convert_in_exclude_argument(paths): | ||
''' | ||
Convert a set of paths in a `--exclude`s arguments of scan-build command. | ||
''' | ||
final_string = '' | ||
for path in paths: | ||
final_string = final_string + " --exclude " + str(path) | ||
return final_string | ||
|
||
def get_effective_key(args): | ||
class Key: | ||
def __init__(self, name): | ||
self.name = name | ||
self.counter = 0 | ||
self.index = 0 | ||
|
||
keys = [Key("--packages-select"), Key("--packages-up-to")] | ||
for i, potential_key in enumerate(keys): | ||
keys[i].counter = args.count(potential_key.name) | ||
if (keys[i].counter > 0): | ||
keys[i].index = args.index(potential_key.name) | ||
|
||
if (keys[0].counter == 0 and keys[1].counter == 0): | ||
return '' | ||
elif (keys[0].counter == keys[1].counter): | ||
# When there are two keys present, it just cares about the first one as colcon does. | ||
return keys[0].name if keys[0].index < keys[1].index else keys[1].name | ||
else: | ||
return keys[0].name if keys[0].counter else keys[1].name | ||
|
||
def is_colcon_option(arg): | ||
return True if (arg[0:2] == '--') else False | ||
|
||
def get_packages_from_args(args): | ||
key = get_effective_key(args) | ||
if not key: | ||
return set() | ||
index_of_key = args.index(key) | ||
|
||
packages = set() | ||
indexer = 1 | ||
while (len(args) > (index_of_key + indexer)) and (not is_colcon_option(args[index_of_key + indexer])): | ||
packages.add(args[index_of_key + indexer]) | ||
indexer += 1 | ||
return packages | ||
|
||
def get_packages_to_get_excludes_file_of(packages): | ||
packages_to_get_exclude_file_of = set() | ||
if not packages: | ||
packages_to_get_exclude_file_of = packages_to_get_exclude_file_of.union(get_package_dependencies_names()) | ||
else: | ||
for package_from_arg in packages: | ||
packages_to_get_exclude_file_of = packages_to_get_exclude_file_of.union(get_package_dependencies_names(package_from_arg)) | ||
return packages_to_get_exclude_file_of | ||
|
||
|
||
def generate_exclude_args(argv): | ||
packages_from_arg = get_packages_from_args(argv) | ||
packages_to_get_exclude_file_of = get_packages_to_get_excludes_file_of(packages_from_arg) | ||
|
||
exclusion_paths = set() | ||
for package in packages_to_get_exclude_file_of: | ||
package_path = os.popen('colcon list --packages-select ' + package + ' --paths-only') | ||
command = 'find ' + package_path.read().splitlines()[0] + ' -name scan_build.supp' | ||
find = os.popen(command) | ||
supp_filepaths = find.read().splitlines() | ||
for filepath in supp_filepaths: | ||
get_exclusion_paths_from_file(filepath, exclusion_paths) | ||
return convert_in_exclude_argument(exclusion_paths) | ||
|
||
def main(argv): | ||
excludes_args = generate_exclude_args(argv) | ||
excludes_args += EXTRA_EXCLUDE_ARGS | ||
|
||
colcon_extra_build_args = " ".join(argv[1:]) if(len(argv) > 1) else "" | ||
cmd = "scan-build-8 --status-bugs --use-cc=clang --use-c++=clang++ {} colcon build {} ".format(excludes_args, colcon_extra_build_args) | ||
print("scan-build command...\n--> " + cmd) | ||
return_code = os.system(cmd) | ||
if return_code > 255 : | ||
sys.exit(1) | ||
else: | ||
sys.exit(0) | ||
|
||
if __name__ == "__main__": | ||
main(sys.argv) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
name: scan_build | ||
|
||
on: | ||
push: | ||
branches: | ||
- master | ||
pull_request: | ||
|
||
env: | ||
PACKAGE_NAME: delphyne-gui | ||
EXTRA_PACKAGE_NAME: delphyne-demos | ||
ROS_DISTRO: dashing | ||
ROS_WS: maliput_ws | ||
|
||
jobs: | ||
static_analysis: | ||
name: Static analysis | ||
runs-on: ubuntu-18.04 | ||
container: | ||
image: ubuntu:18.04 | ||
steps: | ||
# setup-ros first since it installs git, which is needed to fetch all branches from actions/checkout | ||
- uses: ros-tooling/[email protected] | ||
# install git from ppa since git 2.18+ is needed to fetch all branches from actions/checkout | ||
# this step can be removed on 20.04 | ||
- name: install git from ppa | ||
shell: bash | ||
run: | | ||
apt update; | ||
apt install -y software-properties-common; | ||
add-apt-repository -y -u ppa:git-core/ppa; | ||
apt install -y git; | ||
- uses: actions/checkout@v2 | ||
with: | ||
path: ${{ env.ROS_WS }}/src/${{ env.PACKAGE_NAME }} | ||
# clone private dependencies | ||
- uses: actions/checkout@v2 | ||
with: | ||
repository: ToyotaResearchInstitute/maliput | ||
fetch-depth: 0 | ||
path: ${{ env.ROS_WS }}/src/maliput | ||
token: ${{ secrets.MALIPUT_TOKEN }} | ||
- uses: actions/checkout@v2 | ||
with: | ||
repository: ToyotaResearchInstitute/maliput-dragway | ||
fetch-depth: 0 | ||
path: ${{ env.ROS_WS }}/src/maliput_dragway | ||
token: ${{ secrets.MALIPUT_TOKEN }} | ||
- uses: actions/checkout@v2 | ||
with: | ||
repository: ToyotaResearchInstitute/maliput-multilane | ||
fetch-depth: 0 | ||
path: ${{ env.ROS_WS }}/src/maliput_multilane | ||
token: ${{ secrets.MALIPUT_TOKEN }} | ||
- uses: actions/checkout@v2 | ||
with: | ||
repository: ToyotaResearchInstitute/malidrive | ||
fetch-depth: 0 | ||
path: ${{ env.ROS_WS }}/src/malidrive | ||
token: ${{ secrets.MALIPUT_TOKEN }} | ||
- uses: actions/checkout@v2 | ||
with: | ||
repository: ToyotaResearchInstitute/delphyne | ||
fetch-depth: 0 | ||
path: ${{ env.ROS_WS }}/src/delphyne | ||
token: ${{ secrets.MALIPUT_TOKEN }} | ||
- uses: actions/checkout@v2 | ||
with: | ||
repository: ToyotaResearchInstitute/drake-vendor | ||
fetch-depth: 0 | ||
path: ${{ env.ROS_WS }}/src/drake_vendor | ||
token: ${{ secrets.MALIPUT_TOKEN }} | ||
- uses: actions/checkout@v2 | ||
with: | ||
repository: ToyotaResearchInstitute/dsim-repos-index | ||
fetch-depth: 0 | ||
path: dsim-repos-index | ||
token: ${{ secrets.MALIPUT_TOKEN }} | ||
- name: check if dependencies have a matching branch | ||
shell: bash | ||
working-directory: ${{ env.ROS_WS }}/src | ||
run: ./${PACKAGE_NAME}/.github/try_vcs_checkout ${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}} . | ||
# install drake_vendor prereqs using dsim-repos-index/tools/prereqs.lib | ||
- name: install drake_vendor prereqs | ||
shell: bash | ||
working-directory: ${{ env.ROS_WS }}/src/drake_vendor | ||
run: ${GITHUB_WORKSPACE}/dsim-repos-index/tools/prereqs-install -t drake . | ||
# install delphyne prereqs using dsim-repos-index/tools/prereqs.lib | ||
- name: install delphyne prereqs | ||
shell: bash | ||
working-directory: ${{ env.ROS_WS }}/src/delphyne | ||
run: ${GITHUB_WORKSPACE}/dsim-repos-index/tools/prereqs-install -t ignition . | ||
# install delphyne-gui prereqs using dsim-repos-index/tools/prereqs.lib | ||
- name: install delphyne-gui prereqs | ||
shell: bash | ||
working-directory: ${{ env.ROS_WS }}/src/delphyne-gui | ||
run: ${GITHUB_WORKSPACE}/dsim-repos-index/tools/prereqs-install -t ignition . | ||
- name: clang 8 install | ||
shell: bash | ||
run: ${{ env.ROS_WS }}/src/${PACKAGE_NAME}/.github/clang_suite_installation.sh | ||
# clone public dependencies | ||
- name: vcs import | ||
shell: bash | ||
working-directory: ${{ env.ROS_WS }} | ||
run: vcs import src < src/${PACKAGE_NAME}/.github/dependencies.repos | ||
- run: colcon graph | ||
shell: bash | ||
working-directory: ${{ env.ROS_WS }} | ||
- name: rosdep install | ||
shell: bash | ||
working-directory: ${{ env.ROS_WS }} | ||
run: | | ||
rosdep update; | ||
rosdep install -i -y --rosdistro ${ROS_DISTRO} \ | ||
--skip-keys "ignition-transport5 ignition-msgs2 ignition-math6 ignition-common3 ignition-gui0 ignition-rendering2 libqt5multimedia5 pybind11" \ | ||
--from-paths src | ||
- name: scan_build | ||
shell: bash | ||
working-directory: ${{ env.ROS_WS }} | ||
run: | | ||
. /opt/ros/${ROS_DISTRO}/setup.bash; | ||
./src/${PACKAGE_NAME}/.github/run_scan_build \ | ||
--cmake-args -DCMAKE_LINKER=/usr/bin/llvm-ld \ | ||
--packages-up-to ${PACKAGE_NAME} ${EXTRA_PACKAGE_NAME} \ | ||
--event-handlers=console_direct+; |