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]

Reply via email to