Skip to content

update-sdk

update-sdk #257

name: Update and Publish SDK
on:
repository_dispatch:
types: [update-sdk]
workflow_dispatch:
inputs:
republish:
description: "Publish a .postN release even if PyPI already has the API version (to replace a broken upload)."
required: false
type: boolean
default: false
jobs:
update-and-publish:
runs-on: ubuntu-latest
permissions:
contents: write
issues: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: python -m pip install --upgrade pip build twine
- name: Install OpenAPI Generator
run: npm install -g @openapitools/openapi-generator-cli
- name: Choose the version to publish
id: version
env:
REPUBLISH: ${{ github.event_name == 'workflow_dispatch' && inputs.republish || 'false' }}
run: |
API_VERSION=$(curl -fsS https://api.linkbreakers.com/internal/openapi/api/v1/api.swagger.json | jq -r '.info.version')
echo "Swagger version: $API_VERSION"
on_pypi() {
CODE=$(curl -sS -o /dev/null -w '%{http_code}' "https://pypi.org/pypi/linkbreakers/$1/json")
case "$CODE" in
200) return 0 ;;
404) return 1 ;;
*) echo "Unexpected HTTP $CODE from PyPI" >&2; exit 1 ;;
esac
}
PACKAGE_VERSION="$API_VERSION"
if on_pypi "$API_VERSION"; then
if [ "$REPUBLISH" != "true" ]; then
echo "needs_update=false" >> $GITHUB_OUTPUT
echo "PyPI already has $API_VERSION"
exit 0
fi
N=1
while on_pypi "$API_VERSION.post$N"; do N=$((N + 1)); done
PACKAGE_VERSION="$API_VERSION.post$N"
fi
echo "needs_update=true" >> $GITHUB_OUTPUT
echo "api_version=$API_VERSION" >> $GITHUB_OUTPUT
echo "package_version=$PACKAGE_VERSION" >> $GITHUB_OUTPUT
echo "Publishing $PACKAGE_VERSION"
- name: Generate SDK
if: steps.version.outputs.needs_update == 'true'
env:
API_VERSION: ${{ steps.version.outputs.api_version }}
PACKAGE_VERSION: ${{ steps.version.outputs.package_version }}
run: |
curl -fsS https://api.linkbreakers.com/internal/openapi/api/v1/api.swagger.json \
| jq '.openapi = "3.1.0" | del(.jsonSchemaDialect) | .info.license = {"name": "MIT"}' > openapi-3.1.json
rm -rf linkbreakers
openapi-generator-cli generate \
-i openapi-3.1.json \
-g python \
-o . \
-c openapi-config.yaml \
-t templates \
--skip-validate-spec \
--git-host github.com \
--git-user-id linkbreakers-com \
--git-repo-id linkbreakers-python \
--global-property apiTests=false,modelTests=false,apiDocs=false,modelDocs=false \
--additional-properties=packageVersion=$PACKAGE_VERSION
echo "$API_VERSION" > OPENAPI_VERSION
rm openapi-3.1.json
- name: Build distribution
if: steps.version.outputs.needs_update == 'true'
run: |
rm -rf dist build
python -m build
- name: Smoke check the built package
if: steps.version.outputs.needs_update == 'true'
run: |
python -m venv /tmp/sdk-check
/tmp/sdk-check/bin/pip install dist/*.whl
cd /tmp && /tmp/sdk-check/bin/python -I -c "
import linkbreakers
from linkbreakers import ApiClient, Configuration, LinksApi
LinksApi(ApiClient(Configuration(access_token='smoke')))
"
/tmp/sdk-check/bin/python -I "$GITHUB_WORKSPACE/scripts/check_docs.py"
- name: Publish to PyPI
if: steps.version.outputs.needs_update == 'true'
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
run: twine upload dist/*
- name: Commit, tag and push
if: steps.version.outputs.needs_update == 'true'
env:
PACKAGE_VERSION: ${{ steps.version.outputs.package_version }}
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add .
if ! git diff --cached --quiet; then
git commit -m "chore: update SDK to version $PACKAGE_VERSION"
fi
git tag "v$PACKAGE_VERSION"
git push --atomic origin main "v$PACKAGE_VERSION"
- name: Close release failure issues
if: success() && steps.version.outputs.needs_update == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PACKAGE_VERSION: ${{ steps.version.outputs.package_version }}
run: |
for number in $(gh issue list --repo "$GITHUB_REPOSITORY" --state open --label release-failure --json number --jq '.[].number'); do
gh issue close "$number" --repo "$GITHUB_REPOSITORY" --comment "Published $PACKAGE_VERSION."
done
- name: Report failure
if: failure()
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PACKAGE_VERSION: ${{ steps.version.outputs.package_version || 'unknown' }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
MESSAGE="Publishing linkbreakers $PACKAGE_VERSION to PyPI failed. Run: $RUN_URL"
echo "::error title=Release failed::$MESSAGE"
gh label create release-failure --repo "$GITHUB_REPOSITORY" --color B60205 \
--description "The update and publish workflow failed" --force
EXISTING=$(gh issue list --repo "$GITHUB_REPOSITORY" --state open --label release-failure --json number --jq '.[0].number // empty')
if [ -n "$EXISTING" ]; then
gh issue comment "$EXISTING" --repo "$GITHUB_REPOSITORY" --body "$MESSAGE"
else
gh issue create --repo "$GITHUB_REPOSITORY" --label release-failure \
--title "SDK release failing" --body "$MESSAGE"
fi