Spaces:
Runtime error
Runtime error
| name: release | |
| run-name: Release ${{ inputs.working-directory }} by @${{ github.actor }} | |
| 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 | |
| default: 'libs/langchain' | |
| dangerous-nonmaster-release: | |
| required: false | |
| type: boolean | |
| default: false | |
| description: "Release from a non-master branch (danger!)" | |
| env: | |
| PYTHON_VERSION: "3.11" | |
| POETRY_VERSION: "1.7.1" | |
| jobs: | |
| build: | |
| if: github.ref == 'refs/heads/master' || inputs.dangerous-nonmaster-release | |
| environment: Scheduled testing | |
| runs-on: ubuntu-latest | |
| 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 | |
| # We want to keep this build stage *separate* from the release stage, | |
| # so that there's no sharing of permissions between them. | |
| # The release stage has trusted publishing and GitHub repo contents write access, | |
| # and we want to keep the scope of that access limited just to the release job. | |
| # 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: 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 | |
| release-notes: | |
| needs: | |
| - build | |
| runs-on: ubuntu-latest | |
| outputs: | |
| release-body: ${{ steps.generate-release-body.outputs.release-body }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| repository: langchain-ai/langchain | |
| path: langchain | |
| sparse-checkout: | # this only grabs files for relevant dir | |
| ${{ inputs.working-directory }} | |
| ref: master # this scopes to just master 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: | | |
| REGEX="^$PKG_NAME==\\d+\\.\\d+\\.\\d+\$" | |
| echo $REGEX | |
| PREV_TAG=$(git tag --sort=-creatordate | grep -P $REGEX || true | head -1) | |
| 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, then we are releasing the first version | |
| if [ -z "$PREV_TAG" ]; then | |
| PREAMBLE="Initial release" | |
| PREV_TAG=$(git rev-list --max-parents=0 HEAD) | |
| fi | |
| { | |
| echo 'release-body<<EOF' | |
| echo "# Release $TAG" | |
| echo $PREAMBLE | |
| echo | |
| git log --format="%s" "$PREV_TAG"..HEAD -- $WORKING_DIR | |
| echo EOF | |
| } >> "$GITHUB_OUTPUT" | |
| test-pypi-publish: | |
| needs: | |
| - build | |
| - release-notes | |
| uses: | |
| ./.github/workflows/_test_release.yml | |
| with: | |
| working-directory: ${{ inputs.working-directory }} | |
| dangerous-nonmaster-release: ${{ inputs.dangerous-nonmaster-release }} | |
| secrets: inherit | |
| pre-release-checks: | |
| needs: | |
| - build | |
| - release-notes | |
| - test-pypi-publish | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| # 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 + 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: 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: | | |
| poetry run pip install --force-reinstall $MIN_VERSIONS --editable . | |
| make tests | |
| working-directory: ${{ inputs.working-directory }} | |
| - name: 'Authenticate to Google Cloud' | |
| id: 'auth' | |
| uses: google-github-actions/auth@v2 | |
| with: | |
| credentials_json: '${{ secrets.GOOGLE_CREDENTIALS }}' | |
| - name: Run integration tests | |
| 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_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 }} | |
| 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 }} | |
| PINECONE_API_KEY: ${{ secrets.PINECONE_API_KEY }} | |
| PINECONE_ENVIRONMENT: ${{ secrets.PINECONE_ENVIRONMENT }} | |
| 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 }} | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # for airbyte | |
| MONGODB_ATLAS_URI: ${{ secrets.MONGODB_ATLAS_URI }} | |
| VOYAGE_API_KEY: ${{ secrets.VOYAGE_API_KEY }} | |
| UPSTAGE_API_KEY: ${{ secrets.UPSTAGE_API_KEY }} | |
| FIREWORKS_API_KEY: ${{ secrets.FIREWORKS_API_KEY }} | |
| run: make integration_tests | |
| working-directory: ${{ inputs.working-directory }} | |
| publish: | |
| needs: | |
| - build | |
| - release-notes | |
| - test-pypi-publish | |
| - pre-release-checks | |
| 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@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 | |
| - uses: actions/download-artifact@v4 | |
| 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 | |
| mark-release: | |
| needs: | |
| - build | |
| - release-notes | |
| - test-pypi-publish | |
| - pre-release-checks | |
| - publish | |
| runs-on: ubuntu-latest | |
| permissions: | |
| # This permission is needed by `ncipollo/release-action` to | |
| # create the GitHub release. | |
| contents: write | |
| defaults: | |
| run: | |
| working-directory: ${{ inputs.working-directory }} | |
| 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 | |
| - uses: actions/download-artifact@v4 | |
| 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'}} | |