Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7cc98cf

Browse files
drago1216claude
andauthored
[SPN-2930] Add GitHub Actions workflow for SDK generation pipeline (#18)
Adds .github/workflows/generate.yml with a manual workflow_dispatch trigger that runs the full pipeline end-to-end on a clean checkout: 1. Checkout, set up Python 3.12, install dev deps 2. Pull openapitools/openapi-generator-cli:v7.16.0 3. make generate (Docker-based codegen) 4. make format (ruff format + ruff check --fix) 5. make lint (ruff check) 6. make smoke-test (verify generated modules import) 7. make test (pytest + classify_semver bash tests) Supporting changes to make the pipeline pass: - pyproject.toml: per-file-ignores for ruff to relax rules that come from the upstream openapi-generator templates (B028, B904, N805, RUF002, SIM*, TC001/003, UP030/031, etc.) on generated paths, and the equivalent style-only rules on hand-written client/ code. - tests/: fix three real lint findings — two E731 lambda assignments and one F841 unused variable — and prefix unused unpacks with `_` to clear RUF059. Remaining test changes are pure ruff format output (line-length wrapping, removal of unused imports). Verified locally: full pipeline runs cleanly on macOS and produces 451 pytest + 29 classify_semver test passes with no stray files. Co-authored-by: Claude Sonnet 4.6 <[email protected]>
1 parent 9b6dadd commit 7cc98cf

14 files changed

Lines changed: 205 additions & 168 deletions

.github/workflows/generate.yml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: Generate SDK
2+
3+
on:
4+
workflow_dispatch:
5+
6+
jobs:
7+
generate:
8+
name: Generate, lint, and test
9+
runs-on: ubuntu-latest
10+
timeout-minutes: 20
11+
12+
steps:
13+
- name: Check out repository
14+
uses: actions/checkout@v4
15+
16+
- name: Set up Python
17+
uses: actions/setup-python@v5
18+
with:
19+
python-version: "3.12"
20+
cache: pip
21+
22+
- name: Install dependencies
23+
run: |
24+
python -m pip install --upgrade pip
25+
pip install -e ".[dev]"
26+
27+
- name: Pull OpenAPI Generator Docker image
28+
run: docker pull openapitools/openapi-generator-cli:v7.16.0
29+
30+
- name: Generate SDK from committed spec
31+
run: make generate
32+
33+
- name: Format generated code
34+
run: make format
35+
36+
- name: Lint generated code
37+
run: make lint
38+
39+
- name: Run import smoke test
40+
run: make smoke-test
41+
42+
- name: Run unit tests
43+
run: make test

pyproject.toml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,32 @@ ignore = [
101101
[tool.ruff.lint.isort]
102102
known-first-party = ["bamboohr_sdk"]
103103

104+
# Generated code (openapi-generator output) — relax rules that come from
105+
# the upstream templates and aren't worth fixing in our fork.
106+
# Hand-written code lives under bamboohr_sdk/client/ and stays under the
107+
# default rule set.
108+
[tool.ruff.lint.per-file-ignores]
109+
"bamboohr_sdk/api/*.py" = [
110+
"B028", "B904", "F841", "N805", "RUF002", "RUF012", "RUF059",
111+
"SIM101", "SIM105", "SIM108", "SIM118", "TC001", "TC003", "UP030", "UP031",
112+
]
113+
"bamboohr_sdk/models/*.py" = [
114+
"F841", "N805", "N818", "RUF002", "RUF012", "SIM118", "TC001", "TC003",
115+
]
116+
"bamboohr_sdk/api_client.py" = [
117+
"B028", "B904", "F841", "RUF002", "RUF012", "RUF059",
118+
"SIM101", "SIM105", "SIM108", "TC001", "TC003", "UP030", "UP031",
119+
]
120+
"bamboohr_sdk/api_helper.py" = ["TC001", "TC003"]
121+
"bamboohr_sdk/api_response.py" = ["TC001", "TC003"]
122+
"bamboohr_sdk/configuration.py" = ["B028", "B904", "RUF002", "UP030", "UP031"]
123+
"bamboohr_sdk/exceptions.py" = ["N818", "SIM105"]
124+
"bamboohr_sdk/rest.py" = ["B028", "B904", "RUF002", "SIM101", "SIM108"]
125+
# Hand-written client code: relax rules for type-only imports and
126+
# docstring-only stylistic noise. Real bugs would still surface via
127+
# mypy and the test suite.
128+
"bamboohr_sdk/client/**/*.py" = ["B904", "RUF002", "RUF059", "TC001", "TC003"]
129+
104130
[tool.ruff.format]
105131
quote-style = "double"
106132
indent-style = "space"

tests/test_api_error_helper.py

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,32 @@
33
import pytest
44

55
from bamboohr_sdk.api_error_helper import (
6-
ERROR_MESSAGES,
76
create_exception,
87
format_detailed_error_message,
98
get_error_info,
109
)
1110
from bamboohr_sdk.exceptions import (
1211
ApiException,
13-
ClientException,
14-
ServerException,
15-
BadRequestException,
1612
AuthenticationFailedException,
17-
PermissionDeniedException,
18-
ResourceNotFoundException,
19-
MethodNotAllowedException,
20-
RequestTimeoutException,
21-
ConflictException,
22-
PayloadTooLargeException,
23-
UnsupportedMediaTypeException,
24-
UnprocessableEntityException,
25-
RateLimitExceededException,
26-
InternalServerErrorException,
27-
NotImplementedException,
2813
BadGatewayException,
29-
ServiceUnavailableException,
14+
BadRequestException,
15+
ClientException,
16+
ConflictException,
3017
GatewayTimeoutException,
3118
InsufficientStorageException,
19+
InternalServerErrorException,
20+
MethodNotAllowedException,
3221
NetworkReadTimeoutException,
22+
NotImplementedException,
23+
PayloadTooLargeException,
24+
PermissionDeniedException,
25+
RateLimitExceededException,
26+
RequestTimeoutException,
27+
ResourceNotFoundException,
28+
ServerException,
29+
ServiceUnavailableException,
30+
UnprocessableEntityException,
31+
UnsupportedMediaTypeException,
3332
)
3433

3534

@@ -129,9 +128,7 @@ def test_with_request_id(self):
129128
assert "req-123" in msg
130129

131130
def test_with_causes(self):
132-
msg = format_detailed_error_message(
133-
"Error", causes=["Cause A", "Cause B"]
134-
)
131+
msg = format_detailed_error_message("Error", causes=["Cause A", "Cause B"])
135132
assert "This could be due to:" in msg
136133
assert "- Cause A" in msg
137134
assert "- Cause B" in msg
@@ -143,9 +140,7 @@ def test_with_tips(self):
143140
assert "- Try Y" in msg
144141

145142
def test_with_tips_and_request_id(self):
146-
msg = format_detailed_error_message(
147-
"Error", tips=["Try X"], request_id="req-456"
148-
)
143+
msg = format_detailed_error_message("Error", tips=["Try X"], request_id="req-456")
149144
assert "Include this Request ID (req-456)" in msg
150145

151146
def test_full_message(self):

tests/test_api_helper.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
"""Tests for bamboohr_sdk.api_helper module."""
22

3-
import time
43
from unittest.mock import MagicMock, patch
54

65
import pytest
@@ -97,9 +96,7 @@ def test_successful_request_no_retry(self):
9796
response = self._make_response(200)
9897
fn = MagicMock(return_value=response)
9998

100-
result = send_with_retries(
101-
fn, method="GET", url="https://example.com", max_retries=0
102-
)
99+
result = send_with_retries(fn, method="GET", url="https://example.com", max_retries=0)
103100

104101
assert result is response
105102
fn.assert_called_once()

tests/test_auth_builder.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,9 @@ class TestOnTokenRefresh:
9595
"""Tests for the token refresh callback."""
9696

9797
def test_registers_callback(self):
98-
cb = lambda *a: None
98+
def cb(*_a):
99+
return None
100+
99101
ab = AuthBuilder().with_api_key("k").on_token_refresh(cb)
100102
assert ab.token_refresh_callback is cb
101103

@@ -151,9 +153,7 @@ def test_oauth_masks_token(self):
151153

152154
def test_oauth_refresh_includes_client_id(self):
153155
info = (
154-
AuthBuilder()
155-
.with_oauth_refresh("a-long-token", "r-long-token", "my-client", "secret")
156-
.get_sanitized_info()
156+
AuthBuilder().with_oauth_refresh("a-long-token", "r-long-token", "my-client", "secret").get_sanitized_info()
157157
)
158158
assert info["client_id"] == "my-client"
159159
assert info["has_callback"] is False

0 commit comments

Comments
 (0)