feat(apispec): describe /api/v1/import; regenerate openapi + schema.ts
Add import tag, importOperations() (GET + POST /api/v1/import), and schema name mappings (ImportStatusResponse, ImportRunResponse, ImportReport) to build.go. Regenerate openapi.yaml and frontend/src/api/schema.ts. Route-spec parity test passes. Restore the nil-svc-501 import controller test now that the spec includes the operation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
c8a9f6b7fd
commit
9a0e3ccbb7
|
|
@ -51,6 +51,55 @@ paths:
|
|||
summary: Stream CDC events with durable replay
|
||||
tags:
|
||||
- events
|
||||
/api/v1/import:
|
||||
get:
|
||||
operationId: getImportStatus
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ImportStatusResponse'
|
||||
description: OK
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/APIError'
|
||||
description: Internal Server Error
|
||||
"501":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/APIError'
|
||||
description: Not Implemented
|
||||
summary: Check whether a legacy AO install is available to import
|
||||
tags:
|
||||
- import
|
||||
post:
|
||||
operationId: runImport
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ImportRunResponse'
|
||||
description: OK
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/APIError'
|
||||
description: Internal Server Error
|
||||
"501":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/APIError'
|
||||
description: Not Implemented
|
||||
summary: Run the legacy AO project import through the daemon store
|
||||
tags:
|
||||
- import
|
||||
/api/v1/notifications:
|
||||
get:
|
||||
operationId: listNotifications
|
||||
|
|
@ -1600,6 +1649,40 @@ components:
|
|||
required:
|
||||
- harness
|
||||
type: object
|
||||
ImportReport:
|
||||
properties:
|
||||
dryRun:
|
||||
type: boolean
|
||||
notes:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
projectsImported:
|
||||
type: integer
|
||||
projectsSkipped:
|
||||
type: integer
|
||||
required:
|
||||
- dryRun
|
||||
- projectsImported
|
||||
- projectsSkipped
|
||||
type: object
|
||||
ImportRunResponse:
|
||||
properties:
|
||||
report:
|
||||
$ref: '#/components/schemas/ImportReport'
|
||||
required:
|
||||
- report
|
||||
type: object
|
||||
ImportStatusResponse:
|
||||
properties:
|
||||
available:
|
||||
type: boolean
|
||||
legacyRoot:
|
||||
type: string
|
||||
required:
|
||||
- available
|
||||
- legacyRoot
|
||||
type: object
|
||||
KillSessionResponse:
|
||||
properties:
|
||||
freed:
|
||||
|
|
@ -2429,3 +2512,5 @@ tags:
|
|||
name: notifications
|
||||
- description: Server-sent CDC event stream with durable replay
|
||||
name: events
|
||||
- description: Legacy AO project import (availability probe and run)
|
||||
name: import
|
||||
|
|
|
|||
|
|
@ -67,6 +67,8 @@ func Build() ([]byte, error) {
|
|||
"Durable dashboard notifications"),
|
||||
*(&openapi31.Tag{Name: "events"}).WithDescription(
|
||||
"Server-sent CDC event stream with durable replay"),
|
||||
*(&openapi31.Tag{Name: "import"}).WithDescription(
|
||||
"Legacy AO project import (availability probe and run)"),
|
||||
}
|
||||
|
||||
for _, op := range operations() {
|
||||
|
|
@ -186,6 +188,11 @@ var schemaNames = map[string]string{
|
|||
"ControllersSubmitReviewInput": "SubmitReviewInput",
|
||||
// domain review entities
|
||||
"DomainReviewRun": "ReviewRun",
|
||||
// httpd/controllers — import wire envelopes
|
||||
"ControllersImportStatusResponse": "ImportStatusResponse",
|
||||
"ControllersImportRunResponse": "ImportRunResponse",
|
||||
// legacyimport report
|
||||
"LegacyimportReport": "ImportReport",
|
||||
// service/project entities + DTOs
|
||||
"ProjectProject": "Project",
|
||||
"ProjectSummary": "ProjectSummary",
|
||||
|
|
@ -273,9 +280,35 @@ func operations() []operation {
|
|||
ops = append(ops, prOperations()...)
|
||||
ops = append(ops, reviewOperations()...)
|
||||
ops = append(ops, notificationOperations()...)
|
||||
ops = append(ops, importOperations()...)
|
||||
return ops
|
||||
}
|
||||
|
||||
// importOperations declares the 2 /import operations. Must stay 1:1 with
|
||||
// the routes ImportController.Register mounts (enforced by the parity test).
|
||||
func importOperations() []operation {
|
||||
return []operation{
|
||||
{
|
||||
method: http.MethodGet, path: "/api/v1/import", id: "getImportStatus", tag: "import",
|
||||
summary: "Check whether a legacy AO install is available to import",
|
||||
resps: []respUnit{
|
||||
{http.StatusOK, controllers.ImportStatusResponse{}},
|
||||
{http.StatusInternalServerError, envelope.APIError{}},
|
||||
{http.StatusNotImplemented, envelope.APIError{}},
|
||||
},
|
||||
},
|
||||
{
|
||||
method: http.MethodPost, path: "/api/v1/import", id: "runImport", tag: "import",
|
||||
summary: "Run the legacy AO project import through the daemon store",
|
||||
resps: []respUnit{
|
||||
{http.StatusOK, controllers.ImportRunResponse{}},
|
||||
{http.StatusInternalServerError, envelope.APIError{}},
|
||||
{http.StatusNotImplemented, envelope.APIError{}},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func notificationOperations() []operation {
|
||||
return []operation{
|
||||
{
|
||||
|
|
|
|||
|
|
@ -88,10 +88,12 @@ func TestImportAPI_RunError(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestImportAPI_NilSvcReturns501 verifies the controller falls through to the
|
||||
// 501 stub when no import service is wired. This test only passes after
|
||||
// Task 4 regenerates openapi.yaml to include /api/v1/import; until then the
|
||||
// apispec.NotImplemented call panics on the missing operation.
|
||||
// Kept as a reminder; re-enable after api:spec regen.
|
||||
//
|
||||
// func TestImportAPI_NilSvcReturns501(t *testing.T) { ... }
|
||||
func TestImportAPI_NilSvcReturns501(t *testing.T) {
|
||||
log := slog.New(slog.NewTextHandler(io.Discard, nil))
|
||||
srv := httptest.NewServer(httpd.NewRouterWithControl(config.Config{}, log, nil, httpd.APIDeps{}, httpd.ControlDeps{}))
|
||||
t.Cleanup(srv.Close)
|
||||
body, status, _ := doRequest(t, srv, "GET", "/api/v1/import", "")
|
||||
assertErrorCode(t, body, status, http.StatusNotImplemented, "NOT_IMPLEMENTED")
|
||||
body, status, _ = doRequest(t, srv, "POST", "/api/v1/import", "")
|
||||
assertErrorCode(t, body, status, http.StatusNotImplemented, "NOT_IMPLEMENTED")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,24 @@ export interface paths {
|
|||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/v1/import": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/** Check whether a legacy AO install is available to import */
|
||||
get: operations["getImportStatus"];
|
||||
put?: never;
|
||||
/** Run the legacy AO project import through the daemon store */
|
||||
post: operations["runImport"];
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/v1/notifications": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
|
@ -551,6 +569,19 @@ export interface components {
|
|||
DomainReviewerConfig: {
|
||||
harness: string;
|
||||
};
|
||||
ImportReport: {
|
||||
dryRun: boolean;
|
||||
notes?: string[];
|
||||
projectsImported: number;
|
||||
projectsSkipped: number;
|
||||
};
|
||||
ImportRunResponse: {
|
||||
report: components["schemas"]["ImportReport"];
|
||||
};
|
||||
ImportStatusResponse: {
|
||||
available: boolean;
|
||||
legacyRoot: string;
|
||||
};
|
||||
KillSessionResponse: {
|
||||
freed?: boolean;
|
||||
ok: boolean;
|
||||
|
|
@ -918,6 +949,82 @@ export interface operations {
|
|||
};
|
||||
};
|
||||
};
|
||||
getImportStatus: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description OK */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ImportStatusResponse"];
|
||||
};
|
||||
};
|
||||
/** @description Internal Server Error */
|
||||
500: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["APIError"];
|
||||
};
|
||||
};
|
||||
/** @description Not Implemented */
|
||||
501: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["APIError"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
runImport: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description OK */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ImportRunResponse"];
|
||||
};
|
||||
};
|
||||
/** @description Internal Server Error */
|
||||
500: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["APIError"];
|
||||
};
|
||||
};
|
||||
/** @description Not Implemented */
|
||||
501: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["APIError"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
listNotifications: {
|
||||
parameters: {
|
||||
query?: {
|
||||
|
|
|
|||
Loading…
Reference in New Issue