1+ name : release
2+ run-name : Release ${{ inputs.working-directory }} by @${{ github.actor }}
3+ on :
4+ workflow_call :
5+ inputs :
6+ working-directory :
7+ required : true
8+ type : string
9+ description : " From which folder this pipeline executes"
10+ workflow_dispatch :
11+ inputs :
12+ working-directory :
13+ description : " From which folder this pipeline executes"
14+ default : " ."
15+ dangerous-nonmain-release :
16+ required : false
17+ type : boolean
18+ default : false
19+ description : " Release from a non-main branch (danger!)"
20+
21+ env :
22+ PYTHON_VERSION : " 3.11"
23+ UV_FROZEN : " true"
24+ UV_NO_SYNC : " true"
25+
26+ jobs :
27+ build :
28+ if : github.ref == 'refs/heads/main' || inputs.dangerous-nonmain-release
29+ environment : Scheduled testing
30+ runs-on : ubuntu-latest
31+
32+ outputs :
33+ pkg-name : ${{ steps.check-version.outputs.pkg-name }}
34+ version : ${{ steps.check-version.outputs.version }}
35+
36+ steps :
37+ - uses : actions/checkout@v4
38+
39+ - name : Set up Python + uv
40+ uses : " ./.github/actions/uv_setup"
41+ with :
42+ python-version : ${{ env.PYTHON_VERSION }}
43+
44+ # We want to keep this build stage *separate* from the release stage,
45+ # so that there's no sharing of permissions between them.
46+ # The release stage has trusted publishing and GitHub repo contents write access,
47+ # and we want to keep the scope of that access limited just to the release job.
48+ # Otherwise, a malicious `build` step (e.g. via a compromised dependency)
49+ # could get access to our GitHub or PyPI credentials.
50+ #
51+ # Per the trusted publishing GitHub Action:
52+ # > It is strongly advised to separate jobs for building [...]
53+ # > from the publish job.
54+ # https://github.com/pypa/gh-action-pypi-publish#non-goals
55+ - name : Build project for distribution
56+ run : uv build
57+ - name : Upload build
58+ uses : actions/upload-artifact@v4
59+ with :
60+ name : dist
61+ path : ${{ inputs.working-directory }}/dist/
62+
63+ - name : Check Version
64+ id : check-version
65+ shell : python
66+ working-directory : ${{ inputs.working-directory }}
67+ run : |
68+ import os
69+ import tomllib
70+ with open("pyproject.toml", "rb") as f:
71+ data = tomllib.load(f)
72+ pkg_name = data["project"]["name"]
73+ version = data["project"]["version"]
74+ with open(os.environ["GITHUB_OUTPUT"], "a") as f:
75+ f.write(f"pkg-name={pkg_name}\n")
76+ f.write(f"version={version}\n")
77+ publish :
78+ needs :
79+ - build
80+ runs-on : ubuntu-latest
81+ permissions :
82+ # This permission is used for trusted publishing:
83+ # https://blog.pypi.org/posts/2023-04-20-introducing-trusted-publishers/
84+ #
85+ # Trusted publishing has to also be configured on PyPI for each package:
86+ # https://docs.pypi.org/trusted-publishers/adding-a-publisher/
87+ id-token : write
88+
89+ defaults :
90+ run :
91+ working-directory : ${{ inputs.working-directory }}
92+
93+ steps :
94+ - uses : actions/checkout@v4
95+
96+ - name : Set up Python + uv
97+ uses : " ./.github/actions/uv_setup"
98+ with :
99+ python-version : ${{ env.PYTHON_VERSION }}
100+
101+ - uses : actions/download-artifact@v4
102+ with :
103+ name : dist
104+ path : ${{ inputs.working-directory }}/dist/
105+
106+ - name : Publish package distributions to PyPI
107+ uses : pypa/gh-action-pypi-publish@release/v1
108+ with :
109+ packages-dir : ${{ inputs.working-directory }}/dist/
110+ verbose : true
111+ print-hash : true
112+ # Temp workaround since attestations are on by default as of gh-action-pypi-publish v1.11.0
113+ attestations : false
114+
115+ mark-release :
116+ needs :
117+ - build
118+ - publish
119+ runs-on : ubuntu-latest
120+ permissions :
121+ # This permission is needed by `ncipollo/release-action` to
122+ # create the GitHub release.
123+ contents : write
124+
125+ defaults :
126+ run :
127+ working-directory : ${{ inputs.working-directory }}
128+
129+ steps :
130+ - uses : actions/checkout@v4
131+
132+ - name : Set up Python + uv
133+ uses : " ./.github/actions/uv_setup"
134+ with :
135+ python-version : ${{ env.PYTHON_VERSION }}
136+
137+ - uses : actions/download-artifact@v4
138+ with :
139+ name : dist
140+ path : ${{ inputs.working-directory }}/dist/
141+
142+ - name : Create Tag
143+ uses : ncipollo/release-action@v1
144+ with :
145+ artifacts : " dist/*"
146+ token : ${{ secrets.GITHUB_TOKEN }}
147+ generateReleaseNotes : true
148+ tag : ${{needs.build.outputs.pkg-name}}==${{ needs.build.outputs.version }}
149+ body : ${{ needs.release-notes.outputs.release-body }}
150+ commit : main
151+ makeLatest : true
0 commit comments