Skip to content

Commit 805d69e

Browse files
Add new reusable workflows for unit-test, codeql and python-check
1 parent 068cff4 commit 805d69e

File tree

3 files changed

+292
-0
lines changed

3 files changed

+292
-0
lines changed
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
name: Build the application for all devices and upload the artifact
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
app_repository:
7+
description: 'The GIT repository to build (defaults to `github.repository`)'
8+
required: false
9+
default: ${{ github.repository }}
10+
type: string
11+
app_branch_name:
12+
description: 'The GIT branch to build (defaults to `github.ref`)'
13+
required: false
14+
default: ${{ github.ref }}
15+
type: string
16+
run_for_devices:
17+
description: |
18+
The list of device(s) on which the CI will run.
19+
20+
Defaults to the full list of device(s) supported by the application as configured in the
21+
'ledger_app.toml' manifest.
22+
If the manifest is missing, defaults to ALL (["nanos", "nanox", "nanosp", "stax", "flex", "apex_m", "apex_p"]).
23+
required: false
24+
default: 'None'
25+
type: string
26+
builder:
27+
description: "The docker image to build the application in (defaults to ledger-app-builder-lite)"
28+
required: false
29+
default: 'ledger-app-builder-lite'
30+
type: string
31+
flags:
32+
description: "Additional flags (default to none)"
33+
required: false
34+
default: ''
35+
type: string
36+
37+
jobs:
38+
call_get_app_metadata:
39+
# This job digests inputs and repository metadata provided by the `ledger_app.toml` manifest
40+
# file, in order to output relevant compatible devices needed by following jobs.
41+
name: Retrieve application metadata
42+
uses: ./.github/workflows/_get_app_metadata.yml
43+
with:
44+
app_repository: ${{ inputs.app_repository }}
45+
app_branch_name: ${{ inputs.app_branch_name }}
46+
compatible_devices: ${{ inputs.run_for_devices }}
47+
secrets:
48+
token: ${{ secrets.token }}
49+
50+
build_device_matrix:
51+
name: Build device matrix
52+
needs: call_get_app_metadata
53+
runs-on: ubuntu-latest
54+
outputs:
55+
sdks_config: ${{ steps.sdk_list.outputs.sdks_config }}
56+
57+
steps:
58+
- name: Define the list of devices to target
59+
id: sdk_list
60+
shell: bash
61+
run: |
62+
if [ "${{ inputs.run_for_devices }}" = "None" ]; then
63+
# Use the compatible devices from metadata
64+
devices_json='${{ needs.call_get_app_metadata.outputs.compatible_devices }}'
65+
else
66+
# Convert space-separated string to JSON array
67+
devices_string="${{ inputs.run_for_devices }}"
68+
devices_json=$(echo "${devices_string}" | jq -R 'split(" ")')
69+
fi
70+
71+
# Generate SDK environment variables from device names
72+
sdks_json=$(echo "${devices_json}" | jq -c 'map("$" + (. | ascii_upcase) + "_SDK")')
73+
74+
echo "sdks_config=${sdks_json}" >> "$GITHUB_OUTPUT"
75+
76+
- name: Print devices and SDKs
77+
run: |
78+
echo "SDKs: ${{ steps.sdk_list.outputs.sdks_config }}"
79+
80+
analyse:
81+
name: Analyse application
82+
needs: build_device_matrix
83+
strategy:
84+
fail-fast: false
85+
matrix:
86+
sdk: ${{ fromJSON(needs.build_device_matrix.outputs.sdks_config) }}
87+
# 'cpp' covers C and C++
88+
language: ['cpp']
89+
runs-on: ubuntu-latest
90+
container:
91+
image: ghcr.io/ledgerhq/ledger-app-builder/${{ inputs.builder }}:latest
92+
93+
steps:
94+
- name: Clone
95+
uses: actions/checkout@v4
96+
with:
97+
repository: ${{ inputs.app_repository }}
98+
ref: ${{ inputs.app_branch_name }}
99+
submodules: recursive
100+
token: ${{ secrets.token && secrets.token || github.token }}
101+
102+
- name: Initialize CodeQL
103+
uses: github/codeql-action/init@v3
104+
with:
105+
languages: ${{ matrix.language }}
106+
queries: security-and-quality
107+
108+
# CodeQL will create the database during the compilation
109+
- name: Build
110+
run: |
111+
${{ inputs.flags }} make BOLOS_SDK=${{ matrix.sdk }}
112+
113+
- name: Perform CodeQL Analysis
114+
uses: github/codeql-action/analyze@v3
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
name: Code style check
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
run_linter:
7+
description: "Select the Linter to run (pylint or flake8)"
8+
type: string
9+
required: true
10+
default: ''
11+
run_type_check:
12+
description: "Whether to run mypy type check (defaults to false)"
13+
required: true
14+
default: false
15+
type: boolean
16+
src_directory:
17+
description: "The directory containing the python sources to check"
18+
required: true
19+
default: ''
20+
type: string
21+
req_directory:
22+
description: "The directory containing the requirements.txt (if any)"
23+
required: false
24+
default: ''
25+
type: string
26+
setup_directory:
27+
description: "The directory containing the setup.cfg (if any)"
28+
required: false
29+
default: ''
30+
type: string
31+
additional_packages:
32+
description: "Additional packages to install (default to none)"
33+
required: false
34+
default: ''
35+
type: string
36+
37+
jobs:
38+
pylint:
39+
name: Python Linting with pylint
40+
if: ${{ inputs.run_linter == 'pylint' }}
41+
runs-on: ubuntu-latest
42+
steps:
43+
- name: Clone
44+
uses: actions/checkout@v4
45+
46+
- name: Installing PIP dependencies
47+
run: |
48+
if [ -n "${{ inputs.additional_packages }}" ]; then
49+
sudo apt-get update && sudo apt-get install -y ${{ inputs.additional_packages }}
50+
fi
51+
pip install pylint
52+
if [ -n "${{ inputs.req_directory }}" ] && [ -f "${{ inputs.req_directory }}/requirements.txt" ]; then
53+
pip install -r ${{ inputs.req_directory }}/requirements.txt
54+
fi
55+
56+
- name: Lint Python code
57+
run: |
58+
ARGS=(-j 0)
59+
if [ -n "${{ inputs.setup_directory }}" ] && [ -f "${{ inputs.setup_directory }}/setup.cfg" ]; then
60+
ARGS+=(--rcfile "${{ inputs.setup_directory }}/setup.cfg")
61+
fi
62+
pylint "${ARGS[@]}" ${{ inputs.src_directory }}
63+
64+
flake8:
65+
name: Python Linting with flake8
66+
if: ${{ inputs.run_linter == 'flake8' }}
67+
runs-on: ubuntu-latest
68+
steps:
69+
- name: Clone
70+
uses: actions/checkout@v4
71+
72+
- name: Installing PIP dependencies
73+
run: |
74+
pip install flake8 flake8-pyproject
75+
if [ -n "${{ inputs.req_directory }}" ] && [ -f "${{ inputs.req_directory }}/requirements.txt" ]; then
76+
pip install -r ${{ inputs.req_directory }}/requirements.txt
77+
fi
78+
79+
- name: Lint Python code
80+
run: |
81+
cd ${{ inputs.setup_directory }} && flake8 ${{ inputs.src_directory }}
82+
83+
mypy:
84+
name: Type checking
85+
if: ${{ inputs.run_type_check == true }}
86+
runs-on: ubuntu-latest
87+
steps:
88+
- name: Clone
89+
uses: actions/checkout@v4
90+
91+
- name: Installing PIP dependencies
92+
run: |
93+
pip install mypy
94+
if [ -n "${{ inputs.req_directory }}" ] && [ -f "${{ inputs.req_directory }}/requirements.txt" ]; then
95+
pip install -r ${{ inputs.req_directory }}/requirements.txt
96+
fi
97+
98+
- name: Mypy type checking
99+
run: mypy ${{ inputs.src_directory }}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
name: Unit testing with Codecov coverage checking and upload the result
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
app_repository:
7+
description: 'The GIT repository to test (defaults to `github.repository`)'
8+
required: false
9+
default: ${{ github.repository }}
10+
type: string
11+
app_branch_name:
12+
description: 'The GIT branch to test (defaults to `github.ref`)'
13+
required: false
14+
default: ${{ github.ref }}
15+
type: string
16+
test_directory:
17+
description: "The directory containing the unit-tests to run"
18+
required: true
19+
default: ''
20+
type: string
21+
builder:
22+
description: "The docker image to build the application in (defaults to ledger-app-builder-lite)"
23+
required: false
24+
default: 'ledger-app-builder-lite'
25+
type: string
26+
27+
jobs:
28+
unit_test:
29+
name: Unit test
30+
runs-on: ubuntu-latest
31+
container:
32+
image: ghcr.io/ledgerhq/ledger-app-builder/${{ inputs.builder }}:latest
33+
34+
steps:
35+
- name: Clone
36+
uses: actions/checkout@v4
37+
with:
38+
repository: ${{ inputs.app_repository }}
39+
ref: ${{ inputs.app_branch_name }}
40+
submodules: recursive
41+
token: ${{ secrets.token && secrets.token || github.token }}
42+
43+
- name: Build unit tests
44+
run: |
45+
cd ${{ inputs.test_directory }}
46+
cmake -Bbuild -H. && make -C build
47+
48+
- name: Run unit tests
49+
run: |
50+
cd ${{ inputs.test_directory }}
51+
make -C build test
52+
53+
- name: Generate code coverage
54+
run: |
55+
cd ${{ inputs.test_directory }}
56+
lcov --directory . -b "$(realpath build/)" --capture --initial -o coverage.base
57+
lcov --rc lcov_branch_coverage=1 --directory . -b "$(realpath build/)" --capture -o coverage.capture
58+
lcov --directory . -b "$(realpath build/)" --add-tracefile coverage.base --add-tracefile coverage.capture -o coverage.info
59+
lcov --directory . -b "$(realpath build/)" --remove coverage.info "*/${{ inputs.test_directory }}/*" -o coverage.info
60+
genhtml coverage.info -o coverage
61+
62+
- uses: actions/upload-artifact@v4
63+
with:
64+
name: code-coverage
65+
path: ${{ inputs.test_directory }}/coverage
66+
67+
- name: Install codecov dependencies
68+
run: apt install --no-install-recommends -y curl gpg
69+
70+
- name: Upload to codecov.io
71+
uses: codecov/codecov-action@v5
72+
env:
73+
CODECOV_TOKEN: ${{ secrets.codecov_token }}
74+
with:
75+
files: ./${{ inputs.test_directory }}/coverage.info
76+
flags: unittests
77+
name: codecov-${{ inputs.app_repository }}
78+
fail_ci_if_error: true
79+
verbose: true

0 commit comments

Comments
 (0)