From a7d1449e9d0215cfdc7aca8a579fff6af110e801 Mon Sep 17 00:00:00 2001 From: Jordan Frazier <122494242+jordanrfrazier@users.noreply.github.com> Date: Tue, 17 Sep 2024 18:03:48 -0700 Subject: [PATCH] ci: tag fixes and robustness to workflow failures (#3838) --- .github/workflows/docker-build.yml | 16 ++-- .github/workflows/nightly_build.yml | 106 ++++++++++++++++++++---- .github/workflows/python_test.yml | 4 +- .github/workflows/release_nightly.yml | 8 +- .github/workflows/typescript_test.yml | 1 + poetry.lock | 5 -- scripts/ci/pypi_nightly_tag.py | 5 ++ scripts/ci/update_lf_base_dependency.py | 6 +- scripts/ci/update_pyproject_version.py | 5 ++ scripts/update_dependencies.py | 4 + 10 files changed, 125 insertions(+), 35 deletions(-) diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 5e31c4a10..007209920 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -76,10 +76,10 @@ jobs: echo "nightly_build=false" >> $GITHUB_OUTPUT fi - - name: Check out the code at a specific ref (e.g., nightly tag) + - name: Check out the code at a specific ref uses: actions/checkout@v4 with: - ref: ${{ steps.resolve-nightly-tag.outputs.nightly_tag || github.ref }} + ref: ${{ inputs.nightly_tag_main || github.ref }} - name: Set up Python 3.12 + Poetry ${{ env.POETRY_VERSION }} uses: "./.github/actions/poetry_caching" with: @@ -114,10 +114,10 @@ jobs: env: NIGHTLY_TAG: ${{ needs.get-version.outputs.nightly-tag }} steps: - - name: Check out the code at a specific ref (e.g., nightly tag) + - name: Check out the code at a specific ref uses: actions/checkout@v4 with: - ref: ${{ env.NIGHTLY_TAG || github.ref }} + ref: ${{ inputs.nightly_tag_main || github.ref }} - name: Set Dockerfile and Tags id: set-vars @@ -145,10 +145,10 @@ jobs: runs-on: ubuntu-latest needs: [get-version, setup] steps: - - name: Check out the code at a specific ref (e.g., nightly tag) + - name: Check out the code at a specific ref uses: actions/checkout@v4 with: - ref: ${{ needs.get-version.outputs.nightly-tag || github.ref }} + ref: ${{ inputs.nightly_tag_main || github.ref }} - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -210,10 +210,10 @@ jobs: tags: ${{ format('ghcr.io/langflow-ai/langflow-frontend{0}:{1},ghcr.io/langflow-ai/langflow-frontend{0}:latest', needs.get-version.outputs.nightly-build && '-nightly' || '', needs.get-version.outputs.version) }} langflow_image: ghcr.io/langflow-ai/langflow${{ needs.get-version.outputs.nightly-build && '-nightly' || '' }}:${{ needs.get-version.outputs.version }} steps: - - name: Check out the code at a specific ref (e.g., nightly tag) + - name: Check out the code at a specific ref uses: actions/checkout@v4 with: - ref: ${{ needs.get-version.outputs.nightly-tag || github.ref }} + ref: ${{ inputs.nightly_tag_main || github.ref }} - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 diff --git a/.github/workflows/nightly_build.yml b/.github/workflows/nightly_build.yml index d26435afe..d3740bd63 100644 --- a/.github/workflows/nightly_build.yml +++ b/.github/workflows/nightly_build.yml @@ -12,6 +12,7 @@ env: jobs: create-nightly-tag: + if: github.repository == 'langflow-ai/langflow' runs-on: ubuntu-latest defaults: run: @@ -20,8 +21,8 @@ jobs: # Required to create tag contents: write outputs: - main_tag: ${{ steps.create_tag.outputs.main_tag }} - base_tag: ${{ steps.create_tag.outputs.base_tag }} + main_tag: ${{ steps.generate_main_tag.outputs.main_tag }} + base_tag: ${{ steps.set_base_tag.outputs.base_tag }} steps: - name: Checkout code uses: actions/checkout@v4 @@ -40,53 +41,125 @@ jobs: poetry env use ${{ env.PYTHON_VERSION }} poetry install - - name: Create tag - id: create_tag + - name: Generate main nightly tag + id: generate_main_tag run: | + # NOTE: This outputs the tag with the `v` prefix. + MAIN_TAG="$(poetry run python ./scripts/ci/pypi_nightly_tag.py main)" + echo "main_tag=$MAIN_TAG" >> $GITHUB_OUTPUT + echo "main_tag=$MAIN_TAG" + + - name: Check if main tag already exists + id: check_main_tag + run: | + git fetch --tags + if git rev-parse -q --verify "refs/tags/${{ steps.generate_main_tag.outputs.main_tag }}" >/dev/null; then + echo "main_tag_exists=true" >> $GITHUB_OUTPUT + else + echo "main_tag_exists=false" >> $GITHUB_OUTPUT + fi + + - name: Generate base nightly tag + id: generate_base_tag + if: ${{ steps.check_main_tag.outputs.main_tag_exists == 'false' }} + run: | + # NOTE: This outputs the tag with the `v` prefix. + BASE_TAG="$(poetry run python ./scripts/ci/pypi_nightly_tag.py base)" + echo "base_tag=$BASE_TAG" >> $GITHUB_OUTPUT + echo "base_tag=$BASE_TAG" + + - name: Commit tag + id: commit_tag + if: ${{ steps.check_main_tag.outputs.main_tag_exists == 'false' }} + run: | + # If the main tag does not exist in GH, we create the base tag from the existing codebase. + git config --global user.email "bot-nightly-builds@langflow.org" git config --global user.name "Langflow Bot" # WARNING: These scripts must be run in this order. # Poetry will use a different cached virtual environment once the main pyproject.toml # project-name is updated, which does not have dependencies installed. - BASE_TAG="$(poetry run python ./scripts/ci/pypi_nightly_tag.py base)" - echo "base_tag=$BASE_TAG" >> $GITHUB_OUTPUT + BASE_TAG="${{ steps.generate_base_tag.outputs.base_tag }}" + echo "Updating base project version to $BASE_TAG" poetry run python ./scripts/ci/update_pyproject_name.py langflow-base-nightly base poetry run python ./scripts/ci/update_pyproject_version.py $BASE_TAG base # This updates the dependency of langflow-base to langflow-base-nightly in {project_root}/pyproject.toml poetry run python ./scripts/ci/update_lf_base_dependency.py $BASE_TAG - MAIN_TAG="$(poetry run python ./scripts/ci/pypi_nightly_tag.py main)" - echo "main_tag=$MAIN_TAG" >> $GITHUB_OUTPUT + # Use the main tag created earlier + MAIN_TAG="${{ steps.generate_main_tag.outputs.main_tag }}" + echo "Updating main project version to $MAIN_TAG" poetry run python ./scripts/ci/update_pyproject_version.py $MAIN_TAG main poetry run python ./scripts/ci/update_pyproject_name.py langflow-nightly main git add pyproject.toml src/backend/base/pyproject.toml - git commit -m "Update version and project name in files" + git commit -m "Update version and project name" - git tag -a $MAIN_TAG -m "Langflow nightly $MAIN_TAG" - git push origin $MAIN_TAG || echo "Tag push failed. Check if the tag already exists." + echo "Tagging main with $MAIN_TAG" + if ! git tag -a $MAIN_TAG -m "Langflow nightly $MAIN_TAG"; then + echo "Tag creation failed. Exiting the workflow." + exit 1 + fi + + echo "Pushing main tag $MAIN_TAG" + if ! git push origin $MAIN_TAG; then + echo "Tag push failed. Check if the tag already exists. Exiting the workflow." + exit 1 + fi # TODO: notify on failure + - name: Checkout main nightly tag + uses: actions/checkout@v4 + if: ${{ steps.check_main_tag.outputs.main_tag_exists == 'true' }} + with: + ref: ${{ steps.generate_main_tag.outputs.main_tag }} + + - name: Retrieve Base Tag + id: retrieve_base_tag + if: ${{ steps.check_main_tag.outputs.main_tag_exists == 'true' }} + working-directory: src/backend/base + run: | + # If the main tag already exists, we need to retrieve the base version from the main tag codebase. + version=$(poetry version --short) + echo "base_tag=v$version" >> $GITHUB_OUTPUT + echo "base_tag=v$version" + + - name: Set Base Tag + id: set_base_tag + run: | + if [ "${{ steps.retrieve_base_tag.conclusion }}" != "skipped" ] && [ "${{ steps.retrieve_base_tag.outputs.base_tag }}" ]; then + BASE_TAG="${{ steps.retrieve_base_tag.outputs.base_tag }}" + echo "base_tag=$BASE_TAG" >> $GITHUB_OUTPUT + echo "base_tag=$BASE_TAG" + elif [ "${{ steps.commit_tag.conclusion }}" != "skipped" ] && [ "${{ steps.generate_base_tag.outputs.base_tag }}" ]; then + BASE_TAG="${{ steps.generate_base_tag.outputs.base_tag }}" + echo "base_tag=$BASE_TAG" >> $GITHUB_OUTPUT + echo "base_tag=$BASE_TAG" + else + echo "No base tag found. Exiting the workflow." + exit 1 + fi + frontend-tests: + if: github.repository == 'langflow-ai/langflow' name: Run Frontend Tests needs: create-nightly-tag uses: ./.github/workflows/typescript_test.yml with: tests_folder: "tests/core" - ref: ${{ needs.create-nightly-tag.outputs.tag }} - secrets: - OPENAI_API_KEY: "${{ secrets.OPENAI_API_KEY }}" - STORE_API_KEY: "${{ secrets.STORE_API_KEY }}" + ref: ${{ needs.create-nightly-tag.outputs.main_tag }} + secrets: inherit backend-unit-tests: + if: github.repository == 'langflow-ai/langflow' name: Run Backend Unit Tests needs: create-nightly-tag uses: ./.github/workflows/python_test.yml with: python-versions: '["3.10", "3.11", "3.12"]' - ref: ${{ needs.create-nightly-tag.outputs.tag }} + ref: ${{ needs.create-nightly-tag.outputs.main_tag }} # Not making nightly builds dependent on integration test success # due to inherent flakiness of 3rd party integrations @@ -100,6 +173,7 @@ jobs: # ref: ${{ needs.create-nightly-tag.outputs.tag }} release-nightly-build: + if: github.repository == 'langflow-ai/langflow' name: Run Nightly Langflow Build needs: [frontend-tests, backend-unit-tests, create-nightly-tag] uses: ./.github/workflows/release_nightly.yml diff --git a/.github/workflows/python_test.yml b/.github/workflows/python_test.yml index 1b9e75a3b..fb2e48c9a 100644 --- a/.github/workflows/python_test.yml +++ b/.github/workflows/python_test.yml @@ -55,6 +55,7 @@ jobs: - name: Install Python dependencies run: | poetry env use ${{ matrix.python-version }} + poetry lock --no-update poetry install - name: Run unit tests uses: nick-fields/retry@v3 @@ -71,7 +72,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ inputs.branch || github.ref }} + ref: ${{ inputs.ref || github.ref }} - name: Set up Python ${{ matrix.python-version }} + Poetry ${{ env.POETRY_VERSION }} uses: "./.github/actions/poetry_caching" with: @@ -81,6 +82,7 @@ jobs: - name: Install Python dependencies run: | poetry env use ${{ matrix.python-version }} + poetry lock --no-update poetry install - name: Run integration tests run: make integration_tests_no_api_keys diff --git a/.github/workflows/release_nightly.yml b/.github/workflows/release_nightly.yml index 6b2445df5..37d295d51 100644 --- a/.github/workflows/release_nightly.yml +++ b/.github/workflows/release_nightly.yml @@ -55,7 +55,7 @@ jobs: run: shell: bash steps: - - name: Check out the code at a specific ref (e.g., nightly tag) + - name: Check out the code at a specific ref uses: actions/checkout@v4 with: ref: ${{ inputs.nightly_tag_main }} @@ -77,7 +77,7 @@ jobs: working-directory: src/backend/base run: | name=$(poetry version | cut -d' ' -f1) - version=$(poetry version --short) + version=v$(poetry version --short) if [ "$name" != "langflow-base-nightly" ]; then echo "Name $name does not match langflow-base-nightly. Exiting the workflow." exit 1 @@ -128,7 +128,7 @@ jobs: run: shell: bash steps: - - name: Check out the code at a specific ref (e.g., nightly tag) + - name: Check out the code at a specific ref uses: actions/checkout@v4 with: ref: ${{ inputs.nightly_tag_main }} @@ -147,7 +147,7 @@ jobs: - name: Verify Nightly Name and Version run: | name=$(poetry version | cut -d' ' -f1) - version=$(poetry version --short) + version=v$(poetry version --short) if [ "$name" != "langflow-nightly" ]; then echo "Name $name does not match langflow-nightly. Exiting the workflow." exit 1 diff --git a/.github/workflows/typescript_test.yml b/.github/workflows/typescript_test.yml index 025165491..811f86f15 100644 --- a/.github/workflows/typescript_test.yml +++ b/.github/workflows/typescript_test.yml @@ -113,6 +113,7 @@ jobs: - name: Install Python dependencies run: | poetry env use ${{ env.PYTHON_VERSION }} + poetry lock --no-update poetry install - name: create .env diff --git a/poetry.lock b/poetry.lock index a72ed562d..a2d91564e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -10644,11 +10644,6 @@ files = [ {file = "triton-3.0.0-1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:34e509deb77f1c067d8640725ef00c5cbfcb2052a1a3cb6a6d343841f92624eb"}, {file = "triton-3.0.0-1-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bcbf3b1c48af6a28011a5c40a5b3b9b5330530c3827716b5fbf6d7adcc1e53e9"}, {file = "triton-3.0.0-1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6e5727202f7078c56f91ff13ad0c1abab14a0e7f2c87e91b12b6f64f3e8ae609"}, - {file = "triton-3.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39b052da883351fdf6be3d93cedae6db3b8e3988d3b09ed221bccecfa9612230"}, - {file = "triton-3.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd34f19a8582af96e6291d4afce25dac08cb2a5d218c599163761e8e0827208e"}, - {file = "triton-3.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d5e10de8c011adeb7c878c6ce0dd6073b14367749e34467f1cff2bde1b78253"}, - {file = "triton-3.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8903767951bf86ec960b4fe4e21bc970055afc65e9d57e916d79ae3c93665e3"}, - {file = "triton-3.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41004fb1ae9a53fcb3e970745feb87f0e3c94c6ce1ba86e95fa3b8537894bef7"}, ] [package.dependencies] diff --git a/scripts/ci/pypi_nightly_tag.py b/scripts/ci/pypi_nightly_tag.py index f54df491b..f11742736 100755 --- a/scripts/ci/pypi_nightly_tag.py +++ b/scripts/ci/pypi_nightly_tag.py @@ -48,6 +48,11 @@ def create_tag(build_type: str): new_nightly_version = latest_base_version + ".dev" + build_number + # Prepend "v" to the version, if DNE. + # This is an update to the nightly version format. + if not new_nightly_version.startswith("v"): + new_nightly_version = "v" + new_nightly_version + # X.Y.Z.dev.YYYYMMDD # This takes the base version of the current version and appends the # current date. If the last release was on the same day, we exit, as diff --git a/scripts/ci/update_lf_base_dependency.py b/scripts/ci/update_lf_base_dependency.py index c7fd7e7e3..e0eb870c1 100755 --- a/scripts/ci/update_lf_base_dependency.py +++ b/scripts/ci/update_lf_base_dependency.py @@ -29,7 +29,7 @@ def update_base_dep(pyproject_path: str, new_version: str) -> None: if not pattern.search(content): raise Exception(f'langflow-base dependency not found in "{filepath}"') - replacement = f'langflow-base-nightly = "^{new_version}"' + replacement = f'langflow-base-nightly = "{new_version}"' content = pattern.sub(replacement, content) with open(filepath, "w") as file: @@ -54,6 +54,10 @@ def main() -> None: raise Exception("New version not specified") base_version = sys.argv[1] + # Strip "v" prefix from version if present + if base_version.startswith("v"): + base_version = base_version[1:] + verify_pep440(base_version) update_base_dep("pyproject.toml", base_version) diff --git a/scripts/ci/update_pyproject_version.py b/scripts/ci/update_pyproject_version.py index ac2ea29ee..93c4511d1 100755 --- a/scripts/ci/update_pyproject_version.py +++ b/scripts/ci/update_pyproject_version.py @@ -42,6 +42,11 @@ def main() -> None: if len(sys.argv) != 3: raise Exception("New version not specified") new_version = sys.argv[1] + + # Strip "v" prefix from version if present + if new_version.startswith("v"): + new_version = new_version[1:] + build_type = sys.argv[2] verify_pep440(new_version) diff --git a/scripts/update_dependencies.py b/scripts/update_dependencies.py index c4355da53..38dd9b226 100644 --- a/scripts/update_dependencies.py +++ b/scripts/update_dependencies.py @@ -41,6 +41,10 @@ def is_development_release(version): def update_pyproject_dependency(pyproject_path, version, is_nightly): + # Strip "v" prefix from version if present + if version.startswith("v"): + version = version[1:] + pattern = re.compile(r'langflow-base = \{ path = "\./src/backend/base", develop = true \}') if is_nightly: # NOTE: This process can be simplified; see the note in update_lf_base_dependency.py