11# This workflow builds the python package.
2- # On release tags, it also publishes to PyPI and DockerHub.
3- # If we rename the workflow file name, we have to also update the
4- # Trusted Publisher settings on PyPI.
2+
3+ # When from from a release tags or a workflow dispatch, it also publishes to PyPI and DockerHub along
4+ # with bumping the Connector Builder pinned version.
5+ # Note: We may want to rename this file at some point. However, if we rename the workflow file name,
6+ # we have to also update the Trusted Publisher settings on PyPI.
7+
58name : Packaging and Publishing
69
710on :
811 push :
12+ tags :
13+ - ' v*'
914 workflow_dispatch :
1015 inputs :
1116 version :
12- description : " The version to publish, ie 1.0.0 or 1.0.0-dev1"
17+ description : " Version. The version to publish, ie 1.0.0 or 1.0.0-dev1. In most cases, you can leave this blank. If run from a release tag (recommended), the version number will be inferred from the git tag."
18+ required : false
19+ publish_to_pypi :
20+ description : " Publish to PyPI. If true, the workflow will publish to PyPI."
21+ type : boolean
22+ required : true
23+ default : true
24+ publish_to_dockerhub :
25+ description : " Publish to DockerHub. If true, the workflow will publish the SDM connector to DockerHub."
26+ type : boolean
1327 required : true
28+ default : true
29+ update_connector_builder :
30+ description : " Update Connector Builder. If true, the workflow will create a PR to bump the CDK version used by Connector Builder."
31+ type : boolean
32+ required : true
33+ default : true
1434
1535jobs :
1636 build :
37+ name : Build Python Package
1738 runs-on : ubuntu-latest
1839 steps :
40+ - name : Detect Release Tag Version
41+ if : startsWith(github.ref, 'refs/tags/v')
42+ run : |
43+ DETECTED_VERSION=${{ github.ref_name }}
44+ echo "Version ref set to '${DETECTED_VERSION}'"
45+ # Remove the 'v' prefix if it exists
46+ DETECTED_VERSION="${DETECTED_VERSION#v}"
47+ echo "Setting version to '$DETECTED_VERSION'"
48+ echo "DETECTED_VERSION=${DETECTED_VERSION}" >> $GITHUB_ENV
49+
50+ - name : Validate and set VERSION from git ref ('${{ github.ref_name }}') and input (${{ github.event.inputs.version || 'none' }})
51+ id : set_version
52+ run : |
53+ INPUT_VERSION=${{ github.event.inputs.version }}
54+ echo "Version input set to '${INPUT_VERSION}'"
55+ # Exit with success if both detected and input versions are empty
56+ if [ -z "${DETECTED_VERSION:-}" ] && [ -z "${INPUT_VERSION:-}" ]; then
57+ echo "No version detected or input. Will publish to SHA tag instead."
58+ echo 'VERSION=' >> $GITHUB_ENV
59+ exit 0
60+ fi
61+ # Remove the 'v' prefix if it exists
62+ INPUT_VERSION="${INPUT_VERSION#v}"
63+ # Fail if detected version is non-empty and different from the input version
64+ if [ -n "${DETECTED_VERSION:-}" ] && [ -n "${INPUT_VERSION:-}" ] && [ "${DETECTED_VERSION}" != "${INPUT_VERSION}" ]; then
65+ echo "Error: Version input '${INPUT_VERSION}' does not match detected version '${DETECTED_VERSION}'."
66+ exit 1
67+ fi
68+ # Set the version to the input version if non-empty, otherwise the detected version
69+ VERSION="${INPUT_VERSION:-$DETECTED_VERSION}"
70+ # Fail if the version is still empty
71+ if [ -z "$VERSION" ]; then
72+ echo "Error: VERSION is not set. Ensure the tag follows the format 'refs/tags/vX.Y.Z'."
73+ exit 1
74+ fi
75+ echo "Setting version to '$VERSION'"
76+ echo "VERSION=${VERSION}" >> $GITHUB_ENV
77+ echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT
78+ # Check if version is a prerelease version (will not tag 'latest')
79+ if [[ "${VERSION}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
80+ echo "IS_PRERELEASE=false" >> $GITHUB_ENV
81+ echo "IS_PRERELEASE=false" >> $GITHUB_OUTPUT
82+ else
83+ echo "IS_PRERELEASE=true" >> $GITHUB_ENV
84+ echo "IS_PRERELEASE=true" >> $GITHUB_OUTPUT
85+ fi
86+
1987 - uses : actions/checkout@v4
2088 with :
2189 fetch-depth : 0
22- ref : ${{ github.event_name == 'workflow_dispatch' && format('v{0}', github.event.inputs.version) || github.ref }}
2390
2491 - uses : hynek/build-and-inspect-python-package@v2
92+ env :
93+ # Pass in the evaluated version from the previous step
94+ # More info: https://github.com/mtkennerly/poetry-dynamic-versioning#user-content-environment-variables
95+ POETRY_DYNAMIC_VERSIONING_BYPASS : ${{ env.VERSION || '0.0.0dev0'}}
2596
2697 - uses : actions/upload-artifact@v4
2798 with :
@@ -30,7 +101,11 @@ jobs:
30101 /tmp/baipp/dist/*.whl
31102 /tmp/baipp/dist/*.tar.gz
32103
33- publish :
104+ outputs :
105+ VERSION : ${{ steps.set_version.outputs.VERSION }}
106+ IS_PRERELEASE : ${{ steps.set_version.outputs.IS_PRERELEASE }}
107+
108+ publish_cdk :
34109 name : Publish CDK version to PyPI
35110 runs-on : ubuntu-latest
36111 needs : [build]
@@ -39,8 +114,11 @@ jobs:
39114 contents : write
40115 environment :
41116 name : PyPi
42- url : https://pypi.org/p/airbyte
43- if : startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch'
117+ url : https://pypi.org/p/airbyte-cdk/
118+ if : (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.publish_to_pypi == 'true' || github.event.inputs.update_connector_builder == 'true'))
119+ env :
120+ VERSION : ${{ needs.build.outputs.VERSION }}
121+ IS_PRERELEASE : ${{ needs.build.outputs.IS_PRERELEASE }}
44122 steps :
45123 - uses : actions/download-artifact@v4
46124 with :
@@ -58,4 +136,217 @@ jobs:
58136 file_glob : true
59137
60138 - name : Publish to PyPI
139+ if : (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')) || github.event.inputs.publish_to_pypi == 'true'
61140141+
142+ publish_sdm :
143+ name : Publish SDM to DockerHub
144+ # TODO: When we're ready to publish after each release, prefix the `if` below with:
145+ # (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')) ||
146+ # Until then, this workflow needs to be kicked off manually.
147+ # Last remaining blocker documented here: https://github.com/airbytehq/airbyte-python-cdk/issues/64
148+ if : (github.event_name == 'workflow_dispatch' && github.event.inputs.publish_to_dockerhub == 'true')
149+ runs-on : ubuntu-latest
150+ needs : [build]
151+ environment :
152+ name : DockerHub
153+ url : https://hub.docker.com/r/airbyte/source-declarative-manifest/tags
154+ env :
155+ VERSION : ${{ needs.build.outputs.VERSION }}
156+ IS_PRERELEASE : ${{ needs.build.outputs.IS_PRERELEASE }}
157+
158+ steps :
159+ - uses : actions/checkout@v4
160+ with :
161+ fetch-depth : 0
162+
163+ # We need to download the build artifact again because the previous job was on a different runner
164+ - name : Download Build Artifact
165+ uses : actions/download-artifact@v4
166+ with :
167+ name : Packages-${{ github.run_id }}
168+ path : dist
169+
170+ - name : Set up QEMU for multi-platform builds
171+ uses : docker/setup-qemu-action@v3
172+
173+ - name : Set up Docker Buildx
174+ uses : docker/setup-buildx-action@v3
175+
176+ - name : Login to Docker Hub
177+ uses : docker/login-action@v3
178+ with :
179+ username : ${{ secrets.DOCKER_HUB_USERNAME }}
180+ password : ${{ secrets.DOCKER_HUB_PASSWORD }}
181+
182+ - name : " Check for existing tag (version: ${{ env.VERSION || 'none' }} )"
183+ if : env.VERSION != ''
184+ run : |
185+ tag="airbyte/source-declarative-manifest:${{ env.VERSION }}"
186+ if [ -z "$tag" ]; then
187+ echo "Error: VERSION is not set. Ensure the tag follows the format 'refs/tags/vX.Y.Z'."
188+ exit 1
189+ fi
190+ echo "Checking if tag '$tag' exists on DockerHub..."
191+ if DOCKER_CLI_EXPERIMENTAL=enabled docker manifest inspect "$tag" > /dev/null 2>&1; then
192+ echo "The tag '$tag' already exists on DockerHub. Skipping publish to prevent overwrite."
193+ exit 1
194+ fi
195+ echo "No existing tag '$tag' found. Proceeding with publish."
196+
197+ - name : " Build and push (sha tag: '${{ github.sha }}')"
198+ # Only run if the version is not set
199+ if : env.VERSION == ''
200+ uses : docker/build-push-action@v5
201+ with :
202+ context : .
203+ platforms : linux/amd64,linux/arm64
204+ push : true
205+ tags : |
206+ airbyte/source-declarative-manifest:${{ github.sha }}
207+
208+ - name : " Build and push (version tag: ${{ env.VERSION || 'none'}})"
209+ # Only run if the version is set
210+ if : env.VERSION != ''
211+ uses : docker/build-push-action@v5
212+ with :
213+ context : .
214+ platforms : linux/amd64,linux/arm64
215+ push : true
216+ tags : |
217+ airbyte/source-declarative-manifest:${{ env.VERSION }}
218+
219+ - name : Build and push ('latest' tag)
220+ # Only run if version is set and IS_PRERELEASE is false
221+ if : env.VERSION != '' && env.IS_PRERELEASE == 'false'
222+ uses : docker/build-push-action@v5
223+ with :
224+ context : .
225+ platforms : linux/amd64,linux/arm64
226+ push : true
227+ tags : |
228+ airbyte/source-declarative-manifest:latest
229+
230+ update-connector-builder :
231+ # Create a PR against the Builder, to update the CDK version that it uses.
232+ # In the future, Builder may use the SDM docker image instead of the Python CDK package.
233+ name : Bump Connector Builder CDK version
234+ needs :
235+ - build
236+ - publish_cdk
237+ if : (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')) || (github.event_name == 'workflow_dispatch' && github.event.inputs.update_connector_builder == 'true')
238+ env :
239+ VERSION : ${{ needs.build.outputs.VERSION }}
240+ IS_PRERELEASE : ${{ needs.build.outputs.IS_PRERELEASE }}
241+ runs-on : ubuntu-latest
242+ steps :
243+ - uses : actions/setup-python@v5
244+ with :
245+ python-version : " 3.10"
246+ - name : Checkout Airbyte Platform Internal
247+ uses : actions/checkout@v4
248+ with :
249+ repository : airbytehq/airbyte-platform-internal
250+ token : ${{ secrets.GH_PAT_MAINTENANCE_OCTAVIA }}
251+ - name : Update Builder's CDK version to ${{ env.VERSION }}
252+ # PyPI servers aren't immediately updated so we may need to retry a few times.
253+ uses : nick-fields/retry@v3
254+ with :
255+ shell : bash
256+ max_attempts : 5
257+ retry_wait_seconds : 30
258+ timeout_minutes : 7
259+ command : |
260+ set -euo pipefail
261+ PREVIOUS_VERSION=$(cat oss/airbyte-connector-builder-resources/CDK_VERSION)
262+ sed -i "s/${PREVIOUS_VERSION}/${VERSION}/g" "oss/airbyte-connector-builder-server/Dockerfile"
263+ sed -i "s/${PREVIOUS_VERSION}/${VERSION}/g" "cloud/airbyte-connector-builder-server-wrapped/Dockerfile"
264+ sed -i "s/airbyte-cdk==${PREVIOUS_VERSION}/airbyte-cdk==${VERSION}/g" oss/airbyte-connector-builder-server/requirements.in
265+ echo ${VERSION} > oss/airbyte-connector-builder-resources/CDK_VERSION
266+ cd oss/airbyte-connector-builder-server
267+ python -m pip install --no-cache-dir pip-tools
268+ pip-compile --upgrade
269+ - name : Create Pull Request
270+ id : create-pull-request
271+ uses : peter-evans/create-pull-request@v6
272+ with :
273+ token : ${{ secrets.GH_PAT_MAINTENANCE_OCTAVIA }}
274+ commit-message : " chore: update CDK version following release"
275+ title : " chore: update CDK version following release"
276+ body : This is an automatically generated PR triggered by a CDK release
277+ branch : automatic-cdk-release
278+ base : master
279+ delete-branch : true
280+ - name : Post success to Slack channel dev-connectors-extensibility
281+ 282+ continue-on-error : true
283+ env :
284+ SLACK_BOT_TOKEN : ${{ secrets.SLACK_BOT_TOKEN_AIRBYTE_TEAM }}
285+ with :
286+ channel-id : C04J1M66D8B
287+ # Channel: #dev-connectors-extensibility-releases
288+ # Link (internal): https://airbytehq-team.slack.com/archives/C04J1M66D8B
289+ payload : |
290+ {
291+ "text": "A new version of Python CDK has been released!",
292+ "blocks": [
293+ {
294+ "type": "section",
295+ "text": {
296+ "type": "mrkdwn",
297+ "text": "Python CDK `v${{ env.VERSION }}` has been <https://github.com/airbytehq/airbyte-python-cdk/releases|released>\n\n"
298+ }
299+ },
300+ {
301+ "type": "section",
302+ "text": {
303+ "type": "mrkdwn",
304+ "text": "A PR has also been created for the <${{ steps.create-pull-request.outputs.pull-request-url }}|Connector Builder>\n"
305+ }
306+ },
307+ {
308+ "type": "section",
309+ "text": {
310+ "type": "mrkdwn",
311+ "text": "See details on <https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}|GitHub>\n"
312+ }
313+ }
314+ ]
315+ }
316+ - name : Post failure to Slack channel dev-connectors-extensibility
317+ if : failure()
318+ 319+ continue-on-error : true
320+ env :
321+ SLACK_BOT_TOKEN : ${{ secrets.SLACK_BOT_TOKEN_AIRBYTE_TEAM }}
322+ with :
323+ channel-id : C04J1M66D8B
324+ # Channel: #dev-connectors-extensibility-releases
325+ # Link (internal): https://airbytehq-team.slack.com/archives/C04J1M66D8B
326+ payload : |
327+ {
328+ "text": ":warning: A new version of Python CDK has been released but Connector Builder hasn't been automatically updated",
329+ "blocks": [
330+ {
331+ "type": "section",
332+ "text": {
333+ "type": "mrkdwn",
334+ "text": "Python CDK `v${{ env.VERSION }}` has been <https://github.com/airbytehq/airbyte-python-cdk/releases|released>\n\n"
335+ }
336+ },
337+ {
338+ "type": "section",
339+ "text": {
340+ "type": "mrkdwn",
341+ "text": ":warning: Could not automatically create a PR for Connector Builder>\n"
342+ }
343+ },
344+ {
345+ "type": "section",
346+ "text": {
347+ "type": "mrkdwn",
348+ "text": "See details on <https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}|GitHub>\n"
349+ }
350+ }
351+ ]
352+ }
0 commit comments