Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 155 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
name: CI

on:
push:
branches: [ main, dev ]
pull_request:
branches: [ main, dev ]

jobs:
lint:
name: Lint
runs-on: ubuntu-latest
container:
image: osrf/ros:humble-desktop
steps:
- uses: actions/checkout@v4

- name: Install dependencies
run: |
apt-get update && apt-get install -y \
python3-pip \
python3-pytest \
python3-pytest-mock \
python3-opencv \
gstreamer1.0-tools \
gstreamer1.0-plugins-base \
gstreamer1.0-plugins-good \
gstreamer1.0-plugins-bad \
gstreamer1.0-plugins-ugly \
v4l-utils \
build-essential \
cmake \
git \
&& rm -rf /var/lib/apt/lists/*

- name: Setup workspace structure
run: |
mkdir -p ws/src
cp -r camera_ros lucy_bringup ws/src/

- name: Build workspace
working-directory: /__w/lucy_ros_packages/lucy_ros_packages/ws
shell: bash
run: |
source /opt/ros/humble/setup.bash
colcon build --packages-select camera_ros lucy_bringup --cmake-args -DBUILD_TESTING=ON

- name: Run linters
working-directory: /__w/lucy_ros_packages/lucy_ros_packages/ws
shell: bash
run: |
source /opt/ros/humble/setup.bash
source install/setup.bash
colcon test --packages-select camera_ros lucy_bringup --event-handlers console_direct+ || true

- name: Check lint results
working-directory: /__w/lucy_ros_packages/lucy_ros_packages/ws
shell: bash
run: |
source /opt/ros/humble/setup.bash
source install/setup.bash
colcon test-result --verbose || true

test:
name: Unit Tests
runs-on: ubuntu-latest
container:
image: osrf/ros:humble-desktop
steps:
- uses: actions/checkout@v4

- name: Install dependencies
run: |
apt-get update && apt-get install -y \
python3-pip \
python3-pytest \
python3-pytest-mock \
python3-opencv \
gstreamer1.0-tools \
gstreamer1.0-plugins-base \
gstreamer1.0-plugins-good \
gstreamer1.0-plugins-bad \
gstreamer1.0-plugins-ugly \
v4l-utils \
build-essential \
cmake \
git \
&& rm -rf /var/lib/apt/lists/*

- name: Install Python test dependencies
run: |
pip3 install --no-cache-dir pytest pytest-mock pytest-cov

- name: Setup workspace structure
run: |
mkdir -p ws/src
cp -r camera_ros lucy_bringup ws/src/

- name: Build workspace with tests
working-directory: /__w/lucy_ros_packages/lucy_ros_packages/ws
shell: bash
run: |
source /opt/ros/humble/setup.bash
colcon build --packages-select camera_ros lucy_bringup --cmake-args -DBUILD_TESTING=ON

- name: Run unit tests
working-directory: /__w/lucy_ros_packages/lucy_ros_packages/ws
shell: bash
run: |
source /opt/ros/humble/setup.bash
source install/setup.bash
colcon test --packages-select camera_ros lucy_bringup --event-handlers console_direct+

- name: Check test results
working-directory: /__w/lucy_ros_packages/lucy_ros_packages/ws
shell: bash
run: |
source /opt/ros/humble/setup.bash
source install/setup.bash
colcon test-result --verbose
# Fail if any tests failed
if colcon test-result --verbose | grep -q "failed"; then
echo "Some tests failed!"
exit 1
fi

- name: Generate coverage report
working-directory: /__w/lucy_ros_packages/lucy_ros_packages/ws
shell: bash
run: |
source /opt/ros/humble/setup.bash
source install/setup.bash
cd build/camera_ros
python3 -m pytest ../../src/camera_ros/test/ \
--cov=../../src/camera_ros/scripts \
--cov-report=xml:coverage.xml \
--cov-report=html:htmlcov \
--cov-report=term-missing \
--cov-branch || true

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
file: ${{ github.workspace }}/ws/build/camera_ros/coverage.xml
flags: unittests
name: codecov-umbrella
fail_ci_if_error: false

- name: Upload coverage HTML report
uses: actions/upload-artifact@v4
if: always()
with:
name: coverage-report
path: ${{ github.workspace }}/ws/build/camera_ros/htmlcov/
retention-days: 30
56 changes: 56 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,57 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
*.egg-info/
dist/
build/
.eggs/

# Virtual environments
.venv
venv/
ENV/
env/

# Coverage reports
htmlcov/
.coverage
.coverage.*
coverage.xml
*.cover
.hypothesis/

# Test artifacts
.pytest_cache/
test_results/
*.xunit.xml
.tox/
.nox/

# ROS2 build artifacts
install/
log/
build/

# IDE
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store

# OS
Thumbs.db
.DS_Store

# ROS2 specific
.ros/

# Temporary files
*.tmp
*.log
*.bak
*.orig
85 changes: 74 additions & 11 deletions camera_ros/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,85 @@ if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()

# find dependencies
# Find dependencies
find_package(ament_cmake REQUIRED)
# uncomment the following section in order to fill in
# further dependencies manually.
# find_package(<dependency> REQUIRED)
find_package(ament_cmake_python REQUIRED)
find_package(rclpy REQUIRED)
find_package(sensor_msgs REQUIRED)
find_package(std_srvs REQUIRED)
find_package(std_msgs REQUIRED)
find_package(cv_bridge REQUIRED)
find_package(rosidl_default_generators REQUIRED)

# Generate Python classes for the custom service
rosidl_generate_interfaces(${PROJECT_NAME}
"srv/GetInt.srv"
DEPENDENCIES std_msgs
ADD_LINTER_TESTS
)

# Install Python scripts
install(PROGRAMS
scripts/camera_publisher.py
scripts/camera_stream_controller.py
DESTINATION lib/${PROJECT_NAME}
)

# Install launch files
install(DIRECTORY
launch
DESTINATION share/${PROJECT_NAME}/
)

# Install launch files
install(FILES
launch/camera.launch.py
DESTINATION share/${PROJECT_NAME}/launch
)

# Install package.xml
install(FILES
package.xml
DESTINATION share/${PROJECT_NAME}/
)

# Install README
install(FILES
README.md
DESTINATION share/${PROJECT_NAME}/
)

if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
# the following line skips the linter which checks for copyrights
# comment the line when a copyright and license is added to all source files
set(ament_cmake_copyright_FOUND TRUE)
# the following line skips cpplint (only works in a git repo)
# comment the line when this package is in a git repo and when
# a copyright and license is added to all source files
set(ament_cmake_cpplint_FOUND TRUE)
find_package(ament_cmake_pytest REQUIRED)
ament_lint_auto_find_test_dependencies()

# Install test files
install(DIRECTORY test
DESTINATION share/${PROJECT_NAME}
)

# Install pytest.ini for coverage configuration
install(FILES
pytest.ini
DESTINATION share/${PROJECT_NAME}
)

# Add pytest tests with coverage
ament_add_pytest_test(test_camera_publisher test/test_camera_publisher.py
TIMEOUT 60
PYTHON_EXECUTABLE "${PYTHON3_EXECUTABLE}"
APPEND_ENV PYTHONPATH="${CMAKE_CURRENT_SOURCE_DIR}/scripts:${CMAKE_CURRENT_SOURCE_DIR}"
)

ament_add_pytest_test(test_camera_stream_controller test/test_camera_stream_controller.py
TIMEOUT 60
PYTHON_EXECUTABLE "${PYTHON3_EXECUTABLE}"
APPEND_ENV PYTHONPATH="${CMAKE_CURRENT_SOURCE_DIR}/scripts:${CMAKE_CURRENT_SOURCE_DIR}"
)
endif()

# Export the generated interfaces
ament_export_dependencies(rosidl_default_runtime)

ament_package()
Loading