From 4e939f7934c6cb513c808849eca52ced3f2edd8d Mon Sep 17 00:00:00 2001 From: Github Actions Date: Tue, 24 Sep 2024 17:21:14 +0000 Subject: [PATCH 01/21] Version bump --- box.json | 2 +- changelog.md | 146 ++++++++++++++++++++++++++------------------------- 2 files changed, 76 insertions(+), 72 deletions(-) diff --git a/box.json b/box.json index af45a54..d03a852 100644 --- a/box.json +++ b/box.json @@ -1,6 +1,6 @@ { "name":"cbSwagger", - "version":"3.1.2", + "version":"3.1.3", "location":"https://downloads.ortussolutions.com/ortussolutions/coldbox-modules/cbswagger/@build.version@/cbswagger-@build.version@.zip", "author":"Ortus Solutions, Corp", "slug":"cbSwagger", diff --git a/changelog.md b/changelog.md index e30c784..db9dd6c 100644 --- a/changelog.md +++ b/changelog.md @@ -9,190 +9,194 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [3.1.2] - 2024-09-24 + ### Fixed -* Coldbox 7 updates for router declarations which don't declare a handler +- Coldbox 7 updates for router declarations which don't declare a handler ## [3.1.1] - 2024-06-05 ### Fixed -* Fix `box.json` version of `swagger-sdk` +- Fix `box.json` version of `swagger-sdk` ## [3.0.0] - 2024-05-30 ### Changed -* Interaction to WireBox via base test case and not application scope -* Removed support for Adobe Coldfusion 2016 -* Removes `default` key from response object if empty and other status code keys are present [Issue #28](https://github.com/coldbox-modules/cbSwagger/issues/28) +- Interaction to WireBox via base test case and not application scope +- Removed support for Adobe Coldfusion 2016 +- Removes `default` key from response object if empty and other status code keys are present [Issue #28](https://github.com/coldbox-modules/cbSwagger/issues/28) ### Added -* Virtual application testing -* Updated github actions -* Updated module template provisions -* Added support for samples path shortcut annotation (`~`) in annotation JSON `$ref` pointers -* Added support for using globbing patterns in `excludeRoutes` array. [Issue #37](https://github.com/coldbox-modules/cbSwagger/issues/37) -* Added `cbswagger` endpoint caching ( defaults to `true` ) and `cacheEnabled` setting. -* Added URL convention for clearing/bypassing endpoint cache ( `swaggerCache=false` ) +- Virtual application testing +- Updated github actions +- Updated module template provisions +- Added support for samples path shortcut annotation (`~`) in annotation JSON `$ref` pointers +- Added support for using globbing patterns in `excludeRoutes` array. [Issue #37](https://github.com/coldbox-modules/cbSwagger/issues/37) +- Added `cbswagger` endpoint caching ( defaults to `true` ) and `cacheEnabled` setting. +- Added URL convention for clearing/bypassing endpoint cache ( `swaggerCache=false` ) ## [2.7.0] => 2021-OCT-1 ### Added -* Added the ability to excludes routes by prefix +- Added the ability to excludes routes by prefix ## [2.5.1] => 2021-MAY-12 ### Fixed -* Regression on `@tags` being json syntax +- Regression on `@tags` being json syntax ## [2.5.0] => 2021-MAY-10 ### Added -* Added the ability to add `@tags` to annotations so they can show up on the operations metadata as array of `tags` +- Added the ability to add `@tags` to annotations so they can show up on the operations metadata as array of `tags` ## [2.4.0] => 2021-MAY-04 ### Removed -* Removed `externalDocs` from the `info` struct as it is not supported on the OpenApi Spec v3. +- Removed `externalDocs` from the `info` struct as it is not supported on the OpenApi Spec v3. ### Changed -* `operationID` renamed to `x-coldbox-operation` since they are ColdBox centric. It was also causing issues using `operationID` as it needed to be unique across the entire swagger document. +- `operationID` renamed to `x-coldbox-operation` since they are ColdBox centric. It was also causing issues using `operationID` as it needed to be unique across the entire swagger document. ## [2.3.0] => 2020-SEP-08 ### Added -* Add CORS support for cbswagger endpoint #25 +- Add CORS support for cbswagger endpoint #25 ## [2.2.1] => 2020-MAY-12 ### Fixed -* On lucee the `displayName` defaults to `Component`, skipping this default to select the correct `operationId` for the resource -* The `moduleName` hint for the `appendFunctionInfo` was mispelled +- On lucee the `displayName` defaults to `Component`, skipping this default to select the correct `operationId` for the resource +- The `moduleName` hint for the `appendFunctionInfo` was mispelled ## [2.2.0] => 2020-MAY-12 ### Added -* When defining external files in annotations, you can now prefix them with `~` and this will expand to the module setting of `samplesPath`. This way you can write your annotations in a more cleaner manner. -* Auto-publishing of changelog's to github -* New changelog looks according to keepachangelog.com +- When defining external files in annotations, you can now prefix them with `~` and this will expand to the module setting of `samplesPath`. This way you can write your annotations in a more cleaner manner. +- Auto-publishing of changelog's to github +- New changelog looks according to keepachangelog.com ## [2.1.1] => 2020-MAY-06 -* Updates to support ColdBox 6 +- Updates to support ColdBox 6 ## [2.1.0] => 2020-APR-16 ### Features -* Allow `@security` annotation to override the security mechanisms defined in config. The value can be a JSON array of security directives, a file pointer, or for convenience the name of a security schema. See readme for examples. -* Support for discovering responses and examples by conventions in the `resources/apidocs` folder convention. See readme for examples. -* Ability to exclude routes from the generated spec via the `excludeRoutes` configuration key. +- Allow `@security` annotation to override the security mechanisms defined in config. The value can be a JSON array of security directives, a file pointer, or for convenience the name of a security schema. See readme for examples. +- Support for discovering responses and examples by conventions in the `resources/apidocs` folder convention. See readme for examples. +- Ability to exclude routes from the generated spec via the `excludeRoutes` configuration key. ### Improvements -* Add default `samplesPath` config item to `resources/apidocs` in the ModuleConfig -* Add convention samples parsing and refactor segment parsing to separate methods +- Add default `samplesPath` config item to `resources/apidocs` in the ModuleConfig +- Add convention samples parsing and refactor segment parsing to separate methods ### Bugs -* Fixes for new router syntax not parsing actions correctly or not taking into account actions attached to verbs +- Fixes for new router syntax not parsing actions correctly or not taking into account actions attached to verbs ## [2.0.0] => 2019-SEP-02 -* `feature`: Upgraded to swagger-sdk 2.0.0 to support OpenAPI 3.0.x. A great guide on migrating is here: +- `feature`: Upgraded to swagger-sdk 2.0.0 to support OpenAPI 3.0.x. A great guide on migrating is here: -* Migrated `cbSwagger` settings to the `moduleSettings` struct instead of top-level in the `config/ColdBox.cfc`. Make sure you move your settings. +- Migrated `cbSwagger` settings to the `moduleSettings` struct instead of top-level in the `config/ColdBox.cfc`. Make sure you move your settings. -* `feature` : You can now pass a `format` to the `/cbSwagger` endpoint to either get the OpenAPI doc as `json` or `yml`. Eg: `/cbswagger?format=yml` +- `feature` : You can now pass a `format` to the `/cbSwagger` endpoint to either get the OpenAPI doc as `json` or `yml`. Eg: `/cbswagger?format=yml` -* `feature` : You have two distinct routes for the json and yml formats: `/cbSwagger/json` and `/cbSwagger/yml` +- `feature` : You have two distinct routes for the json and yml formats: `/cbSwagger/json` and `/cbSwagger/yml` -* You can choose your default output format via the module settings: `defaultFormat` setting. Valid options are `json` and `yml` +- You can choose your default output format via the module settings: `defaultFormat` setting. Valid options are `json` and `yml` -* `features` : Support for ColdBox 5 event routing and response routing. +- `features` : Support for ColdBox 5 event routing and response routing. -* `improvement` : You can now tag your handlers with a `displayName` that will be used for operation ID building +- `improvement` : You can now tag your handlers with a `displayName` that will be used for operation ID building -* `improvement` : Improved the way operation Ids are reported so they can be unique when reusing handler actions. +- `improvement` : Improved the way operation Ids are reported so they can be unique when reusing handler actions. -* `improvement` : Refactored `createLinkedHashMap()` -> `structNew( "ordered" )` +- `improvement` : Refactored `createLinkedHashMap()` -> `structNew( "ordered" )` -* `improvement`: Removed lucee 4.5, acf11 support. +- `improvement`: Removed lucee 4.5, acf11 support. ## 1.4.1 -* Fix for detecting ColdBox 5 +- Fix for detecting ColdBox 5 ## 1.4.0 -* Update build process for new module standards -* ColdBox 5 Compatiblity for inherited entry points -* Non RESTFul action params where not being translated on routes. -* Fixed `int32` to `integer` on examples and tests so they can validate in the schema +- Update build process for new module standards +- ColdBox 5 Compatiblity for inherited entry points +- Non RESTFul action params where not being translated on routes. +- Fixed `int32` to `integer` on examples and tests so they can validate in the schema ## 1.3.0 -* Added Editor standards -* Fix to modules invocation path on RouteParser when no cfmapping defined. -* Updates to readme -* Set the contact object and license object according to spec 2 defaults -* Default the API schemes to http/s -* Dropped cf10 from automated tests -* Added API Docs to S3 via Travis +- Added Editor standards +- Fix to modules invocation path on RouteParser when no cfmapping defined. +- Updates to readme +- Set the contact object and license object according to spec 2 defaults +- Default the API schemes to http/s +- Dropped cf10 from automated tests +- Added API Docs to S3 via Travis ## 1.2.1 -* Fixes a bug where an error was thrown when an api route does not contain a handler -* Implements parsing of Coldbox route parameter types +- Fixes a bug where an error was thrown when an api route does not contain a handler +- Implements parsing of Coldbox route parameter types ## 1.2.0 -* Adds new function metadata handling for parameters and responses -* Auto maps hints provided in function metadata to as method descriptions +- Adds new function metadata handling for parameters and responses +- Auto maps hints provided in function metadata to as method descriptions ## 1.1.2 -* Add `$ref` sanitization and inherited metadata introspection -* Add the ability to handle arrays returned from `$ref` keys. Prepends moudule routing to operation id -* ACF syntax corrections and add better throw for attempts to parse component with syntax errors +- Add `$ref` sanitization and inherited metadata introspection +- Add the ability to handle arrays returned from `$ref` keys. Prepends moudule routing to operation id +- ACF syntax corrections and add better throw for attempts to parse component with syntax errors ## 1.1.0 -* Normalization to new module templates -* HTTP Verbs should be lower case [#1](https://github.com/coldbox-modules/cbSwagger/issues/1) +- Normalization to new module templates +- HTTP Verbs should be lower case [#1](https://github.com/coldbox-modules/cbSwagger/issues/1) ## 1.0.3 -* Exception when `handler` or `module` does not exist in a route. +- Exception when `handler` or `module` does not exist in a route. ## 1.0.2 -* Overall syntax Ortus standards -* Some var scoping issues -* Added persistence and injections to services -* Added more documentation to handler, services and readme -* Added swagger-sdk as a module dependency +- Overall syntax Ortus standards +- Some var scoping issues +- Added persistence and injections to services +- Added more documentation to handler, services and readme +- Added swagger-sdk as a module dependency ## 1.0.1 -* Add module introspection -* Forgebox integration updates +- Add module introspection +- Forgebox integration updates ## 1.0.0 -* Initial Module Release +- Initial Module Release + +[Unreleased]: https://github.com/coldbox-modules/cbSwagger/compare/v3.1.2...HEAD -[Unreleased]: https://github.com/coldbox-modules/cbSwagger/compare/v3.1.1...HEAD +[3.1.2]: https://github.com/coldbox-modules/cbSwagger/compare/v3.1.1...v3.1.2 [3.1.1]: https://github.com/coldbox-modules/cbSwagger/compare/v3.1.0...v3.1.1 From 12d0f33739ad7fcf4bc625c5edfa1d0dc9de163f Mon Sep 17 00:00:00 2001 From: jclausen Date: Wed, 25 Sep 2024 10:35:39 -0400 Subject: [PATCH 02/21] use lower casing on module name everywhere --- .github/workflows/release.yml | 2 +- .vscode/settings.json | 2 +- ModuleConfig.cfc | 12 +- box.json | 12 +- build/.travis.yml | 2 +- changelog.md | 140 +++++++++--------- models/RoutesParser.cfc | 6 +- readme.md | 24 +-- server-adobe@2018.json | 2 +- server-adobe@2021.json | 2 +- server-adobe@2023.json | 2 +- server-lucee@5.json | 2 +- test-harness/Application.cfc | 2 +- test-harness/handlers/api/v1/Users.cfc | 2 +- .../test-api-module/ModuleConfig.cfc | 2 +- .../test-api-module/handlers/UserPosts.cfc | 2 +- .../test-api-module/handlers/UserSettings.cfc | 2 +- .../test-api-module/handlers/Users.cfc | 2 +- test-harness/tests/Application.cfc | 4 +- test-harness/tests/specs/RoutesParserTest.cfc | 8 +- test-harness/views/main/index.cfm | 4 +- 21 files changed, 118 insertions(+), 118 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8166c2b..dbe588a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,7 +16,7 @@ on: type: boolean env: - MODULE_ID: cbSwagger + MODULE_ID: cbswagger SNAPSHOT: ${{ inputs.snapshot || false }} jobs: diff --git a/.vscode/settings.json b/.vscode/settings.json index 49c30ae..8f01489 100755 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -11,7 +11,7 @@ "isPhysicalDirectoryPath": false }, { - "logicalPath": "/cbSwagger", + "logicalPath": "/cbswagger", "directoryPath": "./", "isPhysicalDirectoryPath": false } diff --git a/ModuleConfig.cfc b/ModuleConfig.cfc index 2aa16bf..0f11d70 100644 --- a/ModuleConfig.cfc +++ b/ModuleConfig.cfc @@ -7,14 +7,14 @@ component { // Module Properties - this.title = "cbSwagger"; + this.title = "cbswagger"; this.author = "Jon Clausen "; - this.webURL = "https://github.com/coldbox-modules/cbSwagger"; + this.webURL = "https://github.com/coldbox-modules/cbswagger"; this.version = "@version.number@+@build.number@"; this.description = "A coldbox module to auto-generate Swagger API documentation from your configured routes"; - this.entryPoint = "cbSwagger"; - this.modelNamespace = "cbSwagger"; - this.cfmapping = "cbSwagger"; + this.entryPoint = "cbswagger"; + this.modelNamespace = "cbswagger"; + this.cfmapping = "cbswagger"; this.autoMapModels = true; this.dependencies = [ "swagger-sdk" ]; @@ -75,7 +75,7 @@ component { // A list of tags used by the specification with additional metadata. // https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#tagObject "tags" : [], - // Whether to enable endpoint and parsed doc caching by cbSwagger + // Whether to enable endpoint and parsed doc caching by cbswagger "cacheEnabled" : true }; diff --git a/box.json b/box.json index d03a852..8e6845d 100644 --- a/box.json +++ b/box.json @@ -1,18 +1,18 @@ { - "name":"cbSwagger", + "name":"cbswagger", "version":"3.1.3", "location":"https://downloads.ortussolutions.com/ortussolutions/coldbox-modules/cbswagger/@build.version@/cbswagger-@build.version@.zip", "author":"Ortus Solutions, Corp", - "slug":"cbSwagger", + "slug":"cbswagger", "type":"modules", "keywords":"Swagger,OpenAPI,API Docs", - "homepage":"https://github.com/coldbox-modules/cbSwagger", - "documentation":"https://github.com/coldbox-modules/cbSwagger/wiki", + "homepage":"https://github.com/coldbox-modules/cbswagger", + "documentation":"https://github.com/coldbox-modules/cbswagger/wiki", "repository":{ "type":"git", - "url":"https://github.com/coldbox-modules/cbSwagger" + "url":"https://github.com/coldbox-modules/cbswagger" }, - "bugs":"https://github.com/coldbox-modules/cbSwagger/issues", + "bugs":"https://github.com/coldbox-modules/cbswagger/issues", "shortDescription":"A Coldbox Module which automatically generates api documentation from your configured SES routes", "license":[ { diff --git a/build/.travis.yml b/build/.travis.yml index 8fa34f3..1bf6a8f 100644 --- a/build/.travis.yml +++ b/build/.travis.yml @@ -5,7 +5,7 @@ notifications: env: # Fill out these global variables for build process global: - - MODULE_ID=cbSwagger + - MODULE_ID=cbswagger matrix: - ENGINE=lucee@5 - ENGINE=adobe@2016 diff --git a/changelog.md b/changelog.md index db9dd6c..370cd6c 100644 --- a/changelog.md +++ b/changelog.md @@ -19,180 +19,180 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed -- Fix `box.json` version of `swagger-sdk` +* Fix `box.json` version of `swagger-sdk` ## [3.0.0] - 2024-05-30 ### Changed -- Interaction to WireBox via base test case and not application scope -- Removed support for Adobe Coldfusion 2016 -- Removes `default` key from response object if empty and other status code keys are present [Issue #28](https://github.com/coldbox-modules/cbSwagger/issues/28) +* Interaction to WireBox via base test case and not application scope +* Removed support for Adobe Coldfusion 2016 +* Removes `default` key from response object if empty and other status code keys are present [Issue #28](https://github.com/coldbox-modules/cbswagger/issues/28) ### Added -- Virtual application testing -- Updated github actions -- Updated module template provisions -- Added support for samples path shortcut annotation (`~`) in annotation JSON `$ref` pointers -- Added support for using globbing patterns in `excludeRoutes` array. [Issue #37](https://github.com/coldbox-modules/cbSwagger/issues/37) -- Added `cbswagger` endpoint caching ( defaults to `true` ) and `cacheEnabled` setting. -- Added URL convention for clearing/bypassing endpoint cache ( `swaggerCache=false` ) +* Virtual application testing +* Updated github actions +* Updated module template provisions +* Added support for samples path shortcut annotation (`~`) in annotation JSON `$ref` pointers +* Added support for using globbing patterns in `excludeRoutes` array. [Issue #37](https://github.com/coldbox-modules/cbswagger/issues/37) +* Added `cbswagger` endpoint caching ( defaults to `true` ) and `cacheEnabled` setting. +* Added URL convention for clearing/bypassing endpoint cache ( `swaggerCache=false` ) ## [2.7.0] => 2021-OCT-1 ### Added -- Added the ability to excludes routes by prefix +* Added the ability to excludes routes by prefix ## [2.5.1] => 2021-MAY-12 ### Fixed -- Regression on `@tags` being json syntax +* Regression on `@tags` being json syntax ## [2.5.0] => 2021-MAY-10 ### Added -- Added the ability to add `@tags` to annotations so they can show up on the operations metadata as array of `tags` +* Added the ability to add `@tags` to annotations so they can show up on the operations metadata as array of `tags` ## [2.4.0] => 2021-MAY-04 ### Removed -- Removed `externalDocs` from the `info` struct as it is not supported on the OpenApi Spec v3. +* Removed `externalDocs` from the `info` struct as it is not supported on the OpenApi Spec v3. ### Changed -- `operationID` renamed to `x-coldbox-operation` since they are ColdBox centric. It was also causing issues using `operationID` as it needed to be unique across the entire swagger document. +* `operationID` renamed to `x-coldbox-operation` since they are ColdBox centric. It was also causing issues using `operationID` as it needed to be unique across the entire swagger document. ## [2.3.0] => 2020-SEP-08 ### Added -- Add CORS support for cbswagger endpoint #25 +* Add CORS support for cbswagger endpoint #25 ## [2.2.1] => 2020-MAY-12 ### Fixed -- On lucee the `displayName` defaults to `Component`, skipping this default to select the correct `operationId` for the resource -- The `moduleName` hint for the `appendFunctionInfo` was mispelled +* On lucee the `displayName` defaults to `Component`, skipping this default to select the correct `operationId` for the resource +* The `moduleName` hint for the `appendFunctionInfo` was mispelled ## [2.2.0] => 2020-MAY-12 ### Added -- When defining external files in annotations, you can now prefix them with `~` and this will expand to the module setting of `samplesPath`. This way you can write your annotations in a more cleaner manner. -- Auto-publishing of changelog's to github -- New changelog looks according to keepachangelog.com +* When defining external files in annotations, you can now prefix them with `~` and this will expand to the module setting of `samplesPath`. This way you can write your annotations in a more cleaner manner. +* Auto-publishing of changelog's to github +* New changelog looks according to keepachangelog.com ## [2.1.1] => 2020-MAY-06 -- Updates to support ColdBox 6 +* Updates to support ColdBox 6 ## [2.1.0] => 2020-APR-16 ### Features -- Allow `@security` annotation to override the security mechanisms defined in config. The value can be a JSON array of security directives, a file pointer, or for convenience the name of a security schema. See readme for examples. -- Support for discovering responses and examples by conventions in the `resources/apidocs` folder convention. See readme for examples. -- Ability to exclude routes from the generated spec via the `excludeRoutes` configuration key. +* Allow `@security` annotation to override the security mechanisms defined in config. The value can be a JSON array of security directives, a file pointer, or for convenience the name of a security schema. See readme for examples. +* Support for discovering responses and examples by conventions in the `resources/apidocs` folder convention. See readme for examples. +* Ability to exclude routes from the generated spec via the `excludeRoutes` configuration key. ### Improvements -- Add default `samplesPath` config item to `resources/apidocs` in the ModuleConfig -- Add convention samples parsing and refactor segment parsing to separate methods +* Add default `samplesPath` config item to `resources/apidocs` in the ModuleConfig +* Add convention samples parsing and refactor segment parsing to separate methods ### Bugs -- Fixes for new router syntax not parsing actions correctly or not taking into account actions attached to verbs +* Fixes for new router syntax not parsing actions correctly or not taking into account actions attached to verbs ## [2.0.0] => 2019-SEP-02 -- `feature`: Upgraded to swagger-sdk 2.0.0 to support OpenAPI 3.0.x. A great guide on migrating is here: +* `feature`: Upgraded to swagger-sdk 2.0.0 to support OpenAPI 3.0.x. A great guide on migrating is here: -- Migrated `cbSwagger` settings to the `moduleSettings` struct instead of top-level in the `config/ColdBox.cfc`. Make sure you move your settings. +* Migrated `cbswagger` settings to the `moduleSettings` struct instead of top-level in the `config/ColdBox.cfc`. Make sure you move your settings. -- `feature` : You can now pass a `format` to the `/cbSwagger` endpoint to either get the OpenAPI doc as `json` or `yml`. Eg: `/cbswagger?format=yml` +* `feature` : You can now pass a `format` to the `/cbswagger` endpoint to either get the OpenAPI doc as `json` or `yml`. Eg: `/cbswagger?format=yml` -- `feature` : You have two distinct routes for the json and yml formats: `/cbSwagger/json` and `/cbSwagger/yml` +* `feature` : You have two distinct routes for the json and yml formats: `/cbswagger/json` and `/cbswagger/yml` -- You can choose your default output format via the module settings: `defaultFormat` setting. Valid options are `json` and `yml` +* You can choose your default output format via the module settings: `defaultFormat` setting. Valid options are `json` and `yml` -- `features` : Support for ColdBox 5 event routing and response routing. +* `features` : Support for ColdBox 5 event routing and response routing. -- `improvement` : You can now tag your handlers with a `displayName` that will be used for operation ID building +* `improvement` : You can now tag your handlers with a `displayName` that will be used for operation ID building -- `improvement` : Improved the way operation Ids are reported so they can be unique when reusing handler actions. +* `improvement` : Improved the way operation Ids are reported so they can be unique when reusing handler actions. -- `improvement` : Refactored `createLinkedHashMap()` -> `structNew( "ordered" )` +* `improvement` : Refactored `createLinkedHashMap()` -> `structNew( "ordered" )` -- `improvement`: Removed lucee 4.5, acf11 support. +* `improvement`: Removed lucee 4.5, acf11 support. ## 1.4.1 -- Fix for detecting ColdBox 5 +* Fix for detecting ColdBox 5 ## 1.4.0 -- Update build process for new module standards -- ColdBox 5 Compatiblity for inherited entry points -- Non RESTFul action params where not being translated on routes. -- Fixed `int32` to `integer` on examples and tests so they can validate in the schema +* Update build process for new module standards +* ColdBox 5 Compatiblity for inherited entry points +* Non RESTFul action params where not being translated on routes. +* Fixed `int32` to `integer` on examples and tests so they can validate in the schema ## 1.3.0 -- Added Editor standards -- Fix to modules invocation path on RouteParser when no cfmapping defined. -- Updates to readme -- Set the contact object and license object according to spec 2 defaults -- Default the API schemes to http/s -- Dropped cf10 from automated tests -- Added API Docs to S3 via Travis +* Added Editor standards +* Fix to modules invocation path on RouteParser when no cfmapping defined. +* Updates to readme +* Set the contact object and license object according to spec 2 defaults +* Default the API schemes to http/s +* Dropped cf10 from automated tests +* Added API Docs to S3 via Travis ## 1.2.1 -- Fixes a bug where an error was thrown when an api route does not contain a handler -- Implements parsing of Coldbox route parameter types +* Fixes a bug where an error was thrown when an api route does not contain a handler +* Implements parsing of Coldbox route parameter types ## 1.2.0 -- Adds new function metadata handling for parameters and responses -- Auto maps hints provided in function metadata to as method descriptions +* Adds new function metadata handling for parameters and responses +* Auto maps hints provided in function metadata to as method descriptions ## 1.1.2 -- Add `$ref` sanitization and inherited metadata introspection -- Add the ability to handle arrays returned from `$ref` keys. Prepends moudule routing to operation id -- ACF syntax corrections and add better throw for attempts to parse component with syntax errors +* Add `$ref` sanitization and inherited metadata introspection +* Add the ability to handle arrays returned from `$ref` keys. Prepends moudule routing to operation id +* ACF syntax corrections and add better throw for attempts to parse component with syntax errors ## 1.1.0 -- Normalization to new module templates -- HTTP Verbs should be lower case [#1](https://github.com/coldbox-modules/cbSwagger/issues/1) +* Normalization to new module templates +* HTTP Verbs should be lower case [#1](https://github.com/coldbox-modules/cbswagger/issues/1) ## 1.0.3 -- Exception when `handler` or `module` does not exist in a route. +* Exception when `handler` or `module` does not exist in a route. ## 1.0.2 -- Overall syntax Ortus standards -- Some var scoping issues -- Added persistence and injections to services -- Added more documentation to handler, services and readme -- Added swagger-sdk as a module dependency +* Overall syntax Ortus standards +* Some var scoping issues +* Added persistence and injections to services +* Added more documentation to handler, services and readme +* Added swagger-sdk as a module dependency ## 1.0.1 -- Add module introspection -- Forgebox integration updates +* Add module introspection +* Forgebox integration updates ## 1.0.0 -- Initial Module Release +* Initial Module Release [Unreleased]: https://github.com/coldbox-modules/cbSwagger/compare/v3.1.2...HEAD @@ -200,4 +200,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [3.1.1]: https://github.com/coldbox-modules/cbSwagger/compare/v3.1.0...v3.1.1 -[3.0.0]: https://github.com/coldbox-modules/cbSwagger/compare/5be045e7bd456304f3e338fd5e4f5ca94342dad0...v3.0.0 +[3.0.0]: https://github.com/coldbox-modules/cbswagger/compare/5be045e7bd456304f3e338fd5e4f5ca94342dad0...v3.0.0 diff --git a/models/RoutesParser.cfc b/models/RoutesParser.cfc index b13cd14..b9b73ce 100644 --- a/models/RoutesParser.cfc +++ b/models/RoutesParser.cfc @@ -72,7 +72,7 @@ component accessors="true" threadsafe singleton { } /** - * Filters the designated routes as provided in the cbSwagger configuration + * Filters the designated routes as provided in the cbswagger configuration */ private any function filterDesignatedRoutes(){ // make a copy of our routes array so we can append it @@ -421,7 +421,7 @@ component accessors="true" threadsafe singleton { * * @return struct of handlerMetadata * - * @throws cbSwagger.RoutesParse.handlerSyntaxException + * @throws cbswagger.RoutesParse.handlerSyntaxException */ private any function getHandlerMetadata( required any route ){ var module = ( isNull( arguments.route.module ) ? "" : arguments.route.module ); @@ -452,7 +452,7 @@ component accessors="true" threadsafe singleton { return util.getInheritedMetadata( invocationPath ); } catch ( any e ) { throw( - type = "cbSwagger.RoutesParse.handlerSyntaxException", + type = "cbswagger.RoutesParse.handlerSyntaxException", message = "The handler at #invocationPath# could not be parsed. The error that occurred: #e.message#", extendedInfo = e.detail ); diff --git a/readme.md b/readme.md index 64b4f51..5abfdab 100644 --- a/readme.md +++ b/readme.md @@ -25,7 +25,7 @@ Apache License, Version 2.0. ## Important links -- https://github.com/coldbox-modules/cbSwagger +- https://github.com/coldbox-modules/cbswagger ## Resources @@ -45,13 +45,13 @@ To operate, the module requires that SES routing be enabled in your application. ## Install cbSWagger ( via Commandbox ) -`box install cbSwagger` +`box install cbswagger` > Note: Omit the `box` from your command, if you are already in the Commandbox interactive shell -## Configure cbSwagger to auto-detect your API Routes +## Configure cbswagger to auto-detect your API Routes -By default, cbSwagger looks for routes beginning with `/api/*` prefix. By adding a `cbSwagger` configuration key to your Coldbox configuration, you can add additional metadata to the OpenAPI JSON produced by the module entry point and configure this module for operation. +By default, cbswagger looks for routes beginning with `/api/*` prefix. By adding a `cbswagger` configuration key to your Coldbox configuration, you can add additional metadata to the OpenAPI JSON produced by the module entry point and configure this module for operation. * `routes:array` : An array of route prefixes to search for and add to the resulting documentation. * `defaultFormat:string` : The default output format of the documentation. Valid options are `json` and `yml`. @@ -64,7 +64,7 @@ cbswagger = { "routes" : [ "api" ], // The default output format: json or yml // Routes to exclude by prefix. Routes beginning with this prefix will be excluded - "excludeRoutesPrefix" : [ "cbSwagger", "relax" ], + "excludeRoutesPrefix" : [ "cbswagger", "relax" ], // Any routes to exclude - may use exact matches or globbing patterns e.g `[ "api/v1/mysecret" ]` or `[ "**/secret", "**/undocumented" ]` (no initial `/`, trailing `/` optional for routes) "excludeRoutes" : [], // Routes to exclude based on event @@ -159,22 +159,22 @@ cbswagger = { ## Outputting Documentation (json|yml) -You can visit the API documentation by hitting the `/cbSwagger` route. This will trigger the default format (json) to be sent to the output. +You can visit the API documentation by hitting the `/cbswagger` route. This will trigger the default format (json) to be sent to the output. ### Format Parameter You can force the format by using the `?format={format}` in the URI. The valid options are `json` and `yml` ``` -http://localhost/cbSwagger?format=yml -http://localhost/cbSwagger?format=json -http://localhost/cbSwagger/json -http://localhost/cbSwagger/yml +http://localhost/cbswagger?format=yml +http://localhost/cbswagger?format=json +http://localhost/cbswagger/json +http://localhost/cbswagger/yml ``` ## Handler Introspection & Documentation attributes -`cbSwagger` will automatically introspect your API handlers provided by your routing configuration. You may provide additional function attributes (**metadata**), which will be picked up and included in your documentation. +`cbswagger` will automatically introspect your API handlers provided by your routing configuration. You may provide additional function attributes (**metadata**), which will be picked up and included in your documentation. The content body of these function metadata/attributes may be provided as: @@ -187,7 +187,7 @@ Here are some additional pointers for you: - Metadata attributes using a `response-` prefix in the annotation will be parsed as responses. For example `@response-200 { "description" : "User successfully updated", "schema" : "/resources/apidocs/schema.json##user" }` would populate the `200` responses node for the given method ( in this case, `PUT /api/v1/users/:id` ). If the annotation text is not valid JSON or a file pointer, this will be provided as the response description. - Metadata attributes prefixed with `param-` will be included as parameters to the method/action. Example: `@param-firstname { "type": "string", "required" : "false", "in" : "query" }` If the annotation text is not valid JSON or a file pointer, this will be provided as the parameter description and the parameter requirement will be set to `false`. - Parameters provided via the route ( e.g. the `id` in `/api/v1/users/:id` ) will always be included in the array of parameters as required for the method. Annotations on those parameters may be used to provide additional documentation. -- [Security Requirement Objects](https://swagger.io/specification/#securityRequirementObject) defined in the cbSwagger config will be displayed on every API method, except methods that override the default with `@security`. You may use the name of a security scheme, a JSON array of Security Requirement Objects, or a file pointer. Security Requirement Objects must have the same name as a Security Scheme Object defined under components in `cbSwagger` settings. +- [Security Requirement Objects](https://swagger.io/specification/#securityRequirementObject) defined in the cbswagger config will be displayed on every API method, except methods that override the default with `@security`. You may use the name of a security scheme, a JSON array of Security Requirement Objects, or a file pointer. Security Requirement Objects must have the same name as a Security Scheme Object defined under components in `cbswagger` settings. - You may also provide paths to JSON files which describe complex objects which may not be expressed within the attributes themselves. This is ideal to provide an endpoint for [parameters](https://swagger.io/specification/#parameterObject) and [responses](https://swagger.io/specification/#responsesObject) If the atttribute ends with `.json`, this will be included in the generated OpenAPI document as a [$ref include](https://swagger.io/specification/#pathItemObject). - Attributes which are not part of the swagger path specification should be prefixed with an `x-`, [x-attributes](https://swagger.io/specification/#specificationExtensions) are an official part of the OpenAPI Specification and may be used to provide additional information for your developers and consumers - `hint` attributes, provided as either comment `@` annotations or as function body attributes will be treated as the description for the method diff --git a/server-adobe@2018.json b/server-adobe@2018.json index 1473e84..0479108 100644 --- a/server-adobe@2018.json +++ b/server-adobe@2018.json @@ -13,7 +13,7 @@ }, "webroot": "test-harness", "aliases":{ - "/moduleroot/cbSwagger":"../" + "/moduleroot/cbswagger":"../" } }, "openBrowser":"false", diff --git a/server-adobe@2021.json b/server-adobe@2021.json index f10ef13..1e11647 100644 --- a/server-adobe@2021.json +++ b/server-adobe@2021.json @@ -13,7 +13,7 @@ }, "webroot": "test-harness", "aliases":{ - "/moduleroot/cbSwagger":"../" + "/moduleroot/cbswagger":"../" } }, "openBrowser":"false", diff --git a/server-adobe@2023.json b/server-adobe@2023.json index 8499be2..e889825 100644 --- a/server-adobe@2023.json +++ b/server-adobe@2023.json @@ -13,7 +13,7 @@ }, "webroot":"test-harness", "aliases":{ - "/moduleroot/cbSwagger":"../" + "/moduleroot/cbswagger":"../" } }, "openBrowser":"false", diff --git a/server-lucee@5.json b/server-lucee@5.json index b046de2..7c3211f 100644 --- a/server-lucee@5.json +++ b/server-lucee@5.json @@ -13,7 +13,7 @@ }, "webroot":"test-harness", "aliases":{ - "/moduleroot/cbSwagger":"../" + "/moduleroot/cbswagger":"../" } }, "openBrowser":"false", diff --git a/test-harness/Application.cfc b/test-harness/Application.cfc index 07a2275..d687f2a 100644 --- a/test-harness/Application.cfc +++ b/test-harness/Application.cfc @@ -7,7 +7,7 @@ www.ortussolutions.com component{ // UPDATE THE NAME OF THE MODULE IN TESTING BELOW - request.MODULE_NAME = "cbSwagger"; + request.MODULE_NAME = "cbswagger"; // Application properties this.name = hash( getCurrentTemplatePath() ); diff --git a/test-harness/handlers/api/v1/Users.cfc b/test-harness/handlers/api/v1/Users.cfc index 164225b..48cfa79 100755 --- a/test-harness/handlers/api/v1/Users.cfc +++ b/test-harness/handlers/api/v1/Users.cfc @@ -1,7 +1,7 @@ /** * * @name User API Controller - * @package cbSwagger-shell + * @package cbswagger-shell * @description This is the User API Controller * @author Jon Clausen * diff --git a/test-harness/modules_app/test-api-module/ModuleConfig.cfc b/test-harness/modules_app/test-api-module/ModuleConfig.cfc index 232db8d..113da84 100644 --- a/test-harness/modules_app/test-api-module/ModuleConfig.cfc +++ b/test-harness/modules_app/test-api-module/ModuleConfig.cfc @@ -9,7 +9,7 @@ component { this.title = "test-api-module"; this.author = "Jon Clausen "; this.webURL = "N/A"; - this.description = "A test api module for cbSwagger"; + this.description = "A test api module for cbswagger"; this.version = "0.0.1"; // If true, looks for views in the parent first, if not found, then in the module. Else vice-versa this.viewParentLookup = true; diff --git a/test-harness/modules_app/test-api-module/handlers/UserPosts.cfc b/test-harness/modules_app/test-api-module/handlers/UserPosts.cfc index cbde5ea..fd27ba5 100644 --- a/test-harness/modules_app/test-api-module/handlers/UserPosts.cfc +++ b/test-harness/modules_app/test-api-module/handlers/UserPosts.cfc @@ -1,7 +1,7 @@ /** * * @name User API Controller - * @package cbSwagger-shell + * @package cbswagger-shell * @description This is the User Posts API Controller * @author Jon Clausen * diff --git a/test-harness/modules_app/test-api-module/handlers/UserSettings.cfc b/test-harness/modules_app/test-api-module/handlers/UserSettings.cfc index 8544a80..8efeb75 100644 --- a/test-harness/modules_app/test-api-module/handlers/UserSettings.cfc +++ b/test-harness/modules_app/test-api-module/handlers/UserSettings.cfc @@ -1,7 +1,7 @@ /** * * @name UserSettings API Controller - * @package cbSwagger-shell + * @package cbswagger-shell * @description This is the User Settings API Controller * @author Jon Clausen * diff --git a/test-harness/modules_app/test-api-module/handlers/Users.cfc b/test-harness/modules_app/test-api-module/handlers/Users.cfc index 8c4d8bc..7a504a8 100755 --- a/test-harness/modules_app/test-api-module/handlers/Users.cfc +++ b/test-harness/modules_app/test-api-module/handlers/Users.cfc @@ -1,7 +1,7 @@ /** * * @name User API Controller - * @package cbSwagger-shell + * @package cbswagger-shell * @description This is the User API Controller * @author Jon Clausen * diff --git a/test-harness/tests/Application.cfc b/test-harness/tests/Application.cfc index 21fca6f..49097dd 100644 --- a/test-harness/tests/Application.cfc +++ b/test-harness/tests/Application.cfc @@ -6,9 +6,9 @@ component { // The name of the module used in cfmappings ,etc - request.MODULE_NAME = "cbSwagger"; + request.MODULE_NAME = "cbswagger"; // The directory name of the module on disk. Usually, it's the same as the module name - request.MODULE_PATH = "cbSwagger"; + request.MODULE_PATH = "cbswagger"; // APPLICATION CFC PROPERTIES this.name = "#request.MODULE_NAME# Testing Suite"; diff --git a/test-harness/tests/specs/RoutesParserTest.cfc b/test-harness/tests/specs/RoutesParserTest.cfc index 2c1e3cd..b3a9f02 100644 --- a/test-harness/tests/specs/RoutesParserTest.cfc +++ b/test-harness/tests/specs/RoutesParserTest.cfc @@ -15,9 +15,9 @@ component // Wire up this object getWireBox().autowire( this ); variables.testHandlerMetadata = getMetadata( createObject( "component", "handlers.api.v1.Users" ) ); - variables.cbSwaggerSettings = controller.getSetting( "modules" ).cbSwagger.settings; + variables.cbswaggerSettings = controller.getSetting( "modules" ).cbswagger.settings; - variables.model = prepareMock( new cbSwagger.models.RoutesParser() ); + variables.model = prepareMock( new cbswagger.models.RoutesParser() ); getWireBox().autowire( variables.model ); variables.samplesPath = controller.getAppRootPath() & variables.model.getModuleSettings().samplesPath; @@ -115,7 +115,7 @@ component var APIPaths = normalizedDoc[ "paths" ]; // pull our routing configuration - var apiPrefixes = cbSwaggerSettings.routes; + var apiPrefixes = cbswaggerSettings.routes; expect( apiPrefixes ).toBeArray(); var CBRoutes = getController() @@ -150,7 +150,7 @@ component var APIPaths = normalizedDoc[ "paths" ]; // pull our routing configuration - var apiPrefixes = cbSwaggerSettings.routes; + var apiPrefixes = cbswaggerSettings.routes; expect( apiPrefixes ).toBeArray(); var TLRoutes = getController().getRoutingService().getRoutes(); diff --git a/test-harness/views/main/index.cfm b/test-harness/views/main/index.cfm index 2c3ee59..44bcdd4 100644 --- a/test-harness/views/main/index.cfm +++ b/test-harness/views/main/index.cfm @@ -1,4 +1,4 @@ -

cbSwagger is Up and Running!

-

Go visit it at /cbSwagger

+

cbswagger is Up and Running!

+

Go visit it at /cbswagger

From ad821962c30ad592c90865af066d71821f4a4d1e Mon Sep 17 00:00:00 2001 From: Oscar Tisnado <68830577+otisnado@users.noreply.github.com> Date: Fri, 6 Dec 2024 12:40:12 -0600 Subject: [PATCH 03/21] add boxlang to matrix --- .github/workflows/tests.yml | 3 +++ server-boxlag@1.json | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 server-boxlag@1.json diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index fa20851..2f06cb6 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -33,6 +33,9 @@ jobs: - coldboxVersion: "be" cfengine: "adobe@2021" experimental: true + - coldboxVersion: "be" + cfengine: "boxlang@1" + experimental: true steps: - name: Checkout Repository uses: actions/checkout@v3 diff --git a/server-boxlag@1.json b/server-boxlag@1.json new file mode 100644 index 0000000..bb1c16c --- /dev/null +++ b/server-boxlag@1.json @@ -0,0 +1,36 @@ +{ + "app":{ + "cfengine":"boxlang@be", + "serverHomeDirectory":".engine/boxlang" + }, + "name":"cbSwagger-boxlang@1", + "force":true, + "openBrowser":false, + "web":{ + "directoryBrowsing":true, + "http":{ + "port":"60299" + }, + "rewrites":{ + "enable":"true" + }, + "webroot":"test-harness", + "aliases":{ + "/moduleroot/cbSwagger":"./" + } + }, + "JVM":{ + "heapSize":"1024", + "javaVersion":"openjdk21_jdk", + "args":"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=9999" + }, + "cfconfig":{ + "file":".cfconfig.json" + }, + "env":{ + "BOXLANG_DEBUG":true + }, + "scripts":{ + "onServerInitialInstall":"install bx-mail,bx-mysql,bx-derby,bx-compat-cfml@be,bx-unsafe-evaluate,bx-esapi --noSave" + } +} \ No newline at end of file From f24031da5f878cc071ecc5a3d989e1baa704e7f6 Mon Sep 17 00:00:00 2001 From: Oscar Tisnado <68830577+otisnado@users.noreply.github.com> Date: Fri, 24 Jan 2025 12:40:37 -0600 Subject: [PATCH 04/21] ci: enable workflow dispatch to run test from trigger --- .github/workflows/snapshot.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index 45d7dd1..152c9c8 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -4,6 +4,7 @@ on: push: branches: - 'development' + workflow_dispatch: jobs: ########################################################################################## From 7b0db55015aea2a0bd8038afaf67125ddb79db76 Mon Sep 17 00:00:00 2001 From: Oscar Tisnado <68830577+otisnado@users.noreply.github.com> Date: Fri, 24 Jan 2025 13:00:09 -0600 Subject: [PATCH 05/21] fix: rename server-boxlag@1.json to server-boxlang@1.json --- server-boxlag@1.json => server-boxlang@1.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename server-boxlag@1.json => server-boxlang@1.json (99%) diff --git a/server-boxlag@1.json b/server-boxlang@1.json similarity index 99% rename from server-boxlag@1.json rename to server-boxlang@1.json index bb1c16c..923c647 100644 --- a/server-boxlag@1.json +++ b/server-boxlang@1.json @@ -33,4 +33,4 @@ "scripts":{ "onServerInitialInstall":"install bx-mail,bx-mysql,bx-derby,bx-compat-cfml@be,bx-unsafe-evaluate,bx-esapi --noSave" } -} \ No newline at end of file +} From 8c168b6618b2d60fc98958a107b016012c265216 Mon Sep 17 00:00:00 2001 From: Oscar Tisnado <68830577+otisnado@users.noreply.github.com> Date: Sun, 26 Jan 2025 10:52:06 -0600 Subject: [PATCH 06/21] change repository directory to match 12d0f33739ad7fcf4bc625c5edfa1d0dc9de163f change --- .github/workflows/tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2f06cb6..0fa487b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -39,6 +39,8 @@ jobs: steps: - name: Checkout Repository uses: actions/checkout@v3 + with: + path: cbswagger # - name: Setup Database and Fixtures # run: | From 240dd4799ab218189e22b8710f87d6e6764a5fb7 Mon Sep 17 00:00:00 2001 From: Oscar Tisnado <68830577+otisnado@users.noreply.github.com> Date: Sun, 26 Jan 2025 11:04:20 -0600 Subject: [PATCH 07/21] set default working directory due module name is in lower case --- .github/workflows/tests.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0fa487b..605911d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -11,6 +11,9 @@ jobs: tests: name: Tests runs-on: ubuntu-20.04 + defaults: + run: + working-directory: ${{ github.workspace }}/cbswagger env: DB_USER: root DB_PASSWORD: root From 4cd4bc3b1f9841592fc28c6379fb3e6a21806ee4 Mon Sep 17 00:00:00 2001 From: Oscar Tisnado <68830577+otisnado@users.noreply.github.com> Date: Sun, 26 Jan 2025 11:23:24 -0600 Subject: [PATCH 08/21] EnricoMi/publish-unit-test-result-action@v2 and actions/upload-artifact@v3 don't care about workflow default workfing directory? --- .github/workflows/tests.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 605911d..8c873dc 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -96,7 +96,7 @@ jobs: uses: EnricoMi/publish-unit-test-result-action@v2 if: always() with: - junit_files: test-harness/tests/results/**/*.xml + junit_files: ${{ github.workspace }}/cbswagger/test-harness/tests/results/**/*.xml check_name: "${{ matrix.cfengine }} ColdBox ${{ matrix.coldboxVersion }} Test Results" - name: Upload Test Results to Artifacts @@ -105,7 +105,7 @@ jobs: with: name: test-results-${{ matrix.cfengine }}-${{ matrix.coldboxVersion }} path: | - test-harness/tests/results/**/* + ${{ github.workspace }}/cbswagger/test-harness/tests/results/**/* - name: Show Server Log On Failures if: ${{ failure() }} @@ -118,8 +118,8 @@ jobs: with: name: Failure Debugging Info - ${{ matrix.cfengine }} - ${{ matrix.coldboxVersion }} path: | - .engine/**/logs/* - .engine/**/WEB-INF/cfusion/logs/* + ${{ github.workspace }}/cbswagger/.engine/**/logs/* + ${{ github.workspace }}/cbswagger/.engine/**/WEB-INF/cfusion/logs/* - name: Slack Notifications # Only on failures and NOT in pull requests From c01fe65001475d048b634b1627685c2c29b0d2af Mon Sep 17 00:00:00 2001 From: Oscar Tisnado <68830577+otisnado@users.noreply.github.com> Date: Fri, 31 Jan 2025 15:00:17 -0600 Subject: [PATCH 09/21] ci: upgrade deprecated version of actions/upload-artifact --- .github/workflows/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8c873dc..2d8971b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -101,7 +101,7 @@ jobs: - name: Upload Test Results to Artifacts if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: test-results-${{ matrix.cfengine }}-${{ matrix.coldboxVersion }} path: | @@ -114,7 +114,7 @@ jobs: - name: Upload Debug Logs To Artifacts if: ${{ failure() }} - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: Failure Debugging Info - ${{ matrix.cfengine }} - ${{ matrix.coldboxVersion }} path: | From 6a9032e8e996ee5974530d3fe52f868aeeee464a Mon Sep 17 00:00:00 2001 From: Oscar Tisnado <68830577+otisnado@users.noreply.github.com> Date: Fri, 31 Jan 2025 16:49:33 -0600 Subject: [PATCH 10/21] build: install commandbox-boxlang with force till commandbox 6.2.0 --- .github/workflows/tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2d8971b..c010fd2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -77,6 +77,7 @@ jobs: - name: Install Test Harness with ColdBox ${{ matrix.coldboxVersion }} run: | + box install commandbox-boxlang --force box install cd test-harness box package set dependencies.coldbox=${{ matrix.coldboxVersion }} From dd635f71b2b16fa95f7c1c273345ece4be78bf3e Mon Sep 17 00:00:00 2001 From: Oscar Tisnado <68830577+otisnado@users.noreply.github.com> Date: Tue, 4 Feb 2025 22:50:24 -0600 Subject: [PATCH 11/21] ci: use ubuntu-24.04 runner --- .github/workflows/pr.yml | 2 +- .github/workflows/release.yml | 4 ++-- .github/workflows/snapshot.yml | 2 +- .github/workflows/tests.yml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 1635707..76b81f6 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -18,7 +18,7 @@ jobs: formatCheck: name: Checks Source Code Formatting - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 steps: - name: Checkout Repository uses: actions/checkout@v3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index dbe588a..b7017cc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -25,7 +25,7 @@ jobs: ########################################################################################## build: name: Build & Publish - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 steps: - name: Checkout Repository uses: actions/checkout@v3 @@ -133,7 +133,7 @@ jobs: prep_next_release: name: Prep Next Release if: github.ref == 'refs/heads/main' - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 needs: [build] steps: # Checkout development diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index 152c9c8..387ea5f 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -19,7 +19,7 @@ jobs: ########################################################################################## format: name: Code Auto-Formatting - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c010fd2..388ba3d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -10,7 +10,7 @@ on: jobs: tests: name: Tests - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 defaults: run: working-directory: ${{ github.workspace }}/cbswagger From ba765ff686b880da530933186a4186ecbd0ff23e Mon Sep 17 00:00:00 2001 From: Jon Clausen Date: Fri, 1 Nov 2024 17:27:33 -0400 Subject: [PATCH 12/21] add lucee@6 to matrix --- .github/workflows/tests.yml | 6 +++--- server-lucee@6.json | 23 +++++++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 server-lucee@6.json diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 388ba3d..f67eec3 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -20,8 +20,8 @@ jobs: strategy: fail-fast: false matrix: - cfengine: [ "lucee@5", "adobe@2018", "adobe@2021" ] - coldboxVersion: [ "^6.0.0" ] + cfengine: [ "lucee@5", "lucee@6" ,"adobe@2018", "adobe@2021" ] + coldboxVersion: [ "^6.0.0", "^7.0.0" ] experimental: [ false ] include: - cfengine: "adobe@2023" @@ -34,7 +34,7 @@ jobs: cfengine: "adobe@2018" experimental: true - coldboxVersion: "be" - cfengine: "adobe@2021" + cfengine: "adobe@2023" experimental: true - coldboxVersion: "be" cfengine: "boxlang@1" diff --git a/server-lucee@6.json b/server-lucee@6.json new file mode 100644 index 0000000..706e573 --- /dev/null +++ b/server-lucee@6.json @@ -0,0 +1,23 @@ +{ + "name":"cbswagger-lucee@6", + "app":{ + "serverHomeDirectory":".engine/lucee5", + "cfengine":"lucee@6" + }, + "web":{ + "http":{ + "port":"60299" + }, + "rewrites":{ + "enable":"true" + }, + "webroot":"test-harness", + "aliases":{ + "/moduleroot/cbswagger":"../" + } + }, + "openBrowser":"false", + "cfconfig":{ + "file":".cfconfig.json" + } +} From 9f480af473f98f9f5da4fe8db6e3ec8fb1df997f Mon Sep 17 00:00:00 2001 From: Eric Peterson Date: Tue, 11 Feb 2025 13:34:47 -0700 Subject: [PATCH 13/21] Generate cbValidation constraints from Swagger docs --- models/OpenAPIConstraintsGenerator.cfc | 226 ++++++++++++++++++ readme.md | 42 ++++ server-adobe@2018.json | 10 +- .../resources/users.add.requestBody.json | 49 ++++ .../specs/OpenAPIConstraintsGeneratorTest.cfc | 39 +++ 5 files changed, 361 insertions(+), 5 deletions(-) create mode 100644 models/OpenAPIConstraintsGenerator.cfc create mode 100644 test-harness/includes/resources/users.add.requestBody.json create mode 100644 test-harness/tests/specs/OpenAPIConstraintsGeneratorTest.cfc diff --git a/models/OpenAPIConstraintsGenerator.cfc b/models/OpenAPIConstraintsGenerator.cfc new file mode 100644 index 0000000..8435f8f --- /dev/null +++ b/models/OpenAPIConstraintsGenerator.cfc @@ -0,0 +1,226 @@ +component name="OpenAPIConstraintsGenerator" { + + property name="cache" inject="cachebox:template"; + + public struct function generateConstraintsFromOpenAPISchema( + string parametersPath = "", + string requestBodyPath = "", + boolean discoverPaths = true, + string callingFunctionName + ){ + var paths = _discoverPaths( argumentCollection = arguments ); + + var constraints = {}; + + if ( paths.parametersPath != "" ) { + var parametersJSON = variables.cache.getOrSet( + paths.parametersPath, + () => { + return deserializeJSON( fileRead( expandPath( paths.parametersPath ) ) ); + }, + createTimespan( 1, 0, 0, 0 ) + ); + structAppend( constraints, generateConstraintsFromParameters( parametersJSON[ paths.parametersKey ] ) ) + } + + if ( paths.requestBodyPath != "" ) { + var requestBodyJSON = variables.cache.getOrSet( + paths.requestBodyPath, + () => { + return deserializeJSON( fileRead( expandPath( paths.requestBodyPath ) ) ); + }, + createTimespan( 1, 0, 0, 0 ) + ); + var schema = requestBodyJSON[ "content" ][ "application/json" ][ "schema" ]; + structAppend( + constraints, + generateConstraintsFromRequestBodyProperties( schema.properties, schema.required ) + ); + } + + return constraints; + } + + private struct function generateConstraintsFromParameters( required array parameters ){ + return arguments.parameters.reduce( ( allConstraints, parameter ) => { + allConstraints[ parameter.name ] = generateConstraint( + schema = ( parameter.schema ?: {} ), + isRequired = ( parameter.required ?: false ) + ); + return allConstraints; + }, {} ); + } + + private struct function generateConstraintsFromRequestBodyProperties( + required struct properties, + required array requiredFields + ){ + return arguments.properties.map( ( fieldName, schema ) => { + return generateConstraint( + schema = schema, + isRequired = arrayContainsNoCase( requiredFields, fieldName ) > 0 + ); + } ); + } + + private struct function generateConstraint( required struct schema, required boolean isRequired ){ + var constraints = {}; + constraints[ "required" ] = arguments.isRequired; + addValidationType( constraints, schema ); + if ( constraints[ "type" ] == "struct" ) { + constraints[ "constraints" ] = generateConstraintsFromRequestBodyProperties( + schema.properties, + schema.required ?: [] + ); + } + if ( constraints[ "type" ] == "array" ) { + constraints[ "items" ] = generateConstraint( schema.items, arguments.isRequired ); + } + if ( schema.keyExists( "enum" ) ) { + constraints[ "inList" ] = arrayToList( schema[ "enum" ] ); + } + if ( schema.keyExists( "minimum" ) ) { + constraints[ "min" ] = schema[ "minimum" ]; + } + if ( schema.keyExists( "maximum" ) ) { + constraints[ "max" ] = schema[ "maximum" ]; + } + if ( schema.keyExists( "default" ) ) { + constraints[ "defaultValue" ] = schema[ "default" ]; + } + if ( schema.keyExists( "minLength" ) || schema.keyExists( "maxLength" ) ) { + param schema.minLength = ""; + param schema.maxLength = ""; + constraints[ "size" ] = "#schema.minLength#..#schema.maxLength#"; + } + if ( schema.keyExists( "x-coldbox-additional-validation" ) ) { + structAppend( constraints, schema[ "x-coldbox-additional-validation" ] ); + } + for ( + var c in [ + "after", + "afterOrEqual", + "before", + "beforeOrEqual", + "dateEquals" + ] + ) { + if ( constraints.keyExists( c ) && constraints[ c ] == "now" ) { + constraints[ c ] = now(); + } + } + return constraints; + } + + private string function addValidationType( required struct constraints, required struct metadata ){ + param arguments.metadata.type = ""; + param arguments.metadata.format = ""; + switch ( arguments.metadata.type ) { + case "integer": + arguments.constraints[ "type" ] = "integer"; + break; + case "number": + switch ( arguments.metadata.format ) { + case "double": + case "float": + arguments.constraints[ "type" ] = "float"; + break; + default: + arguments.constraints[ "type" ] = "numeric"; + break; + } + break; + case "boolean": + arguments.constraints[ "type" ] = "boolean"; + break; + case "array": + arguments.constraints[ "type" ] = "array"; + break; + case "object": + arguments.constraints[ "type" ] = "struct"; + break; + case "string": + switch ( arguments.metadata.format ) { + case "date-time-without-timezone": + arguments.constraints[ "type" ] = "date"; + break; + default: + arguments.constraints[ "type" ] = "string"; + break; + } + break; + } + } + + private struct function _discoverPaths( + string parametersPath = "", + string requestBodyPath = "", + boolean discoverPaths = true, + string callingComponent, + string callingFunctionName + ){ + var parametersKey = "parameters"; + if ( arguments.parametersPath != "" ) { + parametersKey = listLast( arguments.parametersPath, "####" ); + arguments.parametersPath = reReplaceNoCase( + listFirst( arguments.parametersPath, "####" ), + "^~", + "/resources/apidocs/" + ); + if ( parametersKey == "" ) { + parametersKey = "parameters"; + } + } + + if ( arguments.discoverPaths ) { + if ( arguments.parametersPath == "" || arguments.requestBodyPath == "" ) { + param variables.localActions = getMetadata( variables.$parent ).functions; + if ( isNull( arguments.callingFunctionName ) ) { + var stackFrames = callStackGet(); + for ( var stackFrame in stackFrames ) { + if ( + !arrayContains( + [ + "_discoverPaths", + "generateConstraintsFromOpenAPISchema", + "getByDelegate" + ], + stackFrame[ "function" ] + ) + ) { + arguments.callingFunctionName = stackFrame[ "function" ]; + break; + } + } + } + var callingFunction = variables.localActions.filter( ( action ) => { + return action.name == callingFunctionName; + } ); + if ( !callingFunction.isEmpty() ) { + if ( arguments.parametersPath == "" && callingFunction[ 1 ].keyExists( "x-parameters" ) ) { + parametersKey = listLast( callingFunction[ 1 ][ "x-parameters" ], "####" ); + arguments.parametersPath = reReplaceNoCase( + listFirst( callingFunction[ 1 ][ "x-parameters" ], "####" ), + "^~", + "/resources/apidocs/" + ); + } + if ( arguments.requestBodyPath == "" && callingFunction[ 1 ].keyExists( "requestBody" ) ) { + arguments.requestBodyPath = reReplaceNoCase( + listFirst( callingFunction[ 1 ][ "requestBody" ], "####" ), + "^~", + "/resources/apidocs/" + ); + } + } + } + } + + return { + "parametersPath" : arguments.parametersPath, + "parametersKey" : parametersKey, + "requestBodyPath" : arguments.requestBodyPath + }; + } + +} diff --git a/readme.md b/readme.md index 5abfdab..24f60e0 100644 --- a/readme.md +++ b/readme.md @@ -295,6 +295,48 @@ component displayName="API.v1.Users"{ } ``` +## Integration with cbValidation + +You can utilize your Swagger docs to generate constraints to use with cbValidation. You can do so by utilizing +`OpenAPIConstraintsGenerator@cbSwagger` as a delegate. Doing so exposes a `generateConstraintsFromOpenAPISchema` function +that will generate the constraints. + +``` +component delegates="OpenAPIConstraintsGenerator@cbSwagger" { + + /** + * @route (GET) /api/v1/jokes + * + * Returns a random dad joke + * + * @x-parameters ~api/v1/Jokes/index/parameters.json##parameters + * @requestBody ~api/v1/Jokes/index/requestBody.json + * @response-200 ~api/v1/Jokes/index/responses.200.json + * @response-403 ~api/v1/errors/example.403.json + */ + function index( event, rc, prc ) { + var validated = validateOrFail( target = rc, constraints = generateConstraintsFromOpenAPISchema() ); + // ... + } + +} +``` + +Using `OpenAPIConstraintsGenerator@cbSwagger` as a delegate allows it to auto discover the parameters and +request body for the action using the annotations on your action. + +If you prefer to manually pass in the parameters and/or requestBody path or use the `OpenAPIConstraintsGenerator@cbSwagger` +as an injection, you can pass in the paths as arguments to the `generateConstraintsFromOpenAPISchema` function. + +``` +public struct function generateConstraintsFromOpenAPISchema( + string parametersPath = "", + string requestBodyPath = "", + boolean discoverPaths = true, // this only discovers paths not explicitly passed in + string callingFunctionName // this will look itself up using the current call stack +) +``` + ******************************************************************************** Copyright Since 2016 Ortus Solutions, Corp www.ortussolutions.com diff --git a/server-adobe@2018.json b/server-adobe@2018.json index 0479108..3d1d728 100644 --- a/server-adobe@2018.json +++ b/server-adobe@2018.json @@ -11,13 +11,13 @@ "rewrites":{ "enable":"true" }, - "webroot": "test-harness", - "aliases":{ + "webroot":"test-harness", + "aliases":{ "/moduleroot/cbswagger":"../" } }, "openBrowser":"false", - "cfconfig": { - "file" : ".cfconfig.json" - } + "cfconfig":{ + "file":".cfconfig.json" + } } diff --git a/test-harness/includes/resources/users.add.requestBody.json b/test-harness/includes/resources/users.add.requestBody.json new file mode 100644 index 0000000..ddb676a --- /dev/null +++ b/test-harness/includes/resources/users.add.requestBody.json @@ -0,0 +1,49 @@ +{ + "description": "Required parameters for user address", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "address1", + "city", + "state", + "zipCode" + ], + "properties": { + "address1": { + "description": "The first line of the address.", + "type": "string" + }, + "address2": { + "description": "The second line of the address.", + "type": "string" + }, + "city": { + "description": "The city of the address.", + "type": "string" + }, + "state": { + "description": "The state of the address.", + "type": "string" + }, + "country": { + "description": "The country of the address.", + "type": "string" + }, + "zipCode": { + "description": "The postal code of the address.", + "type": "string" + } + }, + "example": { + "address1" : "123 Elm Street", + "city" : "Beverly Hills", + "state" : "CA", + "postalCode" : "90210" + } + } + } + } +} diff --git a/test-harness/tests/specs/OpenAPIConstraintsGeneratorTest.cfc b/test-harness/tests/specs/OpenAPIConstraintsGeneratorTest.cfc new file mode 100644 index 0000000..9f0e2bb --- /dev/null +++ b/test-harness/tests/specs/OpenAPIConstraintsGeneratorTest.cfc @@ -0,0 +1,39 @@ +component + extends ="coldbox.system.testing.BaseTestCase" + appMapping="/" + accessors =true +{ + + function run(){ + describe( "OpenAPI Constraints Generator", () => { + it( "can generate constraints using parameters.json and requestBody.json", () => { + var generator = getInstance( "OpenAPIConstraintsGenerator@cbSwagger" ); + var constraints = generator.generateConstraintsFromOpenAPISchema( + parametersPath = "/includes/resources/users.add.parameters.json##user", + requestBodyPath = "/includes/resources/users.add.requestBody.json", + autoDiscover = false + ); + + expect( constraints ).toBeStruct(); + expect( constraints ).toBe( { + "country" : { "required" : false, "type" : "string" }, + "address2" : { "required" : false, "type" : "string" }, + "zipCode" : { "required" : true, "type" : "string" }, + "address1" : { "required" : true, "type" : "string" }, + "state" : { "required" : true, "type" : "string" }, + "city" : { "required" : true, "type" : "string" }, + "user" : { + "required" : true, + "constraints" : { + "firstname" : { "required" : true, "type" : "string" }, + "lastname" : { "required" : true, "type" : "string" }, + "email" : { "required" : true, "type" : "string" } + }, + "type" : "struct" + } + } ); + } ); + } ); + } + +} From f2531dbddab49c421f1e6fcf65f5561dc386501b Mon Sep 17 00:00:00 2001 From: Eric Peterson Date: Thu, 13 Feb 2025 13:58:02 -0700 Subject: [PATCH 14/21] BoxLang compatibility --- models/OpenAPIConstraintsGenerator.cfc | 8 ++--- models/RoutesParser.cfc | 49 ++++++++++++++------------ test-harness/box.json | 2 +- 3 files changed, 32 insertions(+), 27 deletions(-) diff --git a/models/OpenAPIConstraintsGenerator.cfc b/models/OpenAPIConstraintsGenerator.cfc index 8435f8f..d54d1dd 100644 --- a/models/OpenAPIConstraintsGenerator.cfc +++ b/models/OpenAPIConstraintsGenerator.cfc @@ -18,7 +18,7 @@ component name="OpenAPIConstraintsGenerator" { () => { return deserializeJSON( fileRead( expandPath( paths.parametersPath ) ) ); }, - createTimespan( 1, 0, 0, 0 ) + 1 // 1 day ); structAppend( constraints, generateConstraintsFromParameters( parametersJSON[ paths.parametersKey ] ) ) } @@ -29,7 +29,7 @@ component name="OpenAPIConstraintsGenerator" { () => { return deserializeJSON( fileRead( expandPath( paths.requestBodyPath ) ) ); }, - createTimespan( 1, 0, 0, 0 ) + 1 // 1 day ); var schema = requestBodyJSON[ "content" ][ "application/json" ][ "schema" ]; structAppend( @@ -67,13 +67,13 @@ component name="OpenAPIConstraintsGenerator" { var constraints = {}; constraints[ "required" ] = arguments.isRequired; addValidationType( constraints, schema ); - if ( constraints[ "type" ] == "struct" ) { + if ( constraints[ "type" ] == "struct" && schema.keyExists( "properties" ) ) { constraints[ "constraints" ] = generateConstraintsFromRequestBodyProperties( schema.properties, schema.required ?: [] ); } - if ( constraints[ "type" ] == "array" ) { + if ( constraints[ "type" ] == "array" && schema.keyExists( "items" ) ) { constraints[ "items" ] = generateConstraint( schema.items, arguments.isRequired ); } if ( schema.keyExists( "enum" ) ) { diff --git a/models/RoutesParser.cfc b/models/RoutesParser.cfc index b9b73ce..d78267c 100644 --- a/models/RoutesParser.cfc +++ b/models/RoutesParser.cfc @@ -64,7 +64,11 @@ component accessors="true" threadsafe singleton { // Incorporate our API routes into the document filterDesignatedRoutes().each( function( key, value ){ - template[ "paths" ].putAll( createPathsFromRouteConfig( value ) ); + structAppend( + template[ "paths" ], + createPathsFromRouteConfig( value ), + true + ); } ); // Build out the Open API Document object @@ -192,7 +196,7 @@ component accessors="true" threadsafe singleton { for ( var pathEntry in entrySet ) { for ( var routeKey in designatedRoutes ) { if ( replaceNoCase( routeKey, "/", "", "ALL" ) == pathEntry ) { - sortedRoutes.put( routeKey, designatedRoutes[ routeKey ] ); + sortedRoutes[ routeKey ] = designatedRoutes[ routeKey ]; } } } @@ -287,7 +291,7 @@ component accessors="true" threadsafe singleton { // method not in error methods if ( !arrayFindNoCase( errorMethods, actions[ methodList ] ) ) { // Create new path template - path.put( lCase( methodName ), getOpenAPIUtil().newMethod() ); + path[ lCase( methodName ) ] = getOpenAPIUtil().newMethod(); // Append Params appendPathParams( pathKey = arguments.pathKey, method = path[ lCase( methodName ) ] ); // Append Function metadata @@ -309,7 +313,7 @@ component accessors="true" threadsafe singleton { } else { for ( var methodName in getOpenAPIUtil().defaultMethods() ) { // Insert path template for default method - path.put( lCase( methodName ), getOpenAPIUtil().newMethod() ); + path[ lCase( methodName ) ] = getOpenAPIUtil().newMethod(); // Append Params appendPathParams( pathKey = arguments.pathKey, method = path[ lCase( methodName ) ] ); // Append metadata @@ -346,7 +350,7 @@ component accessors="true" threadsafe singleton { } } - arguments.existingPaths.put( "/" & arrayToList( pathSegments, "/" ), path ); + arguments.existingPaths[ "/" & arrayToList( pathSegments, "/" ) ] = path; } /** @@ -358,7 +362,7 @@ component accessors="true" threadsafe singleton { private void function appendPathParams( required string pathKey, required struct method ){ // Verify parameters array in the method definition if ( !structKeyExists( arguments.method, "parameters" ) ) { - arguments.method.put( "parameters", [] ); + arguments.method[ "parameters" ] = []; } // handle any parameters in the url now @@ -508,44 +512,41 @@ component accessors="true" threadsafe singleton { // hint/description if ( infoKey == "hint" ) { - if ( !method.containsKey( "description" ) || method[ "description" ] == "" ) { - method.put( "description", infoMetadata ); + if ( !structKeyExists( method, "description" ) || method[ "description" ] == "" ) { + method[ "description" ] = infoMetadata; } - if ( !functionMetadata.containsKey( "summary" ) ) { - method.put( "summary", infoMetadata ); + if ( !structKeyExists( functionMetadata, "summary" ) ) { + method[ "summary" ] = infoMetadata; } continue; } if ( infoKey == "description" && infoMetadata != "" ) { - method.put( "description", infoMetadata ); + method[ "description" ] = infoMetadata; continue; } if ( infoKey == "summary" ) { - method.put( "summary", infoMetadata ); + method[ "summary" ] = infoMetadata; continue; } // Operation Tags if ( infoKey == "tags" ) { - method.put( - "tags", - ( isSimpleValue( infoMetadata ) ? listToArray( infoMetadata ) : infoMetadata ) - ); + method[ "tags" ] = isSimpleValue( infoMetadata ) ? listToArray( infoMetadata ) : infoMetadata; continue; } // Request body: { description, required, content : {} } if simple, we just add it as required, with listed as content if ( left( infoKey, 12 ) == "requestBody" ) { - method.put( "requestBody", structNew( "ordered" ) ); + method[ "requestBody" ] = structNew( "ordered" ); if ( isSimpleValue( infoMetadata ) ) { method[ "requestBody" ][ "description" ] = infoMetadata; method[ "requestBody" ][ "required" ] = true; method[ "requestBody" ][ "content" ] = { "#infoMetadata#" : {} }; } else { - method[ "requestBody" ].putAll( infoMetadata ); + structAppend( method[ "requestBody" ], infoMetadata, true ); } continue; } @@ -635,13 +636,13 @@ component accessors="true" threadsafe singleton { var filterString = arrayToList( [ moduleName, - listLast( handlerMetadata.name, "." ), + listLast( handlerMetadata.fullname, "." ), methodName ], "." ); } else { - var filterString = arrayToList( [ handlerMetadata.name, methodName ], "." ); + var filterString = arrayToList( [ handlerMetadata.fullname, methodName ], "." ); } availableFiles @@ -754,14 +755,18 @@ component accessors="true" threadsafe singleton { // get reponse name var responseName = right( infoKey, len( infoKey ) - 9 ); - method[ "responses" ].put( responseName, structNew( "ordered" ) ); + method[ "responses" ][ responseName ] = structNew( "ordered" ); // Use simple value for description and content type if ( isSimpleValue( infoMetadata ) ) { method[ "responses" ][ responseName ][ "description" ] = infoMetadata; method[ "responses" ][ responseName ][ "content" ] = { "#infoMetadata#" : {} }; } else { - method[ "responses" ][ responseName ].putAll( infoMetadata ); + structAppend( + method[ "responses" ][ responseName ], + infoMetadata, + true + ); } } ); diff --git a/test-harness/box.json b/test-harness/box.json index 434a081..bf7a30f 100644 --- a/test-harness/box.json +++ b/test-harness/box.json @@ -10,7 +10,7 @@ "coldbox":"be" }, "devDependencies":{ - "testbox":"^4.0.0", + "testbox":"be", "route-visualizer":"^2.0.0+6" }, "installPaths":{ From 66c327996e36a5f79f339a4dbc032312286a988e Mon Sep 17 00:00:00 2001 From: Eric Peterson Date: Mon, 27 Oct 2025 09:09:13 -0600 Subject: [PATCH 15/21] Trigger build From c82579c6d0dcbce53cd193a5da2f4789a6d84670 Mon Sep 17 00:00:00 2001 From: Eric Peterson Date: Mon, 27 Oct 2025 10:01:39 -0600 Subject: [PATCH 16/21] Fix BoxLang and expand testing matrix --- .github/workflows/tests.yml | 55 ++++--- models/RoutesParser.cfc | 316 ++++++++++++++++++++---------------- server-adobe@2023.json | 2 +- server-adobe@2025.json | 26 +++ server-adobe@be.json | 26 +++ server-boxlang-cfml@1.json | 35 ++++ server-boxlang-cfml@be.json | 35 ++++ server-boxlang@1.json | 7 +- server-boxlang@be.json | 35 ++++ server-lucee@be.json | 23 +++ 10 files changed, 394 insertions(+), 166 deletions(-) create mode 100644 server-adobe@2025.json create mode 100644 server-adobe@be.json create mode 100644 server-boxlang-cfml@1.json create mode 100644 server-boxlang-cfml@be.json create mode 100644 server-boxlang@be.json create mode 100644 server-lucee@be.json diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f67eec3..c2a4e8e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -10,7 +10,7 @@ on: jobs: tests: name: Tests - runs-on: ubuntu-24.04 + runs-on: ubuntu-latest defaults: run: working-directory: ${{ github.workspace }}/cbswagger @@ -20,28 +20,52 @@ jobs: strategy: fail-fast: false matrix: - cfengine: [ "lucee@5", "lucee@6" ,"adobe@2018", "adobe@2021" ] - coldboxVersion: [ "^6.0.0", "^7.0.0" ] + cfengine: [ "lucee@5", "lucee@6" ,"adobe@2018", "adobe@2021", "adobe@2023", "adobe@2025", "boxlang-cfml@1" ] + coldboxVersion: [ "^6.0.0", "^7.0.0", "^8.0.0" ] experimental: [ false ] include: - - cfengine: "adobe@2023" - coldboxVersion: "^6.0.0" - experimental: true + - coldboxVersion: "^8.0.0" + cfengine: "boxlang@1" + experimental: false - coldboxVersion: "be" cfengine: "lucee@5" experimental: true + - coldboxVersion: "be" + cfengine: "lucee@6" + experimental: true + - coldboxVersion: "be" + cfengine: "lucee@be" + experimental: true - coldboxVersion: "be" cfengine: "adobe@2018" experimental: true + - coldboxVersion: "be" + cfengine: "adobe@2021" + experimental: true - coldboxVersion: "be" cfengine: "adobe@2023" experimental: true + - coldboxVersion: "be" + cfengine: "adobe@2025" + experimental: true + - coldboxVersion: "be" + cfengine: "adobe@be" + experimental: true - coldboxVersion: "be" cfengine: "boxlang@1" experimental: true + - coldboxVersion: "be" + cfengine: "boxlang@be" + experimental: true + - coldboxVersion: "be" + cfengine: "boxlang-cfml@1" + experimental: true + - coldboxVersion: "be" + cfengine: "boxlang-cfml@be" + experimental: true steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v5 with: path: cbswagger @@ -52,7 +76,7 @@ jobs: # mysql -u${{ env.DB_USER }} -p${{ env.DB_PASSWORD }} < test-harness/tests/resources/coolblog.sql - name: Setup Java - uses: actions/setup-java@v3 + uses: actions/setup-java@v5 with: distribution: "temurin" java-version: "11" @@ -60,21 +84,6 @@ jobs: - name: Setup CommandBox CLI uses: Ortus-Solutions/setup-commandbox@v2.0.1 - # Not Needed in this module - #- name: Setup Environment For Testing Process - # run: | - # # Setup .env - # touch .env - # # ENV - # printf "DB_HOST=localhost\n" >> .env - # printf "DB_DATABASE=mydatabase\n" >> .env - # printf "DB_DRIVER=MySQL\n" >> .env - # printf "DB_USER=${{ env.DB_USER }}\n" >> .env - # printf "DB_PASSWORD=${{ env.DB_PASSWORD }}\n" >> .env - # printf "DB_CLASS=com.mysql.cj.jdbc.Driver\n" >> .env - # printf "DB_BUNDLEVERSION=8.0.19\n" >> .env - # printf "DB_BUNDLENAME=com.mysql.cj\n" >> .env - - name: Install Test Harness with ColdBox ${{ matrix.coldboxVersion }} run: | box install commandbox-boxlang --force diff --git a/models/RoutesParser.cfc b/models/RoutesParser.cfc index d78267c..12cc2c4 100644 --- a/models/RoutesParser.cfc +++ b/models/RoutesParser.cfc @@ -501,96 +501,114 @@ component accessors="true" threadsafe singleton { appendFunctionParams( argumentCollection = arguments ); appendFunctionResponses( argumentCollection = arguments ); - functionMetadata - .keyArray() - .each( function( infoKey ){ - // is !simple, continue to next key - if ( !isSimpleValue( functionMetaData[ infoKey ] ) ) continue; - - // parse values from each key - var infoMetadata = parseMetadataValue( functionMetaData[ infoKey ] ); + var parseGenericMetadata = function( md ){ + arguments.md + .keyArray() + .each( function( infoKey ){ + // is !simple, continue to next key + if ( !isSimpleValue( md[ infoKey ] ) ) continue; + + // parse values from each key + var infoMetadata = parseMetadataValue( md[ infoKey ] ); + + // hint/description + if ( infoKey == "hint" ) { + if ( !structKeyExists( method, "description" ) || method[ "description" ] == "" ) { + method[ "description" ] = infoMetadata; + } + if ( !structKeyExists( md, "summary" ) ) { + method[ "summary" ] = infoMetadata; + } + continue; + } - // hint/description - if ( infoKey == "hint" ) { - if ( !structKeyExists( method, "description" ) || method[ "description" ] == "" ) { + if ( infoKey == "description" && infoMetadata != "" ) { method[ "description" ] = infoMetadata; + continue; } - if ( !structKeyExists( functionMetadata, "summary" ) ) { + + if ( infoKey == "summary" ) { method[ "summary" ] = infoMetadata; + continue; } - continue; - } - - if ( infoKey == "description" && infoMetadata != "" ) { - method[ "description" ] = infoMetadata; - continue; - } - - if ( infoKey == "summary" ) { - method[ "summary" ] = infoMetadata; - continue; - } - - // Operation Tags - if ( infoKey == "tags" ) { - method[ "tags" ] = isSimpleValue( infoMetadata ) ? listToArray( infoMetadata ) : infoMetadata; - continue; - } - // Request body: { description, required, content : {} } if simple, we just add it as required, with listed as content - if ( left( infoKey, 12 ) == "requestBody" ) { - method[ "requestBody" ] = structNew( "ordered" ); + // Operation Tags + if ( infoKey == "tags" ) { + method[ "tags" ] = isSimpleValue( infoMetadata ) ? listToArray( infoMetadata ) : infoMetadata; + continue; + } - if ( isSimpleValue( infoMetadata ) ) { - method[ "requestBody" ][ "description" ] = infoMetadata; - method[ "requestBody" ][ "required" ] = true; - method[ "requestBody" ][ "content" ] = { "#infoMetadata#" : {} }; - } else { - structAppend( method[ "requestBody" ], infoMetadata, true ); + // Request body: { description, required, content : {} } if simple, we just add it as required, with listed as content + if ( left( infoKey, 12 ) == "requestBody" ) { + method[ "requestBody" ] = structNew( "ordered" ); + + if ( isSimpleValue( infoMetadata ) ) { + method[ "requestBody" ][ "description" ] = infoMetadata; + method[ "requestBody" ][ "required" ] = true; + method[ "requestBody" ][ "content" ] = { "#infoMetadata#" : {} }; + } else { + structAppend( method[ "requestBody" ], infoMetadata, true ); + } + continue; } - continue; - } - // security - if ( infoKey == "security" ) { - if ( isSimpleValue( infoMetadata ) ) { - // expect a list of pre-defined securitySchemes - method[ "security" ] = listToArray( infoMetadata ) - .filter( function( security ){ - return structKeyList( moduleSettings.components.securitySchemes ).find( - security - ); - } ) - .map( function( item ){ - return { "#item#" : [] }; - } ); - } else { - method[ "security" ] = infoMetadata; + // security + if ( infoKey == "security" ) { + if ( isSimpleValue( infoMetadata ) ) { + // expect a list of pre-defined securitySchemes + method[ "security" ] = listToArray( infoMetadata ) + .filter( function( security ){ + return structKeyList( moduleSettings.components.securitySchemes ).find( + security + ); + } ) + .map( function( item ){ + return { "#item#" : [] }; + } ); + } else { + method[ "security" ] = infoMetadata; + } + continue; } - continue; - } - // Spec Extensions x-{name}, must be in lowercase - if ( left( infoKey, 2 ) == "x-" ) { - var normalizedKey = replaceNoCase( infoKey, "x-", "" ).lcase(); - // evaluate whether we have an x- replacement or a standard x-attribute - if ( arrayContainsNoCase( defaultKeys, normalizedKey ) ) { - method[ normalizedKey ] = infoMetadata; - } else { - method[ infoKey.lcase() ] = infoMetadata; + // Spec Extensions x-{name}, must be in lowercase + if ( left( infoKey, 2 ) == "x-" ) { + var normalizedKey = replaceNoCase( infoKey, "x-", "" ).lcase(); + // evaluate whether we have an x- replacement or a standard x-attribute + if ( arrayContainsNoCase( defaultKeys, normalizedKey ) ) { + method[ normalizedKey ] = infoMetadata; + } else { + method[ infoKey.lcase() ] = infoMetadata; + } + continue; } - continue; - } - if ( arrayContainsNoCase( defaultKeys, infoKey ) ) { - // don't override any previously set convention assignments - if ( isSimpleValue( infoMetadata ) && len( infoMetadata ) ) { - method[ infoKey ] = infoMetadata; - } else if ( !isSimpleValue( infoMetadata ) ) { - method[ infoKey ] = infoMetadata; + if ( arrayContainsNoCase( defaultKeys, infoKey ) ) { + // don't override any previously set convention assignments + if ( isSimpleValue( infoMetadata ) && len( infoMetadata ) ) { + method[ infoKey ] = infoMetadata; + } else if ( !isSimpleValue( infoMetadata ) ) { + method[ infoKey ] = infoMetadata; + } } - } - } ); + } ); + }; + + parseGenericMetadata( arguments.functionMetadata ); + if ( + functionMetadata.keyExists( "annotations" ) && !isNull( functionMetadata.annotations ) && isStruct( + functionMetadata.annotations + ) + ) { + parseGenericMetadata( functionMetadata.annotations ); + } + if ( + functionMetadata.keyExists( "documentation" ) && !isNull( functionMetadata.documentation ) && isStruct( + functionMetadata.documentation + ) + ) { + parseGenericMetadata( functionMetadata.documentation ); + } // check for a request body convention file if ( !method.keyExists( "requestBody" ) || structIsEmpty( method[ "requestBody" ] ) ) { @@ -688,48 +706,59 @@ component accessors="true" threadsafe singleton { required any functionMetadata, moduleName ){ - functionMetadata - .keyArray() - .filter( function( key ){ - return left( key, 6 ) == "param-"; - } ) - .each( function( infoKey ){ - // parse values from each key - var infoMetadata = parseMetadataValue( functionMetaData[ infoKey ] ); - // Get the param name - var paramName = right( infoKey, len( infoKey ) - 6 ); - - // See if our parameter was already provided through URL parsing - var paramSearch = arrayFilter( method[ "parameters" ], function( item ){ - return item.name == paramName; - } ); + var parseParamsFromStruct = function( md ){ + arguments.md + .keyArray() + .filter( function( key ){ + return left( key, 6 ) == "param-"; + } ) + .each( function( infoKey ){ + // parse values from each key + var infoMetadata = parseMetadataValue( md[ infoKey ] ); + // Get the param name + var paramName = right( infoKey, len( infoKey ) - 6 ); - if ( arrayLen( paramSearch ) ) { - var parameter = paramSearch[ 1 ]; - if ( isSimpleValue( infoMetadata ) ) { - parameter[ "description" ] = infoMetadata; - } else { - structAppend( parameter, infoMetadata ); - } - } else { - // Default Params - var parameter = { - "name" : paramName, - "description" : "", - "in" : "query", - "required" : false, - "schema" : { "type" : "string", "default" : "" } - }; + // See if our parameter was already provided through URL parsing + var paramSearch = arrayFilter( method[ "parameters" ], function( item ){ + return item.name == paramName; + } ); - if ( isSimpleValue( infoMetadata ) ) { - parameter[ "description" ] = infoMetadata; + if ( arrayLen( paramSearch ) ) { + var parameter = paramSearch[ 1 ]; + if ( isSimpleValue( infoMetadata ) ) { + parameter[ "description" ] = infoMetadata; + } else { + structAppend( parameter, infoMetadata ); + } } else { - structAppend( parameter, infoMetadata ); + // Default Params + var parameter = { + "name" : paramName, + "description" : "", + "in" : "query", + "required" : false, + "schema" : { "type" : "string", "default" : "" } + }; + + if ( isSimpleValue( infoMetadata ) ) { + parameter[ "description" ] = infoMetadata; + } else { + structAppend( parameter, infoMetadata ); + } + + arrayAppend( method[ "parameters" ], parameter ); } + } ); + }; - arrayAppend( method[ "parameters" ], parameter ); - } - } ); + parseParamsFromStruct( functionMetadata ); + if ( + functionMetadata.keyExists( "annotations" ) && !isNull( functionMetadata.annotations ) && isStruct( + functionMetadata.annotations + ) + ) { + parseParamsFromStruct( functionMetadata.annotations ); + } sampleArgs = { "type" : "parameters" }; sampleArgs.append( arguments ); @@ -744,31 +773,42 @@ component accessors="true" threadsafe singleton { required any functionMetadata, moduleName ){ - functionMetadata - .keyArray() - .filter( function( key ){ - return left( key, 9 ) == "response-"; - } ) - .each( function( infoKey ){ - // parse values from each key - var infoMetadata = parseMetadataValue( functionMetaData[ infoKey ] ); - // get reponse name - var responseName = right( infoKey, len( infoKey ) - 9 ); - - method[ "responses" ][ responseName ] = structNew( "ordered" ); - - // Use simple value for description and content type - if ( isSimpleValue( infoMetadata ) ) { - method[ "responses" ][ responseName ][ "description" ] = infoMetadata; - method[ "responses" ][ responseName ][ "content" ] = { "#infoMetadata#" : {} }; - } else { - structAppend( - method[ "responses" ][ responseName ], - infoMetadata, - true - ); - } - } ); + var parseResponsesFromStruct = function( md ){ + arguments.md + .keyArray() + .filter( function( key ){ + return left( key, 9 ) == "response-"; + } ) + .each( function( infoKey ){ + // parse values from each key + var infoMetadata = parseMetadataValue( md[ infoKey ] ); + // get response name + var responseName = right( infoKey, len( infoKey ) - 9 ); + + method[ "responses" ][ responseName ] = structNew( "ordered" ); + + // Use simple value for description and content type + if ( isSimpleValue( infoMetadata ) ) { + method[ "responses" ][ responseName ][ "description" ] = infoMetadata; + method[ "responses" ][ responseName ][ "content" ] = { "#infoMetadata#" : {} }; + } else { + structAppend( + method[ "responses" ][ responseName ], + infoMetadata, + true + ); + } + } ); + }; + + parseResponsesFromStruct( functionMetadata ); + if ( + functionMetadata.keyExists( "annotations" ) && !isNull( functionMetadata.annotations ) && isStruct( + functionMetadata.annotations + ) + ) { + parseResponsesFromStruct( functionMetadata.annotations ); + } // Remove our empty default response if other responses were provided if ( diff --git a/server-adobe@2023.json b/server-adobe@2023.json index e889825..e074f44 100644 --- a/server-adobe@2023.json +++ b/server-adobe@2023.json @@ -2,7 +2,7 @@ "name":"swagger-sdk-adobe@2023", "app":{ "serverHomeDirectory":".engine/adobe2023", - "cfengine":"adobe@2023.0.0-beta.1" + "cfengine":"adobe@2023" }, "web":{ "http":{ diff --git a/server-adobe@2025.json b/server-adobe@2025.json new file mode 100644 index 0000000..3643b51 --- /dev/null +++ b/server-adobe@2025.json @@ -0,0 +1,26 @@ +{ + "name":"swagger-sdk-adobe@2025", + "app":{ + "serverHomeDirectory":".engine/adobe2025", + "cfengine":"adobe@2025" + }, + "web":{ + "http":{ + "port":"60299" + }, + "rewrites":{ + "enable":true + }, + "webroot":"test-harness", + "aliases":{ + "/moduleroot/cbswagger":"../" + } + }, + "openBrowser":"false", + "cfconfig":{ + "file":".cfconfig.json" + }, + "scripts":{ + "onServerInstall":"cfpm install zip" + } +} diff --git a/server-adobe@be.json b/server-adobe@be.json new file mode 100644 index 0000000..95a2ced --- /dev/null +++ b/server-adobe@be.json @@ -0,0 +1,26 @@ +{ + "name":"swagger-sdk-adobe@be", + "app":{ + "serverHomeDirectory":".engine/adobeBE", + "cfengine":"adobe@be" + }, + "web":{ + "http":{ + "port":"60299" + }, + "rewrites":{ + "enable":true + }, + "webroot":"test-harness", + "aliases":{ + "/moduleroot/cbswagger":"../" + } + }, + "openBrowser":"false", + "cfconfig":{ + "file":".cfconfig.json" + }, + "scripts":{ + "onServerInstall":"cfpm install zip" + } +} diff --git a/server-boxlang-cfml@1.json b/server-boxlang-cfml@1.json new file mode 100644 index 0000000..7515c3f --- /dev/null +++ b/server-boxlang-cfml@1.json @@ -0,0 +1,35 @@ +{ + "app":{ + "cfengine":"boxlang@^1", + "serverHomeDirectory":".engine/boxlangCFML" + }, + "name":"cbSwagger-boxlang-cfml@1", + "force":true, + "openBrowser":false, + "web":{ + "directoryBrowsing":true, + "http":{ + "port":"60299" + }, + "rewrites":{ + "enable":"true" + }, + "webroot":"test-harness", + "aliases":{ + "/moduleroot/cbSwagger":"./" + } + }, + "JVM":{ + "heapSize":"1024", + "javaVersion":"openjdk21_jdk" + }, + "cfconfig":{ + "file":".cfconfig.json" + }, + "env":{ + "BOXLANG_DEBUG":true + }, + "scripts":{ + "onServerInitialInstall":"install bx-mail,bx-mysql,bx-derby,bx-compat-cfml@be,bx-unsafe-evaluate,bx-esapi --noSave" + } +} diff --git a/server-boxlang-cfml@be.json b/server-boxlang-cfml@be.json new file mode 100644 index 0000000..9cee3e9 --- /dev/null +++ b/server-boxlang-cfml@be.json @@ -0,0 +1,35 @@ +{ + "app":{ + "cfengine":"boxlang@be", + "serverHomeDirectory":".engine/boxlangCFMLBE" + }, + "name":"cbSwagger-boxlang-cfml@be", + "force":true, + "openBrowser":false, + "web":{ + "directoryBrowsing":true, + "http":{ + "port":"60299" + }, + "rewrites":{ + "enable":"true" + }, + "webroot":"test-harness", + "aliases":{ + "/moduleroot/cbSwagger":"./" + } + }, + "JVM":{ + "heapSize":"1024", + "javaVersion":"openjdk21_jdk" + }, + "cfconfig":{ + "file":".cfconfig.json" + }, + "env":{ + "BOXLANG_DEBUG":true + }, + "scripts":{ + "onServerInitialInstall":"install bx-mail,bx-mysql,bx-derby,bx-compat-cfml@be,bx-unsafe-evaluate,bx-esapi --noSave" + } +} diff --git a/server-boxlang@1.json b/server-boxlang@1.json index 923c647..fb91865 100644 --- a/server-boxlang@1.json +++ b/server-boxlang@1.json @@ -1,6 +1,6 @@ { "app":{ - "cfengine":"boxlang@be", + "cfengine":"boxlang@^1", "serverHomeDirectory":".engine/boxlang" }, "name":"cbSwagger-boxlang@1", @@ -21,8 +21,7 @@ }, "JVM":{ "heapSize":"1024", - "javaVersion":"openjdk21_jdk", - "args":"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=9999" + "javaVersion":"openjdk21_jdk" }, "cfconfig":{ "file":".cfconfig.json" @@ -31,6 +30,6 @@ "BOXLANG_DEBUG":true }, "scripts":{ - "onServerInitialInstall":"install bx-mail,bx-mysql,bx-derby,bx-compat-cfml@be,bx-unsafe-evaluate,bx-esapi --noSave" + "onServerInitialInstall":"install bx-mail,bx-mysql,bx-derby,bx-unsafe-evaluate,bx-esapi --noSave" } } diff --git a/server-boxlang@be.json b/server-boxlang@be.json new file mode 100644 index 0000000..253a0fd --- /dev/null +++ b/server-boxlang@be.json @@ -0,0 +1,35 @@ +{ + "app":{ + "cfengine":"boxlang@be", + "serverHomeDirectory":".engine/boxlangBE" + }, + "name":"cbSwagger-boxlang@be", + "force":true, + "openBrowser":false, + "web":{ + "directoryBrowsing":true, + "http":{ + "port":"60299" + }, + "rewrites":{ + "enable":"true" + }, + "webroot":"test-harness", + "aliases":{ + "/moduleroot/cbSwagger":"./" + } + }, + "JVM":{ + "heapSize":"1024", + "javaVersion":"openjdk21_jdk" + }, + "cfconfig":{ + "file":".cfconfig.json" + }, + "env":{ + "BOXLANG_DEBUG":true + }, + "scripts":{ + "onServerInitialInstall":"install bx-mail,bx-mysql,bx-derby,bx-unsafe-evaluate,bx-esapi --noSave" + } +} diff --git a/server-lucee@be.json b/server-lucee@be.json new file mode 100644 index 0000000..e380a63 --- /dev/null +++ b/server-lucee@be.json @@ -0,0 +1,23 @@ +{ + "name":"cbswagger-lucee@be", + "app":{ + "serverHomeDirectory":".engine/luceeBE", + "cfengine":"lucee@be" + }, + "web":{ + "http":{ + "port":"60299" + }, + "rewrites":{ + "enable":"true" + }, + "webroot":"test-harness", + "aliases":{ + "/moduleroot/cbswagger":"../" + } + }, + "openBrowser":"false", + "cfconfig":{ + "file":".cfconfig.json" + } +} From 4cf958c1d38b21ddf858867d16a184aae9b0ba15 Mon Sep 17 00:00:00 2001 From: Eric Peterson Date: Mon, 27 Oct 2025 13:21:06 -0600 Subject: [PATCH 17/21] Add Java version for ACF 2025 --- server-adobe@2025.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server-adobe@2025.json b/server-adobe@2025.json index 3643b51..fbbcea7 100644 --- a/server-adobe@2025.json +++ b/server-adobe@2025.json @@ -15,6 +15,10 @@ "aliases":{ "/moduleroot/cbswagger":"../" } + }, + "jvm":{ + "heapSize":"1024", + "javaVersion":"openjdk21_jre" }, "openBrowser":"false", "cfconfig":{ From 24038548694745b44ff9040bf2526048b952c8e6 Mon Sep 17 00:00:00 2001 From: Eric Peterson Date: Mon, 27 Oct 2025 13:22:05 -0600 Subject: [PATCH 18/21] Mark BoxLang Prime as experimental for now --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c2a4e8e..7178a8f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -26,7 +26,7 @@ jobs: include: - coldboxVersion: "^8.0.0" cfengine: "boxlang@1" - experimental: false + experimental: true - coldboxVersion: "be" cfengine: "lucee@5" experimental: true From 2c313ffb92040a725f2d3a561da55bc6e0fc8369 Mon Sep 17 00:00:00 2001 From: Eric Peterson Date: Mon, 27 Oct 2025 14:00:04 -0600 Subject: [PATCH 19/21] Use Java 21 for CommandBox --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 7178a8f..8b653cf 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -79,7 +79,7 @@ jobs: uses: actions/setup-java@v5 with: distribution: "temurin" - java-version: "11" + java-version: 21 - name: Setup CommandBox CLI uses: Ortus-Solutions/setup-commandbox@v2.0.1 From 7b96ca95b897eebbd63de3f2bd0dbef86ffb9426 Mon Sep 17 00:00:00 2001 From: Eric Peterson Date: Mon, 27 Oct 2025 14:08:07 -0600 Subject: [PATCH 20/21] Specify more Java versions --- server-adobe@2018.json | 4 ++++ server-adobe@2021.json | 4 ++++ test-harness/tests/specs/RoutesParserTest.cfc | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/server-adobe@2018.json b/server-adobe@2018.json index 3d1d728..12b1f83 100644 --- a/server-adobe@2018.json +++ b/server-adobe@2018.json @@ -15,6 +15,10 @@ "aliases":{ "/moduleroot/cbswagger":"../" } + }, + "jvm":{ + "heapSize":"1024", + "javaVersion":"openjdk8_jre" }, "openBrowser":"false", "cfconfig":{ diff --git a/server-adobe@2021.json b/server-adobe@2021.json index 1e11647..9fcca8f 100644 --- a/server-adobe@2021.json +++ b/server-adobe@2021.json @@ -15,6 +15,10 @@ "aliases":{ "/moduleroot/cbswagger":"../" } + }, + "jvm":{ + "heapSize":"1024", + "javaVersion":"openjdk11_jre" }, "openBrowser":"false", "cfconfig": { diff --git a/test-harness/tests/specs/RoutesParserTest.cfc b/test-harness/tests/specs/RoutesParserTest.cfc index b3a9f02..dbce73f 100644 --- a/test-harness/tests/specs/RoutesParserTest.cfc +++ b/test-harness/tests/specs/RoutesParserTest.cfc @@ -22,7 +22,7 @@ component variables.samplesPath = controller.getAppRootPath() & variables.model.getModuleSettings().samplesPath; // make all of our private model methods public - var privateMethods = getMetadata( variables.model ).functions + var privateMethods = arraySlice( getMetadata( variables.model ).functions, 1 ) .filter( function( fn ){ return fn.keyExists( "access" ) && fn.access == "private"; } ) From da7c732ae2ea78530e6802f9696389d0f899a6bc Mon Sep 17 00:00:00 2001 From: Eric Peterson Date: Tue, 28 Oct 2025 10:16:11 -0600 Subject: [PATCH 21/21] Make experimental tests able to fail --- .github/workflows/tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8b653cf..da7532f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -17,6 +17,7 @@ jobs: env: DB_USER: root DB_PASSWORD: root + continue-on-error: ${{ matrix.experimental }} strategy: fail-fast: false matrix: