diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml new file mode 100644 index 0000000..5b34179 --- /dev/null +++ b/.github/workflows/docker.yaml @@ -0,0 +1,102 @@ +name: Build a Docker Image First +on: + push: + # Will trigger on MERGES (or pushes) to main branch. + branches: + - 'main' + pull_request: + # Will ALSO trigger any time a PR is opened merging to main. + # Specify '*' here to merge on PRs being opened against ANY branch. + branches: + - 'main' + +# This creates environment variables that can be shared between all the jobs. +env: + # This will use docker.io for Dockerhub if empty, so we want to tell it to + # use the github one (ghcr.io which stands for... GitHub Container Registry) + REGISTRY: ghcr.io + # Name the docker image after the repo: github.repository as / + IMAGE_NAME: ${{ github.repository }} + +jobs: + # First we'll build the docker image in a separate job. Then we actually + # build the code in a separate job. + docker: + runs-on: ubuntu-latest + # Note that here we DON'T have a container because github refuses to allow + # us to do docker-in-docker. So docker build runs natively on the machine. + # The outputs tags gives us an output variabel that can be used in other + # jobs. In this case, it's the name of the docker file. + outputs: + docker_image_name: ${{ steps.meta.outputs.tags }} + steps: + - name: Check out repository + # We still need to do this to actually build the docker file. + uses: actions/checkout@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - name: Log into registry ${{ env.REGISTRY }} + # Github pre-populates all of these for you! So you don't have to do + # anything fancy. Just make sure the env.REGISTRY is set to ghcr.io + uses: docker/login-action@v2 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Extract Docker metadata + # This just figures out what to tag our docker file as. It's less + # complicated than it looks, and you have a lot of flexibility in + # how you build tags here. + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + - name: Build and push docker + uses: docker/build-push-action@v4 + with: + context: toy_example_package/docker/ + file: toy_example_package/docker/Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + + # The name of the job is "build". All jobs run in SEPARATE containers, so + # they may run on separate machines and have the workspace wiped inbetween. + build: + # You need to specify the dependency on the previous job (docker) here! + needs: docker + # Run on a github-hosted runner. To specify our own, select: + # [self-hosted, linux] instead. + runs-on: ubuntu-latest + # This will now use the container we build above! The "needs" specifies that + # this must be populated and finished by the other job before we can run. + container: ${{ needs.docker.outputs.docker_image_name }} + steps: + # Name is optional, uses: specify which ACTION is used (basically github + # macros). You can write your own! Use with: to specify extra parameters. + - name: Check out repository + uses: actions/checkout@v3 + with: + # This path is relative to ${GITHUB_WORKSPACE}. You can also use + # "/${HOME}/" if you want but be sure to have the leading slash. + path: catkin_ws/src/toy_example_package + - name: Setup workspace & install ROS dependencies + # We can skip the other setup steps now because it's all in the docker. + run: | + cd ${GITHUB_WORKSPACE}/catkin_ws + catkin init + catkin config --extend "/opt/ros/noetic" + catkin config --merge-devel + rosdep update + rosdep install --from-paths src --ignore-src -y --rosdistro noetic + catkin config --cmake-args -DCMAKE_BUILD_TYPE=Release + shell: bash + - name: Catkin build + # The working directory is reset for each individual run command, so just + # be aware! + run: | + cd ${GITHUB_WORKSPACE}/catkin_ws + catkin build --continue toy_example_package + shell: bash diff --git a/.github/workflows/simple.yaml b/.github/workflows/simple.yaml new file mode 100644 index 0000000..b453a05 --- /dev/null +++ b/.github/workflows/simple.yaml @@ -0,0 +1,65 @@ +name: Simple Build +on: + push: + # Will trigger on MERGES (or pushes) to main branch. + branches: + - 'main' + pull_request: + # Will ALSO trigger any time a PR is opened merging to main. + # Specify '*' here to merge on PRs being opened against ANY branch. + branches: + - 'main' + +jobs: + # The name of the job is "build". All jobs run in SEPARATE containers, so + # they may run on separate machines and have the workspace wiped inbetween. + build: + # Run on a github-hosted runner. To specify our own, select: + # [self-hosted, linux] instead. + runs-on: ubuntu-latest + # This is the docker container that the image will run in. This is 20.04 + # with ros-noetic-desktop meta-package. + container: osrf/ros:noetic-desktop + steps: + # Name is optional, uses: specify which ACTION is used (basically github + # macros). You can write your own! Use with: to specify extra parameters. + - name: Check out repository + uses: actions/checkout@v3 + with: + # This path is relative to ${GITHUB_WORKSPACE}. You can also use + # "/${HOME}/" if you want but be sure to have the leading slash. + path: catkin_ws/src/toy_example_package + - name: Install catkin-tools on Noetic + # This, well, makes sure you have catkin tools installed. + run: | + apt update && apt install -y python3-pip + pip3 install osrf-pycommon + apt update && apt install -y python3-wstool python3-catkin-tools + shell: bash + - name: Install dependencies + # Replace this with your actual deps. But cowsay is fun. + run: | + apt update && apt install -y fortune cowsay + shell: bash + - name: Setup workspace & install ROS dependencies + run: | + cd ${GITHUB_WORKSPACE}/catkin_ws + catkin init + catkin config --extend "/opt/ros/noetic" + catkin config --merge-devel + rosdep update + rosdep install --from-paths src --ignore-src -y --rosdistro noetic + catkin config --cmake-args -DCMAKE_BUILD_TYPE=Release + shell: bash + - name: Catkin build + # The working directory is reset for each individual run command, so just + # be aware! + run: | + cd ${GITHUB_WORKSPACE}/catkin_ws + catkin build --continue toy_example_package + shell: bash + - name: Get a fortune from a cow + # Replace this with a testing script or anything else you need to do. + run: /usr/games/fortune | /usr/games/cowsay + shell: bash + diff --git a/README.md b/README.md index 2f8bcbe..20f8fb7 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,16 @@ # asl-actions -Github Actions for ASL +Github Actions and documentation for ASL. + +## Getting Started +First, you can start with the quick-start docs from GitHub: https://docs.github.com/en/actions/quickstart + +Then you can follow along with a few simple tutorial workflows. + +So far we have a simple example, which just checks out a Github repo containing one or more ROS packages and builds it within a default OSRF environment: + +[Simple Example](https://github.com/ethz-asl/asl-actions/blob/main/.github/workflows/simple.yaml) + +There is also an example of using the Github Container Registry to first build a custom docker image, push it to the container registry, and then use it in the following step to build the code itself: + +[Docker Example](https://github.com/ethz-asl/asl-actions/blob/main/.github/workflows/docker.yaml) + diff --git a/actions/delete-workspace/Dockerfile b/actions/delete-workspace/Dockerfile new file mode 100644 index 0000000..040bfa0 --- /dev/null +++ b/actions/delete-workspace/Dockerfile @@ -0,0 +1,7 @@ +FROM ubuntu:22.04 + +# Copies your code file from your action repository to the filesystem path `/` of the container +COPY entrypoint.sh /entrypoint.sh + +# Code file to execute when the docker container starts up (`entrypoint.sh`) +ENTRYPOINT ["/entrypoint.sh"] diff --git a/actions/delete-workspace/action.yml b/actions/delete-workspace/action.yml new file mode 100644 index 0000000..706034d --- /dev/null +++ b/actions/delete-workspace/action.yml @@ -0,0 +1,8 @@ +# action.yml +name: 'Clean Up State' +description: 'Clean up the workspace state before and/or after running.' + +runs: + using: 'docker' + image: 'Dockerfile' + diff --git a/actions/delete-workspace/entrypoint.sh b/actions/delete-workspace/entrypoint.sh new file mode 100755 index 0000000..7344729 --- /dev/null +++ b/actions/delete-workspace/entrypoint.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +# Nuke it! +rm -rf ~/* \ No newline at end of file diff --git a/toy_example_package/CMakeLists.txt b/toy_example_package/CMakeLists.txt new file mode 100644 index 0000000..6189bca --- /dev/null +++ b/toy_example_package/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.0.2) +project(toy_example_package) + +add_compile_options(-std=c++11) + +find_package(catkin REQUIRED COMPONENTS roscpp std_msgs) +catkin_package( + CATKIN_DEPENDS std_msgs roscpp +) + +include_directories(include ${catkin_INCLUDE_DIRS}) + +add_executable(publisher_node src/publisher.cpp) +add_dependencies(publisher_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) +target_link_libraries(publisher_node + ${catkin_LIBRARIES} +) + + diff --git a/toy_example_package/docker/Dockerfile b/toy_example_package/docker/Dockerfile new file mode 100644 index 0000000..e038e2b --- /dev/null +++ b/toy_example_package/docker/Dockerfile @@ -0,0 +1,8 @@ +FROM osrf/ros:noetic-desktop + +# Install catkin tools. +RUN apt-get -qq update && \ + apt-get install -y python3-catkin-tools python3-vcstool python3-pip \ + python-is-python3 && \ + rm -rf /var/lib/apt/lists/* + diff --git a/toy_example_package/package.xml b/toy_example_package/package.xml new file mode 100644 index 0000000..fc2a8a3 --- /dev/null +++ b/toy_example_package/package.xml @@ -0,0 +1,17 @@ + + + toy_example_package + 0.0.0 + Toy example package for Github Actions workflows. + + Helen Oleynikova + + BSD + + roscpp + std_msgs + catkin + + + + diff --git a/toy_example_package/src/publisher.cpp b/toy_example_package/src/publisher.cpp new file mode 100644 index 0000000..94f2e03 --- /dev/null +++ b/toy_example_package/src/publisher.cpp @@ -0,0 +1,36 @@ +#include +#include + +#include + +// All this code is from the publisher tutorial: +// https://wiki.ros.org/ROS/Tutorials/WritingPublisherSubscriber%28c%2B%2B%29 +int main(int argc, char **argv) { + ros::init(argc, argv, "toy_example_publisher"); + + ros::NodeHandle nh, nh_private("~"); + + ros::Publisher pub = nh_private.advertise("hello", 1); + + ros::Rate loop_rate(10); // Hz + + int count = 0; + while (ros::ok()) { + std_msgs::String msg; + + std::stringstream ss; + ss << "hello world " << count; + msg.data = ss.str(); + + ROS_INFO("%s", msg.data.c_str()); + + pub.publish(msg); + + ros::spinOnce(); + + loop_rate.sleep(); + ++count; + } + + return 0; +}