Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
194 changes: 175 additions & 19 deletions .github/workflows/_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,44 +6,200 @@
# separate terms of service, privacy policy, and support
# documentation.

name: Upload Python Package
name: Build and Publish Python Package

on:
release:
types: [published]
workflow_dispatch:
inputs:
working-directory:
required: true
type: string
default: 'libs/oci'

permissions:
contents: read
env:
PYTHON_VERSION: "3.11"
POETRY_VERSION: "1.7.1"

jobs:
build-n-publish:
name: Build and publish Python 🐍 distribution 📦 to PyPI
build:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
defaults:
run:
working-directory: libs/oci # Set default for all steps
environment:
name: pypi
url: https://pypi.org/p/langchain-oci

outputs:
pkg-name: ${{ steps.check-version.outputs.pkg-name }}
version: ${{ steps.check-version.outputs.version }}

steps:
- uses: actions/checkout@v4

- name: Set up Python + Poetry ${{ env.POETRY_VERSION }}
uses: "./.github/actions/poetry_setup"
with:
python-version: ${{ env.PYTHON_VERSION }}
poetry-version: ${{ env.POETRY_VERSION }}
working-directory: ${{ inputs.working-directory }}
cache-key: release

- name: Build project for distribution
run: poetry build
working-directory: ${{ inputs.working-directory }}

- name: Upload build
uses: actions/upload-artifact@v4
with:
name: dist
path: ${{ inputs.working-directory }}/dist/

- name: Check Version
id: check-version
shell: bash
working-directory: ${{ inputs.working-directory }}
run: |
echo pkg-name="$(poetry version | cut -d ' ' -f 1)" >> $GITHUB_OUTPUT
echo version="$(poetry version --short)" >> $GITHUB_OUTPUT

test-pypi-publish:
needs: build
runs-on: ubuntu-latest
environment:
name: testpypi
url: https://test.pypi.org/project/${{ needs.build.outputs.pkg-name }}/
steps:
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: dist
path: ${{ inputs.working-directory }}/dist/

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.x"
- name: Build distribution 📦
python-version: '3.x'

- name: Publish distribution 📦 to TestPyPI
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.GH_LC_OCI_TESTPYPI_TOKEN }}
run: |
pip install build
python -m build
- name: Validate
pip install twine
twine upload --repository-url https://test.pypi.org/legacy/ ${{ inputs.working-directory }}/dist/* -u $TWINE_USERNAME -p $TWINE_PASSWORD

pre-release-checks:
needs:
- build
- test-pypi-publish
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Python + Poetry ${{ env.POETRY_VERSION }}
uses: "./.github/actions/poetry_setup"
with:
python-version: ${{ env.PYTHON_VERSION }}
poetry-version: ${{ env.POETRY_VERSION }}
working-directory: ${{ inputs.working-directory }}

- name: Import published package
shell: bash
working-directory: ${{ inputs.working-directory }}
env:
PKG_NAME: ${{ needs.build.outputs.pkg-name }}
VERSION: ${{ needs.build.outputs.version }}
# Here we use:
# - The default regular PyPI index as the *primary* index, meaning
# that it takes priority (https://pypi.org/simple)
# - The test PyPI index as an extra index, so that any dependencies that
# are not found on test PyPI can be resolved and installed anyway.
# (https://test.pypi.org/simple). This will include the PKG_NAME==VERSION
# package because VERSION will not have been uploaded to regular PyPI yet.
# - attempt install again after 5 seconds if it fails because there is
# sometimes a delay in availability on test pypi
run: |
poetry run pip install \
--extra-index-url https://test.pypi.org/simple/ \
"$PKG_NAME==$VERSION" || \
( \
sleep 5 && \
poetry run pip install \
--extra-index-url https://test.pypi.org/simple/ \
"$PKG_NAME==$VERSION" \
)

# Replace all dashes in the package name with underscores,
# since that's how Python imports packages with dashes in the name.
IMPORT_NAME="$(echo "$PKG_NAME" | sed s/-/_/g)"

poetry run python -c "import $IMPORT_NAME; print(dir($IMPORT_NAME))"

- name: Import test dependencies
run: poetry install --with test,test_integration
working-directory: ${{ inputs.working-directory }}

# Overwrite the local version of the package with the test PyPI version.
- name: Import published package (again)
working-directory: ${{ inputs.working-directory }}
shell: bash
env:
PKG_NAME: ${{ needs.build.outputs.pkg-name }}
VERSION: ${{ needs.build.outputs.version }}
run: |
poetry run pip install \
--extra-index-url https://test.pypi.org/simple/ \
"$PKG_NAME==$VERSION"

- name: Run unit tests
run: make tests
working-directory: ${{ inputs.working-directory }}

- name: Run integration tests
run: make integration_tests
working-directory: ${{ inputs.working-directory }}

- name: Get minimum versions
working-directory: ${{ inputs.working-directory }}
id: min-version
run: |
poetry run pip install packaging
min_versions="$(poetry run python $GITHUB_WORKSPACE/.github/scripts/get_min_versions.py pyproject.toml)"
echo "min-versions=$min_versions" >> "$GITHUB_OUTPUT"
echo "min-versions=$min_versions"

- name: Run unit tests with minimum dependency versions
if: ${{ steps.min-version.outputs.min-versions != '' }}
env:
MIN_VERSIONS: ${{ steps.min-version.outputs.min-versions }}
run: |
pip install dist/*.whl
python -c "import langchain_oci;"
poetry run pip install $MIN_VERSIONS
make tests
working-directory: ${{ inputs.working-directory }}

publish:
needs:
- build
- test-pypi-publish
- pre-release-checks
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/${{ needs.build.outputs.pkg-name }}
steps:
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: dist
path: ${{ inputs.working-directory }}/dist/

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'

- name: Publish distribution 📦 to PyPI
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.GH_LC_OCI_PYPI_TOKEN }}
run: |
pip install twine
twine upload dist/* -u $TWINE_USERNAME -p $TWINE_PASSWORD
twine upload ${{ inputs.working-directory }}/dist/* -u $TWINE_USERNAME -p $TWINE_PASSWORD