@@ -28,9 +28,41 @@ defaults:
2828 shell : bash
2929
3030jobs :
31- build_and_test :
31+ build_sdist :
32+ name : Build an sdist and determine versions
33+ uses : ./.github/workflows/packaging_sdist.yml
34+ with :
35+ testsuite : all
36+ git-ref : ${{ github.ref }}
37+ duckdb-git-ref : ${{ inputs.duckdb-sha }}
38+ set-version : ${{ inputs.stable-version }}
39+
40+ check_pypi :
41+ name : Check whether this version was already released
42+ needs : build_sdist
43+ outputs :
44+ can_upload : ${{ steps.index_check.outputs.can_upload }}
45+ runs-on : ubuntu-latest
46+ steps :
47+ - id : index_check
48+ run : |
49+ # Check PyPI whether the release we're building is already present
50+ pypi_hostname="${{ inputs.pypi-index == 'test' && 'test.' || '' }}pypi.org"
51+ pkg_version=${{ needs.build_sdist.outputs.package-version }}
52+ http_status=$( curl -s -o /dev/null -w "%{http_code}" https://${pypi_hostname}/pypi/duckdb/${pkg_version}/json )
53+ if [ "$http_status" == "200" ]; then
54+ echo "::warning::DuckDB ${pkg_version} is already present on ${pypi_hostname}, will not release"
55+ echo "can_upload=true" >> $GITHUB_GITHUB_OUTPUT
56+ else
57+ echo "can_upload=false" >> $GITHUB_GITHUB_OUTPUT
58+ fi
59+
60+
61+ build_wheels :
3262 name : Build and test releases
33- uses : ./.github/workflows/packaging.yml
63+ needs : check_pypi
64+ if : ${{ needs.check_pypi.outputs.can_upload }}
65+ uses : ./.github/workflows/packaging_wheels.yml
3466 with :
3567 minimal : false
3668 testsuite : all
4173 upload_s3 :
4274 name : Upload Artifacts to S3
4375 runs-on : ubuntu-latest
44- needs : [build_and_test ]
76+ needs : [build_sdist, build_wheels ]
4577 if : ${{ github.repository_owner == 'duckdb' && ( inputs.pypi-index == 'prod' || inputs.store-s3 ) }}
78+ outputs :
79+ s3-upload-url : ${{ steps.input.outputs.s3_upload_url }}
4680 steps :
4781 - name : Fetch artifacts
4882 uses : actions/download-artifact@v4
5690 run : |
5791 sha=${{ github.sha }}
5892 dsha=${{ inputs.duckdb-sha }}
59- version=$(basename artifacts/*.tar.gz | sed 's/duckdb-\(.*\).tar.gz/\1/g')
93+ version=${{ needs.build_sdist.outputs.package-version }}
6094 url="s3://duckdb-staging/python/${version}/${sha:0:10}-duckdb-${dsha:0:10}/"
61- echo "short_sha=${sha:0:10}" >> $GITHUB_OUTPUT
62- echo "short_dsha=${dsha:0:10}" >> $GITHUB_OUTPUT
63- echo "version=${version}" >> $GITHUB_OUTPUT
6495 echo "s3_upload_url=${url}" >> $GITHUB_OUTPUT
6596
6697 - name : Authenticate with AWS
@@ -74,18 +105,10 @@ jobs:
74105 run : |
75106 aws s3 cp artifacts ${{ steps.input.outputs.s3_upload_url }} --recursive
76107
77- - name : S3 Upload Summary
78- run : |
79- echo "## S3 Upload Summary" >> $GITHUB_STEP_SUMMARY
80- echo "* Version: ${{ steps.input.outputs.version }}" >> $GITHUB_STEP_SUMMARY
81- echo "* SHA: ${{ steps.input.outputs.short_sha }}" >> $GITHUB_STEP_SUMMARY
82- echo "* DuckDB SHA: ${{ steps.input.outputs.short_dsha }}" >> $GITHUB_STEP_SUMMARY
83- echo "* S3 URL: ${{ steps.input.outputs.s3_upload_url }}" >> $GITHUB_STEP_SUMMARY
84-
85108 determine_environment :
86109 name : Determine the Github Actions environment to use
87110 runs-on : ubuntu-latest
88- needs : build_and_test
111+ needs : [build_sdist, build_wheels]
89112 outputs :
90113 env_name : ${{ steps.set-env.outputs.env_name }}
91114 steps :
@@ -105,7 +128,7 @@ jobs:
105128 fi
106129 ;;
107130 *)
108- echo "Error: invalid combination of inputs.pypi-index='${{ inputs.pypi-index }}' and inputs.stable-version='${{ inputs.stable-version }}'" >&2
131+ echo "::error:: invalid combination of inputs.pypi-index='${{ inputs.pypi-index }}' and inputs.stable-version='${{ inputs.stable-version }}'"
109132 exit 1
110133 ;;
111134 esac
@@ -139,17 +162,9 @@ jobs:
139162 packages-dir : packages
140163 verbose : ' true'
141164
142- - name : PyPI Upload Summary
143- run : |
144- version=$(basename packages/*.tar.gz | sed 's/duckdb-\(.*\).tar.gz/\1/g')
145- echo "## PyPI Upload Summary" >> $GITHUB_STEP_SUMMARY
146- echo "* Version: ${version}" >> $GITHUB_STEP_SUMMARY
147- echo "* PyPI Host: ${{ vars.PYPI_HOST }}" >> $GITHUB_STEP_SUMMARY
148- echo "* CI Environment: ${{ needs.determine_environment.outputs.env_name }}" >> $GITHUB_STEP_SUMMARY
149-
150165 cleanup_nightlies :
151166 name : Remove Nightlies from PyPI
152- needs : [determine_environment, publish_pypi]
167+ needs : [ determine_environment, publish_pypi ]
153168 if : ${{ inputs.stable-version == '' }}
154169 uses : ./.github/workflows/cleanup_pypi.yml
155170 with :
@@ -158,3 +173,23 @@ jobs:
158173 # reusable workflows and secrets are not great: https://github.com/actions/runner/issues/3206
159174 PYPI_CLEANUP_OTP : ${{secrets.PYPI_CLEANUP_OTP}}
160175 PYPI_CLEANUP_PASSWORD : ${{secrets.PYPI_CLEANUP_PASSWORD}}
176+
177+ summary :
178+ name : Release summary
179+ runs-on : ubuntu-latest
180+ needs : [build_sdist, check_pypi, upload_s3, determine_environment]
181+ if : true
182+ steps :
183+ - run : |
184+ sha=${{ github.sha }}
185+ dsha=${{ inputs.duckdb-sha }}
186+ echo "## Release Summary" >> $GITHUB_STEP_SUMMARY
187+ echo "* Package Version: ${{ needs.build_sdist.outputs.package-version }} (${sha:0:10})" >> $GITHUB_STEP_SUMMARY
188+ echo "* DuckDB Version: ${{ needs.build_sdist.outputs.duckdb-version }} (${dsha:0:10})" >> $GITHUB_STEP_SUMMARY
189+ echo "* PyPI: ${{ vars.PYPI_HOST }}" >> $GITHUB_STEP_SUMMARY
190+ if [ "${{ needs.check_pypi.outputs.can_upload }}" == "false" ]; then
191+ echo " * Package already exists on this PyPI, nothing was uploaded" >> $GITHUB_STEP_SUMMARY
192+ exit 0
193+ fi
194+ echo "* CI Environment: ${{ needs.determine_environment.outputs.env_name }}" >> $GITHUB_STEP_SUMMARY
195+ echo "* S3 URL: ${{ needs.upload_s3.outputs.s3_upload_url }}" >> $GITHUB_STEP_SUMMARY
0 commit comments