Skip to content

Commit 1b90235

Browse files
dixonjoelmshafer-NIbkeryan
authored
Add analyze-project composite action to validate a Python project (#24)
* Add check_analyzers as a trial balloon * Fix project-directory inputs, change name of .yml file. Update install-drivers to install-extras * Rename to analyze-project.yml and 'extras' * Remove bandit checks. Will be covered by ni-python-styleguide soon * Switch to a composite action * Add test for analyze-project * Create project to analyze * Add shell specification for actions * Attempt to fix the project directory for analyze test * Attempt to fix the project directory for analyze test * Produce poetry.lock before analyzing * Add dependency on ni-python-styleguide * Use a compatible Python version * Use matrix Python version * Another attempt at the correct python version * Tenth time is the charm * Eleventh time is the charm * Twelfth time is the charm * Thirteenth time is the charm * Try try again * Try try again * Add docstrings to .py files * Try try again * Whee! Let's try Python * Add mypy dependency * Further restrict the Python version for mypy to work * Show pyproject.toml after the addition of deps * Attempt to use a template project for testing * Add mypy section * Add pyright dependencies * Update poetry .lock * Try different working directory * Try original working directory * Attempt to make it work on Windows * Test more Python versions * Make mypy and pyright optional. * fix yml syntax * Indent python code * Check the outputs * Check packages after install * Use GITHUB_OUTPUT * Move minimal test project under .github to hide it * Simplify Add virtualenv to the path for pyright-action * Various PR feedback * Use poetry env info --path to get the venv path * Add -C parameter to poetry env --info command * Attempt to use {{ github.workspace }} instead of ./ * Attempt to use working-directory instead of -C <path> * Remove stray quote * Try quoting * Remove some bash code to narrow down error * Add back in path * Try another arrangement * Try without echoing the path * Try some quotes, why not? * Try without --path, why not * Try without Python 3.9 * Echo the poetry env info * Add back in path * Try a different arrangement of quotes * Change variable name * Change variable name * print some debug info * don't stop on help * don't fail fast * ok, let's print it out without exiting first * ok, use or * ok, try this... * analyze-project: Fix venv caching (#28) * analyze-project: Fix venv caching * analyze-project: Update prints --------- Co-authored-by: Joel Dixon <[email protected]> * Restore all the matrix of python versions and OSs * Fix copy and paste error in test_actions.yml * Minor PR feedback * Remove 3.13t Python from some spots * Use v0 for actions in README --------- Co-authored-by: mshafer-NI <[email protected]> Co-authored-by: Brad Keryan <[email protected]>
1 parent 8c8e023 commit 1b90235

File tree

8 files changed

+794
-1
lines changed

8 files changed

+794
-1
lines changed

.github/test_projects/minimal/README.md

Whitespace-only changes.

.github/test_projects/minimal/poetry.lock

Lines changed: 597 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
[project]
2+
name = "test-project"
3+
version = "0.1.0"
4+
description = ""
5+
authors = [
6+
{name = "Joel Dixon",email = "[email protected]"}
7+
]
8+
readme = "README.md"
9+
requires-python = ">=3.9,<4.0"
10+
dynamic = ["dependencies"]
11+
12+
[tool.poetry]
13+
packages = [{include = "test_project", from = "src"}]
14+
15+
[tool.poetry.group.lint.dependencies]
16+
ni-python-styleguide = ">=0.4.1"
17+
mypy = ">=1.0"
18+
pyright = { version = ">=1.1.400", extras = ["nodejs"] }
19+
20+
[tool.mypy]
21+
mypy_path = "."
22+
files = "."
23+
namespace_packages = true
24+
strict = true
25+
explicit_package_bases = true
26+
27+
[tool.pyright]
28+
include = ["src/", "tests/"]
29+
30+
[build-system]
31+
requires = ["poetry-core>=2.0.0,<3.0.0"]
32+
build-backend = "poetry.core.masonry.api"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Docstring required."""
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Module docstring."""

.github/workflows/test_actions.yml

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,27 @@ jobs:
212212
project-directory: test-project
213213
expected-version: 1.0.2.dev1
214214

215+
test_analyze_project:
216+
name: Test analyze-project
217+
runs-on: ${{ matrix.os }}
218+
strategy:
219+
matrix:
220+
os: [windows-latest, ubuntu-latest, macos-latest]
221+
python-version: [3.9, '3.10', 3.11, 3.12, 3.13, pypy3.10, pypy3.11]
222+
steps:
223+
- name: Check out repo
224+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
225+
- name: Set up Python
226+
uses: ./setup-python
227+
with:
228+
python-version: ${{ matrix.python-version }}
229+
- name: Set up Poetry
230+
uses: ./setup-poetry
231+
- name: Analyze Python Project
232+
uses: ./analyze-project
233+
with:
234+
project-directory: ${{ github.workspace }}/.github/test_projects/minimal
235+
215236
# This job is intended to combine the test results so we don't have to list
216237
# each matrix combination in the required status check settings. There are a
217238
# lot of corner cases that make this harder than it should be; see See
@@ -225,7 +246,8 @@ jobs:
225246
test_setup_poetry_cache_hit,
226247
test_setup_poetry_no_cache,
227248
test_check_project_version,
228-
test_update_project_version
249+
test_update_project_version,
250+
test_analyze_project,
229251
]
230252
if: ${{ !cancelled() }}
231253
steps:

analyze-project/README.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# `ni/python-actions/analyze-project`
2+
3+
The `ni/python-actions/update-project-version` action analyzes the code quality
4+
of a Python project using various linters and type checkers including
5+
ni-python-styleguide, mypy (if the 'mypy' package is installed), and pyright
6+
(if the 'pyright' package is installed).
7+
8+
This action requires Poetry, so you must call `ni/python-actions/setup-python` and
9+
`ni/python-actions/setup-poetry` first.
10+
11+
## Usage
12+
13+
```yaml
14+
steps:
15+
- uses: ni/python-actions/setup-python@v0
16+
- uses: ni/python-actions/setup-poetry@v0
17+
- uses: ni/python-actions/analyze-project@v0
18+
```
19+
20+
## Inputs
21+
22+
### `project-directory`
23+
24+
You can specify `project-directory` to indicate the location of the pyproject.toml
25+
file associated with the Python project you are analyzing.
26+
27+
```yaml
28+
- uses: ni/python-actions/update-project-version@v0
29+
with:
30+
project-directory: ${{ github.workspace }}/packages/myproject
31+
```
32+
33+
### `extras`
34+
35+
If there are extras you need to install from your pyproject.toml, specify a space-separated list
36+
of extra groups to install. For example,
37+
38+
```yaml
39+
- uses: ni/python-actions/analyze-project@v0
40+
with:
41+
project-directory: ${{ github.workspace }}/packages/myproject
42+
extras: 'docs drivers'
43+
```

analyze-project/action.yml

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
name: Analyze project
2+
description: >
3+
This workflow analyzes the code quality of a Python project using various
4+
linters and type checkers including ni-python-styleguide,
5+
mypy (if the 'mypy' package is installed), and pyright (if the 'pyright'
6+
package is installed).
7+
8+
inputs:
9+
project-directory:
10+
description: Path to the directory containing pyproject.toml.
11+
default: ${{ github.workspace }}
12+
extras:
13+
# E.g. "docs drivers"
14+
description: 'List of Poetry extras to install (separated by spaces)'
15+
default: ''
16+
required: false
17+
type: string
18+
19+
runs:
20+
using: composite
21+
steps:
22+
- name: Get project info
23+
id: get_project_info
24+
run: |
25+
result=$(poetry version)
26+
name=$(echo "$result" | awk '{print $1}')
27+
version=$(echo "$result" | awk '{print $2}')
28+
echo "Name: $name"
29+
echo "Version: $version"
30+
echo "name=$name" >> "$GITHUB_OUTPUT"
31+
echo "version=$version" >> "$GITHUB_OUTPUT"
32+
poetry env activate
33+
venv_path="$(poetry env info --path)"
34+
echo "venv path: $venv_path"
35+
echo "venv-path=$venv_path" >> "$GITHUB_OUTPUT"
36+
shell: bash
37+
working-directory: ${{ inputs.project-directory }}
38+
- name: Check for lock changes
39+
run: poetry check --lock -C "${{ inputs.project-directory }}"
40+
shell: bash
41+
- name: Cache virtualenv
42+
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
43+
with:
44+
path: ${{ steps.get_project_info.outputs.venv-path }}
45+
key: ${{ steps.get_project_info.outputs.name }}-${{ runner.os }}-py${{ env.pythonVersion }}-${{ hashFiles(format('{0}/poetry.lock', inputs.project-directory)) }}
46+
- name: Install ${{ steps.get_project_info.outputs.name }}
47+
run: |
48+
if [ -n "${{ inputs.extras }}" ]; then
49+
poetry install -v --extras '${{ inputs.extras }}'
50+
else
51+
poetry install -v
52+
fi
53+
working-directory: ${{ inputs.project-directory }}
54+
shell: bash
55+
- name: Lint
56+
run: poetry run ni-python-styleguide lint
57+
working-directory: ${{ inputs.project-directory }}
58+
shell: bash
59+
- name: Check for mypy and pyright installation
60+
id: check_tools
61+
run: |
62+
import os
63+
from importlib.metadata import version, PackageNotFoundError
64+
65+
def is_installed(pkg_name):
66+
try:
67+
version(pkg_name)
68+
return "true"
69+
except PackageNotFoundError:
70+
return "false"
71+
72+
with open(os.environ["GITHUB_OUTPUT"], "a") as output:
73+
print(f"mypy={is_installed('mypy')}", file=output)
74+
print(f"pyright={is_installed('pyright')}", file=output)
75+
shell: python
76+
- name: Echo check_tools outputs
77+
run: |
78+
echo "mypy installed: ${{ steps.check_tools.outputs.mypy }}"
79+
echo "pyright installed: ${{ steps.check_tools.outputs.pyright }}"
80+
shell: bash
81+
- name: Mypy static analysis
82+
if: steps.check_tools.outputs.mypy == 'true'
83+
run: poetry run mypy
84+
working-directory: ${{ inputs.project-directory }}
85+
shell: bash
86+
- name: Add virtualenv to the path for pyright-action
87+
if: steps.check_tools.outputs.pyright == 'true'
88+
shell: bash
89+
run: |
90+
echo "$(dirname $(poetry env info --executable))" >> $GITHUB_PATH
91+
working-directory: ${{ inputs.project-directory }}
92+
- name: Pyright static analysis
93+
if: steps.check_tools.outputs.pyright == 'true'
94+
uses: jakebailey/pyright-action@b5d50e5cde6547546a5c4ac92e416a8c2c1a1dfe # v2.3.2
95+
with:
96+
version: PATH
97+
working-directory: ${{ inputs.project-directory }}

0 commit comments

Comments
 (0)