Skip to content

Commit 513d99f

Browse files
authored
Add Lint and Test CI Pipelines (#5)
1 parent cc5b60c commit 513d99f

21 files changed

Lines changed: 902 additions & 54 deletions

File tree

.cruft.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
{
2-
"template": "git@github.com:UrbanMachine/create-ros-app.git",
3-
"commit": "a4e77fcc6f6764f18d0785c030c60dda90e17ed6",
2+
"template": "https://github.com/UrbanMachine/create-ros-app.git",
3+
"commit": "8c8e34317b3cf0db5459958d7a50accfd0cc93cd",
44
"checkout": null,
55
"context": {
66
"cookiecutter": {
77
"email": "alex@urbanmachine.build",
88
"github_username_or_org": "urbanmachine",
99
"dockerhub_username_or_org": "urbanmachine",
1010
"project_name": "node_helpers",
11+
"__project_name_slug": "node_helpers",
1112
"project_description": "An opinionated ROS2 framework that minimizes boilerplate while maximizing reliability. Features intuitive APIs for parameter management, action handling, and error-resilient RPC. Designed by Urban Machine for safe and scalable robotics.",
1213
"version": "0.5.0",
1314
"license": "MIT",
@@ -17,7 +18,7 @@
1718
"example_launch_profile": "node_helpers_showcase",
1819
"example_package_version": "0.5.0",
1920
"__example_messages_package_name": "node_helpers_msgs",
20-
"_template": "git@github.com:UrbanMachine/create-ros-app.git"
21+
"_template": "https://github.com/UrbanMachine/create-ros-app.git"
2122
}
2223
},
2324
"directory": null

.github/lint/lint_eslint.py

Lines changed: 0 additions & 13 deletions
This file was deleted.

.github/lint/main.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,11 @@
66
from .errors import CommandError
77
from .lint_clang_format import lint_clang_format
88
from .lint_darglint import lint_darglint
9-
from .lint_eslint import lint_eslint
109
from .lint_mypy import lint_mypy
1110
from .lint_ruff import lint_ruff_check, lint_ruff_format
1211
from .lint_shellcheck import lint_shellcheck
1312

1413
PYTHON_LANGUAGE = "python"
15-
JAVASCRIPT_LANGUAGE = "javascript"
1614
CPP_LANGUAGE = "cpp"
1715
BASH_LANGUAGE = "bash"
1816
ALL_LANGUAGES = "all"
@@ -26,9 +24,6 @@
2624
lint_darglint,
2725
lint_mypy,
2826
],
29-
JAVASCRIPT_LANGUAGE: [
30-
lint_eslint,
31-
],
3227
CPP_LANGUAGE: [
3328
lint_clang_format,
3429
],

.github/lint/paths.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ def required_path(path_str: str) -> Path:
1111

1212
ROS_PATH = required_path("pkgs")
1313
LINT_PATH = required_path(".github/lint")
14-
JS_PATH = Path()
1514
FIRMWARE_PATH = Path()
1615
LAUNCH_PATH = required_path("launch-profiles")
1716

.github/workflows/lint.yaml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
2+
name: Lint
3+
4+
on: [ push ]
5+
6+
jobs:
7+
check_lint:
8+
runs-on: ubuntu-24.04
9+
10+
steps:
11+
- uses: actions/checkout@v4
12+
- name: pip cache
13+
uses: actions/cache@v4
14+
with:
15+
path: ~/.cache/pip
16+
key: lint-pip-${{ hashFiles('**/pyproject.toml') }}
17+
restore-keys: |
18+
lint-pip-
19+
- name: Set up Python 3.12
20+
uses: actions/setup-python@v5
21+
with:
22+
python-version: '3.12'
23+
- name: Install Python dependencies
24+
run: |
25+
python -m pip install --upgrade pip
26+
python -m pip install --upgrade poetry
27+
poetry install
28+
- name: Install Bash dependencies
29+
run: sudo apt-get install --yes shellcheck
30+
- name: Lint
31+
run: poetry run lint --languages all --mode check
32+
33+
check_upstream_template:
34+
runs-on: ubuntu-24.04
35+
36+
steps:
37+
- uses: actions/checkout@v4
38+
- name: pip cache
39+
uses: actions/cache@v4
40+
with:
41+
path: ~/.cache/pip
42+
key: lint-pip-${{ hashFiles('**/pyproject.toml') }}
43+
restore-keys: |
44+
lint-pip-
45+
- name: Set up Python 3.12
46+
uses: actions/setup-python@v5
47+
with:
48+
python-version: '3.12'
49+
- name: Install Python dependencies
50+
run: |
51+
python -m pip install --upgrade pip
52+
python -m pip install --upgrade poetry
53+
poetry install
54+
- name: Check Upstream Template
55+
run: poetry run cruft check

.github/workflows/test.yaml

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
name: Test
2+
3+
on: [ push ]
4+
5+
jobs:
6+
# This job builds the Docker image that will be used in the following test job.
7+
# It also publishes the image to the GitHub Container Registry, so every PR can
8+
# have an up-to-date image by the name of ghcr.io/GITHUB_USERNAME/PROJECT_NAME:BRANCH_NAME
9+
build-image:
10+
runs-on: ubuntu-24.04
11+
env:
12+
BUILT_IMAGE_NAME: ghcr.io/urbanmachine/node_helpers
13+
PROJECT_NAME: node_helpers
14+
15+
defaults:
16+
run:
17+
shell: bash
18+
steps:
19+
- name: Create A Unique Tag For This Image Based On Branch Name
20+
id: prep
21+
run: |
22+
if [[ "${GITHUB_REF}" == "refs/heads/"* ]]
23+
then
24+
# This is a build on a branch
25+
TAG=${GITHUB_REF#refs/heads/}
26+
elif [[ "${GITHUB_REF}" == "refs/pull/"* ]]
27+
then
28+
# This is a PR build
29+
TAG=${GITHUB_REF#refs/pull/}
30+
elif [[ "${GITHUB_REF}" == "refs/tags/"* ]]
31+
then
32+
# This is a tagged build
33+
TAG=${GITHUB_REF#refs/tags/}
34+
else
35+
echo "Unexpected reference format ${GITHUB_REF}"
36+
exit 1
37+
fi
38+
39+
# Remove slashes, since they're not allowed in Docker tags
40+
TAG=$(echo "${TAG}" | sed 's#/#-#g')
41+
echo "tagged_image=${BUILT_IMAGE_NAME}:${TAG}" >> $GITHUB_OUTPUT
42+
- name: Set up Docker Buildx
43+
uses: docker/setup-buildx-action@v2
44+
- name: Load Previous Docker Layers Cache
45+
uses: actions/cache@v4
46+
with:
47+
path: /tmp/.buildx-cache
48+
# Key is named differently to avoid collision
49+
key: v1-${{ env.PROJECT_NAME }}-${{ runner.os }}-multi-buildx-${{ github.sha }}
50+
restore-keys: v1-${{ env.PROJECT_NAME }}-${{ runner.os }}-multi-buildx
51+
- name: Log in to GitHub Container Registry
52+
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
53+
- name: Checkout
54+
uses: actions/checkout@v4
55+
with:
56+
lfs: true
57+
- name: Get Base Image Name
58+
id: get_base_image
59+
run: |
60+
source .env
61+
echo "base_image=${BASE_IMAGE}" >> $GITHUB_OUTPUT
62+
- name: Build and push
63+
uses: docker/build-push-action@v5
64+
with:
65+
context: .
66+
file: docker/Dockerfile
67+
push: true
68+
tags: ${{ steps.prep.outputs.tagged_image }}
69+
build-args: |
70+
BASE_IMAGE=${{ steps.get_base_image.outputs.base_image }}
71+
cache-from: type=local,src=/tmp/.buildx-cache
72+
# Note the mode=max here
73+
# More: https://github.com/moby/buildkit#--export-cache-options
74+
# And: https://github.com/docker/buildx#--cache-tonametypetypekeyvalue
75+
cache-to: type=local,mode=max,dest=/tmp/.buildx-cache-new
76+
# This is done to avoid storing outdated build steps in the cache, since
77+
# BuildKit never clears stuff out of the cache itself
78+
- name: Move cache
79+
run: |
80+
rm -rf /tmp/.buildx-cache
81+
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
82+
outputs:
83+
tagged_image: ${{ steps.prep.outputs.tagged_image }}
84+
85+
# This job runs the colcon tests for the project
86+
ros-tests:
87+
needs: build-image
88+
runs-on: ubuntu-24.04
89+
defaults:
90+
run:
91+
shell: bash
92+
timeout-minutes: 40
93+
container:
94+
image: ${{needs.build-image.outputs.tagged_image}}
95+
credentials:
96+
username: ${{ github.actor }}
97+
password: ${{ secrets.GITHUB_TOKEN }}
98+
env:
99+
GITHUB_WORKSPACE: /repo/
100+
steps:
101+
- name: Install Git LFS
102+
run: sudo apt-get update && sudo apt-get install git-lfs
103+
- name: Checkout
104+
uses: actions/checkout@v4
105+
with:
106+
lfs: true
107+
- name: Fix git error in the following line
108+
# Caused by an update to git that dislikes when users of different ID's touch
109+
# the same git directory, which happens when using a docker runner in CI
110+
# This fixes test reporting in the `Generate Test Report` section
111+
# https://github.blog/2022-04-12-git-security-vulnerability-announced/
112+
# https://github.com/actions/checkout/issues/760
113+
run: git config --global --add safe.directory ${GITHUB_WORKSPACE}
114+
- name: Copy Python dependencies to github workspace
115+
run: cp -r /robot/install install
116+
- name: Copy Build output to github workspace
117+
run: cp -r /robot/install build
118+
- name: Move launch-profile files to /robot/launch-profiles so hardcoded paths work
119+
run: cp -r ${GITHUB_WORKSPACE}/launch-profiles /robot/
120+
- name: Run tests
121+
run: |
122+
enter-workspaces colcon test \
123+
--base-paths pkgs \
124+
--pytest-with-coverage \
125+
--test-result-base test-results \
126+
--pytest-args \
127+
--durations=50
128+
- name: Generate Test Report
129+
uses: dorny/test-reporter@v1
130+
if: always()
131+
with:
132+
name: "Test report"
133+
path: test-results/**/*.xml
134+
reporter: java-junit
135+
- name: Report Codecov Coverage
136+
uses: codecov/codecov-action@v3.1.0
137+
with:
138+
token: ${{ secrets.CODECOV_TOKEN }}

docker-compose.yaml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ services:
2323
- ${VOLUMES_DIRECTORY:- 'set in .env'}/ros-nodes:/robot/persistent
2424
# Mounts the 'launch-profiles/LAUNCH_PROFILE' directory into '/robot/launch-profile/'
2525
# This way you can save configuration files from GUI's like rviz right back to your source dir
26-
- "./launch-profiles/${LAUNCH_PROFILE:- 'set in docker/_shared'}:/robot/launch-profile/"
26+
# LAUNCH_PROFILE is set in docker/_shared.sh
27+
- "./launch-profiles/${LAUNCH_PROFILE}:/robot/launch-profile/"
2728
# Necessary for display passthrough
2829
- "/tmp/.X11-unix:/tmp/.X11-unix:rw"
2930
# Necessary for PulseAudio passthrough
@@ -75,8 +76,6 @@ services:
7576
loki:
7677
image: grafana/loki:3.2.1
7778
user: "root"
78-
ports:
79-
- 3100:3100
8079
volumes:
8180
- ${VOLUMES_DIRECTORY:- 'set in .env'}/loki:/loki
8281
<<: *common-config

docker/Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ ENV NVIDIA_DRIVER_CAPABILITIES=all
2020
# Set variables for caches
2121
ENV APT_CACHE=/var/cache/apt
2222
ENV PIP_CACHE=/root/.cache/pip
23-
ENV BUILD_CACHE=/cache/build
23+
ENV BUILD_CACHE=/colcon-build-cache/node_helpers/
2424
2525
# TODO: was opengl necessary?
2626
@@ -116,7 +116,7 @@ RUN --mount=type=cache,target="${BUILD_CACHE}" restore-build-cache
116116
# Build all packages, copying project files under a root `/robot/` directory in the container
117117
COPY ../launch-profiles /robot/launch-profiles
118118
COPY ../pkgs /robot/pkgs
119-
RUN enter-workspaces colcon build --symlink-install
119+
RUN enter-workspaces colcon build
120120
RUN add-workspace /robot/install/setup.bash
121121
122122
# Move the build cache back into the Docker cache mount so it can be reused on

docker/_shared.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ function is_stack_running() {
5757
# Then, the stack will be brought down.
5858
function deploy_and_wait {
5959
# Start the stack non-blockingly, because logs are best accessed via the web interface
60-
LAUNCH_PROFILE="${1}" docker compose up --detach
60+
export LAUNCH_PROFILE="${1}"
61+
docker compose up --detach
6162

6263
trap _catch_sigint INT
6364

docker/launch

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ set -o nounset
2727
function usage {
2828
echo "Usage: docker/launch [--no-pull] <launch-profile>" >&2
2929
echo "Available launch profiles are:" >&2
30-
ls -1 launch-profiles/ | sed 's/^/ - /' >&2
30+
find launch-profiles/ -maxdepth 1 -type d >&2
3131
echo "" >&2
3232
echo "Read more about 'launch-profiles' under 'docs/about_template.md'" >&2
3333
exit 1

0 commit comments

Comments
 (0)