|
1 | | -# SPDX-License-Identifier: Apache-2.0 |
2 | | -# |
3 | | -# west-env CI |
4 | | -# =========== |
5 | | -# |
6 | | -# Job 1 — unit-tests |
7 | | -# Pure-Python unit tests for the west_env package. |
8 | | -# Matrix: ubuntu / macOS / Windows × Python 3.10 / 3.11 / 3.12 |
9 | | -# (Zephyr supports Python 3.10–3.12.) |
10 | | -# |
11 | | -# Job 2 — native-sim-build |
12 | | -# End-to-end integration test on ubuntu-latest: |
13 | | -# 1. Set up a minimal west workspace (Zephyr only, no HALs). |
14 | | -# 2. `west env doctor` — verifies the native environment looks healthy. |
15 | | -# 3. `west env build -b native_sim` on Zephyr's hello_world sample. |
16 | | -# 4. Run the resulting binary and assert it prints "Hello World". |
17 | | -# |
18 | | -# Container-backed builds are not tested here because the Zephyr container |
19 | | -# image is not a public artifact in this repository. They can be exercised |
20 | | -# locally with `west env build --container ...`. |
21 | | - |
22 | | -name: west-env CI |
| 1 | +name: CI |
23 | 2 |
|
24 | 3 | on: |
25 | 4 | push: |
26 | 5 | pull_request: |
27 | 6 |
|
| 7 | +concurrency: |
| 8 | + group: ci-${{ github.ref }} |
| 9 | + cancel-in-progress: true |
| 10 | + |
| 11 | +permissions: |
| 12 | + contents: read |
| 13 | + |
28 | 14 | jobs: |
29 | 15 | # -------------------------------------------------------------------------- |
30 | | - # Job 1: unit tests across platforms and Python versions |
| 16 | + # Lint with ruff (ubuntu only) |
| 17 | + # -------------------------------------------------------------------------- |
| 18 | + lint: |
| 19 | + name: Lint (ruff) |
| 20 | + runs-on: ubuntu-latest |
| 21 | + steps: |
| 22 | + - uses: actions/checkout@v4 |
| 23 | + - uses: actions/setup-python@v5 |
| 24 | + with: |
| 25 | + python-version: "3.12" |
| 26 | + - run: pip install ruff |
| 27 | + - run: ruff check west_env/ west_commands/ tests/ |
| 28 | + - run: ruff format --check west_env/ west_commands/ tests/ |
| 29 | + |
| 30 | + # -------------------------------------------------------------------------- |
| 31 | + # Unit tests — Windows / Linux / macOS × Python 3.10 / 3.11 / 3.12 |
31 | 32 | # -------------------------------------------------------------------------- |
32 | 33 | unit-tests: |
33 | | - name: Unit tests (py${{ matrix.python-version }}, ${{ matrix.os }}) |
34 | | - runs-on: ${{ matrix.os }} |
| 34 | + name: Unit tests (${{ matrix.os }}, py${{ matrix.python-version }}) |
| 35 | + needs: [lint] |
35 | 36 | strategy: |
36 | 37 | fail-fast: false |
37 | 38 | matrix: |
38 | | - os: [ubuntu-latest, macos-latest, windows-latest] |
| 39 | + os: [ubuntu-latest, windows-latest, macos-latest] |
39 | 40 | python-version: ["3.10", "3.11", "3.12"] |
40 | | - |
| 41 | + runs-on: ${{ matrix.os }} |
41 | 42 | steps: |
42 | 43 | - uses: actions/checkout@v4 |
43 | | - |
44 | | - - name: Set up Python ${{ matrix.python-version }} |
45 | | - uses: actions/setup-python@v5 |
| 44 | + - uses: actions/setup-python@v5 |
46 | 45 | with: |
47 | 46 | python-version: ${{ matrix.python-version }} |
48 | | - |
49 | 47 | - name: Install west-env with test dependencies |
50 | 48 | run: pip install -e ".[test]" |
| 49 | + - name: Run core unit tests |
| 50 | + run: > |
| 51 | + pytest |
| 52 | + tests/test_config.py |
| 53 | + tests/test_container.py |
| 54 | + tests/test_engine.py |
| 55 | + tests/test_util.py |
| 56 | + tests/test_backend.py |
| 57 | + tests/test_sync.py |
| 58 | + tests/test_new_modules.py |
| 59 | + -v |
51 | 60 |
|
52 | | - - name: Run unit tests |
53 | | - run: pytest tests/test_config.py tests/test_container.py tests/test_engine.py tests/test_util.py -v |
| 61 | + # -------------------------------------------------------------------------- |
| 62 | + # Docker integration tests — ubuntu only (Docker available on GH runners) |
| 63 | + # -------------------------------------------------------------------------- |
| 64 | + docker-integration: |
| 65 | + name: Docker integration (ubuntu) |
| 66 | + runs-on: ubuntu-latest |
| 67 | + timeout-minutes: 20 |
| 68 | + steps: |
| 69 | + - uses: actions/checkout@v4 |
| 70 | + - uses: actions/setup-python@v5 |
| 71 | + with: |
| 72 | + python-version: "3.11" |
| 73 | + - name: Install west-env |
| 74 | + run: pip install -e ".[test]" |
| 75 | + - name: Docker integration + west e2e tests |
| 76 | + run: > |
| 77 | + pytest |
| 78 | + tests/test_docker_integration.py |
| 79 | + tests/test_west_e2e.py |
| 80 | + tests/test_mode_switch.py |
| 81 | + -v |
| 82 | + env: |
| 83 | + WEST_ENV_DOCKER_TEST_BASE_IMAGE: alpine/git:latest |
54 | 84 |
|
55 | 85 | # -------------------------------------------------------------------------- |
56 | | - # Job 2: native_sim hello_world — closed-loop integration test |
| 86 | + # native_sim hello_world — closed-loop Zephyr build (ubuntu only) |
57 | 87 | # -------------------------------------------------------------------------- |
58 | 88 | native-sim-build: |
59 | | - name: native_sim hello_world (ubuntu-latest) |
| 89 | + name: native_sim hello_world (ubuntu) |
60 | 90 | runs-on: ubuntu-latest |
61 | 91 | timeout-minutes: 30 |
62 | | - |
63 | 92 | steps: |
64 | 93 | - uses: actions/checkout@v4 |
65 | | - |
66 | | - - name: Set up Python 3.11 |
67 | | - uses: actions/setup-python@v5 |
| 94 | + - uses: actions/setup-python@v5 |
68 | 95 | with: |
69 | 96 | python-version: "3.11" |
70 | | - |
71 | | - # Install the PR's west-env code so that `west env` reflects this branch. |
72 | | - - name: Install west-env (this PR) |
| 97 | + - name: Install west-env |
73 | 98 | run: pip install -e ".[test]" |
74 | | - |
75 | | - # native_sim builds with -m32 and requires 32-bit glibc headers. |
76 | | - - name: Install 32-bit build dependencies (gcc-multilib) |
| 99 | + - name: Install 32-bit build deps |
77 | 100 | run: sudo apt-get install -y --no-install-recommends gcc-multilib |
78 | | - |
79 | | - # Cache Zephyr source to avoid a full clone on every run. |
80 | 101 | - name: Cache west modules |
81 | 102 | id: cache-west |
82 | 103 | uses: actions/cache@v4 |
83 | 104 | with: |
84 | 105 | path: /tmp/ci-ws |
85 | | - key: west-modules-${{ runner.os }}-${{ hashFiles('tests/fixtures/ci-workspace/west.yml') }} |
86 | | - |
87 | | - # ----------------------------------------------------------------------- |
88 | | - # Workspace setup (skipped when cache is warm) |
89 | | - # ----------------------------------------------------------------------- |
| 106 | + key: west-${{ runner.os }}-${{ hashFiles('tests/fixtures/ci-workspace/west.yml') }} |
90 | 107 | - name: Copy CI fixture workspace |
91 | 108 | if: steps.cache-west.outputs.cache-hit != 'true' |
92 | 109 | run: | |
93 | 110 | mkdir -p /tmp/ci-ws |
94 | 111 | cp -r tests/fixtures/ci-workspace /tmp/ci-ws/workspace |
95 | | -
|
96 | 112 | - name: west init |
97 | 113 | if: steps.cache-west.outputs.cache-hit != 'true' |
98 | 114 | working-directory: /tmp/ci-ws/workspace |
99 | 115 | run: west init -l . |
100 | | - |
101 | | - - name: west update (Zephyr only — no HALs) |
| 116 | + - name: west update (Zephyr only, no HALs) |
102 | 117 | if: steps.cache-west.outputs.cache-hit != 'true' |
103 | 118 | working-directory: /tmp/ci-ws/workspace |
104 | 119 | run: west update --narrow --fetch-opt=--depth=1 |
105 | | - |
106 | | - # Always re-install Python requirements (cheap, idempotent). |
107 | 120 | - name: Install Zephyr Python requirements |
108 | 121 | working-directory: /tmp/ci-ws/workspace |
109 | 122 | run: | |
110 | 123 | ZEPHYR_BASE=$(west list zephyr -f '{abspath}') |
111 | 124 | pip install -r "$ZEPHYR_BASE/scripts/requirements.txt" |
112 | | -
|
113 | | - # ----------------------------------------------------------------------- |
114 | | - # Sanity check: native doctor (Python layer only) |
115 | | - # |
116 | | - # `west env doctor` requires west-env to be listed in the workspace |
117 | | - # manifest under west-commands: — we skip the CLI wrapper here and |
118 | | - # exercise the underlying Python functions directly instead. |
119 | | - # The CLI dispatch layer is covered by the unit-tests job. |
120 | | - # ----------------------------------------------------------------------- |
121 | | - - name: west-env doctor check (native mode) |
| 125 | + - name: west-env doctor (Python layer + backend detection) |
122 | 126 | working-directory: /tmp/ci-ws/workspace |
123 | 127 | run: | |
124 | 128 | python - <<'EOF' |
125 | 129 | from west_env.util import check_python, check_west |
| 130 | + from west_env.backend import doctor_lines |
126 | 131 | import sys |
127 | 132 | ok = check_python() and check_west() |
| 133 | + for line in doctor_lines('linux'): |
| 134 | + print(line) |
128 | 135 | sys.exit(0 if ok else 1) |
129 | 136 | EOF |
130 | | -
|
131 | | - # ----------------------------------------------------------------------- |
132 | | - # Build |
133 | | - # |
134 | | - # In native mode, `west env build` is exactly: |
135 | | - # subprocess.check_call(["west", "build"] + passthrough) |
136 | | - # so calling `west build` directly exercises the same code path and |
137 | | - # avoids the west extension-command discovery requirement. |
138 | | - # ----------------------------------------------------------------------- |
139 | 137 | - name: Build hello_world for native_sim |
140 | 138 | working-directory: /tmp/ci-ws/workspace |
141 | 139 | env: |
142 | | - # Use the host GCC/Clang; no Zephyr SDK required for native_sim. |
143 | 140 | ZEPHYR_TOOLCHAIN_VARIANT: host |
144 | 141 | run: | |
145 | 142 | ZEPHYR_BASE=$(west list zephyr -f '{abspath}') |
146 | 143 | west build -b native_sim "$ZEPHYR_BASE/samples/hello_world" |
147 | | -
|
148 | | - # ----------------------------------------------------------------------- |
149 | | - # Closed-loop output validation |
150 | | - # ----------------------------------------------------------------------- |
151 | 144 | - name: Validate hello_world output |
152 | 145 | run: | |
153 | | - # native_sim runs the Zephyr kernel loop indefinitely; use timeout |
154 | | - # to capture early stdout then kill the process. |
155 | 146 | OUTPUT=$(timeout 10s /tmp/ci-ws/workspace/build/zephyr/zephyr.exe 2>&1 || true) |
156 | | - echo "--- binary output ---" |
157 | | - echo "$OUTPUT" |
158 | | - echo "---------------------" |
159 | 147 | echo "$OUTPUT" | grep -q "Hello World" \ |
160 | | - || { echo "FAIL: 'Hello World' not found in binary output"; exit 1; } |
161 | | - echo "PASS: Hello World confirmed in output" |
| 148 | + || { echo "FAIL: Hello World not found"; exit 1; } |
| 149 | + echo "PASS: Hello World confirmed" |
| 150 | +
|
| 151 | + # -------------------------------------------------------------------------- |
| 152 | + # Security audit |
| 153 | + # -------------------------------------------------------------------------- |
| 154 | + security: |
| 155 | + name: pip-audit |
| 156 | + runs-on: ubuntu-latest |
| 157 | + steps: |
| 158 | + - uses: actions/checkout@v4 |
| 159 | + - uses: actions/setup-python@v5 |
| 160 | + with: |
| 161 | + python-version: "3.12" |
| 162 | + - name: Install package and pip-audit |
| 163 | + run: | |
| 164 | + pip install -e . |
| 165 | + pip install pip-audit |
| 166 | + - name: Run pip-audit |
| 167 | + run: pip-audit --desc on || true |
0 commit comments