mirror of
https://github.com/hwchase17/langchain.git
synced 2026-03-18 02:53:16 +00:00
Bumps the github-actions group with 2 updates: [actions/upload-artifact](https://github.com/actions/upload-artifact) and [actions/download-artifact](https://github.com/actions/download-artifact). Updates `actions/upload-artifact` from 6 to 7 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/actions/upload-artifact/releases">actions/upload-artifact's releases</a>.</em></p> <blockquote> <h2>v7.0.0</h2> <h2>v7 What's new</h2> <h3>Direct Uploads</h3> <p>Adds support for uploading single files directly (unzipped). Callers can set the new <code>archive</code> parameter to <code>false</code> to skip zipping the file during upload. Right now, we only support single files. The action will fail if the glob passed resolves to multiple files. The <code>name</code> parameter is also ignored with this setting. Instead, the name of the artifact will be the name of the uploaded file.</p> <h3>ESM</h3> <p>To support new versions of the <code>@actions/*</code> packages, we've upgraded the package to ESM.</p> <h2>What's Changed</h2> <ul> <li>Add proxy integration test by <a href="https://github.com/Link"><code>@Link</code></a>- in <a href="https://redirect.github.com/actions/upload-artifact/pull/754">actions/upload-artifact#754</a></li> <li>Upgrade the module to ESM and bump dependencies by <a href="https://github.com/danwkennedy"><code>@danwkennedy</code></a> in <a href="https://redirect.github.com/actions/upload-artifact/pull/762">actions/upload-artifact#762</a></li> <li>Support direct file uploads by <a href="https://github.com/danwkennedy"><code>@danwkennedy</code></a> in <a href="https://redirect.github.com/actions/upload-artifact/pull/764">actions/upload-artifact#764</a></li> </ul> <h2>New Contributors</h2> <ul> <li><a href="https://github.com/Link"><code>@Link</code></a>- made their first contribution in <a href="https://redirect.github.com/actions/upload-artifact/pull/754">actions/upload-artifact#754</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/actions/upload-artifact/compare/v6...v7.0.0">https://github.com/actions/upload-artifact/compare/v6...v7.0.0</a></p> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="bbbca2ddaa"><code>bbbca2d</code></a> Support direct file uploads (<a href="https://redirect.github.com/actions/upload-artifact/issues/764">#764</a>)</li> <li><a href="589182c5a4"><code>589182c</code></a> Upgrade the module to ESM and bump dependencies (<a href="https://redirect.github.com/actions/upload-artifact/issues/762">#762</a>)</li> <li><a href="47309c993a"><code>47309c9</code></a> Merge pull request <a href="https://redirect.github.com/actions/upload-artifact/issues/754">#754</a> from actions/Link-/add-proxy-integration-tests</li> <li><a href="02a8460834"><code>02a8460</code></a> Add proxy integration test</li> <li>See full diff in <a href="https://github.com/actions/upload-artifact/compare/v6...v7">compare view</a></li> </ul> </details> <br /> Updates `actions/download-artifact` from 7 to 8 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/actions/download-artifact/releases">actions/download-artifact's releases</a>.</em></p> <blockquote> <h2>v8.0.0</h2> <h2>v8 - What's new</h2> <h3>Direct downloads</h3> <p>To support direct uploads in <code>actions/upload-artifact</code>, the action will no longer attempt to unzip all downloaded files. Instead, the action checks the <code>Content-Type</code> header ahead of unzipping and skips non-zipped files. Callers wishing to download a zipped file as-is can also set the new <code>skip-decompress</code> parameter to <code>false</code>.</p> <h3>Enforced checks (breaking)</h3> <p>A previous release introduced digest checks on the download. If a download hash didn't match the expected hash from the server, the action would log a warning. Callers can now configure the behavior on mismatch with the <code>digest-mismatch</code> parameter. To be secure by default, we are now defaulting the behavior to <code>error</code> which will fail the workflow run.</p> <h3>ESM</h3> <p>To support new versions of the @actions/* packages, we've upgraded the package to ESM.</p> <h2>What's Changed</h2> <ul> <li>Don't attempt to un-zip non-zipped downloads by <a href="https://github.com/danwkennedy"><code>@danwkennedy</code></a> in <a href="https://redirect.github.com/actions/download-artifact/pull/460">actions/download-artifact#460</a></li> <li>Add a setting to specify what to do on hash mismatch and default it to <code>error</code> by <a href="https://github.com/danwkennedy"><code>@danwkennedy</code></a> in <a href="https://redirect.github.com/actions/download-artifact/pull/461">actions/download-artifact#461</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/actions/download-artifact/compare/v7...v8.0.0">https://github.com/actions/download-artifact/compare/v7...v8.0.0</a></p> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="70fc10c6e5"><code>70fc10c</code></a> Merge pull request <a href="https://redirect.github.com/actions/download-artifact/issues/461">#461</a> from actions/danwkennedy/digest-mismatch-behavior</li> <li><a href="f258da9a50"><code>f258da9</code></a> Add change docs</li> <li><a href="ccc058e5fb"><code>ccc058e</code></a> Fix linting issues</li> <li><a href="bd7976ba57"><code>bd7976b</code></a> Add a setting to specify what to do on hash mismatch and default it to <code>error</code></li> <li><a href="ac21fcf45e"><code>ac21fcf</code></a> Merge pull request <a href="https://redirect.github.com/actions/download-artifact/issues/460">#460</a> from actions/danwkennedy/download-no-unzip</li> <li><a href="15999bff51"><code>15999bf</code></a> Add note about package bumps</li> <li><a href="974686ed50"><code>974686e</code></a> Bump the version to <code>v8</code> and add release notes</li> <li><a href="fbe48b1d27"><code>fbe48b1</code></a> Update test names to make it clearer what they do</li> <li><a href="96bf374a61"><code>96bf374</code></a> One more test fix</li> <li><a href="b8c4819ef5"><code>b8c4819</code></a> Fix skip decompress test</li> <li>Additional commits viewable in <a href="https://github.com/actions/download-artifact/compare/v7...v8">compare view</a></li> </ul> </details> <br /> Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
626 lines
24 KiB
YAML
626 lines
24 KiB
YAML
# Builds and publishes LangChain packages to PyPI.
|
|
#
|
|
# Manually triggered, though can be used as a reusable workflow (workflow_call).
|
|
#
|
|
# Handles version bumping, building, and publishing to PyPI with authentication.
|
|
|
|
name: "🚀 Package Release"
|
|
run-name: "Release ${{ inputs.working-directory }} ${{ inputs.release-version }}"
|
|
on:
|
|
workflow_call:
|
|
inputs:
|
|
working-directory:
|
|
required: true
|
|
type: string
|
|
description: "From which folder this pipeline executes"
|
|
workflow_dispatch:
|
|
inputs:
|
|
working-directory:
|
|
required: true
|
|
type: string
|
|
description: "From which folder this pipeline executes"
|
|
default: "libs/langchain_v1"
|
|
release-version:
|
|
required: true
|
|
type: string
|
|
default: "0.1.0"
|
|
description: "New version of package being released"
|
|
dangerous-nonmaster-release:
|
|
required: false
|
|
type: boolean
|
|
default: false
|
|
description: "Release from a non-master branch (danger!) - Only use for hotfixes"
|
|
|
|
env:
|
|
PYTHON_VERSION: "3.11"
|
|
UV_FROZEN: "true"
|
|
UV_NO_SYNC: "true"
|
|
|
|
permissions:
|
|
contents: write # Required for creating GitHub releases
|
|
|
|
jobs:
|
|
# Build the distribution package and extract version info
|
|
# Runs in isolated environment with minimal permissions for security
|
|
build:
|
|
if: github.ref == 'refs/heads/master' || inputs.dangerous-nonmaster-release
|
|
environment: Scheduled testing
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
|
|
outputs:
|
|
pkg-name: ${{ steps.check-version.outputs.pkg-name }}
|
|
version: ${{ steps.check-version.outputs.version }}
|
|
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- name: Set up Python + uv
|
|
uses: "./.github/actions/uv_setup"
|
|
with:
|
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
|
|
# We want to keep this build stage *separate* from the release stage,
|
|
# so that there's no sharing of permissions between them.
|
|
# (Release stage has trusted publishing and GitHub repo contents write access,
|
|
#
|
|
# Otherwise, a malicious `build` step (e.g. via a compromised dependency)
|
|
# could get access to our GitHub or PyPI credentials.
|
|
#
|
|
# Per the trusted publishing GitHub Action:
|
|
# > It is strongly advised to separate jobs for building [...]
|
|
# > from the publish job.
|
|
# https://github.com/pypa/gh-action-pypi-publish#non-goals
|
|
- name: Build project for distribution
|
|
run: uv build
|
|
working-directory: ${{ inputs.working-directory }}
|
|
|
|
- name: Upload build
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: dist
|
|
path: ${{ inputs.working-directory }}/dist/
|
|
|
|
- name: Check version
|
|
id: check-version
|
|
shell: python
|
|
working-directory: ${{ inputs.working-directory }}
|
|
run: |
|
|
import os
|
|
import tomllib
|
|
with open("pyproject.toml", "rb") as f:
|
|
data = tomllib.load(f)
|
|
pkg_name = data["project"]["name"]
|
|
version = data["project"]["version"]
|
|
with open(os.environ["GITHUB_OUTPUT"], "a") as f:
|
|
f.write(f"pkg-name={pkg_name}\n")
|
|
f.write(f"version={version}\n")
|
|
release-notes:
|
|
needs:
|
|
- build
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
outputs:
|
|
release-body: ${{ steps.generate-release-body.outputs.release-body }}
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
repository: langchain-ai/langchain
|
|
path: langchain
|
|
sparse-checkout: | # this only grabs files for relevant dir
|
|
${{ inputs.working-directory }}
|
|
ref: ${{ github.ref }} # this scopes to just ref'd branch
|
|
fetch-depth: 0 # this fetches entire commit history
|
|
- name: Check tags
|
|
id: check-tags
|
|
shell: bash
|
|
working-directory: langchain/${{ inputs.working-directory }}
|
|
env:
|
|
PKG_NAME: ${{ needs.build.outputs.pkg-name }}
|
|
VERSION: ${{ needs.build.outputs.version }}
|
|
run: |
|
|
# Handle regular versions and pre-release versions differently
|
|
if [[ "$VERSION" == *"-"* ]]; then
|
|
# This is a pre-release version (contains a hyphen)
|
|
# Extract the base version without the pre-release suffix
|
|
BASE_VERSION=${VERSION%%-*}
|
|
# Look for the latest release of the same base version
|
|
REGEX="^$PKG_NAME==$BASE_VERSION\$"
|
|
PREV_TAG=$(git tag --sort=-creatordate | (grep -P "$REGEX" || true) | head -1)
|
|
|
|
# If no exact base version match, look for the latest release of any kind
|
|
if [ -z "$PREV_TAG" ]; then
|
|
REGEX="^$PKG_NAME==\\d+\\.\\d+\\.\\d+\$"
|
|
PREV_TAG=$(git tag --sort=-creatordate | (grep -P "$REGEX" || true) | head -1)
|
|
fi
|
|
else
|
|
# Regular version handling
|
|
PREV_TAG="$PKG_NAME==${VERSION%.*}.$(( ${VERSION##*.} - 1 ))"; [[ "${VERSION##*.}" -eq 0 ]] && PREV_TAG=""
|
|
|
|
# backup case if releasing e.g. 0.3.0, looks up last release
|
|
# note if last release (chronologically) was e.g. 0.1.47 it will get
|
|
# that instead of the last 0.2 release
|
|
if [ -z "$PREV_TAG" ]; then
|
|
REGEX="^$PKG_NAME==\\d+\\.\\d+\\.\\d+\$"
|
|
echo $REGEX
|
|
PREV_TAG=$(git tag --sort=-creatordate | (grep -P $REGEX || true) | head -1)
|
|
fi
|
|
fi
|
|
|
|
# if PREV_TAG is empty or came out to 0.0.0, let it be empty
|
|
if [ -z "$PREV_TAG" ] || [ "$PREV_TAG" = "$PKG_NAME==0.0.0" ]; then
|
|
echo "No previous tag found - first release"
|
|
else
|
|
# confirm prev-tag actually exists in git repo with git tag
|
|
GIT_TAG_RESULT=$(git tag -l "$PREV_TAG")
|
|
if [ -z "$GIT_TAG_RESULT" ]; then
|
|
echo "Previous tag $PREV_TAG not found in git repo"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
|
|
TAG="${PKG_NAME}==${VERSION}"
|
|
if [ "$TAG" == "$PREV_TAG" ]; then
|
|
echo "No new version to release"
|
|
exit 1
|
|
fi
|
|
echo tag="$TAG" >> $GITHUB_OUTPUT
|
|
echo prev-tag="$PREV_TAG" >> $GITHUB_OUTPUT
|
|
- name: Generate release body
|
|
id: generate-release-body
|
|
working-directory: langchain
|
|
env:
|
|
WORKING_DIR: ${{ inputs.working-directory }}
|
|
PKG_NAME: ${{ needs.build.outputs.pkg-name }}
|
|
TAG: ${{ steps.check-tags.outputs.tag }}
|
|
PREV_TAG: ${{ steps.check-tags.outputs.prev-tag }}
|
|
run: |
|
|
PREAMBLE="Changes since $PREV_TAG"
|
|
# if PREV_TAG is empty or 0.0.0, then we are releasing the first version
|
|
if [ -z "$PREV_TAG" ] || [ "$PREV_TAG" = "$PKG_NAME==0.0.0" ]; then
|
|
PREAMBLE="Initial release"
|
|
PREV_TAG=$(git rev-list --max-parents=0 HEAD)
|
|
fi
|
|
{
|
|
echo 'release-body<<EOF'
|
|
echo $PREAMBLE
|
|
echo
|
|
git log --format="%s" "$PREV_TAG"..HEAD -- $WORKING_DIR
|
|
echo EOF
|
|
} >> "$GITHUB_OUTPUT"
|
|
|
|
test-pypi-publish:
|
|
needs:
|
|
- build
|
|
- release-notes
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
# This permission is used for trusted publishing:
|
|
# https://blog.pypi.org/posts/2023-04-20-introducing-trusted-publishers/
|
|
#
|
|
# Trusted publishing has to also be configured on PyPI for each package:
|
|
# https://docs.pypi.org/trusted-publishers/adding-a-publisher/
|
|
id-token: write
|
|
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- uses: actions/download-artifact@v8
|
|
with:
|
|
name: dist
|
|
path: ${{ inputs.working-directory }}/dist/
|
|
|
|
- name: Publish to test PyPI
|
|
uses: pypa/gh-action-pypi-publish@release/v1
|
|
with:
|
|
packages-dir: ${{ inputs.working-directory }}/dist/
|
|
verbose: true
|
|
print-hash: true
|
|
repository-url: https://test.pypi.org/legacy/
|
|
# We overwrite any existing distributions with the same name and version.
|
|
# This is *only for CI use* and is *extremely dangerous* otherwise!
|
|
# https://github.com/pypa/gh-action-pypi-publish#tolerating-release-package-file-duplicates
|
|
skip-existing: true
|
|
# Temp workaround since attestations are on by default as of gh-action-pypi-publish v1.11.0
|
|
attestations: false
|
|
|
|
pre-release-checks:
|
|
needs:
|
|
- build
|
|
- release-notes
|
|
- test-pypi-publish
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
timeout-minutes: 20
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
# We explicitly *don't* set up caching here. This ensures our tests are
|
|
# maximally sensitive to catching breakage.
|
|
#
|
|
# For example, here's a way that caching can cause a falsely-passing test:
|
|
# - Make the langchain package manifest no longer list a dependency package
|
|
# as a requirement. This means it won't be installed by `pip install`,
|
|
# and attempting to use it would cause a crash.
|
|
# - That dependency used to be required, so it may have been cached.
|
|
# When restoring the venv packages from cache, that dependency gets included.
|
|
# - Tests pass, because the dependency is present even though it wasn't specified.
|
|
# - The package is published, and it breaks on the missing dependency when
|
|
# used in the real world.
|
|
|
|
- name: Set up Python + uv
|
|
uses: "./.github/actions/uv_setup"
|
|
id: setup-python
|
|
with:
|
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
|
|
- uses: actions/download-artifact@v8
|
|
with:
|
|
name: dist
|
|
path: ${{ inputs.working-directory }}/dist/
|
|
|
|
- name: Import dist 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: |
|
|
uv venv
|
|
VIRTUAL_ENV=.venv uv pip install dist/*.whl
|
|
|
|
# Replace all dashes in the package name with underscores,
|
|
# since that's how Python imports packages with dashes in the name.
|
|
# also remove _official suffix
|
|
IMPORT_NAME="$(echo "$PKG_NAME" | sed s/-/_/g | sed s/_official//g)"
|
|
|
|
uv run python -c "import $IMPORT_NAME; print(dir($IMPORT_NAME))"
|
|
|
|
- name: Import test dependencies
|
|
run: uv sync --group test
|
|
working-directory: ${{ inputs.working-directory }}
|
|
|
|
# Overwrite the local version of the package with the built 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: |
|
|
VIRTUAL_ENV=.venv uv pip install dist/*.whl
|
|
|
|
- name: Check for prerelease versions
|
|
# Block release if any dependencies allow prerelease versions
|
|
# (unless this is itself a prerelease version)
|
|
working-directory: ${{ inputs.working-directory }}
|
|
run: |
|
|
uv run python $GITHUB_WORKSPACE/.github/scripts/check_prerelease_dependencies.py pyproject.toml
|
|
|
|
- name: Run unit tests
|
|
run: make tests
|
|
working-directory: ${{ inputs.working-directory }}
|
|
|
|
- name: Get minimum versions
|
|
# Find the minimum published versions that satisfies the given constraints
|
|
working-directory: ${{ inputs.working-directory }}
|
|
id: min-version
|
|
run: |
|
|
VIRTUAL_ENV=.venv uv pip install packaging requests
|
|
python_version="$(uv run python --version | awk '{print $2}')"
|
|
min_versions="$(uv run python $GITHUB_WORKSPACE/.github/scripts/get_min_versions.py pyproject.toml release $python_version)"
|
|
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: |
|
|
VIRTUAL_ENV=.venv uv pip install --force-reinstall --editable .
|
|
VIRTUAL_ENV=.venv uv pip install --force-reinstall $MIN_VERSIONS
|
|
make tests
|
|
working-directory: ${{ inputs.working-directory }}
|
|
|
|
- name: Import integration test dependencies
|
|
run: uv sync --group test --group test_integration
|
|
working-directory: ${{ inputs.working-directory }}
|
|
|
|
- name: Run integration tests
|
|
# Uses the Makefile's `integration_tests` target for the specified package
|
|
if: ${{ startsWith(inputs.working-directory, 'libs/partners/') }}
|
|
env:
|
|
AI21_API_KEY: ${{ secrets.AI21_API_KEY }}
|
|
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
|
|
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
|
|
TOGETHER_API_KEY: ${{ secrets.TOGETHER_API_KEY }}
|
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
AZURE_OPENAI_API_VERSION: ${{ secrets.AZURE_OPENAI_API_VERSION }}
|
|
AZURE_OPENAI_API_BASE: ${{ secrets.AZURE_OPENAI_API_BASE }}
|
|
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
|
|
AZURE_OPENAI_CHAT_DEPLOYMENT_NAME: ${{ secrets.AZURE_OPENAI_CHAT_DEPLOYMENT_NAME }}
|
|
AZURE_OPENAI_LEGACY_CHAT_DEPLOYMENT_NAME: ${{ secrets.AZURE_OPENAI_LEGACY_CHAT_DEPLOYMENT_NAME }}
|
|
AZURE_OPENAI_LLM_DEPLOYMENT_NAME: ${{ secrets.AZURE_OPENAI_LLM_DEPLOYMENT_NAME }}
|
|
AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT_NAME: ${{ secrets.AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT_NAME }}
|
|
NVIDIA_API_KEY: ${{ secrets.NVIDIA_API_KEY }}
|
|
GOOGLE_SEARCH_API_KEY: ${{ secrets.GOOGLE_SEARCH_API_KEY }}
|
|
GOOGLE_CSE_ID: ${{ secrets.GOOGLE_CSE_ID }}
|
|
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
|
|
HUGGINGFACEHUB_API_TOKEN: ${{ secrets.HUGGINGFACEHUB_API_TOKEN }}
|
|
EXA_API_KEY: ${{ secrets.EXA_API_KEY }}
|
|
NOMIC_API_KEY: ${{ secrets.NOMIC_API_KEY }}
|
|
WATSONX_APIKEY: ${{ secrets.WATSONX_APIKEY }}
|
|
WATSONX_PROJECT_ID: ${{ secrets.WATSONX_PROJECT_ID }}
|
|
ASTRA_DB_API_ENDPOINT: ${{ secrets.ASTRA_DB_API_ENDPOINT }}
|
|
ASTRA_DB_APPLICATION_TOKEN: ${{ secrets.ASTRA_DB_APPLICATION_TOKEN }}
|
|
ASTRA_DB_KEYSPACE: ${{ secrets.ASTRA_DB_KEYSPACE }}
|
|
ES_URL: ${{ secrets.ES_URL }}
|
|
ES_CLOUD_ID: ${{ secrets.ES_CLOUD_ID }}
|
|
ES_API_KEY: ${{ secrets.ES_API_KEY }}
|
|
MONGODB_ATLAS_URI: ${{ secrets.MONGODB_ATLAS_URI }}
|
|
UPSTAGE_API_KEY: ${{ secrets.UPSTAGE_API_KEY }}
|
|
FIREWORKS_API_KEY: ${{ secrets.FIREWORKS_API_KEY }}
|
|
XAI_API_KEY: ${{ secrets.XAI_API_KEY }}
|
|
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
|
|
PPLX_API_KEY: ${{ secrets.PPLX_API_KEY }}
|
|
OLLAMA_API_KEY: ${{ secrets.OLLAMA_API_KEY }}
|
|
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
|
|
LANGCHAIN_TESTS_USER_AGENT: ${{ secrets.LANGCHAIN_TESTS_USER_AGENT }}
|
|
run: make integration_tests
|
|
working-directory: ${{ inputs.working-directory }}
|
|
|
|
# Test select published packages against new core
|
|
# Done when code changes are made to langchain-core
|
|
test-prior-published-packages-against-new-core:
|
|
# Installs the new core with old partners: Installs the new unreleased core
|
|
# alongside the previously published partner packages and runs integration tests
|
|
needs:
|
|
- build
|
|
- release-notes
|
|
- test-pypi-publish
|
|
- pre-release-checks
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
if: false # temporarily skip
|
|
strategy:
|
|
matrix:
|
|
partner: [anthropic]
|
|
fail-fast: false # Continue testing other partners if one fails
|
|
env:
|
|
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
ANTHROPIC_FILES_API_IMAGE_ID: ${{ secrets.ANTHROPIC_FILES_API_IMAGE_ID }}
|
|
ANTHROPIC_FILES_API_PDF_ID: ${{ secrets.ANTHROPIC_FILES_API_PDF_ID }}
|
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
AZURE_OPENAI_API_VERSION: ${{ secrets.AZURE_OPENAI_API_VERSION }}
|
|
AZURE_OPENAI_API_BASE: ${{ secrets.AZURE_OPENAI_API_BASE }}
|
|
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
|
|
AZURE_OPENAI_CHAT_DEPLOYMENT_NAME: ${{ secrets.AZURE_OPENAI_CHAT_DEPLOYMENT_NAME }}
|
|
AZURE_OPENAI_LEGACY_CHAT_DEPLOYMENT_NAME: ${{ secrets.AZURE_OPENAI_LEGACY_CHAT_DEPLOYMENT_NAME }}
|
|
AZURE_OPENAI_LLM_DEPLOYMENT_NAME: ${{ secrets.AZURE_OPENAI_LLM_DEPLOYMENT_NAME }}
|
|
AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT_NAME: ${{ secrets.AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT_NAME }}
|
|
LANGCHAIN_TESTS_USER_AGENT: ${{ secrets.LANGCHAIN_TESTS_USER_AGENT }}
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
# We implement this conditional as Github Actions does not have good support
|
|
# for conditionally needing steps. https://github.com/actions/runner/issues/491
|
|
# TODO: this seems to be resolved upstream, so we can probably remove this workaround
|
|
- name: Check if libs/core
|
|
run: |
|
|
if [ "${{ startsWith(inputs.working-directory, 'libs/core') }}" != "true" ]; then
|
|
echo "Not in libs/core. Exiting successfully."
|
|
exit 0
|
|
fi
|
|
|
|
- name: Set up Python + uv
|
|
if: startsWith(inputs.working-directory, 'libs/core')
|
|
uses: "./.github/actions/uv_setup"
|
|
with:
|
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
|
|
- uses: actions/download-artifact@v8
|
|
if: startsWith(inputs.working-directory, 'libs/core')
|
|
with:
|
|
name: dist
|
|
path: ${{ inputs.working-directory }}/dist/
|
|
|
|
- name: Test against ${{ matrix.partner }}
|
|
if: startsWith(inputs.working-directory, 'libs/core')
|
|
run: |
|
|
# Identify latest tag, excluding pre-releases
|
|
LATEST_PACKAGE_TAG="$(
|
|
git ls-remote --tags origin "langchain-${{ matrix.partner }}*" \
|
|
| awk '{print $2}' \
|
|
| sed 's|refs/tags/||' \
|
|
| grep -E '[0-9]+\.[0-9]+\.[0-9]+$' \
|
|
| sort -Vr \
|
|
| head -n 1
|
|
)"
|
|
echo "Latest package tag: $LATEST_PACKAGE_TAG"
|
|
|
|
# Shallow-fetch just that single tag
|
|
git fetch --depth=1 origin tag "$LATEST_PACKAGE_TAG"
|
|
|
|
# Checkout the latest package files
|
|
rm -rf $GITHUB_WORKSPACE/libs/partners/${{ matrix.partner }}/*
|
|
rm -rf $GITHUB_WORKSPACE/libs/standard-tests/*
|
|
cd $GITHUB_WORKSPACE/libs/
|
|
git checkout "$LATEST_PACKAGE_TAG" -- standard-tests/
|
|
git checkout "$LATEST_PACKAGE_TAG" -- partners/${{ matrix.partner }}/
|
|
cd partners/${{ matrix.partner }}
|
|
|
|
# Print as a sanity check
|
|
echo "Version number from pyproject.toml: "
|
|
cat pyproject.toml | grep "version = "
|
|
|
|
# Run tests
|
|
uv sync --group test --group test_integration
|
|
uv pip install ../../core/dist/*.whl
|
|
make integration_tests
|
|
|
|
# Test external packages that depend on langchain-core/langchain against the new release
|
|
# Only runs for core and langchain_v1 releases to catch breaking changes before publish
|
|
test-dependents:
|
|
name: "🐍 Python ${{ matrix.python-version }}: ${{ matrix.package.path }}"
|
|
needs:
|
|
- build
|
|
- release-notes
|
|
- test-pypi-publish
|
|
- pre-release-checks
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
# Only run for core or langchain_v1 releases
|
|
if: startsWith(inputs.working-directory, 'libs/core') || startsWith(inputs.working-directory, 'libs/langchain_v1')
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
python-version: ["3.11", "3.13"]
|
|
package:
|
|
- name: deepagents
|
|
repo: langchain-ai/deepagents
|
|
path: libs/deepagents
|
|
# No API keys needed for now - deepagents `make test` only runs unit tests
|
|
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
path: langchain
|
|
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
repository: ${{ matrix.package.repo }}
|
|
path: ${{ matrix.package.name }}
|
|
|
|
- name: Set up Python + uv
|
|
uses: "./langchain/.github/actions/uv_setup"
|
|
with:
|
|
python-version: ${{ matrix.python-version }}
|
|
|
|
- uses: actions/download-artifact@v8
|
|
with:
|
|
name: dist
|
|
path: dist/
|
|
|
|
- name: Install ${{ matrix.package.name }} with local packages
|
|
# External dependents don't have [tool.uv.sources] pointing to this repo,
|
|
# so we install the package normally then override with the built wheel.
|
|
run: |
|
|
cd ${{ matrix.package.name }}/${{ matrix.package.path }}
|
|
|
|
# Install the package with test dependencies
|
|
uv sync --group test
|
|
|
|
# Override with the built wheel from this release
|
|
uv pip install $GITHUB_WORKSPACE/dist/*.whl
|
|
|
|
- name: Run ${{ matrix.package.name }} tests
|
|
run: |
|
|
cd ${{ matrix.package.name }}/${{ matrix.package.path }}
|
|
make test
|
|
|
|
publish:
|
|
# Publishes the package to PyPI
|
|
needs:
|
|
- build
|
|
- release-notes
|
|
- test-pypi-publish
|
|
- pre-release-checks
|
|
- test-dependents
|
|
# - test-prior-published-packages-against-new-core
|
|
# Run if all needed jobs succeeded or were skipped (test-dependents only runs for core/langchain_v1)
|
|
if: ${{ !cancelled() && !failure() }}
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
# This permission is used for trusted publishing:
|
|
# https://blog.pypi.org/posts/2023-04-20-introducing-trusted-publishers/
|
|
#
|
|
# Trusted publishing has to also be configured on PyPI for each package:
|
|
# https://docs.pypi.org/trusted-publishers/adding-a-publisher/
|
|
id-token: write
|
|
|
|
defaults:
|
|
run:
|
|
working-directory: ${{ inputs.working-directory }}
|
|
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- name: Set up Python + uv
|
|
uses: "./.github/actions/uv_setup"
|
|
with:
|
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
|
|
- uses: actions/download-artifact@v8
|
|
with:
|
|
name: dist
|
|
path: ${{ inputs.working-directory }}/dist/
|
|
|
|
- name: Publish package distributions to PyPI
|
|
uses: pypa/gh-action-pypi-publish@release/v1
|
|
with:
|
|
packages-dir: ${{ inputs.working-directory }}/dist/
|
|
verbose: true
|
|
print-hash: true
|
|
# Temp workaround since attestations are on by default as of gh-action-pypi-publish v1.11.0
|
|
attestations: false
|
|
|
|
mark-release:
|
|
# Marks the GitHub release with the new version tag
|
|
needs:
|
|
- build
|
|
- release-notes
|
|
- test-pypi-publish
|
|
- pre-release-checks
|
|
- publish
|
|
# Run if all needed jobs succeeded or were skipped (test-dependents only runs for core/langchain_v1)
|
|
if: ${{ !cancelled() && !failure() }}
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
# This permission is needed by `ncipollo/release-action` to
|
|
# create the GitHub release/tag
|
|
contents: write
|
|
|
|
defaults:
|
|
run:
|
|
working-directory: ${{ inputs.working-directory }}
|
|
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- name: Set up Python + uv
|
|
uses: "./.github/actions/uv_setup"
|
|
with:
|
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
|
|
- uses: actions/download-artifact@v8
|
|
with:
|
|
name: dist
|
|
path: ${{ inputs.working-directory }}/dist/
|
|
|
|
- name: Create Tag
|
|
uses: ncipollo/release-action@v1
|
|
with:
|
|
artifacts: "dist/*"
|
|
token: ${{ secrets.GITHUB_TOKEN }}
|
|
generateReleaseNotes: false
|
|
tag: ${{needs.build.outputs.pkg-name}}==${{ needs.build.outputs.version }}
|
|
body: ${{ needs.release-notes.outputs.release-body }}
|
|
commit: ${{ github.sha }}
|
|
makeLatest: ${{ needs.build.outputs.pkg-name == 'langchain-core'}}
|