Oh... I am glad it worked this time :) !!! :D Thanks Wei Lee, Buğra... I was afraid something more was broken :)
J. On Thu, Apr 23, 2026 at 9:29 PM Buğra Öztürk <[email protected]> wrote: > +1 (binding), I have checked the following. > - SVN > - Reproducible package build > - Licenses > - Signatures > - Checksums > > I ran a couple of airflowctl management commands with 3.2.1, looks good. > > Bugra Ozturk > Kind regards, > > On Thu, Apr 23, 2026 at 12:18 PM Wei Lee <[email protected]> wrote: > > > +1 (binding), checked: > > > > - Reproducible build > > - SVN > > - Licenses > > - Signatures > > - Checksums > > > > Best regards, > > Wei Lee > > > > Jarek Potiuk <[email protected]> 於 2026年4月23日週四 上午8:23寫道: > > > > > Ok. I think those were accidentally uncommitted binaries - and instead > of > > > rc3, I still had the old rc2 :( > > > I think I missed an error when copying files. > > > > > > It's fantastic that we have reproducibility checks - otherwise we might > > not > > > have found it. Thanks for flagging it Jens! > > > > > > It should all be fixed now. The PyPI packages were correct. > > > > > > Let me restart the voting. The new date for the Vote passing is Monday, > > > 2026-04-27 23:59 UTC. > > > > > > Consider this my (binding) +1. > > > > > > > > > > > > > > > > > > > > > > > > On Wed, Apr 22, 2026 at 8:13 PM Jarek Potiuk <[email protected]> wrote: > > > > > > > Thanks. Will take a look ! > > > > > > > > On Wed, Apr 22, 2026 at 8:12 PM Jens Scheffler <[email protected]> > > > > wrote: > > > > > > > >> Hi Jarek, > > > >> > > > >> i attempted to run PMC Checks but I fail in reproducibility - so > > until I > > > >> know I'd do something wrong I'd need to vote a -1: > > > >> > > > >> SVN: revision 83981. > > > >> > > > >> Branch/Git: tag: airflow-ctl/0.1.4rc3 > > > >> ca53e01b3c8bb00a3ca697b508ab52cdd28f5e68 > > > >> > > > >> Checking if apache_airflow_ctl-0.1.4-py3-none-any.whl is the same as > > > >> > > > >> > > > > > > /home/jscheffl/Workspace/airflow/dist/apache_airflow_ctl-0.1.4-py3-none-any.whl > > > >> Binary files apache_airflow_ctl-0.1.4-py3-none-any.whl and > > > >> > > > > > > /home/jscheffl/Workspace/airflow/dist/apache_airflow_ctl-0.1.4-py3-none-any.whl > > > >> > > > >> differ > > > >> > > > >> Checking if apache_airflow_ctl-0.1.4-source.tar.gz is the same as > > > >> > > > >> > > > > > > /home/jscheffl/Workspace/airflow/dist/apache_airflow_ctl-0.1.4-source.tar.gz > > > >> Binary files apache_airflow_ctl-0.1.4-source.tar.gz and > > > >> > > > > > > /home/jscheffl/Workspace/airflow/dist/apache_airflow_ctl-0.1.4-source.tar.gz > > > >> > > > >> differ > > > >> > > > >> Checking if apache_airflow_ctl-0.1.4.tar.gz is the same as > > > >> > /home/jscheffl/Workspace/airflow/dist/apache_airflow_ctl-0.1.4.tar.gz > > > >> Binary files apache_airflow_ctl-0.1.4.tar.gz and > > > >> > /home/jscheffl/Workspace/airflow/dist/apache_airflow_ctl-0.1.4.tar.gz > > > >> differ > > > >> > > > >> Did I pick the wrong package or branch? > > > >> > > > >> For the WHL file diffoscope tells me: > > > >> > > > >> * a lot of file meta data differences > > > >> o -rw-r--r-- 2.0 unx 1705 b- defN 26-Apr-13 12:48 > > > >> airflowctl/exceptions.py > > > >> to > > > >> o -rw-r--r-- 2.0 unx 1705 b- defN 26-Apr-20 11:13 > > > >> airflowctl/exceptions.py > > > >> * Diff in api/datamodels/generated.py > > > >> > > > >> ├── airflowctl/api/datamodels/generated.py > > > >> │ @@ -169,15 +169,14 @@ > > > >> │ bool | None, > > > >> │ Field( > > > >> │ description="(Experimental) Run on the latest bundle > > > >> version of the dag after clearing the task instances.", > > > >> │ title="Run On Latest Version", > > > >> │ ), > > > >> │ ] = False > > > >> │ prevent_running_task: Annotated[bool | None, > > Field(title="Prevent > > > >> Running Task")] = False > > > >> │ - note: Annotated[Note | None, Field(title="Note")] = None > > > >> │ > > > >> │ > > > >> │ class Value(RootModel[list]): > > > >> │ root: Annotated[list, Field(max_length=2, min_length=2, > > > >> title="Value")] > > > >> │ > > > >> │ > > > >> │ class ConfigOption(BaseModel): > > > >> │ @@ -284,21 +283,14 @@ > > > >> │ """ > > > >> │ > > > >> │ model_config = ConfigDict( > > > >> │ extra="forbid", > > > >> │ ) > > > >> │ dry_run: Annotated[bool | None, Field(title="Dry Run")] = > True > > > >> │ only_failed: Annotated[bool | None, Field(title="Only > > Failed")] = > > > >> False > > > >> │ - only_new: Annotated[ > > > >> │ - bool | None, > > > >> │ - Field( > > > >> │ - description="Only queue newly added tasks in the > latest > > > >> DAG version without clearing existing tasks.", > > > >> │ - title="Only New", > > > >> │ - ), > > > >> │ - ] = False > > > >> │ run_on_latest_version: Annotated[ > > > >> │ bool | None, > > > >> │ Field( > > > >> │ description="(Experimental) Run on the latest bundle > > > >> version of the Dag after clearing the Dag Run.", > > > >> │ title="Run On Latest Version", > > > >> │ ), > > > >> │ ] = False > > > >> │ @@ -398,15 +390,14 @@ > > > >> │ """ > > > >> │ Class with DagRun types. > > > >> │ """ > > > >> │ > > > >> │ BACKFILL = "backfill" > > > >> │ SCHEDULED = "scheduled" > > > >> │ MANUAL = "manual" > > > >> │ - OPERATOR_TRIGGERED = "operator_triggered" > > > >> │ ASSET_TRIGGERED = "asset_triggered" > > > >> │ ASSET_MATERIALIZATION = "asset_materialization" > > > >> │ > > > >> │ > > > >> │ class DagScheduleAssetReference(BaseModel): > > > >> │ """ > > > >> │ DAG schedule reference serializer for assets. > > > >> │ @@ -643,23 +634,14 @@ > > > >> │ logical_date: Annotated[datetime | None, Field(title="Logical > > > >> Date")] = None > > > >> │ run_after: Annotated[datetime | None, Field(title="Run > > After")] = > > > >> None > > > >> │ conf: Annotated[dict[str, Any] | None, Field(title="Conf")] = > > > None > > > >> │ note: Annotated[str | None, Field(title="Note")] = None > > > >> │ partition_key: Annotated[str | None, Field(title="Partition > > > >> Key")] = None > > > >> │ > > > >> │ > > > >> │ -class NewTaskResponse(BaseModel): > > > >> │ - """ > > > >> │ - Lightweight response for new tasks that don't have > > TaskInstances > > > >> yet. > > > >> │ - """ > > > >> │ - > > > >> │ - task_id: Annotated[str, Field(title="Task Id")] > > > >> │ - task_display_name: Annotated[str, Field(title="Task Display > > > Name")] > > > >> │ - > > > >> │ - > > > >> │ class PluginImportErrorResponse(BaseModel): > > > >> │ """ > > > >> │ Plugin Import Error serializer for responses. > > > >> │ """ > > > >> │ > > > >> │ source: Annotated[str, Field(title="Source")] > > > >> │ error: Annotated[str, Field(title="Error")] > > > >> │ @@ -1144,15 +1126,15 @@ > > > >> │ model_config = ConfigDict( > > > >> │ extra="forbid", > > > >> │ ) > > > >> │ dag_id: Annotated[str, Field(title="Dag Id")] > > > >> │ from_date: Annotated[datetime, Field(title="From Date")] > > > >> │ to_date: Annotated[datetime, Field(title="To Date")] > > > >> │ run_backwards: Annotated[bool | None, Field(title="Run > > > >> Backwards")] = False > > > >> │ - dag_run_conf: Annotated[dict[str, Any] | None, > Field(title="Dag > > > >> Run Conf")] = None > > > >> │ + dag_run_conf: Annotated[dict[str, Any] | None, > Field(title="Dag > > > >> Run Conf")] = {} > > > >> │ reprocess_behavior: ReprocessBehavior | None = "none" > > > >> │ max_active_runs: Annotated[int | None, Field(title="Max > Active > > > >> Runs")] = 10 > > > >> │ run_on_latest_version: Annotated[bool | None, > Field(title="Run > > On > > > >> Latest Version")] = True > > > >> │ > > > >> │ > > > >> │ class BackfillResponse(BaseModel): > > > >> │ """ > > > >> │ @@ -1390,15 +1372,14 @@ > > > >> │ bundle_version: Annotated[str | None, Field(title="Bundle > > > >> Version")] = None > > > >> │ relative_fileloc: Annotated[str | None, Field(title="Relative > > > >> Fileloc")] = None > > > >> │ fileloc: Annotated[str, Field(title="Fileloc")] > > > >> │ description: Annotated[str | None, > Field(title="Description")] > > = > > > >> None > > > >> │ timetable_summary: Annotated[str | None, > Field(title="Timetable > > > >> Summary")] = None > > > >> │ timetable_description: Annotated[str | None, > > > >> Field(title="Timetable Description")] = None > > > >> │ timetable_partitioned: Annotated[bool, Field(title="Timetable > > > >> Partitioned")] > > > >> │ - timetable_periodic: Annotated[bool, Field(title="Timetable > > > >> Periodic")] > > > >> │ tags: Annotated[list[DagTagResponse], Field(title="Tags")] > > > >> │ max_active_tasks: Annotated[int, Field(title="Max Active > > Tasks")] > > > >> │ max_active_runs: Annotated[int | None, Field(title="Max > Active > > > >> Runs")] = None > > > >> │ max_consecutive_failed_dag_runs: Annotated[int, > > Field(title="Max > > > >> Consecutive Failed Dag Runs")] > > > >> │ has_task_concurrency_limits: Annotated[bool, Field(title="Has > > > >> Task Concurrency Limits")] > > > >> │ has_import_errors: Annotated[bool, Field(title="Has Import > > > >> Errors")] > > > >> │ next_dagrun_logical_date: Annotated[datetime | None, > > > >> Field(title="Next Dagrun Logical Date")] = None > > > >> │ @@ -1423,17 +1404,14 @@ > > > >> │ template_search_path: Annotated[list[str] | None, > > > >> Field(title="Template Search Path")] = None > > > >> │ timezone: Annotated[str | None, Field(title="Timezone")] = > None > > > >> │ last_parsed: Annotated[datetime | None, Field(title="Last > > > >> Parsed")] = None > > > >> │ default_args: Annotated[dict[str, Any] | None, > > > >> Field(title="Default Args")] = None > > > >> │ owner_links: Annotated[dict[str, str] | None, > > Field(title="Owner > > > >> Links")] = None > > > >> │ is_favorite: Annotated[bool | None, Field(title="Is > > Favorite")] = > > > >> False > > > >> │ active_runs_count: Annotated[int | None, Field(title="Active > > Runs > > > >> Count")] = 0 > > > >> │ - is_backfillable: Annotated[ > > > >> │ - bool, Field(description="Whether this DAG's schedule > > supports > > > >> backfilling.", title="Is Backfillable") > > > >> │ - ] > > > >> │ file_token: Annotated[str, Field(description="Return file > > > >> token.", title="File Token")] > > > >> │ concurrency: Annotated[ > > > >> │ int, > > > >> │ Field( > > > >> │ description="Return max_active_tasks as > > > >> concurrency.\n\nDeprecated: Use max_active_tasks instead.", > > > >> │ title="Concurrency", > > > >> │ ), > > > >> │ @@ -1459,15 +1437,14 @@ > > > >> │ bundle_version: Annotated[str | None, Field(title="Bundle > > > >> Version")] = None > > > >> │ relative_fileloc: Annotated[str | None, Field(title="Relative > > > >> Fileloc")] = None > > > >> │ fileloc: Annotated[str, Field(title="Fileloc")] > > > >> │ description: Annotated[str | None, > Field(title="Description")] > > = > > > >> None > > > >> │ timetable_summary: Annotated[str | None, > Field(title="Timetable > > > >> Summary")] = None > > > >> │ timetable_description: Annotated[str | None, > > > >> Field(title="Timetable Description")] = None > > > >> │ timetable_partitioned: Annotated[bool, Field(title="Timetable > > > >> Partitioned")] > > > >> │ - timetable_periodic: Annotated[bool, Field(title="Timetable > > > >> Periodic")] > > > >> │ tags: Annotated[list[DagTagResponse], Field(title="Tags")] > > > >> │ max_active_tasks: Annotated[int, Field(title="Max Active > > Tasks")] > > > >> │ max_active_runs: Annotated[int | None, Field(title="Max > Active > > > >> Runs")] = None > > > >> │ max_consecutive_failed_dag_runs: Annotated[int, > > Field(title="Max > > > >> Consecutive Failed Dag Runs")] > > > >> │ has_task_concurrency_limits: Annotated[bool, Field(title="Has > > > >> Task Concurrency Limits")] > > > >> │ has_import_errors: Annotated[bool, Field(title="Has Import > > > >> Errors")] > > > >> │ next_dagrun_logical_date: Annotated[datetime | None, > > > >> Field(title="Next Dagrun Logical Date")] = None > > > >> │ @@ -1476,17 +1453,14 @@ > > > >> │ ] = None > > > >> │ next_dagrun_data_interval_end: Annotated[ > > > >> │ datetime | None, Field(title="Next Dagrun Data Interval > > End") > > > >> │ ] = None > > > >> │ next_dagrun_run_after: Annotated[datetime | None, > > > >> Field(title="Next Dagrun Run After")] = None > > > >> │ allowed_run_types: Annotated[list[DagRunType] | None, > > > >> Field(title="Allowed Run Types")] = None > > > >> │ owners: Annotated[list[str], Field(title="Owners")] > > > >> │ - is_backfillable: Annotated[ > > > >> │ - bool, Field(description="Whether this DAG's schedule > > supports > > > >> backfilling.", title="Is Backfillable") > > > >> │ - ] > > > >> │ file_token: Annotated[str, Field(description="Return file > > > >> token.", title="File Token")] > > > >> │ > > > >> │ > > > >> │ class DAGRunPatchBody(BaseModel): > > > >> │ """ > > > >> │ DAG Run Serializer for PATCH requests. > > > >> │ """ > > > >> │ @@ -1954,23 +1928,14 @@ > > > >> │ entities: Annotated[ > > > >> │ list[str | BulkTaskInstanceBody], > > > >> │ Field(description="A list of entity id/key or entity > > objects > > > >> to be deleted.", title="Entities"), > > > >> │ ] > > > >> │ action_on_non_existence: BulkActionNotOnExistence | None = > > "fail" > > > >> │ > > > >> │ > > > >> │ -class ClearTaskInstanceCollectionResponse(BaseModel): > > > >> │ - """ > > > >> │ - Response for clear dag run dry run, which may contain new > tasks > > > >> without full TaskInstance data. > > > >> │ - """ > > > >> │ - > > > >> │ - task_instances: Annotated[list[TaskInstanceResponse | > > > >> NewTaskResponse], Field(title="Task Instances")] > > > >> │ - total_entries: Annotated[int, Field(title="Total Entries")] > > > >> │ - > > > >> │ - > > > >> │ class DAGCollectionResponse(BaseModel): > > > >> │ """ > > > >> │ DAG Collection serializer for responses. > > > >> │ """ > > > >> │ > > > >> │ dags: Annotated[list[DAGResponse], Field(title="Dags")] > > > >> │ total_entries: Annotated[int, Field(title="Total Entries")] > > > >> │ @@ -2070,46 +2035,19 @@ > > > >> │ > > > >> │ tasks: Annotated[list[TaskResponse], Field(title="Tasks")] > > > >> │ total_entries: Annotated[int, Field(title="Total Entries")] > > > >> │ > > > >> │ > > > >> │ class TaskInstanceCollectionResponse(BaseModel): > > > >> │ """ > > > >> │ - Task instance collection response supporting both offset and > > > >> cursor pagination. > > > >> │ - > > > >> │ - A single flat model is used instead of a discriminated union > > > >> │ - (``Annotated[Offset | Cursor, Field(discriminator=...)]``) > > > because > > > >> │ - the OpenAPI ``oneOf`` + ``discriminator`` construct is not > > > handled > > > >> │ - correctly by ``@hey-api/openapi-ts`` / > > > >> ``@7nohe/openapi-react-query-codegen``: > > > >> │ - return types degrade to ``unknown`` in JSDoc and can produce > > > >> │ - incorrect TypeScript types (see hey-api/openapi-ts#1613, > > #3270). > > > >> │ + Task Instance Collection serializer for responses. > > > >> │ """ > > > >> │ > > > >> │ task_instances: Annotated[list[TaskInstanceResponse], > > > >> Field(title="Task Instances")] > > > >> │ - total_entries: Annotated[ > > > >> │ - int | None, > > > >> │ - Field( > > > >> │ - description="Total number of matching items. > Populated > > > >> for offset pagination, ``null`` when using cursor pagination.", > > > >> │ - title="Total Entries", > > > >> │ - ), > > > >> │ - ] = None > > > >> │ - next_cursor: Annotated[ > > > >> │ - str | None, > > > >> │ - Field( > > > >> │ - description="Token pointing to the next page. > Populated > > > >> for cursor pagination, ``null`` when using offset pagination or when > > > >> there is no next page.", > > > >> │ - title="Next Cursor", > > > >> │ - ), > > > >> │ - ] = None > > > >> │ - previous_cursor: Annotated[ > > > >> │ - str | None, > > > >> │ - Field( > > > >> │ - description="Token pointing to the previous page. > > > >> Populated for cursor pagination, ``null`` when using offset > pagination > > > >> or when on the first page.", > > > >> │ - title="Previous Cursor", > > > >> │ - ), > > > >> │ - ] = None > > > >> │ + total_entries: Annotated[int, Field(title="Total Entries")] > > > >> │ > > > >> │ > > > >> │ class TaskInstanceHistoryCollectionResponse(BaseModel): > > > >> │ """ > > > >> │ TaskInstanceHistory Collection serializer for responses. > > > >> │ """ > > > >> > > > >> On 22.04.26 01:55, Jarek Potiuk wrote: > > > >> > The release candidate for **Apache Airflow Ctl**: 0.1.4rc3 is now > > > >> > available for testing! > > > >> > > > > >> > This email is calling for a vote on the release, which will last > at > > > >> least until > > > >> > Friday, 2026-04-24 23:59 UTC and until 3 binding +1 votes have > been > > > >> received. > > > >> > > > > >> > Consider this my +1 (binding) vote. > > > >> > > > > >> > The apache-airflow-ctl 0.1.4rc3 package is available at: > > > >> > > > https://dist.apache.org/repos/dist/dev/airflow/airflow-ctl/0.1.4rc3/ > > > >> > > > > >> > The "apache-airflow-ctl" packages are: > > > >> > > > > >> > - *apache_airflow_ctl-0.1.4-source.tar.gz* is a source release > > > that > > > >> comes > > > >> > with INSTALL instructions. > > > >> > - *apache_airflow_ctl-0.1.4.tar.gz* is the binary Python > "sdist" > > > >> release. > > > >> > - *apache_airflow_ctl-0.1.4-py3-none-any.whl* is the binary > > Python > > > >> wheel > > > >> > "binary" release. > > > >> > > > > >> > Public keys are available at: > > > >> > https://dist.apache.org/repos/dist/release/airflow/KEYS > > > >> > > > > >> > Please vote accordingly: > > > >> > > > > >> > [ ] +1 approve > > > >> > [ ] +0 no opinion > > > >> > [ ] -1 disapprove with the reason > > > >> > > > > >> > Only votes from PMC members are binding, but all members of the > > > >> community are > > > >> > encouraged to test the release and vote with "(non-binding)". > > > >> > > > > >> > The test procedure for PMC members is described in: > > > >> > > > > >> > > > > > > https://github.com/apache/airflow/blob/main/dev/README_RELEASE_AIRFLOWCTL.md#verify-the-release-candidate-by-pmc-members > > > >> > > > > >> > The test procedure for contributors and members of the community > who > > > >> would > > > >> > like to test this RC is described in: > > > >> > > > > >> > > > > > > https://github.com/apache/airflow/blob/main/dev/README_RELEASE_AIRFLOWCTL.md#verify-the-release-candidate-by-contributors > > > >> > > > > >> > Please note that the version number excludes the 'rcX' string, so > > it's > > > >> now > > > >> > simply 0.1.4 for the apache-airflow-ctl package. This will allow > us > > to > > > >> rename > > > >> > the artifact without modifying the artifact checksums when we > > actually > > > >> release. > > > >> > > > > >> > Testing status issue: > > > >> > https://github.com/apache/airflow/issues/65643 > > > >> > > > > >> > *Docs* (for preview): > > > >> > > > > >> > > > > > > https://airflow.staged.apache.org/docs/apache-airflow-ctl/0.1.4/index.html > > > >> > > > > >> > *Release Notes*: > > > >> > > > > >> > > > > > > https://github.com/apache/airflow/blob/airflow-ctl/0.1.4rc3/airflow-ctl/RELEASE_NOTES.rst > > > >> > > > > >> > *Testing Instructions using PyPI*: > > > >> > > > > >> > The packages are available in PyPI: > > > >> > https://pypi.org/project/apache-airflow-ctl/0.1.4rc3/ > > > >> > > > > >> > You can build a virtualenv that installs this and other required > > > >> packages > > > >> > like this: > > > >> > > > > >> > uv venv > > > >> > uv pip install -U apache-airflow-ctl==0.1.4rc3 > > > >> > > > > >> > Regards, > > > >> > Jarek > > > >> > > > > >> > > > --------------------------------------------------------------------- > > > >> > To unsubscribe, e-mail:[email protected] > > > >> > For additional commands, e-mail:[email protected] > > > >> > > > > > > > > > > > > > > >
