diff --git a/.github/workflows/shared_openapi_sync.yaml b/.github/workflows/shared_openapi_sync.yaml new file mode 100644 index 0000000..7fc9644 --- /dev/null +++ b/.github/workflows/shared_openapi_sync.yaml @@ -0,0 +1,52 @@ +name: TinyNode Shared OpenAPI Sync + +on: + push: + branches: + - main + paths: + - openapi/components/tinynode-shared-components.openapi.yaml + workflow_dispatch: + +permissions: + contents: read + +jobs: + sync: + name: Sync shared OpenAPI artifact + runs-on: ubuntu-latest + steps: + - name: Checkout TinyNode + uses: actions/checkout@v4 + + - name: Checkout receiver repository + uses: actions/checkout@v4 + with: + repository: cubap/rerum_openapi + ref: main + token: ${{ secrets.OPENAPI_SYNC_TOKEN }} + path: receiver + + - name: Verify receiver stub exists + run: test -f receiver/schemas/openapi/tinynode-shared-components.openapi.yaml + + - name: Copy canonical shared artifact + run: cp openapi/components/tinynode-shared-components.openapi.yaml receiver/schemas/openapi/tinynode-shared-components.openapi.yaml + + - name: Create or update sync pull request + uses: peter-evans/create-pull-request@v8 + with: + token: ${{ secrets.OPENAPI_SYNC_TOKEN }} + path: receiver + add-paths: schemas/openapi/tinynode-shared-components.openapi.yaml + commit-message: "chore: sync TinyNode shared OpenAPI artifact" + branch: sync/tinynode-shared-openapi + base: main + delete-branch: true + title: "chore: sync TinyNode shared OpenAPI artifact" + body: | + Syncs the canonical TinyNode shared OpenAPI artifact from CenterForDigitalHumanities/TinyNode. + + - Source commit: ${{ github.sha }} + - Source artifact: `openapi/components/tinynode-shared-components.openapi.yaml` + - Target artifact: `schemas/openapi/tinynode-shared-components.openapi.yaml` diff --git a/README.md b/README.md index a1065d3..f66734c 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,10 @@ npm run ci:fast npm run ci:full ``` +### Shared OpenAPI Artifact +TinyNode owns the canonical shared OpenAPI artifact at `openapi/components/tinynode-shared-components.openapi.yaml`. +When that file changes on `main`, the `TinyNode Shared OpenAPI Sync` workflow copies it into `cubap/rerum_openapi` at `schemas/openapi/tinynode-shared-components.openapi.yaml` and opens or updates the sync pull request there. The workflow expects a repository secret named `OPENAPI_SYNC_TOKEN` with permission to push a sync branch and open pull requests in `cubap/rerum_openapi`. + And start the app ```shell npm start diff --git a/openapi/components/tinynode-shared-components.openapi.yaml b/openapi/components/tinynode-shared-components.openapi.yaml new file mode 100644 index 0000000..4201735 --- /dev/null +++ b/openapi/components/tinynode-shared-components.openapi.yaml @@ -0,0 +1,105 @@ +openapi: 3.0.3 +info: + title: TinyNode Shared Components + version: 0.1.0-alpha.1 + description: >- + Shared schema components reused by multiple TinyNode seams. TinyNode route + handlers are sourced from CenterForDigitalHumanities/TinyNode routes/ + (create.js, update.js, overwrite.js, query.js). TinyNode persists to + rerum_server_nodejs at store.rerum.io/v1. +externalDocs: + description: TinyNode routes source of truth + url: https://github.com/CenterForDigitalHumanities/TinyNode/tree/main/routes +x-upstream-provider: + name: rerum_server_nodejs + baseUrl: https://store.rerum.io/v1 +components: + schemas: + HealthResponse: + type: object + required: + - status + properties: + status: + type: string + enum: [ok] + additionalProperties: true + ReadinessResponse: + type: object + required: + - status + - timestamp + properties: + status: + type: string + enum: [ready] + timestamp: + type: string + format: date-time + additionalProperties: true + OpenApiDocumentResponse: + type: object + additionalProperties: true + DocumentPayload: + type: object + description: >- + Request document with stable core fields and open extension fields. + Consumer-specific metadata can be included without breaking this + contract. + properties: + '@id': + type: string + description: Existing identifier for update/overwrite semantics. + '@context': + description: JSON-LD context when present. + oneOf: + - type: string + - type: array + - type: object + '@type': + description: JSON-LD type when present. + oneOf: + - type: string + - type: array + additionalProperties: true + DocumentResponse: + type: object + description: Response document with required identity and open extension fields. + required: + - '@id' + properties: + '@id': + type: string + description: Canonical TinyNode identifier for the document. + additionalProperties: true + QueryResponse: + description: Query responses may be a raw array or a wrapped object. + oneOf: + - type: array + items: + $ref: '#/components/schemas/DocumentResponse' + - type: object + required: + - results + properties: + results: + type: array + items: + $ref: '#/components/schemas/DocumentResponse' + total: + type: integer + minimum: 0 + additionalProperties: true + ErrorResponse: + type: object + description: Generic error envelope used across operations. + properties: + message: + type: string + error: + type: string + status: + type: integer + minimum: 100 + maximum: 599 + additionalProperties: true diff --git a/test/routes/mount.test.js b/test/routes/mount.test.js index 7900977..cf78f94 100644 --- a/test/routes/mount.test.js +++ b/test/routes/mount.test.js @@ -65,5 +65,7 @@ describe("Check to see that critical repo files are present", () => { assert.equal(fs.existsSync(`${filePath}README.md`), true) assert.equal(fs.existsSync(`${filePath}.gitignore`), true) assert.equal(fs.existsSync(`${filePath}package.json`), true) + assert.equal(fs.existsSync(`${filePath}.github/workflows/shared_openapi_sync.yaml`), true) + assert.equal(fs.existsSync(`${filePath}openapi/components/tinynode-shared-components.openapi.yaml`), true) }) })