From 4c320d3369fcc4efa77b6135cd016aa268116531 Mon Sep 17 00:00:00 2001 From: NejcKle Date: Tue, 12 Dec 2023 16:08:23 +0100 Subject: [PATCH 1/2] Add self-hosted workflow files --- .github/workflows/build.yaml | 14 ++++++- .github/workflows/twister.yaml | 37 +++++++++++++++--- README.md | 1 + makefile | 5 +++ scripts/rpi-jlink-server/README.md | 33 ++++++++++++++++ scripts/rpi-jlink-server/request_resource.sh | 40 ++++++++++++++++++++ scripts/rpi-jlink-server/twister_pty.py | 36 ++++++++++++++++++ tests/sample_test/testcase.yaml | 3 +- 8 files changed, 161 insertions(+), 8 deletions(-) create mode 100644 scripts/rpi-jlink-server/README.md create mode 100755 scripts/rpi-jlink-server/request_resource.sh create mode 100755 scripts/rpi-jlink-server/twister_pty.py diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 4ce4692..51223b6 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -12,12 +12,14 @@ on: branches: - "main" + workflow_dispatch: + env: GIT_CREDENTIALS: ${{ secrets.GIT_CREDENTIALS }} jobs: build: - runs-on: ubuntu-20.04 + runs-on: self-hosted defaults: run: shell: bash @@ -57,6 +59,7 @@ jobs: git config --global credential.helper '!f() { printf "%s\n" "username=runner" "password=$GIT_CREDENTIALS"; };f' - name: Install and cache apt packages + if: contains(runner.name, 'Github Action') uses: awalsh128/cache-apt-pkgs-action@latest with: packages: gcc-multilib @@ -65,6 +68,9 @@ jobs: version: 1.0 - name: Retrieve cache + # The retrieve cache job will run only, if the host is not a ubuntu-20.04 runner. + # GitHub hosted runners begin with 'Github Action' + if: contains(runner.name, 'Github Action') uses: actions/cache@v3 env: cache-name: cache-modules @@ -125,3 +131,9 @@ jobs: with: name: artefacts path: project/artefacts/* + + - name: Post-build clean + # Only for self hosted runners + # Makes sure east init does not fail in the project setup + if: ${{ always() && !contains(runner.name, 'Github Action') }} + run: rm -rf ${{ github.workspace }}/.west diff --git a/.github/workflows/twister.yaml b/.github/workflows/twister.yaml index fa3072f..eda76a5 100644 --- a/.github/workflows/twister.yaml +++ b/.github/workflows/twister.yaml @@ -4,6 +4,8 @@ on: pull_request: types: [opened, reopened, synchronize] + workflow_dispatch: + env: GIT_CREDENTIALS: ${{ secrets.GIT_CREDENTIALS }} @@ -13,7 +15,7 @@ jobs: # This version is a must, twister otherwise fails (some Python library # depends on a specific version of libffi that is not present in the # toolchain provided by nordic's toolchain manager). - runs-on: ubuntu-20.04 + runs-on: self-hosted defaults: run: shell: bash @@ -38,6 +40,7 @@ jobs: git config --global credential.helper '!f() { printf "%s\n" "username=runner" "password=$GIT_CREDENTIALS"; };f' - name: Install and cache apt packages + if: contains(runner.name, 'Github Action') uses: awalsh128/cache-apt-pkgs-action@latest with: packages: gcc-multilib lcov @@ -46,6 +49,7 @@ jobs: version: 2.0 - name: Retrieve cache + if: contains(runner.name, 'Github Action') uses: actions/cache@v3 env: cache-name: cache-modules @@ -115,11 +119,25 @@ jobs: path: | project/twister-out/coverage.info + - name: Post-build clean + # Only for self hosted runners + # Makes sure east init does not fail in the project setup + if: ${{ always() && !contains(runner.name, 'Github Action') }} + run: rm -rf ${{ github.workspace }}/.west + twister-test-results: name: "Publish Unit Tests Results" needs: twister-build if: always() - runs-on: ubuntu-20.04 + # These permissions must be set for the EnricoMi/publish-unit-test-result-action + # See https://github.com/EnricoMi/publish-unit-test-result-action#permissions + permissions: + contents: read + issues: read + checks: write + # WARNING: This must be run on Github Hosted Action Runners, as they allow the usage of Docker + # An alternative would be to create a custom Docker image with Docker-in-Docker enabled + runs-on: ubuntu-22.04 steps: - name: Download Artefacts @@ -138,9 +156,16 @@ jobs: coverage-report: name: "Publish Coverage Report" needs: twister-build - runs-on: ubuntu-20.04 - - steps: + # NOTE: This action is not compatible with "workflow_dispatch" event, so + # it's not possible to run it manually. + if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' }} + # Proper permissions are needed to create comments on PRs + permissions: + issues: write + pull-requests: write + runs-on: self-hosted + + steps: - name: Download Artefacts uses: actions/download-artifact@v3 with: @@ -150,4 +175,4 @@ jobs: - name: Publish Coverage Report uses: romeovs/lcov-reporter-action@4cf015aa4afa87b78238301f1e3dc140ea0e1ec6 with: - lcov-file: ./coverage-report/coverage.info + lcov-file: ./coverage-report/coverage.info \ No newline at end of file diff --git a/README.md b/README.md index a0cd159..2eba218 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ of CI workflows for release automation. charge for this** to do it for you. - [ ] Create a new project on the CodeChecker server. You can also **contact person in charge** to do it for you. +- [ ] (Optional) Include the `twister-rpi.yaml` GitHub Actions workflow. Copy it from the `irnas-workflows-software/workflow-templates/rpi-twister-hil/.github/twister-rpi.yaml`. See the [README.md](scripts/rpi-jlink-server/README.md) for more information on the requirements and setup. - [ ] As a final step delete this checklist and commit changes. [repository naming scheme]: diff --git a/makefile b/makefile index f183d2c..d1c4628 100644 --- a/makefile +++ b/makefile @@ -55,6 +55,11 @@ pre-package: test: east twister -T tests --coverage -p native_posix +# Used to run twister on remote RPi with attached nRF52840DK +# The {RPI_IP} variable must be set in the environment using Github Secrets +test-remote: + east twister -T tests -p nrf52840dk_nrf52840 --device-testing --device-serial-pty="scripts/rpi-jlink-server/twister_pty.py --host ${RPI_IP} --port 7777" --west-runner=jlink --west-flash="--tool-opt=ip ${RPI_IP}:7778" + test-report-ci: junit2html twister-out/twister.xml twister-out/twister-report.html diff --git a/scripts/rpi-jlink-server/README.md b/scripts/rpi-jlink-server/README.md new file mode 100644 index 0000000..96fd67d --- /dev/null +++ b/scripts/rpi-jlink-server/README.md @@ -0,0 +1,33 @@ +# Raspberry Pi J-Link Server + +This directory contains two scripts that are used to run tests on a remote Raspberry Pi, which is connected to a J-Link debugger: + +- The `request_resource.sh` script, which should be used inside a GitHub Action Workflow before and after running tests on the device. +- The `twister_pty.py` script, which is used with the `west/east twister` command. This script receives and prints the outputs generated by the device. + +## Remote Raspberry Pi + +Documentation on how to set up the Raspberry Pi and a detailed explanation of the functionality can be found [here](https://github.com/IRNAS/irnas-runners-software/blob/main/rpi-jlink-server/README.md). + +## GitHub Actions Workflow + +The scripts mentioned are used by the `twister-rpi.yaml` GitHub Actions Workflow. +The workflow is not included in this repository, as it is opt-in. It can be found [here](...). To include it, you must copy the workflow file to your repository and add the following GitHub secrets: + +- RPI_IP - IP address of the Raspberry Pi running the JLinkRemoteServer. + +The IP can be the local IP address of the Raspberry Pi, if the GitHub Action runner is running on the same network. Or it has to be the VPN IP address of the Raspberry Pi, if the GitHub Action runner is running on a different network. + +The following make command has been added to the projects `makefile`: + +```bash +test-remote: + east twister -T tests -p nrf52840dk_nrf52840 --device-testing --device-serial-pty="scripts/twister_pty.py --host ${RPI_IP} --port 7777" --west-runner=jlink --west-flash="--tool-opt=ip ${RPI_IP}:7778" +``` + +The command is used to run twister tests on the remote device. The `--device-serial-pty` and `--west-flash` options are used to connect to the remote device. The `twister_pty.py` script is used to print the output of the device to the GitHub Actions log. The `--west-runner` and `--west-flash` options are used to flash the device with the firmware and run the tests. + +**IMPORTANT: The `testcase.yaml` has been modified as well to include the `- CONFIG_NULL_POINTER_EXCEPTION_DETECTION_NONE=y` `extra_configs` option.** + +This flag fixes the tests taking a minute longer, due to a timeout. [This related issue](https://github.com/zephyrproject-rtos/zephyr/issues/39216) describes the problem. + diff --git a/scripts/rpi-jlink-server/request_resource.sh b/scripts/rpi-jlink-server/request_resource.sh new file mode 100755 index 0000000..e11ad49 --- /dev/null +++ b/scripts/rpi-jlink-server/request_resource.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# This scripts send a HTTP POST request to the specified URL and checks if the response code is 200. +# The URL endpoint is a server running on the Raspberry Pi that is connected to the J-Link debugger. +# The script is called from the `` + +# Check if the required arguments are provided +if [ "$#" -ne 3 ]; then + echo "Usage: $0 " + exit 1 +fi + +timeout="$1" +interval="$2" +request_url="$3" +start_time=$(date +%s) # Converts the date into unix timestamp + +echo $start_time + +while true; do + # Send a POST request to the request_url and capture the HTTP response code + response_code=$(curl -s -o /dev/null -w "%{http_code}" -X POST "$request_url") + + # Check if the response code is 200 + if [ "$response_code" -eq 200 ]; then + echo "Request to $request_url succeeded with status code 200." + exit 0 + fi + + current_time=$(date +%s) + elapsed_time=$((current_time - start_time)) + + # Check if the timeout is reached + if [ "$elapsed_time" -ge "$timeout" ]; then + echo "Timeout reached. Request to $request_url failed with status code $response_code." + exit 1 + fi + + echo "Request to $request_url failed with status code $response_code. Retrying in $interval seconds..." + sleep "$interval" +done \ No newline at end of file diff --git a/scripts/rpi-jlink-server/twister_pty.py b/scripts/rpi-jlink-server/twister_pty.py new file mode 100755 index 0000000..1a38219 --- /dev/null +++ b/scripts/rpi-jlink-server/twister_pty.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +# A script used by twister to run the pseudoterminal +# The script opens a telnet connection to the specified IP and PORT and prints the output to the terminal + +import argparse +import telnetlib + +parser = argparse.ArgumentParser(description="Read telnet output") +parser.add_argument("--host", help="Host to connect to") +parser.add_argument("--port", help="Port to connect to") +args = parser.parse_args() + +HOST = args.host +PORT = args.port + +def read_telnet_output(): + + try: + with telnetlib.Telnet(HOST, PORT) as tn: + while True: + line = tn.read_until(b'PROJECT EXECUTION SUCCESSFUL') + print(line.decode("utf-8")) + if b'PROJECT EXECUTION SUCCESSFUL'in line: + print(f"Tests finished running. Exiting!") + return 0 + + except Exception as e: + print(f"An exception occurred when reading telnet output: {e}") + + +# Run the event loop and call the function to start reading the telnet output +if __name__ == "__main__": + if not HOST or not PORT: + print("Please specify a host and port") + exit() + read_telnet_output() diff --git a/tests/sample_test/testcase.yaml b/tests/sample_test/testcase.yaml index 1e9d889..a0af337 100644 --- a/tests/sample_test/testcase.yaml +++ b/tests/sample_test/testcase.yaml @@ -1,10 +1,11 @@ tests: tests.sample_test: # Set of platforms that this test case can be run on. - platform_allow: native_posix nrf52dk_nrf52832 + platform_allow: native_posix nrf52dk_nrf52832 nrf52840dk_nrf52840 harness: ztest # Only build the test, do not run it # build_only: True extra_configs: # Disable fancy test, otherwise stdout parsing does not work. - CONFIG_FANCY_ZTEST=n + - CONFIG_NULL_POINTER_EXCEPTION_DETECTION_NONE=y From 998a5993414133a0533f8b4c8f079e6dadc13972 Mon Sep 17 00:00:00 2001 From: NejcKle Date: Wed, 20 Dec 2023 12:08:56 +0100 Subject: [PATCH 2/2] Move codechecker to self-hosted --- .github/workflows/build.yaml | 3 --- .github/workflows/codechecker.yaml | 13 +++++++++++-- .github/workflows/publish-release.yaml | 1 - .github/workflows/twister.yaml | 25 ++++++++++--------------- README.md | 2 +- scripts/rpi-jlink-server/README.md | 2 +- 6 files changed, 23 insertions(+), 23 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 51223b6..2997ccd 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -11,7 +11,6 @@ on: push: branches: - "main" - workflow_dispatch: env: @@ -68,8 +67,6 @@ jobs: version: 1.0 - name: Retrieve cache - # The retrieve cache job will run only, if the host is not a ubuntu-20.04 runner. - # GitHub hosted runners begin with 'Github Action' if: contains(runner.name, 'Github Action') uses: actions/cache@v3 env: diff --git a/.github/workflows/codechecker.yaml b/.github/workflows/codechecker.yaml index 70c0373..f535b0a 100644 --- a/.github/workflows/codechecker.yaml +++ b/.github/workflows/codechecker.yaml @@ -24,7 +24,7 @@ env: jobs: codechecker: - runs-on: ubuntu-20.04 + runs-on: self-hosted defaults: run: shell: bash @@ -57,13 +57,14 @@ jobs: # This is needed due to the later east update (west update) command that # could be cloning from the private repos. The provided token in # GIT_CREDENTIALS needs to be a fine-grained token, with access to all - # repositores, with "Read-only" access level to the Content repository + # repositories, with "Read-only" access level to the Content repository # permissions. - name: Set Git credentials run: | git config --global credential.helper '!f() { printf "%s\n" "username=runner" "password=$GIT_CREDENTIALS"; };f' - name: Add LLVM repositories + if: contains(runner.name, 'Github Action') run: | # If updating llvm version do not forget to update distro name wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc @@ -71,6 +72,7 @@ jobs: sudo apt-get update - name: Install and cache apt packages + if: contains(runner.name, 'Github Action') uses: awalsh128/cache-apt-pkgs-action@latest with: packages: clang-16 clang-tidy-16 cppcheck gcc-multilib @@ -79,6 +81,7 @@ jobs: version: 3.0 - name: Retrieve cache + if: contains(runner.name, 'Github Action') uses: actions/cache@v3 env: cache-name: cache-modules @@ -146,3 +149,9 @@ jobs: with: name: codechecker-diffs path: project/codechecker-diffs/* + + - name: Post-build clean + # Only for self hosted runners + # Makes sure east init does not fail in the project setup + if: ${{ always() && !contains(runner.name, 'Github Action') }} + run: rm -rf ${{ github.workspace }}/.west \ No newline at end of file diff --git a/.github/workflows/publish-release.yaml b/.github/workflows/publish-release.yaml index 3613177..b3cb2aa 100644 --- a/.github/workflows/publish-release.yaml +++ b/.github/workflows/publish-release.yaml @@ -10,7 +10,6 @@ on: jobs: publish-new-release: runs-on: ubuntu-20.04 - # runs-on: self-hosted steps: - name: Start diff --git a/.github/workflows/twister.yaml b/.github/workflows/twister.yaml index eda76a5..b1c7215 100644 --- a/.github/workflows/twister.yaml +++ b/.github/workflows/twister.yaml @@ -12,9 +12,6 @@ env: jobs: twister-build: name: "Run Unit Tests" - # This version is a must, twister otherwise fails (some Python library - # depends on a specific version of libffi that is not present in the - # toolchain provided by nordic's toolchain manager). runs-on: self-hosted defaults: run: @@ -127,17 +124,16 @@ jobs: twister-test-results: name: "Publish Unit Tests Results" - needs: twister-build - if: always() - # These permissions must be set for the EnricoMi/publish-unit-test-result-action - # See https://github.com/EnricoMi/publish-unit-test-result-action#permissions + # WARNING: This step is incompatible with self-hosted runners as it uses the 'publish-unit-test-result' action. + # This would require us to run docker-in-docker in the self-hosted runner. + + runs-on: ubuntu-22.04 permissions: contents: read issues: read checks: write - # WARNING: This must be run on Github Hosted Action Runners, as they allow the usage of Docker - # An alternative would be to create a custom Docker image with Docker-in-Docker enabled - runs-on: ubuntu-22.04 + needs: twister-build + if: always() steps: - name: Download Artefacts @@ -155,17 +151,16 @@ jobs: coverage-report: name: "Publish Coverage Report" - needs: twister-build # NOTE: This action is not compatible with "workflow_dispatch" event, so # it's not possible to run it manually. - if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' }} - # Proper permissions are needed to create comments on PRs + runs-on: self-hosted permissions: issues: write pull-requests: write - runs-on: self-hosted + needs: twister-build + if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' }} - steps: + steps: - name: Download Artefacts uses: actions/download-artifact@v3 with: diff --git a/README.md b/README.md index 2eba218..6ece1b5 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ of CI workflows for release automation. charge for this** to do it for you. - [ ] Create a new project on the CodeChecker server. You can also **contact person in charge** to do it for you. -- [ ] (Optional) Include the `twister-rpi.yaml` GitHub Actions workflow. Copy it from the `irnas-workflows-software/workflow-templates/rpi-twister-hil/.github/twister-rpi.yaml`. See the [README.md](scripts/rpi-jlink-server/README.md) for more information on the requirements and setup. +- [ ] (Optional) Include the `twister-rpi.yaml` GitHub Actions workflow for the on-target testing. Copy it from the `irnas-workflows-software/workflow-templates/rpi-twister-hil/.github/twister-rpi.yaml`. See the [README.md](scripts/rpi-jlink-server/README.md) for more information on the requirements and setup. - [ ] As a final step delete this checklist and commit changes. [repository naming scheme]: diff --git a/scripts/rpi-jlink-server/README.md b/scripts/rpi-jlink-server/README.md index 96fd67d..fc240b0 100644 --- a/scripts/rpi-jlink-server/README.md +++ b/scripts/rpi-jlink-server/README.md @@ -12,7 +12,7 @@ Documentation on how to set up the Raspberry Pi and a detailed explanation of th ## GitHub Actions Workflow The scripts mentioned are used by the `twister-rpi.yaml` GitHub Actions Workflow. -The workflow is not included in this repository, as it is opt-in. It can be found [here](...). To include it, you must copy the workflow file to your repository and add the following GitHub secrets: +The workflow is not included in this repository, as it is opt-in. To include it, you must copy the `twister-rpi.yaml` from the [linked repository](https://github.com/IRNAS/irnas-workflows-software/blob/main/workflow-templates/rpi-twister-hil/.github/twister-rpi.yaml) into `.github/workflows` folder inside your repository and add the following GitHub secrets: - RPI_IP - IP address of the Raspberry Pi running the JLinkRemoteServer.