This is an automated email from the ASF dual-hosted git repository.
shahar1 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 986066e53d1 Record lessons from the October 2026 providers waves in
the release docs (#75006)
986066e53d1 is described below
commit 986066e53d159e7d42ffcb92726d02ccfa24c5a2
Author: Jarek Potiuk <[email protected]>
AuthorDate: Sun Oct 18 17:39:39 2026 +0200
Record lessons from the October 2026 providers waves in the release docs
(#75006)
The 2026-10-14 and 2026-10-17 waves hit steps the instructions did not
cover:
a provider outside the wave shipping with a common.compat floor below the
first release that has the symbol it imports, a candidate that had to be
rebuilt before its vote email went out, a build clone with no upstream
remote, an svn commit that cannot prompt from an agent session, tester
confirmations that only lived in issue comments, and a PyPI token prompt
that
needs a terminal an agent does not have.
Generated-by: Claude Opus 5
---
.../prepare-providers-documentation/SKILL.md | 8 ++
dev/README_RELEASE_PROVIDERS.md | 100 +++++++++++++++++++--
2 files changed, 101 insertions(+), 7 deletions(-)
diff --git a/.agents/skills/prepare-providers-documentation/SKILL.md
b/.agents/skills/prepare-providers-documentation/SKILL.md
index f706073229c..ecdb78a8db7 100644
--- a/.agents/skills/prepare-providers-documentation/SKILL.md
+++ b/.agents/skills/prepare-providers-documentation/SKILL.md
@@ -696,6 +696,14 @@ vote rather than re-cut in this release.
> doc preparation and PR creation, so it is easy to forget when the skill
> hands back to the regular release workflow.
+The command only resolves pins an author marked. While classifying, also
+note every PR that starts importing a symbol from another provider (most often
+`common.compat`) and check that the importing provider's floor is at least
+the first release that shipped it, even when the importing provider is not in
+this wave. If it is not, raise the floor in this PR and tell the release
+manager. The recipe is in "Update versions of dependent providers to the next
+version" in `dev/README_RELEASE_PROVIDERS.md`.
+
**Provider dependency-bump CI guard.** Every `>=` bump this produces (and any
inter-provider `>=` bump made during the wave, e.g. a `breaking` provider that
dependents must now require) trips the `check_provider_dependency_bumps`
diff --git a/dev/README_RELEASE_PROVIDERS.md b/dev/README_RELEASE_PROVIDERS.md
index ba745516126..af262adda32 100644
--- a/dev/README_RELEASE_PROVIDERS.md
+++ b/dev/README_RELEASE_PROVIDERS.md
@@ -42,6 +42,7 @@
- [Commit the source packages to Apache SVN
repo](#commit-the-source-packages-to-apache-svn-repo)
- [Publish the Regular distributions to PyPI (release
candidates)](#publish-the-regular-distributions-to-pypi-release-candidates)
- [Push the RC tags](#push-the-rc-tags)
+ - [Re-cut a candidate before the vote email is
sent](#re-cut-a-candidate-before-the-vote-email-is-sent)
- [Prepare documentation in Staging](#prepare-documentation-in-staging)
- [Prepare issue in GitHub to keep status of
testing](#prepare-issue-in-github-to-keep-status-of-testing)
- [Prepare voting email for Providers release
candidate](#prepare-voting-email-for-providers-release-candidate)
@@ -516,6 +517,22 @@ breeze release-management update-providers-next-version
> interactive breeze command instead of the skill. Run it regardless of
> whether you think any
> provider uses the `# use next version` comment — the command is a no-op when
> none do.
+The command only acts on lines the PR author marked. It does not notice when a
PR starts importing
+something from another provider (most often `common.compat`) without raising
the minimum version
+pin. That holds even for a provider that is **not** in this wave: its next
release ships with the
+old floor, and users who already have that older dependent provider installed
get an `ImportError`.
+For every new import from another provider in the wave's PRs, find the first
release that shipped
+the symbol and make sure the pin is at least that version:
+
+```shell script
+# The commit that introduced the symbol, then the first provider release tag
that contains it
+git log --reverse --format=%h -S "<symbol>" -- providers/common/compat/src |
head -1
+git tag --contains <commit> "providers-common-compat/*" --sort=v:refname |
grep -v rc | head -1
+```
+
+In the 2026-10-14 wave, `openai` imported `get_async_extra_dejson` but still
pinned
+`common.compat` below 1.21.0, the first release that has it.
+
## Create a PR with the changes
Make sure to set labels: `allow provider dependency bump` and `skip common
compat check` to the PR,
@@ -724,6 +741,11 @@ key you want to use.
```shell script
export RELEASE_DATE=$(date "+%Y-%m-%d%n")
export AIRFLOW_REPO_ROOT=$(pwd -P)
+# The merge commit of the release-prep PR. Tag and build exactly this commit,
never "whatever HEAD is".
+export WAVE_SHA=<sha>
+# The remote that `git remote -v` shows pushing to apache/airflow: `origin` in
a fresh clone
+export APACHE_REMOTE=<remote>
+git checkout ${WAVE_SHA}
rm -rf ${AIRFLOW_REPO_ROOT}/dist/*
```
@@ -732,13 +754,16 @@ rm -rf ${AIRFLOW_REPO_ROOT}/dist/*
These instructions assume the standard remote naming convention
(`upstream` → `apache/airflow`, `origin` → your fork — see
[`contributing-docs/10_working_with_git.rst`](../contributing-docs/10_working_with_git.rst#git-remote-naming-conventions)).
+A fresh `git clone` used for the build (see below) has only `origin`, pointing
at `apache/airflow`.
+Set `APACHE_REMOTE` below to whichever remote `git remote -v` shows pointing
at `apache/airflow` (a
+URL such as `[email protected]:apache/airflow.git` works too). Never push the
tags to your fork.
Set tags for the providers in the repo.
```shell script
echo "Tagging with providers/${RELEASE_DATE}"
-git tag -s providers/${RELEASE_DATE} -m "Tag providers for ${RELEASE_DATE}"
--force
-git push upstream providers/${RELEASE_DATE}
+git tag -s providers/${RELEASE_DATE} ${WAVE_SHA} -m "Tag providers for
${RELEASE_DATE}" --force
+git push ${APACHE_REMOTE} providers/${RELEASE_DATE}
breeze release-management prepare-provider-distributions
--include-removed-providers --distribution-format both --version-suffix ""
breeze release-management prepare-tarball --tarball-type
apache_airflow_providers --version "${RELEASE_DATE}"
```
@@ -768,8 +793,8 @@ if you only build few packages, run:
```shell script
echo "Tagging with providers/${RELEASE_DATE}"
-git tag -s providers/${RELEASE_DATE} -m "Tag providers for ${RELEASE_DATE}"
--force
-git push upstream providers/${RELEASE_DATE}
+git tag -s providers/${RELEASE_DATE} ${WAVE_SHA} -m "Tag providers for
${RELEASE_DATE}" --force
+git push ${APACHE_REMOTE} providers/${RELEASE_DATE}
breeze release-management prepare-provider-distributions
--include-removed-providers --distribution-format both --version-suffix ""
PACKAGE PACKAGE ....
breeze release-management prepare-tarball --tarball-type
apache_airflow_providers --version "${RELEASE_DATE}"
@@ -823,6 +848,10 @@ svn commit -m "Add artifacts for Airflow Providers
${RELEASE_DATE}"
cd "$AIRFLOW_REPO_ROOT"
```
+`svn commit` asks for your ASF password unless SVN has it cached, so run it in
your own terminal.
+From an agent session or a script without a terminal it fails with `E215004`
(authentication
+failed) instead of prompting.
+
Verify that the files are available in the ${RELEASE_DATE} folder under
[providers](https://dist.apache.org/repos/dist/dev/airflow/providers/)
@@ -914,6 +943,22 @@ twine check ${AIRFLOW_REPO_ROOT}/dist/*
read -rs TWINE_PASSWORD && export TWINE_PASSWORD # paste the token,
press Enter
```
+ `read -s` needs a terminal, so it cannot work when an agent or a script
runs the upload for
+ you. In that case, use Magpie's
+
[`secret-prompt`](https://github.com/apache/magpie/tree/main/tools/secret-prompt)
instead of the
+ two exports. It asks for the token in the terminal or, when there is
none, in a dialog (macOS
+ `osascript`, Linux `zenity`/`kdialog`, or `pinentry`). It shows the exact
command that will
+ receive the token and passes the token only to that command, so the token
never lands in your
+ shell, a file or the agent's transcript. Install it once, then prefix
`twine upload` in the
+ command below:
+
+ ```shell script
+ uv tool install
"git+https://github.com/apache/magpie#subdirectory=tools/secret-prompt"
+ # ... then, in the upload command below, replace "twine upload" with:
+ secret-prompt --env TWINE_PASSWORD --set TWINE_USERNAME=__token__
--prefix pypi- \
+ --title "PyPI upload" --prompt "Paste the single-use PyPI token" --
twine upload
+ ```
+
4. Run the upload (below).
5. **Delete the token** at
[Account settings → API
tokens](https://pypi.org/manage/account/#api-tokens) and run
@@ -972,8 +1017,41 @@ Verify the pushed tags point where you think they do.
Plain `git ls-remote` prin
SHA for annotated tags, which never matches the commit and looks alarming;
dereference it with `^{}`:
```shell script
-git ls-remote upstream "refs/tags/providers-<PROVIDER>/<VERSION>^{}"
-```
+git ls-remote ${APACHE_REMOTE} "refs/tags/providers-<PROVIDER>/<VERSION>^{}"
+```
+
+## Re-cut a candidate before the vote email is sent
+
+When a problem turns up after the candidates are built and staged but
**before** the vote email has
+gone out, you can rebuild the same wave instead of starting a new one. Nobody
has started verifying
+it yet. Merge the fix, then:
+
+* Keep `RELEASE_DATE`. The SVN folder, the wave tag and the vote email keep
their names.
+* Check that the fix is the only change to the wave's providers since the
original build:
+ `git log --oneline <old WAVE_SHA>..<new commit> -- providers/<provider>
...`. Anything else listed
+ would ship untested and missing from the changelog and the testing issue:
either fold it in
+ (changelog entries, testing-issue rows) or apply the fix on a branch cut
from the old `WAVE_SHA`
+ and tag that commit instead.
+* Set `WAVE_SHA` to the new commit and move the wave tag there:
+ `git tag -s -f providers/${RELEASE_DATE} ${WAVE_SHA} -m "Tag providers for
${RELEASE_DATE}"`, then
+ `git push --force ${APACHE_REMOTE} refs/tags/providers/${RELEASE_DATE}`.
+* Check out the new commit (`git checkout ${WAVE_SHA}`, and confirm with `git
rev-parse HEAD`), then
+ re-run the [build and
sign](#build-and-sign-the-source-and-convenience-packages) steps from the
+ cleanup of `dist/` onwards, minus the wave tag you just moved. Skip the
`export RELEASE_DATE=...`
+ line there and keep the original date, or a re-cut on a later day renames
the tarball.
+* In `dev/airflow/providers/${RELEASE_DATE}`, `svn rm` the files of any
provider or version that is no
+ longer in the wave, copy the new build over the rest, and commit (`svn add
--force .` picks up any
+ new files). The filenames carry no `rcN`, so unchanged providers' files are
simply replaced.
+* PyPI never lets you reuse a filename, so publish the next candidate number
(`rc2` → `rc3`), and pass
+ it explicitly as `--version-suffix rc3`: breeze only moves past an rcN whose
tag exists locally,
+ and the previous candidate's tags may not have been created yet. If the
wave's providers are at
+ different candidate numbers, build each group with its own next suffix. The
previous `rcN` stays on PyPI,
+ and its tags stay in git if they were pushed. Nobody voted on it, and the
vote email names only the
+ new one.
+* Push the new RC tags at `${WAVE_SHA}` and republish the staging docs.
+
+Once the vote email is out, do not do this: cancel the vote and run a new
wave, or remove the
+provider from it.
## Prepare documentation in Staging
@@ -1104,6 +1182,11 @@ sed -i '' -E "s/- \[ \] (.*\(#(${checked})\))/- [x] \1/"
files/provider_issue.md
sed -i -E "s/- \[ \] (.*\(#(${checked})\))/- [x] \1/" files/provider_issue.md
```
+Testers do not always tick the box: some confirm a PR in a comment instead
("tested #12345, works").
+Before you extract the ticks, read the previous issue's comments and tick any
PR confirmed there in
+the previous issue itself, so the record is complete and the extraction picks
it up. In the
+2026-10-14 wave, five such PRs were confirmed only in comments.
+
Review the resulting `[x]` lines in `files/provider_issue.md` (PRs only
present in the new wave stay
unchecked). If the issue was already created, apply the same local edit and
then edit the online issue as described in Step 3.
@@ -1933,6 +2016,9 @@ twine check ${AIRFLOW_REPO_ROOT}/dist/*.whl
${AIRFLOW_REPO_ROOT}/dist/*.tar.gz
read -rs TWINE_PASSWORD && export TWINE_PASSWORD # paste the token,
press Enter
```
+ When an agent or a script without a terminal runs the upload, use
`secret-prompt` instead, as
+ described in the [release candidate
upload](#publish-the-regular-distributions-to-pypi-release-candidates).
+
4. Run the upload (below).
5. **Delete the token** at
[Account settings → API
tokens](https://pypi.org/manage/account/#api-tokens) and run
@@ -1990,7 +2076,7 @@ breeze release-management tag-providers --release-date
${RELEASE_DATE}
Then confirm each pushed tag resolves to the wave commit (`^{}` dereferences
the annotated tag):
```shell script
-git ls-remote upstream "refs/tags/providers-<PROVIDER>/<VERSION>^{}"
+git ls-remote "${APACHE_REMOTE:?set it to the remote that pushes to
apache/airflow}" "refs/tags/providers-<PROVIDER>/<VERSION>^{}"
```
## Update airflow-site index for new providers