Skip to content

Commit be292de

Browse files
committed
chore: switch to uv/ruff/ty instead of poetry/pylint/isort/black/mypy
1 parent acfe868 commit be292de

20 files changed

Lines changed: 1531 additions & 2184 deletions

.github/actions/poetrybuild/action.yaml

Lines changed: 0 additions & 28 deletions
This file was deleted.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# SPDX-FileCopyrightText: 2024 DB Systel GmbH
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
name: "Reusable uv build workflow"
6+
description: "Reusable workflow to set up Python and install dependencies via uv. The Python version and additional uv arguments can be configured via inputs."
7+
inputs:
8+
python:
9+
default: "3.14"
10+
description: "Value for 'python-version'"
11+
required: false
12+
type: string
13+
uv_args:
14+
default: ""
15+
description: "Additional arguments for the uv install step'"
16+
required: false
17+
type: string
18+
runs:
19+
using: "composite"
20+
steps:
21+
- name: Set up Python
22+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
23+
with:
24+
python-version: ${{ inputs.python }}
25+
- name: Install uv
26+
uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0
27+
with:
28+
enable-cache: true
29+
- name: Setup project
30+
run: |
31+
uv_args="${UV_ARGS}"
32+
uv sync --locked --all-extras --dev $uv_args
33+
env:
34+
UV_ARGS: ${{ inputs.uv_args }}
35+
shell: bash

.github/workflows/publish.yaml

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,30 @@
33
# SPDX-License-Identifier: Apache-2.0
44

55
name: Publish release on PyPI
6-
76
on:
87
release:
98
types: [published]
109

1110
jobs:
12-
build:
11+
pypi-publish:
1312
runs-on: ubuntu-latest
13+
environment:
14+
name: pypi
15+
url: https://pypi.org/p/github-org-manager
16+
permissions:
17+
id-token: write
18+
contents: read
1419
steps:
1520
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
16-
- name: Build and publish to PyPI
17-
uses: JRubics/poetry-publish@4b3306307f536bbfcb559603629b3b4f6aef5ab8 # v2.1
1821
with:
19-
pypi_token: ${{ secrets.PYPI_TOKEN }}
22+
persist-credentials: false
23+
- name: Set up Python
24+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
25+
- name: Install uv
26+
uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0
27+
with:
28+
enable-cache: false # avoid cache-poisoning attacks
29+
- name: Build package
30+
run: uv build
31+
- name: Publish package to PyPI
32+
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0

.github/workflows/real-test.yaml

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ on:
88
pull_request:
99
workflow_dispatch:
1010

11+
permissions:
12+
contents: read
13+
1114
jobs:
1215
selftest:
1316
runs-on: ubuntu-24.04
@@ -16,7 +19,9 @@ jobs:
1619
GITHUB_APP_PRIVATE_KEY: ${{ secrets.TEST_GITHUB_APP_PRIVATE_KEY }}
1720
steps:
1821
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
19-
- uses: ./.github/actions/poetrybuild
22+
with:
23+
persist-credentials: false
24+
- uses: ./.github/actions/uvbuild
2025
- name: Replace data in config files
2126
run: |
2227
sed -i "s/TEST_GITHUB_ORG/${{ secrets.TEST_GITHUB_ORG }}/g" tests/data/config/org_files/*.yaml
@@ -28,14 +33,14 @@ jobs:
2833
cp tests/data/config/teams_files/teams_changes.yaml tests/data/config/teams/teams.yaml
2934
cp tests/data/config/org_files/org_changes.yaml tests/data/config/org.yaml
3035
- name: Run 1 (changes) - dry run
31-
run: poetry run gh-org-mgr sync -c tests/data/config/ --dry -vv
36+
run: uv run gh-org-mgr sync -c tests/data/config/ --dry -vv
3237
- name: Run 1 (changes) - prod run
33-
run: poetry run gh-org-mgr sync -c tests/data/config/ -vv
38+
run: uv run gh-org-mgr sync -c tests/data/config/ -vv
3439
- name: Prepare for second run, reverting to original state
3540
run: |
3641
cp tests/data/config/teams_files/teams_orig.yaml tests/data/config/teams/teams.yaml
3742
cp tests/data/config/org_files/org_orig.yaml tests/data/config/org.yaml
3843
- name: Run 2 (revert) - dry run
39-
run: poetry run gh-org-mgr sync -c tests/data/config/ --dry -vv
44+
run: uv run gh-org-mgr sync -c tests/data/config/ --dry -vv
4045
- name: Run 2 (revert) - prod run
41-
run: poetry run gh-org-mgr sync -c tests/data/config/ -vv
46+
run: uv run gh-org-mgr sync -c tests/data/config/ -vv

.github/workflows/release-vulnerabilities.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ on:
88
schedule:
99
- cron: "35 9 * * 1" # run a check once a week
1010

11+
permissions:
12+
contents: read
13+
1114
jobs:
1215
osv-check:
1316
runs-on: ubuntu-latest

.github/workflows/test.yaml

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,19 @@ on:
1010
- main
1111
pull_request:
1212

13+
permissions:
14+
contents: read
15+
1316
jobs:
14-
# Test using the tool via poetry on different OSes and python versions
17+
# Test using the tool via uv on different OSes and python versions
1518
test-os-python-matrix:
1619
runs-on: ${{ matrix.os }}
1720
strategy:
1821
max-parallel: 10
1922
# do not abort the whole test job if one combination in the matrix fails
2023
fail-fast: false
2124
matrix:
22-
python-version: ["3.10", "3.11", "3.12"]
25+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
2326
os: [ubuntu-22.04]
2427
include:
2528
- python-version: "3.10"
@@ -29,64 +32,65 @@ jobs:
2932

3033
steps:
3134
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
32-
- uses: ./.github/actions/poetrybuild
35+
with:
36+
persist-credentials: false
37+
- uses: ./.github/actions/uvbuild
3338
with:
3439
python: ${{ matrix.python-version }}
35-
poetry_args: --only main
40+
uv_args: --no-dev
3641
- name: Execute gh-org-mgr
37-
run: poetry run gh-org-mgr --help
42+
run: uv run gh-org-mgr --help
3843

3944
# Test building the package and installing it via pip3
4045
test-build-install:
4146
runs-on: ubuntu-24.04
4247
steps:
4348
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
49+
with:
50+
persist-credentials: false
4451
- name: Set up Python
4552
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
4653
with:
4754
python-version: "3.14"
48-
- name: Install poetry
49-
run: pip install poetry
55+
- name: Install uv
56+
uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0
57+
with:
58+
enable-cache: true
5059
- name: Build package
51-
run: poetry build
60+
run: uv build
5261
- name: Install package
5362
run: pip3 install dist/github_org_manager-*.tar.gz
5463
- name: Run package
5564
run: |
5665
gh-org-mgr --version
5766
gh-org-mgr --help
5867
59-
# Formatting
60-
pylint:
68+
# Quality checks
69+
ruff:
6170
runs-on: ubuntu-24.04
6271
steps:
6372
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
64-
- uses: ./.github/actions/poetrybuild
65-
- name: Lint with pylint
66-
run: poetry run pylint --disable=fixme gh_org_mgr/
67-
68-
formatting:
69-
runs-on: ubuntu-24.04
70-
steps:
71-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
72-
- uses: ./.github/actions/poetrybuild
73-
- name: Test formatting with isort and black
74-
run: |
75-
poetry run isort --check gh_org_mgr/
76-
poetry run black --check .
77-
78-
mypy:
73+
with:
74+
persist-credentials: false
75+
- uses: ./.github/actions/uvbuild
76+
- name: Lint with ruff
77+
run: uv run ruff check
78+
ty:
7979
runs-on: ubuntu-24.04
8080
steps:
8181
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
82-
- uses: ./.github/actions/poetrybuild
83-
- name: Test typing with mypy
84-
run: poetry run mypy
82+
with:
83+
persist-credentials: false
84+
- uses: ./.github/actions/uvbuild
85+
- name: Test typing with ty
86+
run: uv run ty check
8587

8688
# REUSE
8789
reuse:
8890
runs-on: ubuntu-latest
8991
steps:
9092
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
93+
with:
94+
persist-credentials: false
9195
- name: Check REUSE Compliance
9296
uses: fsfe/reuse-action@676e2d560c9a403aa252096d99fcab3e1132b0f5 # v6.0.0

CONTRIBUTING.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ This Project welcomes contributions, suggestions, and feedback. All contribution
1111

1212
## Development setup
1313

14-
Starting development is as easy as installing Python `poetry` and running `poetry install` once.
14+
Starting development is as easy as installing [uv](https://docs.astral.sh/uv/) and running `uv sync` once.
1515

16-
In order to run the project in the new virtual environment, run `poetry run gh-org-mgr`.
16+
In order to run the project in the new virtual environment, run `uv run gh-org-mgr`.
1717

1818
---
1919
Based on [GitHub's Minimum Viable Governance (MVG)](https://github.com/github/MVG). Licensed under the [CC-BY 4.0 License](https://creativecommons.org/licenses/by/4.0/).

gh_org_mgr/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#
33
# SPDX-License-Identifier: Apache-2.0
44

5-
"""Global init file"""
5+
"""Global init file."""
66

77
from importlib.metadata import version
88

gh_org_mgr/_config.py

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
#
33
# SPDX-License-Identifier: Apache-2.0
44

5-
"""Handling the private and organisation configuration"""
5+
"""Handling the private and organisation configuration."""
66

77
import logging
8-
import os
98
import re
109
import sys
10+
from pathlib import Path
1111
from typing import Any
1212

1313
import yaml
@@ -100,38 +100,38 @@
100100

101101

102102
def _find_matching_files(directory: str, pattern: str, only_one: bool = False) -> list[str]:
103-
"""
104-
Get all files in a directory matching a regex pattern.
103+
"""Get all files in a directory matching a regex pattern.
105104
106105
Args:
107-
- directory: Path to the directory
108-
- pattern: Regular expression pattern to match filenames
109-
- only_one: Whether only the first match shall be returned.
106+
directory: Path to the directory.
107+
pattern: Regular expression pattern to match filenames.
108+
only_one: Whether only the first match shall be returned.
110109
111110
Returns:
112-
- List of filenames matching the pattern
111+
List of filenames matching the pattern.
113112
"""
114113
matching_files: list[str] = []
115114

115+
dir_path = Path(directory)
116+
116117
# Validate directory existence
117-
if not os.path.isdir(directory):
118+
if not dir_path.is_dir():
118119
logging.error("'%s' is not a valid directory", directory)
119120

120121
else:
121122
# Compile the regex pattern
122123
regex_pattern = re.compile(pattern + "$")
123124

124125
# Traverse the directory and find matching files
125-
for file_name in os.listdir(directory):
126-
if regex_pattern.match(file_name):
127-
file_path = os.path.join(directory, file_name)
128-
if os.path.isfile(file_path):
129-
matching_files.append(file_path)
126+
for entry in dir_path.iterdir():
127+
if regex_pattern.match(entry.name):
128+
if entry.is_file():
129+
matching_files.append(str(entry))
130130
else:
131131
logging.warning(
132132
"'%s' looks like a file we searched for, but it's not. "
133133
"Will not consider its contents",
134-
file_path,
134+
entry,
135135
)
136136

137137
if only_one and len(matching_files) > 1:
@@ -154,7 +154,7 @@ def _find_matching_files(directory: str, pattern: str, only_one: bool = False) -
154154

155155

156156
def _read_config_file(file: str) -> dict:
157-
"""Return dict of a YAML file"""
157+
"""Return dict of a YAML file."""
158158
logging.debug("Attempting to parse YAML file %s", file)
159159
with open(file, encoding="UTF-8") as yamlfile:
160160
config: dict = yaml.safe_load(yamlfile)
@@ -166,7 +166,7 @@ def _read_config_file(file: str) -> dict:
166166

167167

168168
def _validate_config_schema(file: str, cfg: dict, schema: dict) -> None:
169-
"""Validate the config against a JSON schema"""
169+
"""Validate the config against a JSON schema."""
170170
try:
171171
validate(instance=cfg, schema=schema, format_checker=FormatChecker())
172172
except ValidationError as e:
@@ -177,11 +177,12 @@ def _validate_config_schema(file: str, cfg: dict, schema: dict) -> None:
177177

178178
def parse_config_files(path: str) -> tuple[dict[str, str | dict[str, str]], dict, dict]:
179179
"""Parse all relevant files in the configuration directory. Returns a tuple
180-
of org config, app config, and merged teams config"""
180+
of org config, app config, and merged teams config.
181+
"""
181182
# Find the relevant config files for app, org, and teams
182183
cfg_app_files = _find_matching_files(path, APP_CONFIG_FILE, only_one=True)
183184
cfg_org_files = _find_matching_files(path, ORG_CONFIG_FILE, only_one=True)
184-
cfg_teams_files = _find_matching_files(os.path.join(path, TEAM_CONFIG_DIR), TEAM_CONFIG_FILES)
185+
cfg_teams_files = _find_matching_files(str(Path(path) / TEAM_CONFIG_DIR), TEAM_CONFIG_FILES)
185186

186187
# Read and parse config files for app and org
187188
cfg_app = _read_config_file(cfg_app_files[0])

0 commit comments

Comments
 (0)