Skip to content

Commit

Permalink
feat(bulk-import-backend): include pagination info in the `GET /impor…
Browse files Browse the repository at this point in the history
…ts` response structure (#2246)

* feat(bulk-import-backend)!: include pagination info in the `GET /imports` response structure

Change the response structure of 'GET /imports' in the OpenAPI definition

Regenerate type defs and API docs off openapi.yaml spec

Implement the findAllImports API accordingly

Rename the pagePerIntegration and sizePerIntegration query params into page and size

This makes it more clear, and also because the number of imports does not depend on the number of GH integrations

Fix and update tests

Reduce code duplication issues reported by SonarCloud

* Do not break the API as a general rule of thumb

Instead, this allows consumers to specify an 'api-version' field in
the request header (either undefined, `v1` or `v2`, default being `v1` as before).
When `v2` is specified, the `GET /imports` response structure is changed accordingly.

* Mark the `*PerIntegration` query params as deprecated in the OpenAPI spec

Co-authored-by: Dominika Zemanovicova <36102317+dzemanov@users.noreply.github.com>
Signed-off-by: Armel Soro <asoro@redhat.com>

* Fix parameters descriptions and API version changelog in OpenAPI spec

Signed-off-by: Armel Soro <asoro@redhat.com>

---------

Signed-off-by: Armel Soro <asoro@redhat.com>
Co-authored-by: Dominika Zemanovicova <36102317+dzemanov@users.noreply.github.com>
  • Loading branch information
rm3l and dzemanov authored Oct 7, 2024
1 parent fd43dc4 commit ee420f2
Show file tree
Hide file tree
Showing 19 changed files with 1,266 additions and 474 deletions.
4 changes: 4 additions & 0 deletions plugins/bulk-import-backend/api-docs/.openapi-generator/FILES

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 8 additions & 5 deletions plugins/bulk-import-backend/api-docs/Apis/ImportApi.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions plugins/bulk-import-backend/api-docs/Apis/OrganizationApi.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion plugins/bulk-import-backend/api-docs/Apis/RepositoryApi.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions plugins/bulk-import-backend/api-docs/Models/ImportJobListV2.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 0 additions & 11 deletions plugins/bulk-import-backend/api-docs/Models/Import_repository.md

This file was deleted.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions plugins/bulk-import-backend/api-docs/README.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions plugins/bulk-import-backend/scripts/openapi.sh
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ echo '`' >> "${OPENAPI_DOC_JS_FILE}"
echo "export const openApiDocument = JSON.parse(OPENAPI);" >> "${OPENAPI_DOC_JS_FILE}"
rm -f ./src/schema/openapi.json

# Generate doc
#npx --yes --package=openapicmd@2.3.2 -- openapi redoc src/schema/openapi.yaml --bundle docs
# Re-generate doc
rm -rf ./api-docs/
npx --yes --package=@openapitools/openapi-generator-cli@2.13.4 -- \
openapi-generator-cli generate -i ./src/schema/openapi.yaml -g markdown -o ./api-docs/
52 changes: 38 additions & 14 deletions plugins/bulk-import-backend/src/helpers/catalogInfoGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,37 +125,54 @@ ${jsYaml.dump(generatedEntity.entity)}`,
search?: string,
pageNumber: number = DefaultPageNumber,
pageSize: number = DefaultPageSize,
): Promise<string[]> {
const list = await this.listCatalogUrlLocationsById(
): Promise<{ targetUrls: string[]; totalCount?: number }> {
const byId = await this.listCatalogUrlLocationsById(
config,
search,
pageNumber,
pageSize,
);
const result = new Set<string>();
for (const l of list) {
for (const l of byId.locations) {
result.add(l.target);
}
return Array.from(result.values());
return {
targetUrls: Array.from(result.values()),
totalCount: byId.totalCount,
};
}

async listCatalogUrlLocationsById(
config: Config,
search?: string,
pageNumber: number = DefaultPageNumber,
pageSize: number = DefaultPageSize,
): Promise<{ id?: string; target: string }[]> {
): Promise<{
locations: { id?: string; target: string }[];
totalCount?: number;
}> {
const result = await Promise.all([
this.listCatalogUrlLocationsFromConfig(config, search),
this.listCatalogUrlLocationsByIdFromLocationsEndpoint(search),
this.listCatalogUrlLocationEntitiesById(search, pageNumber, pageSize),
]);
return result.flat();
const locations = result.flatMap(u => u.locations);
// we might have duplicate elements here
const totalCount = result
.map(l => l.totalCount ?? 0)
.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
return {
locations,
totalCount,
};
}

async listCatalogUrlLocationsByIdFromLocationsEndpoint(
search?: string,
): Promise<{ id?: string; target: string }[]> {
): Promise<{
locations: { id?: string; target: string }[];
totalCount?: number;
}> {
const url = `${await this.discovery.getBaseUrl('catalog')}/locations`;
const response = await fetch(url, {
headers: {
Expand All @@ -168,7 +185,7 @@ ${jsYaml.dump(generatedEntity.entity)}`,
data: { id: string; target: string; type: string };
}[];
if (!Array.isArray(locations)) {
return [];
return { locations: [] };
}
const res = locations
.filter(
Expand All @@ -180,13 +197,14 @@ ${jsYaml.dump(generatedEntity.entity)}`,
target: location.data.target,
};
});
return this.filterLocations(res, search);
const filtered = this.filterLocations(res, search);
return { locations: filtered, totalCount: filtered.length };
}

listCatalogUrlLocationsFromConfig(
config: Config,
search?: string,
): { id?: string; target: string }[] {
): { locations: { id?: string; target: string }[]; totalCount?: number } {
const locationConfigs =
config.getOptionalConfigArray('catalog.locations') ?? [];
const res = locationConfigs
Expand All @@ -202,23 +220,28 @@ ${jsYaml.dump(generatedEntity.entity)}`,
target,
};
});
return this.filterLocations(res, search);
const filtered = this.filterLocations(res, search);
return { locations: filtered, totalCount: filtered.length };
}

async listCatalogUrlLocationEntitiesById(
search?: string,
_pageNumber: number = DefaultPageNumber,
_pageSize: number = DefaultPageSize,
): Promise<{ id?: string; target: string }[]> {
): Promise<{
locations: { id?: string; target: string }[];
totalCount?: number;
}> {
const result = await this.catalogApi.getEntities(
{
filter: {
kind: 'Location',
},
// There is no query parameter to find entities with target URLs containing a string.
// The existing filter does an exact matching. That's why we are retrieving this hard-coded high number of Locations.
limit: 1000,
limit: 9999,
offset: 0,
order: { field: 'metadata.name', order: 'desc' },
},
{
token: await getTokenForPlugin(this.auth, 'catalog'),
Expand All @@ -235,7 +258,8 @@ ${jsYaml.dump(generatedEntity.entity)}`,
target: location.spec.target!,
};
});
return this.filterLocations(res, search);
const filtered = this.filterLocations(res, search);
return { locations: filtered, totalCount: filtered.length };
}

private filterLocations(
Expand Down
57 changes: 44 additions & 13 deletions plugins/bulk-import-backend/src/openapi.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit ee420f2

Please sign in to comment.