Skip to content

Commit

Permalink
Migrate public endpoint Get Airflow Version to FastAPI (apache#43312)
Browse files Browse the repository at this point in the history
* Migrate public endpoint Get Airflow Version to FastAPI

* Run static checks
  • Loading branch information
omkar-foss authored Oct 24, 2024
1 parent dc25301 commit 27f3be6
Show file tree
Hide file tree
Showing 12 changed files with 268 additions and 0 deletions.
30 changes: 30 additions & 0 deletions airflow/api_fastapi/core_api/openapi/v1-generated.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1358,6 +1358,20 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
/public/version/:
get:
tags:
- Version
summary: Get Version
description: Get version information.
operationId: get_version
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/VersionInfo'
components:
schemas:
AppBuilderMenuItemResponse:
Expand Down Expand Up @@ -2574,3 +2588,19 @@ components:
- value
title: VariableResponse
description: Variable serializer for responses.
VersionInfo:
properties:
version:
type: string
title: Version
git_version:
anyOf:
- type: string
- type: 'null'
title: Git Version
type: object
required:
- version
- git_version
title: VersionInfo
description: Version information serializer for responses.
2 changes: 2 additions & 0 deletions airflow/api_fastapi/core_api/routes/public/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from airflow.api_fastapi.core_api.routes.public.pools import pools_router
from airflow.api_fastapi.core_api.routes.public.providers import providers_router
from airflow.api_fastapi.core_api.routes.public.variables import variables_router
from airflow.api_fastapi.core_api.routes.public.version import version_router

public_router = AirflowRouter(prefix="/public")

Expand All @@ -38,3 +39,4 @@
public_router.include_router(pools_router)
public_router.include_router(providers_router)
public_router.include_router(plugins_router)
public_router.include_router(version_router)
34 changes: 34 additions & 0 deletions airflow/api_fastapi/core_api/routes/public/version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# 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 airflow
from airflow.api_fastapi.common.router import AirflowRouter
from airflow.api_fastapi.core_api.serializers.version import VersionInfo
from airflow.utils.platform import get_airflow_git_version

version_router = AirflowRouter(tags=["Version"], prefix="/version")


@version_router.get("/")
async def get_version() -> VersionInfo:
"""Get version information."""
airflow_version = airflow.__version__
git_version = get_airflow_git_version()
version_info = VersionInfo(version=airflow_version, git_version=git_version)
return VersionInfo.model_validate(version_info)
26 changes: 26 additions & 0 deletions airflow/api_fastapi/core_api/serializers/version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# 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

from pydantic import BaseModel


class VersionInfo(BaseModel):
"""Version information serializer for responses."""

version: str
git_version: str | None
13 changes: 13 additions & 0 deletions airflow/ui/openapi-gen/queries/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
PoolService,
ProviderService,
VariableService,
VersionService,
} from "../requests/services.gen";
import { DagRunState } from "../requests/types.gen";

Expand Down Expand Up @@ -345,6 +346,18 @@ export const UsePluginServiceGetPluginsKeyFn = (
} = {},
queryKey?: Array<unknown>,
) => [usePluginServiceGetPluginsKey, ...(queryKey ?? [{ limit, offset }])];
export type VersionServiceGetVersionDefaultResponse = Awaited<
ReturnType<typeof VersionService.getVersion>
>;
export type VersionServiceGetVersionQueryResult<
TData = VersionServiceGetVersionDefaultResponse,
TError = unknown,
> = UseQueryResult<TData, TError>;
export const useVersionServiceGetVersionKey = "VersionServiceGetVersion";
export const UseVersionServiceGetVersionKeyFn = (queryKey?: Array<unknown>) => [
useVersionServiceGetVersionKey,
...(queryKey ?? []),
];
export type VariableServicePostVariableMutationResult = Awaited<
ReturnType<typeof VariableService.postVariable>
>;
Expand Down
12 changes: 12 additions & 0 deletions airflow/ui/openapi-gen/queries/prefetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
PoolService,
ProviderService,
VariableService,
VersionService,
} from "../requests/services.gen";
import { DagRunState } from "../requests/types.gen";
import * as Common from "./common";
Expand Down Expand Up @@ -429,3 +430,14 @@ export const prefetchUsePluginServiceGetPlugins = (
queryKey: Common.UsePluginServiceGetPluginsKeyFn({ limit, offset }),
queryFn: () => PluginService.getPlugins({ limit, offset }),
});
/**
* Get Version
* Get version information.
* @returns VersionInfo Successful Response
* @throws ApiError
*/
export const prefetchUseVersionServiceGetVersion = (queryClient: QueryClient) =>
queryClient.prefetchQuery({
queryKey: Common.UseVersionServiceGetVersionKeyFn(),
queryFn: () => VersionService.getVersion(),
});
20 changes: 20 additions & 0 deletions airflow/ui/openapi-gen/queries/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
PoolService,
ProviderService,
VariableService,
VersionService,
} from "../requests/services.gen";
import {
DAGPatchBody,
Expand Down Expand Up @@ -562,6 +563,25 @@ export const usePluginServiceGetPlugins = <
queryFn: () => PluginService.getPlugins({ limit, offset }) as TData,
...options,
});
/**
* Get Version
* Get version information.
* @returns VersionInfo Successful Response
* @throws ApiError
*/
export const useVersionServiceGetVersion = <
TData = Common.VersionServiceGetVersionDefaultResponse,
TError = unknown,
TQueryKey extends Array<unknown> = unknown[],
>(
queryKey?: TQueryKey,
options?: Omit<UseQueryOptions<TData, TError>, "queryKey" | "queryFn">,
) =>
useQuery<TData, TError>({
queryKey: Common.UseVersionServiceGetVersionKeyFn(queryKey),
queryFn: () => VersionService.getVersion() as TData,
...options,
});
/**
* Post Variable
* Create a variable.
Expand Down
20 changes: 20 additions & 0 deletions airflow/ui/openapi-gen/queries/suspense.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
PoolService,
ProviderService,
VariableService,
VersionService,
} from "../requests/services.gen";
import { DagRunState } from "../requests/types.gen";
import * as Common from "./common";
Expand Down Expand Up @@ -552,3 +553,22 @@ export const usePluginServiceGetPluginsSuspense = <
queryFn: () => PluginService.getPlugins({ limit, offset }) as TData,
...options,
});
/**
* Get Version
* Get version information.
* @returns VersionInfo Successful Response
* @throws ApiError
*/
export const useVersionServiceGetVersionSuspense = <
TData = Common.VersionServiceGetVersionDefaultResponse,
TError = unknown,
TQueryKey extends Array<unknown> = unknown[],
>(
queryKey?: TQueryKey,
options?: Omit<UseQueryOptions<TData, TError>, "queryKey" | "queryFn">,
) =>
useSuspenseQuery<TData, TError>({
queryKey: Common.UseVersionServiceGetVersionKeyFn(queryKey),
queryFn: () => VersionService.getVersion() as TData,
...options,
});
24 changes: 24 additions & 0 deletions airflow/ui/openapi-gen/requests/schemas.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1856,3 +1856,27 @@ export const $VariableResponse = {
title: "VariableResponse",
description: "Variable serializer for responses.",
} as const;

export const $VersionInfo = {
properties: {
version: {
type: "string",
title: "Version",
},
git_version: {
anyOf: [
{
type: "string",
},
{
type: "null",
},
],
title: "Git Version",
},
},
type: "object",
required: ["version", "git_version"],
title: "VersionInfo",
description: "Version information serializer for responses.",
} as const;
16 changes: 16 additions & 0 deletions airflow/ui/openapi-gen/requests/services.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import type {
GetProvidersResponse,
GetPluginsData,
GetPluginsResponse,
GetVersionResponse,
} from "./types.gen";

export class AssetService {
Expand Down Expand Up @@ -807,3 +808,18 @@ export class PluginService {
});
}
}

export class VersionService {
/**
* Get Version
* Get version information.
* @returns VersionInfo Successful Response
* @throws ApiError
*/
public static getVersion(): CancelablePromise<GetVersionResponse> {
return __request(OpenAPI, {
method: "GET",
url: "/public/version/",
});
}
}
20 changes: 20 additions & 0 deletions airflow/ui/openapi-gen/requests/types.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,14 @@ export type VariableResponse = {
value: string | null;
};

/**
* Version information serializer for responses.
*/
export type VersionInfo = {
version: string;
git_version: string | null;
};

export type NextRunAssetsData = {
dagId: string;
};
Expand Down Expand Up @@ -633,6 +641,8 @@ export type GetPluginsData = {

export type GetPluginsResponse = PluginCollectionResponse;

export type GetVersionResponse = VersionInfo;

export type $OpenApiTs = {
"/ui/next_run_assets/{dag_id}": {
get: {
Expand Down Expand Up @@ -1269,4 +1279,14 @@ export type $OpenApiTs = {
};
};
};
"/public/version/": {
get: {
res: {
/**
* Successful Response
*/
200: VersionInfo;
};
};
};
};
51 changes: 51 additions & 0 deletions tests/api_fastapi/core_api/routes/public/test_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# 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

from unittest import mock

import pytest

from tests_common.test_utils.db import clear_db_jobs

pytestmark = [pytest.mark.db_test, pytest.mark.skip_if_database_isolation_mode]


class TestVersionEndpoint:
@pytest.fixture(autouse=True)
def setup(self) -> None:
clear_db_jobs()

def teardown_method(self):
clear_db_jobs()


class TestGetVersion(TestVersionEndpoint):
@mock.patch(
"airflow.api_fastapi.core_api.routes.public.version.airflow.__version__",
"MOCK_VERSION",
)
@mock.patch(
"airflow.api_fastapi.core_api.routes.public.version.get_airflow_git_version",
return_value="GIT_COMMIT",
)
def test_airflow_version_info(self, mock_get_airflow_get_commit, client):
response = client().get("/public/version")

assert 200 == response.status_code
assert {"git_version": "GIT_COMMIT", "version": "MOCK_VERSION"} == response.json()
mock_get_airflow_get_commit.assert_called_once_with()

0 comments on commit 27f3be6

Please sign in to comment.