11name : CI
22
3- # Integration Test Strategy:
4- # - Fork PRs: Cannot access secrets, so integration tests are skipped with informative feedback
5- # - Same-repo PRs: Have access to secrets, integration tests run normally
6- # - Push to main/develop: Integration tests always run to catch any issues after merge
7- # - Manual trigger: Allows maintainers to run integration tests on demand
8- #
9- # This ensures security while still validating integration tests before release
10-
113on :
124 push :
13- branches : [ main, develop ]
5+ branches : [ main ]
146 pull_request :
15- branches : [ main, develop ]
16- # Run integration tests after PR is merged
17- workflow_dispatch : # Allow manual trigger for integration tests
7+ branches : [ main ]
188
199jobs :
20- test :
10+ lint-and-type-check :
2111 runs-on : ubuntu-latest
22- strategy :
23- matrix :
24- python-version : ['3.10', '3.11', '3.12']
2512
2613 steps :
2714 - uses : actions/checkout@v4
2815
29- - name : Set up Python ${{ matrix.python-version }}
16+ - name : Set up Python
3017 uses : actions/setup-python@v5
3118 with :
32- python-version : ${{ matrix.python-version }}
33-
34- - name : Cache pip dependencies
35- uses : actions/cache@v4
36- with :
37- path : ~/.cache/pip
38- key : ${{ runner.os }}-pip-${{ hashFiles('pyproject.toml') }}
39- restore-keys : |
40- ${{ runner.os }}-pip-
19+ python-version : ' 3.12'
20+ cache : ' pip'
4121
4222 - name : Install dependencies
4323 run : |
44- python -m pip install --upgrade pip
45- pip install -e ".[dev]"
24+ pip install ".[dev]"
4625
47- - name : Run linting with ruff
48- if : matrix.python-version == '3.10'
26+ - name : Run linting
4927 run : |
50- python -m ruff check .
51- python -m ruff format --check .
52-
53- - name : Run type checking with mypy
54- run : python -m mypy --python-version=${{ matrix.python-version }} src tests
28+ python -m ruff check src/
5529
56- - name : Run unit tests with pytest
57- run : python -m pytest tests/unit/ -v --cov=nutrient_dws --cov-report=xml --cov-report=term
30+ - name : Run type checking
31+ run : python -m mypy src/
5832
59- - name : Upload coverage to Codecov
60- uses : codecov/codecov-action@v5
61- with :
62- token : ${{ secrets.CODECOV_TOKEN }}
63- files : ./coverage.xml
64- flags : unittests
65- name : codecov-umbrella
66- fail_ci_if_error : false
33+ unit-tests :
34+ runs-on : ${{ matrix.os }}
35+ needs : lint-and-type-check
6736
68- integration-test :
69- runs-on : ubuntu-latest
70- # Run on: pushes to main/develop, PRs from same repo, and manual triggers
71- if : |
72- github.event_name == 'push' ||
73- github.event_name == 'workflow_dispatch' ||
74- (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository)
7537 strategy :
7638 matrix :
7739 python-version : ['3.10', '3.11', '3.12']
78-
40+ os : [ubuntu-latest, windows-latest, macos-latest]
41+
7942 steps :
8043 - uses : actions/checkout@v4
8144
8245 - name : Set up Python ${{ matrix.python-version }}
8346 uses : actions/setup-python@v5
8447 with :
8548 python-version : ${{ matrix.python-version }}
86-
87- - name : Cache pip dependencies
88- uses : actions/cache@v4
89- with :
90- path : ~/.cache/pip
91- key : ${{ runner.os }}-pip-${{ hashFiles('pyproject.toml') }}
92- restore-keys : |
93- ${{ runner.os }}-pip-
49+ cache : ' pip'
9450
9551 - name : Install dependencies
9652 run : |
97- python -m pip install --upgrade pip
98- pip install -e ".[dev]"
53+ pip install ".[dev]"
9954
100- - name : Check for API key availability
101- run : |
102- if [ -z "${{ secrets.NUTRIENT_DWS_API_KEY }}" ]; then
103- echo "::warning::NUTRIENT_DWS_API_KEY secret not found, skipping integration tests"
104- echo "skip_tests=true" >> $GITHUB_ENV
105-
106- # Provide context about why this might be happening
107- if [ "${{ github.event_name }}" == "pull_request" ]; then
108- if [ "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]; then
109- echo "::notice::This appears to be a PR from a fork. Secrets are not available for security reasons."
110- else
111- echo "::error::This is a PR from the same repository but the API key is missing. Please check repository secrets configuration."
112- fi
113- else
114- echo "::error::Running on ${{ github.event_name }} event but API key is missing. Please configure NUTRIENT_DWS_API_KEY secret."
115- fi
116- else
117- echo "::notice::API key found, integration tests will run"
118- echo "skip_tests=false" >> $GITHUB_ENV
119- fi
120-
121- - name : Create integration config with API key
122- if : env.skip_tests != 'true'
123- run : |
124- python -c "
125- import os
126- with open('tests/integration/integration_config.py', 'w') as f:
127- f.write(f'API_KEY = \"{os.environ[\"NUTRIENT_DWS_API_KEY\"]}\"\n')
128- "
129- env :
130- NUTRIENT_DWS_API_KEY : ${{ secrets.NUTRIENT_DWS_API_KEY }}
131-
132- - name : Run integration tests
133- if : env.skip_tests != 'true'
134- run : python -m pytest tests/integration/ -v
135-
136- - name : Cleanup integration config
137- if : always()
138- run : rm -f tests/integration/integration_config.py
139-
140- # Provide feedback for fork PRs where integration tests can't run
141- integration-test-fork-feedback :
142- runs-on : ubuntu-latest
143- if : |
144- github.event_name == 'pull_request' &&
145- github.event.pull_request.head.repo.full_name != github.repository
146- steps :
147- - name : Comment on PR about integration tests
148- uses : actions/github-script@v7
55+ - name : Run unit tests with coverage
56+ run : python -m pytest tests/unit/ -v --cov=nutrient_dws --cov-report=xml --cov-report=term
57+
58+ - name : Upload coverage to Codecov
59+ uses : codecov/codecov-action@v4
60+ if : matrix.os == 'ubuntu-latest' && matrix.python-version == '3.12'
14961 with :
150- github-token : ${{ secrets.GITHUB_TOKEN }}
151- script : |
152- const issue_number = context.issue.number;
153- const owner = context.repo.owner;
154- const repo = context.repo.repo;
155-
156- // Check if we've already commented
157- const comments = await github.rest.issues.listComments({
158- owner,
159- repo,
160- issue_number,
161- });
162-
163- const botComment = comments.data.find(comment =>
164- comment.user.type === 'Bot' &&
165- comment.body.includes('Integration tests are skipped for pull requests from forks')
166- );
167-
168- if (!botComment) {
169- await github.rest.issues.createComment({
170- owner,
171- repo,
172- issue_number,
173- body: `## Integration Tests Status\n\n` +
174- `Integration tests are skipped for pull requests from forks due to security restrictions. ` +
175- `These tests will run automatically after the PR is merged.\n\n` +
176- `**What this means:**\n` +
177- `- Unit tests, linting, and type checking have passed ✅\n` +
178- `- Integration tests require API credentials that aren't available to fork PRs\n` +
179- `- A maintainer will review your changes and merge if appropriate\n` +
180- `- Integration tests will run on the main branch after merge\n\n` +
181- `Thank you for your contribution! 🙏`
182- });
183- }
62+ files : ./coverage.xml
63+ flags : unittests
64+ name : codecov-umbrella
18465
18566 build :
18667 runs-on : ubuntu-latest
187- needs : test
68+ needs : [lint-and-type-check, unit-tests]
18869
18970 steps :
19071 - uses : actions/checkout@v4
@@ -193,20 +74,14 @@ jobs:
19374 uses : actions/setup-python@v5
19475 with :
19576 python-version : ' 3.12'
77+ cache : ' pip'
19678
19779 - name : Install dependencies
19880 run : |
199- python -m pip install --upgrade pip
200- pip install -e ".[dev]"
81+ pip install ".[dev]"
20182
20283 - name : Build package
20384 run : python -m build
20485
205- - name : Check package with twine
86+ - name : Verify build outputs
20687 run : twine check dist/*
207-
208- - name : Upload artifacts
209- uses : actions/upload-artifact@v4
210- with :
211- name : dist
212- path : dist/
0 commit comments