-
Notifications
You must be signed in to change notification settings - Fork 273
190 lines (167 loc) · 7.4 KB
/
Copy pathpublish.yml
File metadata and controls
190 lines (167 loc) · 7.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# Publishes your package to PyPI using Astral/uv for builds.
# Set PYPI_API_TOKEN in repo secrets.
permissions:
contents: write # Allows writing to the repository
name: Build and Publish to PyPI
on:
push:
branches:
- main
# Serialize publishes: two back-to-back pushes once raced, both bumped to the
# same patch version, and the loser stranded git a version behind PyPI.
# Queue (never cancel) so every push still gets released, one at a time.
concurrency:
group: pypi-publish
cancel-in-progress: false
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest]
python-version: ['3.13']
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install uv
run: pip install uv
- name: Setup uv virtual environment
run: uv venv
- name: Install dependencies
# [durable] extras pulls in dbos, required by integration test
# tests/integration/test_dbos_enabled.py
run: uv pip install -e ".[durable]"
- name: Install pexpect for integration tests
run: uv pip install pexpect>=4.9.0
- name: Provision CI model (lilac synthetic GLM-5.2)
# models.json ships empty. CI gets its model from extra_models.json,
# exactly like a real user would after running /add_model.
run: |
mkdir -p "$HOME/.code_puppy"
cat > "$HOME/.code_puppy/extra_models.json" <<'JSON'
{
"lilac-zai-org-glm-5.2": {
"type": "custom_openai",
"provider": "lilac",
"name": "zai-org/glm-5.2",
"custom_endpoint": {
"url": "https://api.getlilac.com/v1",
"api_key": "$LILAC_API_KEY"
},
"context_length": 524288,
"supported_settings": ["temperature", "seed", "top_p"]
}
}
JSON
# Tests isolate user config, and several fallback contracts require a
# non-empty bundled catalog. Keep this test-only copy out of releases:
# the publish job starts from a fresh checkout.
cp "$HOME/.code_puppy/extra_models.json" code_puppy/models.json
echo "Wrote CI model catalog and test-only bundled fallback"
- name: Debug environment variables
env:
CEREBRAS_API_KEY: ${{ secrets.CEREBRAS_API_KEY || 'fake-key-for-ci-testing' }}
CONTEXT7_API_KEY: ${{ secrets.CONTEXT7_API_KEY || 'fake-key-for-ci-testing' }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY || 'fake-key-for-ci-testing' }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY || 'fake-key-for-ci-testing' }}
SYN_API_KEY: ${{ secrets.SYN_API_KEY || 'fake-key-for-ci-testing' }}
LILAC_API_KEY: ${{ secrets.LILAC_API_KEY || 'fake-key-for-ci-testing' }}
run: |
echo "=== DEBUG: Environment Variables ==="
echo "CEREBRAS_API_KEY is set: ${{ secrets.CEREBRAS_API_KEY != '' }}"
echo "CONTEXT7_API_KEY is set: ${{ secrets.CONTEXT7_API_KEY != '' }}"
echo "OPENAI_API_KEY is set: ${{ secrets.OPENAI_API_KEY != '' }}"
echo "ANTHROPIC_API_KEY is set: ${{ secrets.ANTHROPIC_API_KEY != '' }}"
echo "SYN_API_KEY is set: ${{ secrets.SYN_API_KEY != '' }}"
echo "CEREBRAS_API_KEY length: ${#CEREBRAS_API_KEY}"
echo "CONTEXT7_API_KEY length: ${#CONTEXT7_API_KEY}"
echo "OPENAI_API_KEY length: ${#OPENAI_API_KEY}"
echo "ANTHROPIC_API_KEY length: ${#ANTHROPIC_API_KEY}"
echo "SYN_API_KEY length: ${#SYN_API_KEY}"
echo "=== END DEBUG ==="
- name: Run tests
env:
CI: '1'
CODE_PUPPY_TEST_FAST: '1'
CEREBRAS_API_KEY: ${{ secrets.CEREBRAS_API_KEY || 'fake-key-for-ci-testing' }}
CONTEXT7_API_KEY: ${{ secrets.CONTEXT7_API_KEY || 'fake-key-for-ci-testing' }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY || 'fake-key-for-ci-testing' }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY || 'fake-key-for-ci-testing' }}
SYN_API_KEY: ${{ secrets.SYN_API_KEY || 'fake-key-for-ci-testing' }}
LILAC_API_KEY: ${{ secrets.LILAC_API_KEY || 'fake-key-for-ci-testing' }}
run: |
echo "Running tests (including integration tests) on ${{ runner.os }} with Python ${{ matrix.python-version }}..."
echo "Required environment variables are set (using CI fallbacks if secrets not available)"
uv run pytest tests/ -v --cov=code_puppy --cov-report=term-missing
build-publish:
runs-on: ubuntu-latest
needs: test
permissions:
contents: write # Allows writing to the repository
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Python 3.13
uses: actions/setup-python@v5
with:
python-version: '3.13'
- name: Install uv, build, and twine
run: pip install uv build twine
- name: Setup uv virtual environment
run: uv venv
- name: Bump version
run: uv version --bump patch
- name: Capture new version
id: version
run: |
NEW_VERSION=$(grep '^version = ' pyproject.toml | sed 's/version = "\(.*\)"/\1/')
echo "version=$NEW_VERSION" >> "$GITHUB_OUTPUT"
echo "New version: $NEW_VERSION"
- name: Build package
run: |
uv build
- name: Publish to PyPI
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
# --skip-existing: if a version already reached PyPI from a run that
# died before pushing its bump commit, warn instead of failing so the
# bump+tag still land and the next run moves past the collision.
run: uv run twine upload --verbose --skip-existing dist/*
- name: Push version bump and tag to GitHub
if: ${{ success() }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
git add .
git commit -m "chore: bump version [ci skip]" || echo "No changes to commit"
TAG="v${{ steps.version.outputs.version }}"
# main can advance between our checkout and this push (a human or
# another branch landing a commit while we bump). The bare `git
# push` used to fail the whole publish with "fetch first". Rebase
# onto the latest main and retry instead of going red.
for attempt in 1 2 3 4 5; do
if ! git pull --rebase origin main 2>/dev/null; then
echo "rebase conflicted/running; aborting and retrying"
git rebase --abort 2>/dev/null || true
sleep 5
continue
fi
git tag -f -a "$TAG" -m "Release $TAG"
if git push origin main; then
git push origin "$TAG" || echo "tag $TAG already exists remotely (fine)"
echo "Pushed version bump and tag $TAG"
exit 0
fi
echo "Push rejected (attempt $attempt/5); retrying..."
sleep 5
done
echo "Giving up pushing version bump after 5 attempts"
exit 1