-
Notifications
You must be signed in to change notification settings - Fork 1
129 lines (118 loc) · 5.32 KB
/
Copy pathrelease.yml
File metadata and controls
129 lines (118 loc) · 5.32 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
name: Release
on:
push:
tags: ["v*"]
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
with:
python-version: "3.12"
# Fail before building anything if the tag names a version the tree does
# not declare, has pending change fragments, a stale lock, or no release notes.
- name: Verify tag matches declared version
run: python3 scripts/version.py --check-tag "$TAG"
env:
TAG: ${{ github.ref_name }}
- name: Extract release notes
run: |
set -euo pipefail
version="$(python3 scripts/version.py)"
python3 scripts/changelog_section.py "$version" > release-notes.md
# The tagged tree is re-verified rather than trusting main's CI run: a tag
# can point at a commit that never went through a pull request.
- run: uv sync --frozen --extra dev
- run: uv run ruff check agent_core tests scripts
- run: uv run pyright agent_core
- run: uv run pytest -q
# The gate pins tiktoken's own cache key and content hash, and only a real
# tiktoken can falsify them. Scope that optional dependency to this contract
# test; the isolated run uses the tokenizer version pinned in uv.lock.
- run: uv run --isolated --frozen --extra dev --extra tokenizer pytest -q tests/test_tokenizer_nonblocking.py::test_pinned_cache_metadata_matches_tiktokens_own_declaration
- run: uv build
# A PyPI version number can never be reused, not even after deleting the
# release. Reject malformed metadata here rather than burning the version.
- name: Validate package metadata
run: uv run --with twine twine check dist/*
# The release contract requires the artifact to install and import in a
# clean environment. Checking it here matters more than usual because a
# PyPI version number cannot be reclaimed: a wheel that fails to import
# would burn the version rather than fail the release.
- name: Install and import the built wheel in a clean environment
run: |
set -euo pipefail
uv venv /tmp/wheel-smoke
uv pip install --python /tmp/wheel-smoke/bin/python dist/*.whl
/tmp/wheel-smoke/bin/python - <<'SMOKE'
import agent_core
from agent_core import user_msg
assert user_msg("hi") == {"role": "user", "content": "hi"}
print("imported", agent_core.__name__, "with", len(agent_core.__all__), "exports")
SMOKE
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: release-artifacts
path: |
dist/
release-notes.md
if-no-files-found: error
# Separate job so `id-token: write` — which mints the OIDC identity PyPI
# trusts — is scoped to publishing alone and never exposed to the build or to
# any third-party action running beside it.
publish-pypi:
needs: build
runs-on: ubuntu-latest
environment: pypi
permissions:
id-token: write
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: release-artifacts
path: release-artifacts/
# Trusted Publishing: no API token, no secret. PyPI verifies the OIDC
# claim naming this repository, this workflow file, and the environment
# above, then issues a short-lived upload token itself.
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
with:
packages-dir: release-artifacts/dist/
# Publish the GitHub Release last. A failed PyPI upload therefore cannot leave
# a GitHub Release claiming that a version was published when it was not.
publish-github:
needs: publish-pypi
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: release-artifacts
path: release-artifacts/
# `gh release create` is not retry-safe after a partial API failure. Use
# an upsert so rerunning this job always converges on the same release.
- name: Publish GitHub Release
run: |
set -euo pipefail
if gh release view "$TAG" >/dev/null 2>&1; then
gh release edit "$TAG" \
--title "AgentCore ${TAG#v}" \
--notes-file release-artifacts/release-notes.md
gh release upload "$TAG" --clobber \
release-artifacts/dist/*.whl release-artifacts/dist/*.tar.gz
else
gh release create "$TAG" \
--title "AgentCore ${TAG#v}" \
--notes-file release-artifacts/release-notes.md \
release-artifacts/dist/*.whl release-artifacts/dist/*.tar.gz
fi
env:
TAG: ${{ github.ref_name }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# This job downloads artifacts and never checks out the repository, so
# `gh` has no git remote to infer the target from and fails with
# "not a git repository". Name it explicitly.
GH_REPO: ${{ github.repository }}