Skip to content

Commit 9970ff2

Browse files
committed
Add GitHub Actions CI for external contributors
1 parent ff12318 commit 9970ff2

File tree

3 files changed

+169
-4
lines changed

3 files changed

+169
-4
lines changed

.github/workflows/ci.yml

Lines changed: 81 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,26 @@ concurrency:
1616
cancel-in-progress: true
1717

1818
jobs:
19+
images:
20+
name: Define Base Images
21+
runs-on: ubuntu-latest
22+
outputs:
23+
lint: ghcr.io/nvidia/cutile-python/lint:2026-01-12-aea51b7409cc
24+
docs: ghcr.io/nvidia/cutile-python/docs:2026-01-12-96c265b9029e
25+
build_py310: ghcr.io/nvidia/cutile-python/build_py_3.10_x86_64:2026-01-12-a3f084500fb0
26+
build_py311: ghcr.io/nvidia/cutile-python/build_py_3.11_x86_64:2026-01-12-d0a88a59d0fd
27+
build_py312: ghcr.io/nvidia/cutile-python/build_py_3.12_x86_64:2026-01-12-9cf7e54a5580
28+
build_py313: ghcr.io/nvidia/cutile-python/build_py_3.13_x86_64:2026-01-12-7f9db97c8ad8
29+
steps:
30+
- run: echo "Defining image tags"
31+
1932
lint:
2033
name: Lint
34+
needs: images
2135
runs-on: ubuntu-latest
2236
timeout-minutes: 10
2337
container:
24-
image: ghcr.io/nvidia/cutile-python/lint:2025-12-06-4cb7d16e4c20
38+
image: ${{ needs.images.outputs.lint }}
2539
steps:
2640
- name: Checkout repository
2741
uses: actions/checkout@v6
@@ -30,10 +44,73 @@ jobs:
3044
run: flake8
3145

3246
- name: Run cpplint
33-
run: python3 ci/cpplint.py
47+
run: python scripts/cpplint.py
3448

3549
- name: Check license headers (REUSE)
36-
run: ci/scripts/check_license.sh
50+
run: scripts/check_license.sh
3751

3852
- name: Check inline samples are up to date
39-
run: python3 test/tools/inline_samples.py --check
53+
run: python test/tools/inline_samples.py --check
54+
55+
docs:
56+
name: Build Docs
57+
needs: [images, build]
58+
runs-on: ubuntu-latest
59+
timeout-minutes: 10
60+
container:
61+
image: ${{ needs.images.outputs.docs }}
62+
steps:
63+
- name: Checkout repository
64+
uses: actions/checkout@v6
65+
66+
- name: Download wheel
67+
uses: actions/download-artifact@v4
68+
with:
69+
name: wheel-py3.12-linux-x86_64
70+
path: dist/
71+
72+
- name: Install wheel
73+
run: pip install dist/*.whl
74+
75+
- name: Build documentation
76+
run: make -C docs html
77+
78+
- name: Upload docs artifact
79+
uses: actions/upload-artifact@v4
80+
with:
81+
name: docs-html
82+
path: docs/build/html
83+
retention-days: 7
84+
85+
build:
86+
name: Build Wheel (Python ${{ matrix.python-version }})
87+
needs: images
88+
runs-on: ubuntu-latest
89+
timeout-minutes: 30
90+
strategy:
91+
matrix:
92+
include:
93+
- python-version: "3.10"
94+
image_key: build_py310
95+
- python-version: "3.11"
96+
image_key: build_py311
97+
- python-version: "3.12"
98+
image_key: build_py312
99+
- python-version: "3.13"
100+
image_key: build_py313
101+
container:
102+
image: ${{ needs.images.outputs[matrix.image_key] }}
103+
steps:
104+
- name: Checkout repository
105+
uses: actions/checkout@v6
106+
107+
- name: Build wheel
108+
run: python setup.py bdist_wheel
109+
110+
- name: Upload wheel artifact
111+
uses: actions/upload-artifact@v4
112+
with:
113+
name: wheel-py${{ matrix.python-version }}-linux-x86_64
114+
path: dist/*.whl
115+
if-no-files-found: error
116+
retention-days: 7

scripts/check_license.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/bin/bash
2+
# SPDX-FileCopyrightText: Copyright (c) <2025> NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
6+
ignore_files=("src/cuda/tile/VERSION")
7+
outputs=$(reuse lint --lines | grep -v ${ignore_files[@]/#/-e })
8+
if [ -n "$outputs" ]; then
9+
echo -e "License check failed\n${outputs}"
10+
exit 1
11+
fi
12+

scripts/cpplint.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#!/usr/bin/env python3
2+
# SPDX-FileCopyrightText: Copyright (c) <2025> NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
6+
import os
7+
import sys
8+
9+
file_extensions = [
10+
".h",
11+
".hpp",
12+
".hh",
13+
".c",
14+
".C",
15+
".cpp",
16+
".cxx",
17+
".cc",
18+
".pyx",
19+
".pxd",
20+
]
21+
max_line_len = 100
22+
23+
24+
def should_lint(filename: str):
25+
return any(filename.endswith(x) for x in file_extensions)
26+
27+
28+
def lint(paths):
29+
num_errors = 0
30+
num_files = 0
31+
32+
def report_error(message: str):
33+
nonlocal num_errors
34+
print(f"{full_name[len(path) + 1:]}:{i + 1}: {message}", file=sys.stderr)
35+
num_errors += 1
36+
37+
for path in paths:
38+
for root, dirs, files in os.walk(path):
39+
for filename in files:
40+
if not should_lint(filename):
41+
continue
42+
full_name = os.path.join(root, filename)
43+
with open(full_name, "r") as f:
44+
for i, line in enumerate(f):
45+
if "noqa" in line:
46+
continue
47+
if "SPDX" in line:
48+
continue
49+
50+
length = len(line)
51+
if line.endswith("\n"):
52+
length -= 1
53+
if length > max_line_len:
54+
report_error(
55+
f"Line is longer than {max_line_len} characters"
56+
)
57+
if length > 0 and line[length - 1].isspace():
58+
report_error("Trailing whitespace at the end of the line")
59+
num_files += 1
60+
61+
if num_errors > 0:
62+
print(f"Found {num_errors} errors", file=sys.stderr)
63+
sys.exit(1)
64+
elif num_files == 0:
65+
print("No input files found!", file=sys.stderr)
66+
sys.exit(2)
67+
else:
68+
print(f"Checked {num_files} files, all OK")
69+
70+
71+
if __name__ == "__main__":
72+
script_dir = os.path.dirname(__file__)
73+
project_root = os.getcwd()
74+
dirs = ["cext", "torch_cext", "src"]
75+
paths = [os.path.join(project_root, d) for d in dirs]
76+
lint(paths)

0 commit comments

Comments
 (0)