99 paths :
1010 - grafi/**
1111 - tests/**
12+ - tests_integration/**
1213 - uv.lock
1314 - pyproject.toml
15+ - .github/workflows/ci.yaml
1416
1517concurrency :
16- group : graphite- ci-pipeline
18+ group : ci-${{ github.ref }}
1719 cancel-in-progress : true
1820
1921permissions :
@@ -22,11 +24,40 @@ permissions:
2224
2325env :
2426 PYTHON_VERSION : " 3.12"
27+
2528jobs :
29+ code-quality :
30+ name : Code Quality Checks
31+ runs-on : ubuntu-latest
32+ timeout-minutes : 10
33+
34+ steps :
35+ - name : Checkout code
36+ uses : actions/checkout@v4
37+
38+ - name : Set up Python and uv
39+ uses : astral-sh/setup-uv@v4
40+ with :
41+ enable-cache : true
42+ cache-dependency-glob : " uv.lock"
43+
44+ - name : Set up Python ${{ env.PYTHON_VERSION }}
45+ run : uv python install ${{ env.PYTHON_VERSION }}
46+
47+ - name : Install dependencies
48+ run : uv sync --dev
49+
50+ - name : Run ruff linting
51+ run : uv run pre-commit run --all-files
2652
2753 unit-tests :
28- name : Run Unit Tests
54+ name : Unit Tests (Python ${{ matrix.python-version }})
2955 runs-on : ubuntu-latest
56+ timeout-minutes : 15
57+ strategy :
58+ fail-fast : false
59+ matrix :
60+ python-version : ["3.11", "3.12", "3.13"]
3061
3162 steps :
3263 - name : Checkout code
@@ -35,86 +66,76 @@ jobs:
3566 - name : Set up Python and uv
3667 uses : astral-sh/setup-uv@v4
3768 with :
38- python-version : ${{ env.PYTHON_VERSION }}
39-
40- # ----------------------------------------------
41- # load cached venv if cache exists
42- # ----------------------------------------------
43- - name : Load cached venv
44- id : cached-uv-dependencies
45- uses : actions/cache@v4
46- with :
47- path : .venv
48- key : venv-${{ runner.os }}-${{ env.PYTHON_VERSION }}-${{ hashFiles('**/uv.lock') }}
69+ enable-cache : true
70+ cache-dependency-glob : " uv.lock"
71+
72+ - name : Set up Python ${{ matrix.python-version }}
73+ run : uv python install ${{ matrix.python-version }}
4974
50- # ----------------------------------------------
51- # install dependencies if cache does not exist
52- # ----------------------------------------------
5375 - name : Install dependencies
54- if : steps.cached-uv-dependencies.outputs.cache-hit != 'true'
5576 run : uv sync --dev
5677
57- - name : Check Python and Pytest
58- run : |
59- python --version
60- which python
61- uv run python -m pytest --version
78+ - name : Run unit tests
79+ run : uv run pytest tests/ -v --tb=short
6280
63- - name : Run Tests
64- run : uv run pytest tests/
81+ - name : Generate test summary
82+ if : always()
83+ run : |
84+ echo "### Unit Test Results (Python ${{ matrix.python-version }})" >> $GITHUB_STEP_SUMMARY
85+ echo "Tests completed for Python ${{ matrix.python-version }}" >> $GITHUB_STEP_SUMMARY
6586
6687 integration-tests :
6788 name : Run Integration Tests
6889 runs-on : ubuntu-latest
90+ timeout-minutes : 30
6991 if : github.ref == 'refs/heads/main'
7092
7193 steps :
72- - name : Check out the code
73- uses : actions/checkout@v4
74-
75- - name : Set up Python and uv
76- uses : astral-sh/setup-uv@v4
77- with :
78- python-version : ${{ env.PYTHON_VERSION }}
79-
80- - name : Load cached venv
81- id : cached-uv-dependencies
82- uses : actions/cache@v4
83- with :
84- path : .venv
85- key : venv-${{ runner.os }}-${{ env.PYTHON_VERSION }}-${{ hashFiles('**/uv.lock') }}
86-
87- - name : Install dependencies
88- if : steps.cached-uv-dependencies.outputs.cache-hit != 'true'
89- run : uv sync --dev
90-
91- - name : Run Integration Test ALL
92- run : |
93- set -e
94- output=$(uv run python tests_integration/run_all.py)
95- echo "$output"
96-
97- # Check if there are any failed tests
98- if echo "$output" | grep -q "Failed scripts:"; then
99- echo "❌ Integration tests failed! Check the output above for details."
100- exit 1
101- else
102- echo "✅ All integration tests passed!"
103- fi
104- env :
105- OPENAI_API_KEY : ${{ secrets.OPENAI_API_KEY }}
106- TAVILY_API_KEY : ${{ secrets.TAVILY_API_KEY }}
107- OPENROUTER_API_KEY : ${{ secrets.OPENROUTER_API_KEY }}
108- DEEPSEEK_API_KEY : ${{ secrets.DEEPSEEK_API_KEY }}
109- GEMINI_API_KEY : ${{ secrets.GEMINI_API_KEY }}
110- ANTHROPIC_API_KEY : ${{ secrets.ANTHROPIC_API_KEY }}
94+ - name : Check out the code
95+ uses : actions/checkout@v4
96+
97+ - name : Set up Python and uv
98+ uses : astral-sh/setup-uv@v4
99+ with :
100+ enable-cache : true
101+ cache-dependency-glob : " uv.lock"
111102
103+ - name : Set up Python ${{ env.PYTHON_VERSION }}
104+ run : uv python install ${{ env.PYTHON_VERSION }}
105+
106+ - name : Install dependencies
107+ run : uv sync --dev
108+
109+ - name : Run Integration Test ALL
110+ run : |
111+ set -e
112+ output=$(uv run python tests_integration/run_all.py)
113+ echo "$output"
114+
115+ # Check if there are any failed tests
116+ if echo "$output" | grep -q "Failed scripts:"; then
117+ echo "### Integration Test Results" >> $GITHUB_STEP_SUMMARY
118+ echo "❌ Integration tests failed! Check the output above for details." >> $GITHUB_STEP_SUMMARY
119+ exit 1
120+ else
121+ echo "### Integration Test Results" >> $GITHUB_STEP_SUMMARY
122+ echo "✅ All integration tests passed!" >> $GITHUB_STEP_SUMMARY
123+ fi
124+ env :
125+ OPENAI_API_KEY : ${{ secrets.OPENAI_API_KEY }}
126+ TAVILY_API_KEY : ${{ secrets.TAVILY_API_KEY }}
127+ OPENROUTER_API_KEY : ${{ secrets.OPENROUTER_API_KEY }}
128+ DEEPSEEK_API_KEY : ${{ secrets.DEEPSEEK_API_KEY }}
129+ GEMINI_API_KEY : ${{ secrets.GEMINI_API_KEY }}
130+ ANTHROPIC_API_KEY : ${{ secrets.ANTHROPIC_API_KEY }}
112131
113132 version :
114133 name : Get Package Version
115134 runs-on : ubuntu-latest
135+ timeout-minutes : 5
116136 if : github.ref == 'refs/heads/main'
117137 needs :
138+ - code-quality
118139 - unit-tests
119140 - integration-tests
120141
@@ -126,32 +147,45 @@ jobs:
126147 - name : Checkout code
127148 uses : actions/checkout@v4
128149 with :
129- fetch-depth : 0 # Ensure full history for tagging
150+ fetch-depth : 0
130151
131152 - name : Set up Python and uv
132153 uses : astral-sh/setup-uv@v4
133154 with :
134- python-version : ${{ env.PYTHON_VERSION }}
155+ enable-cache : true
156+
157+ - name : Set up Python ${{ env.PYTHON_VERSION }}
158+ run : uv python install ${{ env.PYTHON_VERSION }}
135159
136160 - name : Get Package Version
137161 id : package-version
138162 run : |
139163 echo "VERSION=$(uv run python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])")" >> $GITHUB_OUTPUT
140164
141- - name : Remote Check PyPI Version
165+ - name : Check PyPI Version
142166 id : remote-version
143167 run : |
144- echo "LATEST_VERSION=$(pip index versions grafi 2>/dev/null | grep 'LATEST:' | awk '{print $2}')" >> $GITHUB_OUTPUT
168+ LATEST_VERSION=$(curl -s https://pypi.org/pypi/grafi/json | jq -r .info.version)
169+ echo "LATEST_VERSION=${LATEST_VERSION}" >> $GITHUB_OUTPUT
145170
171+ - name : Version Check Summary
172+ run : |
173+ echo "### Version Information" >> $GITHUB_STEP_SUMMARY
174+ echo "- Package Version: ${{ steps.package-version.outputs.VERSION }}" >> $GITHUB_STEP_SUMMARY
175+ echo "- PyPI Version: ${{ steps.remote-version.outputs.LATEST_VERSION }}" >> $GITHUB_STEP_SUMMARY
176+ if [ "${{ steps.package-version.outputs.VERSION }}" != "${{ steps.remote-version.outputs.LATEST_VERSION }}" ]; then
177+ echo "- Status: 🚀 New version will be published" >> $GITHUB_STEP_SUMMARY
178+ else
179+ echo "- Status: ✅ Versions match, no publish needed" >> $GITHUB_STEP_SUMMARY
180+ fi
146181
147182 publish_pypi :
148183 name : Publish to PyPI
149184 runs-on : ubuntu-latest
185+ timeout-minutes : 10
150186 needs : version
151- if : github.ref == 'refs/heads/main' && ( needs.version.outputs.package-version != needs.version.outputs.remote-version )
187+ if : github.ref == 'refs/heads/main' && needs.version.outputs.package-version != needs.version.outputs.remote-version
152188
153-
154- # Specifying a GitHub environment is optional, but strongly encouraged
155189 environment : production
156190
157191 steps :
@@ -161,84 +195,43 @@ jobs:
161195 - name : Set up Python and uv
162196 uses : astral-sh/setup-uv@v4
163197 with :
164- python-version : ${{ env.PYTHON_VERSION }}
198+ enable-cache : true
165199
166- - name : Check if new version is different than PyPi remote
167- id : check-version
168- run : |
169- remote_latest_version=$(curl -s https://pypi.org/pypi/grafi/json | jq -r .info.version)
170- current_version=$(uv run python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])")
171- if [ "$remote_latest_version" == "$current_version" ]; then
172- echo "No new version to publish."
173- exit 0
174- else
175- echo "New version available: $current_version"
176- fi
177-
178- # ----------------------------------------------
179- # load cached venv if cache exists
180- # ----------------------------------------------
181- - name : Load cached venv
182- id : cached-uv-dependencies
183- uses : actions/cache@v4
184- with :
185- path : .venv
186- key : venv-${{ runner.os }}-${{ env.PYTHON_VERSION }}-${{ hashFiles('**/uv.lock') }}
187-
188- # ----------------------------------------------
189- # install dependencies if cache does not exist
190- # ----------------------------------------------
191- - name : Install dependencies
192- if : steps.cached-uv-dependencies.outputs.cache-hit != 'true'
193- run : uv sync
200+ - name : Set up Python ${{ env.PYTHON_VERSION }}
201+ run : uv python install ${{ env.PYTHON_VERSION }}
194202
195203 - name : Build project
196204 run : uv build
197205
198- - name : mint API token
199- id : mint-token
200- run : |
201- # retrieve the ambient OIDC token
202- resp=$(curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
203- "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=pypi")
204- oidc_token=$(jq -r '.value' <<< "${resp}")
205-
206- # exchange the OIDC token for an API token
207- resp=$(curl -X POST https://pypi.org/_/oidc/mint-token -d "{\"token\": \"${oidc_token}\"}")
208- api_token=$(jq -r '.token' <<< "${resp}")
209-
210- # mask the newly minted API token, so that we don't accidentally leak it
211- echo "::add-mask::${api_token}"
212-
213- # see the next step in the workflow for an example of using this step output
214- echo "api-token=${api_token}" >> "${GITHUB_OUTPUT}"
215-
216-
217206 - name : Publish package distributions to PyPI
218207 uses : pypa/gh-action-pypi-publish@release/v1
219208
209+ - name : Publish Summary
210+ run : |
211+ echo "### PyPI Publication" >> $GITHUB_STEP_SUMMARY
212+ echo "✅ Published version ${{ needs.version.outputs.package-version }} to PyPI" >> $GITHUB_STEP_SUMMARY
213+
220214 github_release :
221215 name : Github Release
222216 runs-on : ubuntu-latest
217+ timeout-minutes : 5
223218 needs :
224219 - publish_pypi
225220 - version
226- - integration-tests
227221
228222 if : github.ref == 'refs/heads/main'
229223
230224 steps :
231225 - name : Checkout code
232226 uses : actions/checkout@v4
233227 with :
234- fetch-depth : 0 # Ensure full history f
228+ fetch-depth : 0
235229
236230 - name : Set up Git user
237231 run : |
238232 git config --global user.name "github-actions[bot]"
239233 git config --global user.email "github-actions@github.com"
240234
241-
242235 - name : Create Release
243236 uses : ncipollo/release-action@v1.12.0
244237 with :
@@ -250,3 +243,8 @@ jobs:
250243 token : ${{ github.token }}
251244 tag : ${{ needs.version.outputs.package-version }}
252245 skipIfReleaseExists : true
246+
247+ - name : Release Summary
248+ run : |
249+ echo "### GitHub Release" >> $GITHUB_STEP_SUMMARY
250+ echo "✅ Created release for version ${{ needs.version.outputs.package-version }}" >> $GITHUB_STEP_SUMMARY
0 commit comments