From 05e8fbdda186759ed88812598f1fc5f884c7fd40 Mon Sep 17 00:00:00 2001 From: Jens Scheffler Date: Sat, 23 Aug 2025 17:22:31 +0200 Subject: [PATCH] Consolidate scripts to generate openapi specs --- .pre-commit-config.yaml | 4 +- .../ci/prek/generate_openapi_spec_keycloak.py | 38 -------- ....py => generate_openapi_spec_providers.py} | 2 +- .../run_generate_openapi_spec_fab.py | 45 --------- .../run_generate_openapi_spec_keycloak.py | 45 --------- .../run_generate_openapi_spec_providers.py | 92 +++++++++++++++++++ 6 files changed, 95 insertions(+), 131 deletions(-) delete mode 100755 scripts/ci/prek/generate_openapi_spec_keycloak.py rename scripts/ci/prek/{generate_openapi_spec_fab.py => generate_openapi_spec_providers.py} (96%) delete mode 100755 scripts/in_container/run_generate_openapi_spec_fab.py delete mode 100755 scripts/in_container/run_generate_openapi_spec_keycloak.py create mode 100755 scripts/in_container/run_generate_openapi_spec_providers.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4c3eea9d68691..ca5c7b290d88c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1514,14 +1514,14 @@ repos: - id: generate-openapi-spec-fab name: Generate the FastAPI API spec for FAB language: python - entry: ./scripts/ci/prek/generate_openapi_spec_fab.py + entry: ./scripts/ci/prek/generate_openapi_spec_providers.py fab pass_filenames: false files: ^providers/fab/src/airflow/providers/fab/auth_manager/api_fastapi/.*\.py$ additional_dependencies: ['rich>=12.4.4', 'openapi-spec-validator>=0.7.1'] - id: generate-openapi-spec-keycloak name: Generate the FastAPI API spec for Keycloak language: python - entry: ./scripts/ci/prek/generate_openapi_spec_keycloak.py + entry: ./scripts/ci/prek/generate_openapi_spec_providers.py keycloak pass_filenames: false files: ^providers/keycloak/src/airflow/providers/keycloak/auth_manager/.*\.py$ additional_dependencies: [ 'rich>=12.4.4', 'openapi-spec-validator>=0.7.1' ] diff --git a/scripts/ci/prek/generate_openapi_spec_keycloak.py b/scripts/ci/prek/generate_openapi_spec_keycloak.py deleted file mode 100755 index 40ed55eef8528..0000000000000 --- a/scripts/ci/prek/generate_openapi_spec_keycloak.py +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -from __future__ import annotations - -import sys -from pathlib import Path - -sys.path.insert(0, str(Path(__file__).parent.resolve())) -from common_prek_utils import ( - initialize_breeze_prek, - run_command_via_breeze_shell, - validate_cmd_result, -) - -initialize_breeze_prek(__name__, __file__) - -cmd_result = run_command_via_breeze_shell( - ["python3", "/opt/airflow/scripts/in_container/run_generate_openapi_spec_keycloak.py"], - backend="postgres", - skip_environment_initialization=False, -) - -validate_cmd_result(cmd_result) diff --git a/scripts/ci/prek/generate_openapi_spec_fab.py b/scripts/ci/prek/generate_openapi_spec_providers.py similarity index 96% rename from scripts/ci/prek/generate_openapi_spec_fab.py rename to scripts/ci/prek/generate_openapi_spec_providers.py index 34b28c6e0bf60..1e1183fb13840 100755 --- a/scripts/ci/prek/generate_openapi_spec_fab.py +++ b/scripts/ci/prek/generate_openapi_spec_providers.py @@ -30,7 +30,7 @@ initialize_breeze_prek(__name__, __file__) cmd_result = run_command_via_breeze_shell( - ["python3", "/opt/airflow/scripts/in_container/run_generate_openapi_spec_fab.py"], + ["python3", "/opt/airflow/scripts/in_container/run_generate_openapi_spec_providers.py", sys.argv[1]], backend="postgres", skip_environment_initialization=False, ) diff --git a/scripts/in_container/run_generate_openapi_spec_fab.py b/scripts/in_container/run_generate_openapi_spec_fab.py deleted file mode 100755 index 6aa09de304f2a..0000000000000 --- a/scripts/in_container/run_generate_openapi_spec_fab.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -from __future__ import annotations - -import sys -from pathlib import Path - -from airflow.providers.fab.auth_manager.api_fastapi import __file__ as FAB_AUTH_MANAGER_API_PATH -from airflow.providers.fab.auth_manager.fab_auth_manager import FabAuthManager -from airflow.providers_manager import ProvidersManager - -sys.path.insert(0, str(Path(__file__).parent.resolve())) -from in_container_utils import console, generate_openapi_file, validate_openapi_file - -FAB_AUTH_MANAGER_OPENAPI_SPEC_FILE = ( - Path(FAB_AUTH_MANAGER_API_PATH).parent / "openapi" / "v2-fab-auth-manager-generated.yaml" -) - -ProvidersManager().initialize_providers_configuration() - -# Generate FAB auth manager openapi spec -fab_auth_manager_app = FabAuthManager().get_fastapi_app() -if fab_auth_manager_app: - generate_openapi_file( - app=fab_auth_manager_app, file_path=FAB_AUTH_MANAGER_OPENAPI_SPEC_FILE, prefix="/auth" - ) - validate_openapi_file(FAB_AUTH_MANAGER_OPENAPI_SPEC_FILE) -else: - console.print("[red]FAB auth manager app not found. Skipping OpenAPI spec generation.[/]") - sys.exit(1) diff --git a/scripts/in_container/run_generate_openapi_spec_keycloak.py b/scripts/in_container/run_generate_openapi_spec_keycloak.py deleted file mode 100755 index 648bfa1b1790d..0000000000000 --- a/scripts/in_container/run_generate_openapi_spec_keycloak.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -from __future__ import annotations - -import sys -from pathlib import Path - -from airflow.providers.keycloak.auth_manager import __file__ as KEYCLOAK_AUTH_MANAGER_PATH -from airflow.providers.keycloak.auth_manager.keycloak_auth_manager import KeycloakAuthManager -from airflow.providers_manager import ProvidersManager - -sys.path.insert(0, str(Path(__file__).parent.resolve())) -from in_container_utils import console, generate_openapi_file, validate_openapi_file - -KEYCLOAK_AUTH_MANAGER_OPENAPI_SPEC_FILE = ( - Path(KEYCLOAK_AUTH_MANAGER_PATH).parent / "openapi" / "v2-keycloak-auth-manager-generated.yaml" -) - -ProvidersManager().initialize_providers_configuration() - -# Generate Keycloak auth manager openapi spec -keycloak_auth_manager_app = KeycloakAuthManager().get_fastapi_app() -if keycloak_auth_manager_app: - generate_openapi_file( - app=keycloak_auth_manager_app, file_path=KEYCLOAK_AUTH_MANAGER_OPENAPI_SPEC_FILE, prefix="/auth" - ) - validate_openapi_file(KEYCLOAK_AUTH_MANAGER_OPENAPI_SPEC_FILE) -else: - console.print("[red]Keycloak auth manager app not found. Skipping OpenAPI spec generation.[/]") - sys.exit(1) diff --git a/scripts/in_container/run_generate_openapi_spec_providers.py b/scripts/in_container/run_generate_openapi_spec_providers.py new file mode 100755 index 0000000000000..3cff59f3dc53d --- /dev/null +++ b/scripts/in_container/run_generate_openapi_spec_providers.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from __future__ import annotations + +import argparse +import sys +from pathlib import Path +from typing import TYPE_CHECKING, NamedTuple + +from in_container_utils import console, generate_openapi_file, validate_openapi_file + +from airflow.providers.fab.auth_manager.api_fastapi import __file__ as FAB_AUTHMGR_API_PATH +from airflow.providers.fab.auth_manager.fab_auth_manager import FabAuthManager +from airflow.providers.keycloak.auth_manager import __file__ as KEYCLOAK_AUTHMGR_PATH +from airflow.providers.keycloak.auth_manager.keycloak_auth_manager import KeycloakAuthManager +from airflow.providers_manager import ProvidersManager + +if TYPE_CHECKING: + from fastapi import FastAPI + + +class ProviderDef(NamedTuple): + openapi_spec_file: Path + app: FastAPI | None + prefix: str + + +sys.path.insert(0, str(Path(__file__).parent.resolve())) +ProvidersManager().initialize_providers_configuration() + +PROVIDERS_DEFS = { + "fab": ProviderDef( + openapi_spec_file=Path(FAB_AUTHMGR_API_PATH).parent + / "openapi" + / "v2-fab-auth-manager-generated.yaml", + app=FabAuthManager().get_fastapi_app(), + prefix="/auth", + ), + "keycloak": ProviderDef( + openapi_spec_file=Path(KEYCLOAK_AUTHMGR_PATH).parent + / "openapi" + / "v2-keycloak-auth-manager-generated.yaml", + app=KeycloakAuthManager().get_fastapi_app(), + prefix="/auth", + ), +} + + +# Generate FAB auth manager openapi spec +def generate_openapi_specs(provider_name: str): + provider_def = PROVIDERS_DEFS.get(provider_name) + if provider_def is None: + console.print(f"[red]Provider '{provider_name}' not found. Skipping OpenAPI spec generation.[/]") + sys.exit(1) + app = provider_def.app + openapi_spec_file = provider_def.openapi_spec_file + + if app: + generate_openapi_file(app=app, file_path=openapi_spec_file, prefix=provider_def.prefix) + validate_openapi_file(openapi_spec_file) + else: + console.print( + f"[red]Provider '{provider_name}' has no FastAPI app. Skipping OpenAPI spec generation.[/]" + ) + sys.exit(1) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Generate openapi-spec for the specified provider.") + parser.add_argument( + "provider", + type=str, + help="The name of the provider whose openapi-spec should be compiled.", + choices=list(PROVIDERS_DEFS.keys()), + ) + args = parser.parse_args() + generate_openapi_specs(args.provider)