11name : release
2-
2+ run-name : Release ${{ inputs.working-directory }} by @${{ github.actor }}
33on :
44 workflow_call :
55 inputs :
1010 workflow_dispatch :
1111 inputs :
1212 working-directory :
13+ description : " From which folder this pipeline executes"
14+ default : " libs/server"
1315 required : true
14- type : string
15- default : ' .'
16+ type : choice
17+ options :
18+ - " ."
19+ dangerous-nonmain-release :
20+ required : false
21+ type : boolean
22+ default : false
23+ description : " Release from a non-main branch (danger!)"
1624
1725env :
18- POETRY_VERSION : " 1.7.1"
26+ PYTHON_VERSION : " 3.11"
27+ UV_FROZEN : " true"
28+ UV_NO_SYNC : " true"
1929
2030jobs :
21- if_release :
22- # Disallow publishing from branches that aren't `main`.
23- if : github.ref == 'refs/heads/main'
31+ build :
32+ if : github.ref == 'refs/heads/main' || inputs.dangerous-nonmain-release
33+ environment : Scheduled testing
34+ runs-on : ubuntu-latest
35+
36+ outputs :
37+ pkg-name : ${{ steps.check-version.outputs.pkg-name }}
38+ version : ${{ steps.check-version.outputs.version }}
39+
40+ steps :
41+ - uses : actions/checkout@v4
42+
43+ - name : Set up Python + uv
44+ uses : " ./.github/actions/uv_setup"
45+ with :
46+ python-version : ${{ env.PYTHON_VERSION }}
47+
48+ # We want to keep this build stage *separate* from the release stage,
49+ # so that there's no sharing of permissions between them.
50+ # The release stage has trusted publishing and GitHub repo contents write access,
51+ # and we want to keep the scope of that access limited just to the release job.
52+ # Otherwise, a malicious `build` step (e.g. via a compromised dependency)
53+ # could get access to our GitHub or PyPI credentials.
54+ #
55+ # Per the trusted publishing GitHub Action:
56+ # > It is strongly advised to separate jobs for building [...]
57+ # > from the publish job.
58+ # https://github.com/pypa/gh-action-pypi-publish#non-goals
59+ - name : Build project for distribution
60+ run : uv build
61+ working-directory : ${{ inputs.working-directory }}
62+ - name : Upload build
63+ uses : actions/upload-artifact@v4
64+ with :
65+ name : dist
66+ path : ${{ inputs.working-directory }}/dist/
67+
68+ - name : Check Version
69+ id : check-version
70+ shell : python
71+ working-directory : ${{ inputs.working-directory }}
72+ run : |
73+ import os
74+ import tomllib
75+ with open("pyproject.toml", "rb") as f:
76+ data = tomllib.load(f)
77+ pkg_name = data["project"]["name"]
78+ version = data["project"]["version"]
79+ with open(os.environ["GITHUB_OUTPUT"], "a") as f:
80+ f.write(f"pkg-name={pkg_name}\n")
81+ f.write(f"version={version}\n")
82+
83+ publish :
84+ needs :
85+ - build
2486 runs-on : ubuntu-latest
2587 permissions :
2688 # This permission is used for trusted publishing:
@@ -30,37 +92,23 @@ jobs:
3092 # https://docs.pypi.org/trusted-publishers/adding-a-publisher/
3193 id-token : write
3294
33- # This permission is needed by `ncipollo/release-action` to create the GitHub release.
34- contents : write
3595 defaults :
3696 run :
3797 working-directory : ${{ inputs.working-directory }}
98+
3899 steps :
39- - uses : actions/checkout@v3
100+ - uses : actions/checkout@v4
40101
41- - name : Set up Python + Poetry ${{ env.POETRY_VERSION }}
42- uses : " ./.github/actions/poetry_setup "
102+ - name : Set up Python + uv
103+ uses : " ./.github/actions/uv_setup "
43104 with :
44- python-version : " 3.10"
45- poetry-version : ${{ env.POETRY_VERSION }}
46- working-directory : ${{ inputs.working-directory }}
47- cache-key : release
105+ python-version : ${{ env.PYTHON_VERSION }}
48106
49- - name : Build project for distribution
50- run : poetry build
51- - name : Check Version
52- id : check-version
53- run : |
54- echo version=$(poetry version --short) >> $GITHUB_OUTPUT
55- - name : Create Release
56- uses : ncipollo/release-action@v1
107+ - uses : actions/download-artifact@v4
57108 with :
58- artifacts : " dist/*"
59- token : ${{ secrets.GITHUB_TOKEN }}
60- draft : false
61- generateReleaseNotes : true
62- tag : v${{ steps.check-version.outputs.version }}
63- commit : main
109+ name : dist
110+ path : ${{ inputs.working-directory }}/dist/
111+
64112 - name : Publish package distributions to PyPI
65113 uses : pypa/gh-action-pypi-publish@release/v1
66114 with :
@@ -69,3 +117,41 @@ jobs:
69117 print-hash : true
70118 # Temp workaround since attestations are on by default as of gh-action-pypi-publish v1.11.0
71119 attestations : false
120+
121+ mark-release :
122+ needs :
123+ - build
124+ - publish
125+ runs-on : ubuntu-latest
126+ permissions :
127+ # This permission is needed by `ncipollo/release-action` to
128+ # create the GitHub release.
129+ contents : write
130+
131+ defaults :
132+ run :
133+ working-directory : ${{ inputs.working-directory }}
134+
135+ steps :
136+ - uses : actions/checkout@v4
137+
138+ - name : Set up Python + uv
139+ uses : " ./.github/actions/uv_setup"
140+ with :
141+ python-version : ${{ env.PYTHON_VERSION }}
142+
143+ - uses : actions/download-artifact@v4
144+ with :
145+ name : dist
146+ path : ${{ inputs.working-directory }}/dist/
147+
148+ - name : Create Tag
149+ uses : ncipollo/release-action@v1
150+ with :
151+ artifacts : " dist/*"
152+ token : ${{ secrets.GITHUB_TOKEN }}
153+ generateReleaseNotes : true
154+ tag : ${{needs.build.outputs.pkg-name}}==${{ needs.build.outputs.version }}
155+ body : ${{ needs.release-notes.outputs.release-body }}
156+ commit : main
157+ makeLatest : true
0 commit comments