mennanov opened a new pull request, #75571:
URL: https://github.com/apache/airflow/pull/75571
Depends on #75570, which adds the blockwatch hook. Until that PR merges,
this one also shows its commit; only the last commit is new here.
This PR enforces the "keep in sync" comments in the codebase and fixes 2
already out-of-sync values.
#### Rules
##### Cron presets
The Task SDK can't import from core, so it keeps its own copy of the dict.
Both dicts must hold the same lines.
```python
# airflow-core/src/airflow/utils/dates.py
cron_presets: dict[str, str] = {
"@hourly": "0 * * * *",
"@daily": "0 0 * * *",
...
}
```
```python
# task-sdk/src/airflow/sdk/definitions/timetables/_cron.py
CRON_PRESETS: dict[str, str] = {
"@hourly": "0 * * * *",
"@daily": "0 0 * * *",
...
}
```
##### Decorators `__all__`
Both lists must hold the same names, in the same order.
```python
# task-sdk/src/airflow/sdk/definitions/decorators/__init__.py
__all__ = [
"TaskDecorator",
"TaskDecoratorCollection",
...
]
```
```python
# task-sdk/src/airflow/sdk/definitions/decorators/__init__.pyi
__all__ = [
"TaskDecorator",
"TaskDecoratorCollection",
...
]
```
##### Backfill exception reasons
The UI translates each reason in a `switch`. The enum values and the `case`
strings must be the same set.
```python
# airflow-core/src/airflow/models/backfill.py
class BackfillDagRunExceptionReason(str, Enum):
IN_FLIGHT = "in flight" # ←
ALREADY_EXISTS = "already exists" # ←
UNKNOWN = "unknown" # ←
```
```tsx
//
airflow-core/src/airflow/ui/src/pages/Dag/Backfills/BackfillDagRunsModal.tsx
switch (reason) {
case "already exists": // ←
return translate("components:backfill.exceptionReason.alreadyExists");
case "in flight": // ←
return translate("components:backfill.exceptionReason.inFlight");
case "unknown": // ←
return translate("components:backfill.exceptionReason.unknown");
default:
return reason;
}
```
##### Browse menu titles
The menu shows a link only when its `title` is one of the `MenuItem` values
the user may see. The title is cast with `as MenuItem`, so TypeScript doesn't
catch a typo, and the link would just never show. Every title must be a
`MenuItem` value, but `MenuItem` may hold items this menu doesn't show.
```python
# airflow-core/src/airflow/api_fastapi/common/types.py
class MenuItem(Enum):
...
DAG_BUNDLES = "Dag Bundles" # ←
DEADLINES = "Deadlines" # ←
...
```
```tsx
// airflow-core/src/airflow/ui/src/layouts/Nav/BrowseButton.tsx
const links = [
...
{
href: "/dag_bundles",
key: "dagBundles",
title: "Dag Bundles", // ←
},
...
{
href: "/deadlines",
key: "deadlines",
title: "Deadlines", // ←
},
...
];
```
##### Registry `normalize()`
Two copies run in the browser and one at build time under CommonJS, so they
can't share code. All three must be the same, ignoring indentation.
```js
// registry/src/_data/providerKeywordMatch.js
function normalize(text) {
return text.toLowerCase().replace(/[-_\s]+/g, ' ');
}
```
```js
// registry/src/js/search.js and registry/src/js/provider-filters.js
function normalize(text) {
return text.toLowerCase().replace(/[-_\s]+/g, ' ');
}
```
##### `REFERENCE_TYPE_FIELD`
The SDK constant is the source, and the two copies in core must match it.
```python
# task-sdk/src/airflow/sdk/definitions/deadline.py
REFERENCE_TYPE_FIELD = "reference_type"
```
```python
# airflow-core/src/airflow/models/deadline.py and
airflow-core/src/airflow/serialization/definitions/deadline.py
REFERENCE_TYPE_FIELD = "reference_type"
```
##### Kubernetes node port
```python
# dev/breeze/src/airflow_breeze/utils/kubernetes_utils.py
FORWARDED_NODE_PORT = 30007
```
```yaml
# scripts/ci/kubernetes/nodeport.yaml
spec:
ports:
- port: 8080
targetPort: 8080
nodePort: 30007 # ←
```
##### Node for the TypeScript SDK docs
The major version must match.
```python
# dev/breeze/src/airflow_breeze/global_constants.py
TYPESCRIPT_SDK_NODE_VERSION = "22"
```
```jsonc
// ts-sdk/package.json
"engines": {
"node": ">=22" // ←
},
```
##### Node for the TypeScript SDK in CI
The `node-version` of the Node setup step must match in all four jobs. Like
the Go and Java pins in #75570, this rule is in `blockwatch.toml`.
```yaml
# .github/workflows/ts-sdk-release.yml (the build and publish jobs)
# .github/workflows/ci-amd.yml and .github/workflows/ci-arm.yml (the
tests-ts-sdk job)
node-version: "24.19.0"
```
##### pnpm
Every pnpm pin must equal `PNPM_VERSION`, the version the CI and PROD images
install. `package.json` can't hold a comment, so these rules are also in
`blockwatch.toml`.
```dockerfile
# Dockerfile.ci (Dockerfile and scripts/docker/install_os_dependencies.sh
have the first line)
PNPM_VERSION=${PNPM_VERSION:-10.28.1}
...
ENV PNPM_VERSION="10.28.1"
```
```jsonc
// The 8 package.json files that pin pnpm, such as
airflow-core/src/airflow/ui/package.json
"packageManager": "[email protected]",
```
```yaml
# .pre-commit-config.yaml in the root, airflow-core/, providers/common/ai/,
providers/edge3/, providers/fab/ and ts-sdk/
additional_dependencies: ['[email protected]']
```
A new `package.json` that pins pnpm has to be added to the rule in
`blockwatch.toml`: a `**/package.json` glob would also match packages that
don't pin it.
#### Drift fixed
- The Common AI UI pinned `[email protected]`. Its `package.json` sets
`minimumReleaseAge`, which pnpm added in 10.16.0, so that guard did nothing
there. It now pins `10.28.1`, like the images and every other UI. `pnpm install
--frozen-lockfile` with 10.28.1 leaves `pnpm-lock.yaml` unchanged.
- Nine prek hooks in four configs installed `[email protected]`. They now install
`10.28.1`.
#### Testing
`blockwatch` passes. For each rule I made a one-sided edit (18 in total,
such as a new enum member, a nav title typo, a different `nodePort`, or a hook
back on 10.25.0) and blockwatch failed on exactly the files out of sync. The
fast prek checks pass. I left mypy and `generate-openapi-spec` to CI, since the
Python changes are comments only.
---
##### Was generative AI tooling used to co-author this PR?
- [X] Yes — Claude Code (Opus 5.5)
Generated-by: Claude Code (Opus 5.5) following [the
guidelines](https://github.com/apache/airflow/blob/main/contributing-docs/05_pull_requests.rst#gen-ai-assisted-contributions)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]