diff --git a/.github/workflows/build-publish.yml b/.github/workflows/build-publish.yml index 5a8413c..c312b4c 100644 --- a/.github/workflows/build-publish.yml +++ b/.github/workflows/build-publish.yml @@ -2,6 +2,9 @@ name: Build, Test, and Publish on: workflow_dispatch: + repository_dispatch: + types: + - cda-prod-release permissions: pages: write @@ -15,6 +18,12 @@ jobs: - name: Checkout code uses: actions/checkout@v4 + - name: Show trigger context + run: | + echo "Event: ${{ github.event_name }}" + echo "Release tag: ${{ github.event.client_payload.release_tag || 'manual' }}" + echo "Source repository: ${{ github.event.client_payload.source_repository || github.repository }}" + - name: Set up Node.js uses: actions/setup-node@v4 with: diff --git a/README.md b/README.md index b1824c0..5aaeeb3 100644 --- a/README.md +++ b/README.md @@ -50,9 +50,9 @@ Throughout CDA, "time series" is arbitrarily referred to in both a one-word ("ti ## Developers ### Versioning In order to accommodate changes both to the generator and to CDA itself, cwmsjs is versioned in the following format: -`[generator SemVer]-[generation date]` +`[generator SemVer]-[CDA schema version]` -CDA is expected to at some point expose a CalVer for the latest update. When this is available, the generation date will be replaced with the current CDA CalVer. +The generator now uses the live OpenAPI `info.version` published by CDA. If that field is unavailable, it falls back to the current date. ### Publishing Contributors with authorization can publish a new version of cwmsjs by manually running the "Build, Test, and Publish" GitHub Action. @@ -63,6 +63,7 @@ The workflow will build an updated cwmsjs library using the current generator an - Clone this repository - Install dependencies with: `npm install` +- Optionally set `CWMS_SCHEMA_URL` if you need to build from a non-default CDA schema endpoint - Run the generator with: `npm run build` diff --git a/openapitools.json b/openapitools.json index 5571688..9cbc6d5 100644 --- a/openapitools.json +++ b/openapitools.json @@ -2,6 +2,6 @@ "$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json", "spaces": 2, "generator-cli": { - "version": "7.4.0" + "version": "5.4.0" } } diff --git a/package.json b/package.json index 591da05..ee64887 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cwmsjs-generator", - "version": "2.3.2", + "version": "2.4.0", "description": "OpenAPI generator for building the cwmsjs JavaScript/TypeScript library for CWMS Data API", "author": "USACE,HEC,CWMS,OpenApi Contributors", "repository": { @@ -30,15 +30,16 @@ "typings": "./dist/index.d.ts", "scripts": { "build": "npm run buildApi && npm run buildDocs", - "buildApi": "npm run buildSpec && npm run openapi && npm run modPackage && cd cwmsjs && npm run build", + "buildApi": "npm run buildSpec && npm run openapi && npm run modPackage && npm run postGenerate && cd cwmsjs && npm install && npm run build", "buildDocs": "npm run docs && npm run examples", "buildSpec": "npm run getSpec && npm run modSpec", "clean": "shx mkdir -p ./cwmsjs && shx rm -r ./cwmsjs", - "docs": "cd cwmsjs && npx typedoc src/index.ts", + "docs": "node ./scripts/buildTypedoc.js", "examples": "node ./scripts/tests2exampledocs.js ", - "getSpec": "wget https://cwms-data.usace.army.mil/cwms-data/swagger-docs -O cwms-swagger-raw.json", - "modPackage": "./scripts/package-updates/modPackage.sh", - "modSpec": "./scripts/spec-updates/modSpec.sh", + "getSpec": "node ./scripts/getSpec.js", + "modPackage": "node ./scripts/package-updates/modPackage.js", + "modSpec": "node ./scripts/spec-updates/modSpec.js", + "postGenerate": "node ./scripts/postGenerate.js", "link": "cd cwmsjs && npm link && cd ../tests && npm link cwmsjs", "openapi": "npx @openapitools/openapi-generator-cli generate -g typescript-fetch -o ./cwmsjs -i cwms-swagger-mod.json -c openapi.config.json" }, diff --git a/scripts/buildTypedoc.js b/scripts/buildTypedoc.js new file mode 100644 index 0000000..e0183df --- /dev/null +++ b/scripts/buildTypedoc.js @@ -0,0 +1,107 @@ +const { spawnSync } = require("node:child_process"); +const fs = require("node:fs"); +const path = require("node:path"); + +const rootDir = path.resolve(__dirname, ".."); +const cwmsjsDir = path.join(rootDir, "cwmsjs"); +const docsDir = path.join(cwmsjsDir, "docs"); +const tempDocsDir = path.join(cwmsjsDir, "docs-typedoc"); +const packageJson = JSON.parse( + fs.readFileSync(path.join(cwmsjsDir, "package.json"), "utf8"), +); + +removePath(tempDocsDir, { strict: true }); + +const result = spawnSync( + `npx typedoc src/index.ts --name "cwmsjs v${packageJson.version}" --out docs-typedoc`, + { + cwd: cwmsjsDir, + stdio: "inherit", + shell: true, + }, +); + +if (result.error) { + console.error(result.error.message); + process.exit(1); +} + +if (result.status !== 0) { + process.exit(result.status ?? 1); +} + +fs.mkdirSync(docsDir, { recursive: true }); + +for (const entry of fs.readdirSync(tempDocsDir, { withFileTypes: true })) { + const sourcePath = path.join(tempDocsDir, entry.name); + const destinationPath = path.join(docsDir, entry.name); + + removePath(destinationPath); + copyPath(sourcePath, destinationPath); +} + +removePath(tempDocsDir, { strict: true }); + +function removePath(targetPath, { strict = false } = {}) { + if (!fs.existsSync(targetPath)) { + return; + } + + const targetStats = fs.lstatSync(targetPath); + + try { + fs.rmSync(targetPath, { recursive: true, force: true }); + } catch (error) { + if (process.platform !== "win32") { + throw error; + } + + const cleanupCommand = targetStats.isDirectory() + ? `if exist "${targetPath}" rmdir /s /q "${targetPath}"` + : `if exist "${targetPath}" del /f /q "${targetPath}"`; + const cleanup = spawnSync( + "cmd.exe", + ["/d", "/s", "/c", cleanupCommand], + { + stdio: "inherit", + }, + ); + + if (cleanup.status !== 0 && fs.existsSync(targetPath)) { + throw error; + } + } + + if (fs.existsSync(targetPath)) { + if (strict) { + throw new Error(`Unable to remove ${targetPath}`); + } + console.warn(`Skipping cleanup for locked path: ${targetPath}`); + } +} + +function copyPath(sourcePath, destinationPath) { + const sourceStats = fs.statSync(sourcePath); + + if (sourceStats.isDirectory()) { + fs.mkdirSync(destinationPath, { recursive: true }); + + for (const entry of fs.readdirSync(sourcePath, { withFileTypes: true })) { + copyPath( + path.join(sourcePath, entry.name), + path.join(destinationPath, entry.name), + ); + } + return; + } + + try { + fs.copyFileSync(sourcePath, destinationPath); + } catch (error) { + if (error && error.code === "EPERM") { + console.warn(`Skipping locked file: ${destinationPath}`); + return; + } + throw error; + } +} diff --git a/scripts/docker/buildAll.cmd b/scripts/docker/buildAll.cmd index eb33a6c..a12ba52 100644 --- a/scripts/docker/buildAll.cmd +++ b/scripts/docker/buildAll.cmd @@ -1,4 +1,4 @@ @REM runs all scripts start to finish, using docker where windows might be an issue echo Fetching and Manipulating spec... -.\scripts\docker\buildSpec.cmd && npm run openapi && .\scripts\docker\runPkg.cmd && cd cwmsjs && npm install && npm run build && cd .. +npm.cmd run buildSpec && npm.cmd run openapi && .\scripts\docker\runPkg.cmd && cd cwmsjs && npm.cmd install && npm.cmd run build && cd .. echo Done. diff --git a/scripts/docker/buildSpec.cmd b/scripts/docker/buildSpec.cmd index 14c6afe..5155201 100644 --- a/scripts/docker/buildSpec.cmd +++ b/scripts/docker/buildSpec.cmd @@ -1,2 +1,2 @@ -@REM Run scripts from windows -docker run --rm -v %cd%:/scripts -w /scripts node:lts bash -c "npm install -g node-jq && npm run buildSpec" \ No newline at end of file +@REM Build the live spec from Windows without docker +npm.cmd run buildSpec diff --git a/scripts/exampletemplate.html b/scripts/exampletemplate.html index 525fffe..c99504e 100644 --- a/scripts/exampletemplate.html +++ b/scripts/exampletemplate.html @@ -7,7 +7,7 @@
-cwmsjs v${packageVersion}
Groundwork-Water + React
-