fix(ci): lockstep langflow-nightly and langflow-base-nightly versions (forward-port #13413) (#13416)

fix(ci): lockstep langflow-nightly and langflow-base-nightly versions

Forward-port of #13413 (merged to release-1.10.0) to main.

pypi_nightly_tag.py now derives a single shared dev number from
max(dev across BOTH langflow-nightly and langflow-base-nightly PyPI
histories) + 1 (restricted to the root base_version) and emits it twice in
`both` mode. nightly_build.yml reads the release and base tags from one
invocation (single PyPI snapshot) and fails closed on mismatch, so the latest
langflow-nightly always pins a langflow-base-nightly[complete]==X.Y.Z.devN
that was built and published in the same run (no more uninstallable nightly).

Safe to land now: the nightly create-nightly-tag job checks out the latest
release-* branch for the script while taking the run-block from the triggering
ref (main for scheduled runs). release-1.10.0 already carries the new script
(via #13413), so main's `both` run-block matches it, and future release
branches cut from main inherit the lockstep script.

Adds scripts/ci/test_pypi_nightly_tag.py + .github/workflows/ci-scripts-test.yml
and the update_pyproject_combined.py lockstep-invariant note.
This commit is contained in:
Eric Hare
2026-05-29 11:19:29 -07:00
committed by GitHub
parent 30b89779b7
commit 7c01482fa1
7 changed files with 342 additions and 86 deletions

27
.github/workflows/ci-scripts-test.yml vendored Normal file
View File

@ -0,0 +1,27 @@
name: CI Scripts Tests
on:
pull_request:
paths:
- "scripts/ci/**"
workflow_dispatch:
jobs:
test:
runs-on: ubuntu-latest
name: Test CI release scripts
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.13"
- name: Install dependencies
run: pip install pytest requests packaging
- name: Run CI script tests
run: python -m pytest scripts/ci/ -v

View File

@ -82,7 +82,7 @@ jobs:
# Required to create tag
contents: write
outputs:
release_tag: ${{ steps.generate_release_tag.outputs.release_tag }}
release_tag: ${{ steps.generate_shared_tag.outputs.release_tag }}
base_tag: ${{ steps.set_base_tag.outputs.base_tag }}
lfx_tag: ${{ steps.generate_lfx_tag.outputs.lfx_tag }}
sdk_tag: ${{ steps.generate_sdk_tag.outputs.sdk_tag }}
@ -107,30 +107,32 @@ jobs:
run: |
echo "PWD: $(pwd)"
find . -name "pypi_nightly_tag.py"
- name: Generate main nightly tag
id: generate_release_tag
- name: Generate shared nightly tag (main == base, lockstep)
id: generate_shared_tag
run: |
# langflow-nightly pins langflow-base-nightly[complete]==<exact dev>, so both tags
# MUST be identical. Compute them in ONE invocation (single PyPI snapshot) so they
# cannot drift across separate calls.
# NOTE: This outputs the tag with the `v` prefix.
RELEASE_TAG="$(uv run ./scripts/ci/pypi_nightly_tag.py main)"
TAGS_OUTPUT="$(uv run ./scripts/ci/pypi_nightly_tag.py both)"
RELEASE_TAG="$(printf '%s\n' "$TAGS_OUTPUT" | sed -n '1p')"
BASE_TAG="$(printf '%s\n' "$TAGS_OUTPUT" | sed -n '2p')"
if [ -z "$RELEASE_TAG" ] || [ "$RELEASE_TAG" != "$BASE_TAG" ]; then
echo "Shared tag mismatch: release='$RELEASE_TAG' base='$BASE_TAG'. Exiting the workflow."
exit 1
fi
echo "release_tag=$RELEASE_TAG" >> $GITHUB_OUTPUT
echo "release_tag=$RELEASE_TAG"
echo "base_tag=$BASE_TAG" >> $GITHUB_OUTPUT
echo "release_tag=$RELEASE_TAG base_tag=$BASE_TAG"
- name: Delete existing tag if it exists
id: check_release_tag
run: |
git fetch --tags
git tag -d ${{ steps.generate_release_tag.outputs.release_tag }} || true
git push --delete origin ${{ steps.generate_release_tag.outputs.release_tag }} || true
git tag -d ${{ steps.generate_shared_tag.outputs.release_tag }} || true
git push --delete origin ${{ steps.generate_shared_tag.outputs.release_tag }} || true
echo "release_tag_exists=false" >> $GITHUB_OUTPUT
- name: Generate base nightly tag
id: generate_base_tag
run: |
# NOTE: This outputs the tag with the `v` prefix.
BASE_TAG="$(uv run ./scripts/ci/pypi_nightly_tag.py base)"
echo "base_tag=$BASE_TAG" >> $GITHUB_OUTPUT
echo "base_tag=$BASE_TAG"
- name: Generate LFX nightly tag
id: generate_lfx_tag
run: |
@ -155,8 +157,8 @@ jobs:
git config --global user.email "bot-nightly-builds@langflow.org"
git config --global user.name "Langflow Bot"
RELEASE_TAG="${{ steps.generate_release_tag.outputs.release_tag }}"
BASE_TAG="${{ steps.generate_base_tag.outputs.base_tag }}"
RELEASE_TAG="${{ steps.generate_shared_tag.outputs.release_tag }}"
BASE_TAG="${{ steps.generate_shared_tag.outputs.base_tag }}"
LFX_TAG="${{ steps.generate_lfx_tag.outputs.lfx_tag }}"
SDK_TAG="${{ steps.generate_sdk_tag.outputs.sdk_tag }}"
echo "Updating SDK project version to $SDK_TAG"
@ -195,7 +197,7 @@ jobs:
- name: Checkout main nightly tag
uses: actions/checkout@v6
with:
ref: ${{ steps.generate_release_tag.outputs.release_tag }}
ref: ${{ steps.generate_shared_tag.outputs.release_tag }}
persist-credentials: true
- name: Retrieve Base Tag
@ -214,8 +216,8 @@ jobs:
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 }}"
elif [ "${{ steps.commit_tag.conclusion }}" != "skipped" ] && [ "${{ steps.generate_shared_tag.outputs.base_tag }}" ]; then
BASE_TAG="${{ steps.generate_shared_tag.outputs.base_tag }}"
echo "base_tag=$BASE_TAG" >> $GITHUB_OUTPUT
echo "base_tag=$BASE_TAG"
else