diff --git a/test-harness/.cfconfig.json b/.cfconfig.json similarity index 100% rename from test-harness/.cfconfig.json rename to .cfconfig.json diff --git a/.env.template b/.env.template new file mode 100644 index 0000000..3c532fd --- /dev/null +++ b/.env.template @@ -0,0 +1,7 @@ +DB_HOST=127.0.0.1 +DB_PORT=3306 +DB_USER=root +DB_PASSWORD=mysql +DB_CLASS=com.mysql.cj.jdbc.Driver +DB_BUNDLEVERSION=8.0.19 +DB_BUNDLENAME=com.mysql.cj diff --git a/.github/FUNDING.YML b/.github/FUNDING.YML new file mode 100644 index 0000000..7e59d13 --- /dev/null +++ b/.github/FUNDING.YML @@ -0,0 +1 @@ +patreon: ortussolutions diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 52f123b..490f2c8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,104 +11,13 @@ env: MODULE_ID: cbvalidation jobs: - ############################################# + ############################################# # Tests First baby! We fail, no build :( ############################################# tests: - name: Tests - runs-on: ubuntu-20.04 - strategy: - fail-fast: false - matrix: - cfengine: [ "lucee@5", "adobe@2016", "adobe@2018", "adobe@2021" ] - steps: - - name: Checkout Repository - uses: actions/checkout@v2 - - - name: Setup Java - uses: actions/setup-java@v2 - with: - distribution: "adopt" - java-version: "11" - - - name: Cache CommandBox Dependencies - uses: actions/cache@v1 - if: ${{ true }} - with: - path: ~/.CommandBox/artifacts - key: ${{ runner.OS }}-commandbox-cache-${{ hashFiles( 'box.json' ) }}-${{ hashFiles( 'test-harness/box.json' ) }} - restore-keys: | - ${{ runner.OS }}-commandbox-cache-${{ hashFiles( 'box.json' ) }}-${{ hashFiles( 'test-harness/box.json' ) }} - - - name: Setup CommandBox - uses: elpete/setup-commandbox@v1.0.0 - - - name: Install Test Harness Dependencies - working-directory: ./test-harness - run: | - box install - - - name: Start ${{ matrix.cfengine }} Server - working-directory: ./test-harness - run: box server start serverConfigFile="server-${{ matrix.cfengine }}.json" --noSaveSettings --debug - - - name: CFPM Setup - if: ${{ matrix.cfengine == 'adobe@2021' }} - working-directory: ./test-harness - run: box run-script install:2021 - - - name: Prime ${{ matrix.cfengine }} server - working-directory: ./test-harness - run: curl http://127.0.0.1:60299 - - - name: Run Tests - working-directory: ./test-harness - run: | - mkdir tests/results - box package set testbox.runner="http://localhost:60299/tests/runner.cfm" - box testbox run --verbose outputFile=tests/results/test-results outputFormats=json,antjunit - - - name: Publish Test Results - uses: EnricoMi/publish-unit-test-result-action@v1 - if: always() - with: - files: test-harness/tests/results/**/*.xml - check_name: "${{ matrix.cfengine }} Test Results" - - - name: Upload Test Results Artifacts - if: always() - uses: actions/upload-artifact@v2 - with: - name: test-results-${{ matrix.cfengine }} - path: | - test-harness/tests/results/**/* - - - name: Slack Notification - if: failure() - uses: rtCamp/action-slack-notify@v2 - env: - SLACK_CHANNEL: coding - SLACK_COLOR: ${{ job.status }} # or a specific color like 'green' or '#ff00ff' - SLACK_ICON_EMOJI: ":bell:" - SLACK_MESSAGE: '${{ env.MODULE_ID }} tests failed :cry:' - SLACK_TITLE: ${{ env.MODULE_ID }} Tests For ${{ matrix.cfengine }} failed - SLACK_USERNAME: CI - SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }} - - - name: Failure Debugging Info - if: ${{ failure() }} - working-directory: ./test-harness - run: | - box server log serverConfigFile="server-${{ matrix.cfengine }}.json" - - - name: Upload Debugging Info To Artifacts - if: ${{ failure() }} - uses: actions/upload-artifact@v2 - with: - name: Failure Debugging Info - ${{ matrix.cfengine }} - path: | - test-harness/.engine/**/logs/* - test-harness/.engine/**/WEB-INF/cfusion/logs/* + uses: ./.github/workflows/tests.yml + secrets: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} ############################################# # Build Module @@ -129,17 +38,8 @@ jobs: distribution: "adopt" java-version: "11" - - name: Cache CommandBox Dependencies - uses: actions/cache@v1 - if: ${{ true }} - with: - path: ~/.CommandBox/artifacts - key: ${{ runner.OS }}-commandbox-cache-${{ hashFiles( 'box.json' ) }}-${{ hashFiles( 'test-harness/box.json' ) }} - restore-keys: | - ${{ runner.OS }}-commandbox-cache-${{ hashFiles( 'box.json' ) }}-${{ hashFiles( 'test-harness/box.json' ) }} - - name: Setup CommandBox - uses: elpete/setup-commandbox@v1.0.0 + uses: Ortus-Solutions/setup-commandbox@main with: forgeboxAPIKey: ${{ secrets.FORGEBOX_TOKEN }} diff --git a/.github/workflows/gh-release.yml b/.github/workflows/gh-release.yml new file mode 100644 index 0000000..5193ae5 --- /dev/null +++ b/.github/workflows/gh-release.yml @@ -0,0 +1,19 @@ +# Publish Github Release +name: Github Release + +on: + push: + tags: + - v[0-9]+.* + +jobs: + create-release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: taiki-e/create-gh-release-action@v1.5.0 + with: + # Produced by the build/Build.cfc + changelog: changelog.md + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 849a752..de1f895 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -12,66 +12,9 @@ on: jobs: tests: - name: Tests - runs-on: ubuntu-20.04 - env: - DB_USER: root - DB_PASSWORD: root - strategy: - fail-fast: false - matrix: - cfengine: [ "lucee@5", "adobe@2016", "adobe@2018", "adobe@2021" ] - steps: - - name: Checkout Repository - uses: actions/checkout@v2 - - - name: Setup Java - uses: actions/setup-java@v2 - with: - distribution: "adopt" - java-version: "11" - - - name: Setup CommandBox - uses: elpete/setup-commandbox@v1.0.0 - - - name: Install Test Harness Dependencies - working-directory: ./test-harness - run: | - box install - - - name: Start ${{ matrix.cfengine }} Server - working-directory: ./test-harness - run: box server start serverConfigFile="server-${{ matrix.cfengine }}.json" --noSaveSettings --debug - - - name: CFPM Setup - if: ${{ matrix.cfengine == 'adobe@2021' }} - working-directory: ./test-harness - run: box run-script install:2021 - - - name: Prime ${{ matrix.cfengine }} server - working-directory: ./test-harness - run: curl http://127.0.0.1:60299 - - - name: Run Tests - working-directory: ./test-harness - run: | - mkdir tests/results - box package set testbox.runner="http://localhost:60299/tests/runner.cfm" - box testbox run --verbose outputFile=tests/results/test-results outputFormats=json,antjunit - - - name: Publish PR Test Reports - uses: mikepenz/action-junit-report@v2 - with: - report_paths: 'test-harness/tests/results/**/*.xml' - check_name: "${{ matrix.cfengine }} Test Results" - summary: true - - - name: Failure Debugging Info - if: ${{ failure() }} - working-directory: ./test-harness - run: | - box server log serverConfigFile="server-${{ matrix.cfengine }}.json" + uses: coldbox-modules/cbvalidation/.github/workflows/tests.yml@development + # Format PR format: name: Format runs-on: ubuntu-20.04 @@ -79,22 +22,11 @@ jobs: - name: Checkout Repository uses: actions/checkout@v2 - - name: Setup Java - uses: actions/setup-java@v2 + - uses: Ortus-Solutions/commandbox-action@v1.0.2 with: - distribution: "adopt" - java-version: "11" - - - name: Set Up CommandBox - uses: elpete/setup-commandbox@v1.0.0 - - - name: Install CFFormat - run: box install commandbox-cfformat - - - name: Run CFFormat - run: box run-script format + cmd: run-script format - name: Commit Format Changes uses: stefanzweifel/git-auto-commit-action@v4 with: - commit_message: Apply cfformat changes \ No newline at end of file + commit_message: Apply cfformat changes diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..96281f4 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,107 @@ +name: Test Suites + +# We are a reusable Workflow only +on: + workflow_call: + secrets: + SLACK_WEBHOOK_URL: + required: true + +jobs: + tests: + name: Tests + runs-on: ubuntu-20.04 + env: + DB_USER: root + DB_PASSWORD: root + strategy: + fail-fast: false + matrix: + cfengine: [ "lucee@5", "adobe@2016", "adobe@2018", "adobe@2021" ] + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + + - name: Setup Java + uses: actions/setup-java@v2 + with: + distribution: "adopt" + java-version: "11" + + - name: Setup Environment For Testing Process + run: | + # Setup .env + touch .env + # ENV + printf "ENVIRONMENT=development\n" >> .env + printf "DB_HOST=localhost\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: Setup CommandBox CLI + uses: Ortus-Solutions/setup-commandbox@main + + - name: Install Dependencies + run: | + box install + cd test-harness && box install + + - name: Start ${{ matrix.cfengine }} Server + run: | + box server start serverConfigFile="server-${{ matrix.cfengine }}.json" --noSaveSettings --debug + # Install Adobe 2021 cfpm modules + if [[ "${{ matrix.cfengine }}" == "adobe@2021" ]] ; then + box run-script install:2021 + fi + curl http://127.0.0.1:60299 + + - name: Run Tests + run: | + mkdir -p test-harness/tests/results + box testbox run --verbose outputFile=test-harness/tests/results/test-results outputFormats=json,antjunit + ls -lR test-harness/tests + + - name: Publish Test Results + uses: EnricoMi/publish-unit-test-result-action@v1 + if: always() + with: + files: test-harness/tests/results/**/*.xml + check_name: "${{ matrix.cfengine }} Test Results" + + - name: Upload Test Results to Artifacts + if: always() + uses: actions/upload-artifact@v2 + with: + name: test-results-${{ matrix.cfengine }} + path: | + test-harness/tests/results/**/* + + - name: Failure Debugging Log + if: ${{ failure() }} + run: | + box server log serverConfigFile="server-${{ matrix.cfengine }}.json" + + - name: Upload Debugging Log To Artifacts + if: ${{ failure() }} + uses: actions/upload-artifact@v2 + with: + name: Failure Debugging Info - ${{ matrix.cfengine }} + path: | + .engine/**/logs/* + .engine/**/WEB-INF/cfusion/logs/* + + - name: Slack Notifications + # Only on failures and NOT in pull requests + if: ${{ failure() && !startsWith( 'pull_request', github.event_name ) }} + uses: rtCamp/action-slack-notify@v2 + env: + SLACK_CHANNEL: coding + SLACK_COLOR: ${{ job.status }} # or a specific color like 'green' or '#ff00ff' + SLACK_ICON_EMOJI: ":bell:" + SLACK_MESSAGE: '${{ github.repository }} tests failed :cry:' + SLACK_TITLE: ${{ github.repository }} Tests For ${{ matrix.cfengine }} failed + SLACK_USERNAME: CI + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/.gitignore b/.gitignore index 6dff3c5..3a96469 100644 --- a/.gitignore +++ b/.gitignore @@ -1,17 +1,21 @@ -.vscode - +# Artifacts and temp folders .artifacts/** .tmp/** -modules/ +# Engine + Secrets + databases +.env +.engine/** +.db/** -test-harness/.engine/** -test-harness/.env +# Dependencies test-harness/coldbox/** test-harness/docbox/** test-harness/testbox/** test-harness/logs/** test-harness/modules/** +# modules +modules/** + # log files -logs/** \ No newline at end of file +logs/** diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..2b41e59 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,14 @@ +{ + "cfml.mappings": [ + { + "logicalPath": "/coldbox", + "directoryPath": "./test-harness/coldbox", + "isPhysicalDirectoryPath": false + }, + { + "logicalPath": "/cbvalidation", + "directoryPath": "./", + "isPhysicalDirectoryPath": false + } + ] +} diff --git a/box.json b/box.json index a9ebbde..ff10686 100644 --- a/box.json +++ b/box.json @@ -24,19 +24,31 @@ ], "dependencies":{ "cbi18n":"^2.0.0" + }, + "devDependencies":{ + "commandbox-cfformat":"*", + "commandbox-docbox":"*", + "commandbox-dotenv":"*", + "commandbox-cfconfig":"*" }, "ignore":[ "**/.*", - "tests/*", - ".git*" + "test-harness", + "/server*.json" ], + "testbox":{ + "runner":"http://localhost:60299/tests/runner.cfm" + }, "scripts":{ + "build:module":"task run taskFile=build/Build.cfc :projectName=`package show slug` :version=`package show version`", + "build:docs":"task run taskFile=build/Build.cfc target=docs :projectName=`package show slug` :version=`package show version`", "release":"recipe build/release.boxr", - "format":"cfformat run interfaces,models/,test-harness/tests/,ModuleConfig.cfc --overwrite", - "format:watch":"cfformat watch interfaces,models/,test-harness/tests/,ModuleConfig.cfc ./.cfformat.json", - "format:check":"cfformat check interfaces,models/,test-harness/tests/,ModuleConfig.cfc" - }, - "installPaths":{ - "cbi18n":"modules/cbi18n/" + "format":"cfformat run helpers,interfaces,models,test-harness/tests/,ModuleConfig.cfc --overwrite", + "format:watch":"cfformat watch helpers,interfaces,models,test-harness/tests/,ModuleConfig.cfc ./.cfformat.json", + "format:check":"cfformat check helpers,interfaces,models,test-harness/tests/,ModuleConfig.cfc", + "cfpm":"echo '\".engine/adobe2021/WEB-INF/cfusion/bin/cfpm.sh\"' | run", + "cfpm:install":"echo '\".engine/adobe2021/WEB-INF/cfusion/bin/cfpm.sh\" install ${1}' | run", + "install:2021":"run-script cfpm:install zip", + "install:dependencies":"install && cd test-harness && install" } } diff --git a/build/Build.cfc b/build/Build.cfc index ae94650..926cce1 100644 --- a/build/Build.cfc +++ b/build/Build.cfc @@ -23,6 +23,8 @@ component { "test-harness", "(package|package-lock).json", "webpack.config.js", + "server-.*\.json", + "docker-compose.yml", "^\..*" ]; diff --git a/build/release.boxr b/build/release.boxr index e216f22..d0ba4f7 100755 --- a/build/release.boxr +++ b/build/release.boxr @@ -22,4 +22,4 @@ # Bump to prepare for a new release, do minor, change if needed and don't tag bump --minor --!tagVersion !git commit -a -m "version bump" -!git push origin development \ No newline at end of file +!git push origin development diff --git a/changelog.md b/changelog.md index c3f7f2a..080bf7e 100644 --- a/changelog.md +++ b/changelog.md @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ---- +## [3.4.0] => 2022-JUN- + +### Added + +* `EmptyValidator` by @elpete. This validator is useful when a field is not required but if it exists it cannot be empty: https://github.com/coldbox-modules/cbvalidation/pull/61 +* New module template updates and enhancements +* Update to use the new virtual app from ColdBox 6.7 + +---- + ## [3.3.0] => 2022-JAN-12 ### Added diff --git a/test-harness/server-adobe@2016.json b/server-adobe@2016.json similarity index 67% rename from test-harness/server-adobe@2016.json rename to server-adobe@2016.json index e5e16bf..6b49a0a 100644 --- a/test-harness/server-adobe@2016.json +++ b/server-adobe@2016.json @@ -11,9 +11,13 @@ "rewrites":{ "enable":"true" }, + "webroot":"test-harness", "aliases":{ - "/moduleroot/cbvalidation":"../" + "/moduleroot/cbvalidation":"./" } }, - "openBrowser":"false" -} \ No newline at end of file + "openBrowser":"false", + "cfconfig": { + "file" : ".cfconfig.json" + } +} diff --git a/test-harness/server-adobe@2018.json b/server-adobe@2018.json similarity index 66% rename from test-harness/server-adobe@2018.json rename to server-adobe@2018.json index f7dae9e..76ac693 100644 --- a/test-harness/server-adobe@2018.json +++ b/server-adobe@2018.json @@ -11,9 +11,13 @@ "rewrites":{ "enable":"true" }, + "webroot":"test-harness", "aliases":{ - "/moduleroot/cbvalidation":"../" + "/moduleroot/cbvalidation":"./" } }, - "openBrowser":"false" -} \ No newline at end of file + "openBrowser":"false", + "cfconfig": { + "file" : ".cfconfig.json" + } +} diff --git a/test-harness/server-adobe@2021.json b/server-adobe@2021.json similarity index 67% rename from test-harness/server-adobe@2021.json rename to server-adobe@2021.json index bfe0799..76bc71b 100644 --- a/test-harness/server-adobe@2021.json +++ b/server-adobe@2021.json @@ -11,9 +11,13 @@ "rewrites":{ "enable":"true" }, + "webroot":"test-harness", "aliases":{ - "/moduleroot/cbvalidation":"../" + "/moduleroot/cbvalidation":"./" } }, - "openBrowser":"false" -} \ No newline at end of file + "openBrowser":"false", + "cfconfig": { + "file" : ".cfconfig.json" + } +} diff --git a/test-harness/server-lucee@5.json b/server-lucee@5.json similarity index 66% rename from test-harness/server-lucee@5.json rename to server-lucee@5.json index 0a87f0d..07543ff 100644 --- a/test-harness/server-lucee@5.json +++ b/server-lucee@5.json @@ -11,9 +11,13 @@ "rewrites":{ "enable":"true" }, + "webroot":"test-harness", "aliases":{ - "/moduleroot/cbvalidation":"../" + "/moduleroot/cbvalidation":"./" } }, - "openBrowser":"false" -} \ No newline at end of file + "openBrowser":"false", + "cfconfig": { + "file" : ".cfconfig.json" + } +} diff --git a/test-harness/Application.cfc b/test-harness/Application.cfc index d8f85b2..a60cd3b 100644 --- a/test-harness/Application.cfc +++ b/test-harness/Application.cfc @@ -8,6 +8,7 @@ component { // UPDATE THE NAME OF THE MODULE IN TESTING BELOW request.MODULE_NAME = "cbvalidation"; + request.MODULE_PATH = "cbvalidation"; // Application properties this.name = hash( getCurrentTemplatePath() ); @@ -71,6 +72,13 @@ component { // request start public boolean function onRequestStart( String targetPage ){ + + if ( url.keyExists( "fwreinit" ) ) { + if ( server.keyExists( "lucee" ) ) { + pagePoolClear(); + } + } + // Process ColdBox Request application.cbBootstrap.onRequestStart( arguments.targetPage ); diff --git a/test-harness/config/Coldbox.cfc b/test-harness/config/Coldbox.cfc index a5af19a..6c08dcc 100644 --- a/test-harness/config/Coldbox.cfc +++ b/test-harness/config/Coldbox.cfc @@ -54,12 +54,14 @@ filename : "tester", filePath : "/#appMapping#/logs" } - } + }, + console : { class : "coldbox.system.logging.appenders.ConsoleAppender" } }, // Root Logger root : { levelmax : "DEBUG", appenders : "*" }, // Implicit Level Categories - info : [ "coldbox.system" ] + info : [ "coldbox.system" ], + debug : [ "cbvalidation.*" ] }; moduleSettings = { diff --git a/test-harness/tests/Application.cfc b/test-harness/tests/Application.cfc index 62db57c..f452d23 100644 --- a/test-harness/tests/Application.cfc +++ b/test-harness/tests/Application.cfc @@ -1,11 +1,23 @@ -component { +/** +* Copyright 2005-2007 ColdBox Framework by Luis Majano and Ortus Solutions, Corp +* www.ortussolutions.com +* --- +*/ +component { + + // UPDATE THE NAME OF THE MODULE IN TESTING BELOW + request.MODULE_NAME = "cbvalidation"; + request.MODULE_PATH = "cbvalidation"; // APPLICATION CFC PROPERTIES - this.name = "ColdBoxTestingSuite" & hash( getCurrentTemplatePath() ); - this.sessionManagement = true; - this.sessionTimeout = createTimespan( 0, 0, 15, 0 ); - this.applicationTimeout = createTimespan( 0, 0, 15, 0 ); - this.setClientCookies = true; + this.name = "ColdBoxTestingSuite"; + this.sessionManagement = true; + this.setClientCookies = true; + this.sessionTimeout = createTimeSpan( 0, 0, 15, 0 ); + this.applicationTimeout = createTimeSpan( 0, 0, 15, 0 ); + // Turn on/off white space management + this.whiteSpaceManagement = "smart"; + this.enableNullSupport = shouldEnableFullNullSupport(); // Create testing mapping this.mappings[ "/tests" ] = getDirectoryFromPath( getCurrentTemplatePath() ); @@ -13,10 +25,6 @@ // The application root rootPath = reReplaceNoCase( this.mappings[ "/tests" ], "tests(\\|/)", "" ); this.mappings[ "/root" ] = rootPath; - - // UPDATE THE NAME OF THE MODULE IN TESTING BELOW - request.MODULE_NAME = "cbvalidation"; - this.mappings[ "/cbi18n" ] = rootPath & "modules/cbi18n"; // The module root path @@ -26,27 +34,40 @@ "" ); this.mappings[ "/moduleroot" ] = moduleRootPath; - this.mappings[ "/#request.MODULE_NAME#" ] = moduleRootPath & "#request.MODULE_NAME#"; + this.mappings[ "/#request.MODULE_NAME#" ] = moduleRootPath & "#request.MODULE_PATH#"; // request start public boolean function onRequestStart( String targetPage ){ - if ( url.keyExists( "fwreinit" ) ) { - if ( structKeyExists( server, "lucee" ) ) { + // Set a high timeout for long running tests + setting requestTimeout="9999"; + // New ColdBox Virtual Application Starter + request.coldBoxVirtualApp = new coldbox.system.testing.VirtualApp( appMapping = "/root" ); + + // If hitting the runner or specs, prep our virtual app + if ( getBaseTemplatePath().replace( expandPath( "/tests" ), "" ).reFindNoCase( "(runner|specs)" ) ) { + request.coldBoxVirtualApp.startup(); + } + + // ORM Reload for fresh results + if( structKeyExists( url, "fwreinit" ) ){ + if( structKeyExists( server, "lucee" ) ){ pagePoolClear(); } + // ormReload(); + request.coldBoxVirtualApp.restart(); } return true; } - public function onRequestEnd(){ - // CB 6 graceful shutdown - if ( !isNull( application.cbController ) ) { - application.cbController.getLoaderService().processShutdown(); - } - - structDelete( application, "cbController" ); - structDelete( application, "wirebox" ); + public void function onRequestEnd( required targetPage ) { + request.coldBoxVirtualApp.shutdown(); } + private boolean function shouldEnableFullNullSupport() { + var system = createObject( "java", "java.lang.System" ); + var value = system.getEnv( "FULL_NULL" ); + return isNull( value ) ? false : !!value; + } + }