diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000000..46f49004950 --- /dev/null +++ b/.npmrc @@ -0,0 +1,5 @@ +color=false +engine-strict=true +fund=false +progress=true +unicode=false diff --git a/build.gradle b/build.gradle index 1d99742224f..eb9553e43d8 100644 --- a/build.gradle +++ b/build.gradle @@ -25,8 +25,8 @@ buildscript { classpath "com.bertramlabs.plugins:asset-pipeline-gradle:${assetPipelineVersion}" classpath "org.grails:grails-gradle-plugin:${grailsVersion}" classpath "org.grails.plugins:database-migration:${databaseMigrationVersion}" - classpath 'org.grails.plugins:views-gradle:1.3.0' - classpath 'org.owasp:dependency-check-gradle:7.2.1' + classpath "org.grails.plugins:views-gradle:${grailsViewsVersion}" + classpath "org.owasp:dependency-check-gradle:${owaspVersion}" } repositories { mavenCentral() @@ -35,19 +35,25 @@ buildscript { } plugins { - + // enable the top-level `mainClassName` field id 'application' + id 'eclipse' id 'groovy' id 'idea' + + // expose `pom` object, https://docs.gradle.org/4.10.3/userguide/maven_plugin.html id 'maven' + + // enable `grails gradle dependencyReport`, etc. id 'project-report' + id 'war' // git magic, but releases past v2.3.0 require Gradle 5.1+ id 'com.gorylenko.gradle-git-properties' version '2.2.4' - // enable `npmInstall` target, as well as the `node` block below + // enable `npmInstall` and `npm_run_*` targets, and the `node` block below id 'com.moowork.node' version '1.3.1' // resolve a Windows-specific build issue @@ -58,34 +64,58 @@ plugins { apply plugin: 'org.grails.grails-web' apply plugin: 'asset-pipeline' // enable `assets` block, but see deps below -apply plugin: 'org.grails.plugins.views-json' // .gson support -apply plugin: 'org.owasp.dependencycheck' // enable dependencyCheckAnalyze task // prevent warfile issues by applying this after `asset-pipeline`. OBGM-353 apply plugin: 'org.grails.grails-gsp' +/* + * This plugin must load *after* the core grails/gradle plugins. + * http://views.grails.org/latest/#_installation + */ +apply plugin: 'org.grails.plugins.views-json' + +// enable `grails gradle dependencyCheckAnalyze` (security checker) +apply plugin: 'org.owasp.dependencycheck' + group 'com.openboxes' mainClassName = 'org.pih.warehouse.Application' sourceCompatibility = 1.8 targetCompatibility = 1.8 version '0.9.0-SNAPSHOT' -assetCompile.dependsOn(['npmInstall', 'npm_run_bundle']) +assetCompile { + dependsOn 'npm_run_bundle' + /* + * Webpack's FileManagerPlugin modifies asset-pipeline's working + * directory every time we build, but Gradle's "up-to-date" checks do + * not reliably detect those changes. This directive instructs gradle + * to always (re)run this task, which only takes a few seconds anyway. + */ + outputs.upToDateWhen { false } +} + +/* + * From the asset-pipeline manual: "If you want settings to apply to + * both development runtime and build time the properties have to be + * duplicated in your application's application.yml [and build.gradle]." + * + * http://www.asset-pipeline.com/manual/index.html#configuration + * http://www.asset-pipeline.com/manual/index.html#configuration-2 + */ assets { - excludes = [ - '**/bundle.*.css', - '**/bundle.*.js', - ] + enableDigests = false + enableGzip = false + maxThreads = 1 + minifyJs = false // defer to webpack + minifyCss = false // defer to webpack minifyOptions = [ - languageMode: 'ES6', - optimizationLevel: 'SIMPLE', - targetLanguage: 'ES5', + languageMode: 'ES6' ] } bootRun { addResources = true - dependsOn = ['npmInstall', 'npm_run_bundle'] + dependsOn 'npm_run_bundle' jvmArgs = [ '-Dspring.output.ansi.enabled=never', '-Xdebug', @@ -257,7 +287,7 @@ configurations { } } -dependencyCheckAnalyze.dependsOn(['npmInstall', 'npm_run_bundle']) +dependencyCheckAnalyze.dependsOn 'npm_run_bundle' dependencyCheck { analyzers { assemblyEnabled = false @@ -280,7 +310,7 @@ node { distBaseUrl = 'https://nodejs.org/dist' download = true npmVersion = '6.14.17' - version = '14.20.0' + version = '14.20.1' } repositories { @@ -323,11 +353,8 @@ dependencies { * See https://github.com/bertramdev/asset-pipeline#documentation-1 */ runtime "com.bertramlabs.plugins:asset-pipeline-grails:${assetPipelineVersion}" - assets "com.bertramlabs.plugins:less-asset-pipeline:${assetPipelineVersion}" - assets "com.bertramlabs.plugins:sass-asset-pipeline:${assetPipelineVersion}" // security patch - assets 'com.google.code.gson:gson:2.8.9' compile 'com.google.code.gson:gson:2.8.9' // expose javax.annotation.Nullable, com.google.common.base.Enums, etc. @@ -340,7 +367,6 @@ dependencies { // expose com.sun.mail.imap.IMAPStore to MailServiceTests testImplementation 'com.sun.mail:javax.mail:1.5.6' - assets 'commons-beanutils:commons-beanutils:1.9.4' compile 'commons-beanutils:commons-beanutils:1.9.4' compile 'commons-codec:commons-codec:1.15' @@ -378,12 +404,10 @@ dependencies { * https://tomcat.apache.org/tomcat-8.5-doc/RELEASE-NOTES.txt */ provided 'javax.annotation:javax.annotation-api:1.3.2' - provided 'javax.el:javax.el-api:2.2.5' provided "javax.servlet:javax.servlet-api:${servletVersion}" provided "javax.servlet.jsp:javax.servlet.jsp-api:${jspVersion}" provided "javax.websocket:javax.websocket-api:${websocketVersion}" - assets 'junit:junit:4.13.2' testCompile 'junit:junit:4.13.2' compile "mysql:mysql-connector-java:${mySqlConnectorVersion}" @@ -402,6 +426,8 @@ dependencies { implementation 'org.apache.poi:poi' implementation 'org.apache.poi:poi-scratchpad' + provided "org.apache.tomcat:tomcat-el-api:${minimumTomcatVersion}" + // tomcat native connection pooling provided "org.apache.tomcat:tomcat-jdbc:${minimumTomcatVersion}" @@ -683,6 +709,16 @@ buildProperties.doLast { } } +/* + * This lightweight task logs release info for node, npm and friends. + */ +task nodeVersionInfo(type: NpmTask) { + dependsOn npmSetup + args = ['version'] +} + +npm_run_bundle.dependsOn nodeVersionInfo + task prepareDocker(type: Copy, dependsOn: assemble) { description = 'Copy files from ./docker and openboxes.war to build directory' group = 'Docker' diff --git a/gradle.properties b/gradle.properties index 151025fd785..62c5306697c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,12 +4,14 @@ org.gradle.daemon=true org.gradle.parallel=false org.gradle.warning.mode=all -assetPipelineVersion=3.2.5 +# logging mysteriously broke in 3.2.4+ +assetPipelineVersion=3.2.3 # our dependencies request 3.x and 4.x, but only 5.x+ supports Java 8 asmVersion=5.0.4 bouncyCastleVersion=1.38 gradleWrapperVersion=4.10.3 grailsVersion=3.3.16 +grailsViewsVersion=1.3.0 grailsWrapperVersion=1.0.0 groovyVersion=2.4.21 htmlUnitVersion=2.62.0 @@ -22,6 +24,7 @@ jettyVersion=9.4.48.v20220622 jspVersion=2.3.0 # Grails's Spring Boot dependency doesn't play well with Logback 1.3+ logbackVersion=1.2.11 +owaspVersion=7.2.1 poiVersion=3.17 # minimum version supported by spring-boot-starter-tomcat=1.5.22.RELEASE minimumTomcatVersion=8.5.43 diff --git a/grails-app/conf/application.yml b/grails-app/conf/application.yml index 707bdd111f0..39f43f38067 100644 --- a/grails-app/conf/application.yml +++ b/grails-app/conf/application.yml @@ -77,10 +77,25 @@ server: timeout: 3600 --- grails: + # + # From the asset-pipeline manual: "If you want settings to apply to + # both development runtime and build time the properties have to be + # duplicated in your application's application.yml [and build.gradle]." + # + # http://www.asset-pipeline.com/manual/index.html#configuration + # http://www.asset-pipeline.com/manual/index.html#configuration-2 + # + # Every field except `bundle` should also be set in build.gradle. + # assets: - minifyJs: false - minifyCss: false - bundle: false + bundle: false # defer to webpack + enableDigests: false + enableGzip: false + maxThreads: 1 + minifyCss: false # defer to webpack + minifyJs: false # defer to webpack + minifyOptions: + - languageMode: 'ES6' cache: clearAtStartup: true doc: diff --git a/package.json b/package.json index 12f1e18e130..1fbb94232ef 100644 --- a/package.json +++ b/package.json @@ -128,7 +128,6 @@ "cache-loader": "4.1.0", "browserslist": "4.21.2", "cache-loader": "4.1.0", - "clean-webpack-plugin": "0.1.19", "css-loader": "3.6.0", "eslint": "6.1.0", "eslint-config-airbnb": "16.1.0", @@ -137,22 +136,23 @@ "eslint-plugin-jsx-a11y": "6.1.1", "eslint-plugin-react": "7.10.0", "eslint-plugin-simple-import-sort": "7.0.0", - "file-loader": "1.1.11", - "filemanager-webpack-plugin": "2.0.5", + "file-loader": "4.3.0", + "filemanager-webpack-plugin": "3.1.1", "html-webpack-plugin": "3.2.0", "jest": "29.2.1", "jest-environment-jsdom": "29.2.1", "jquery": "3.6.0", "jss": "9.8.7", - "mini-css-extract-plugin": "0.4.4", + "mini-css-extract-plugin": "0.10.0", "mock-local-storage": "1.1.23", "node-sass": "^5.0.0", "npm": "6.14.6", "optimize-css-assets-webpack-plugin": "5.0.8", "react-styleguidist": "9.2.0", "react-test-renderer": "16.8.6", - "sass-loader": "7.3.1", - "url-loader": "1.1.2", + "sass": "1.55.0", + "sass-loader": "10.3.1", + "url-loader": "4.1.1", "webpack": "4.46.0", "webpack-cli": "4.10.0" } diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 00000000000..e9ad61eeb71 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,11 @@ +/* + * By default, gradle's build cache lives in $HOME, meaning that neither + * `git clean -dxf` nor Bamboo's 'Force Clean Build' actually do what + * they say on the tin. Here, we put the cache in the project root. + */ +buildCache { + local(DirectoryBuildCache) { + directory = new File(rootDir, '.gradle/caches/build') + removeUnusedEntriesAfterDays = 30 + } +} diff --git a/webpack.config.js b/webpack.config.js index 4a7a889a524..ccae9998be1 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -27,38 +27,51 @@ module.exports = { chunkFilename: 'bundle.[hash].[name].js', }, stats: { - colors: true, + colors: false, }, plugins: [ new FileManagerPlugin({ - onStart: { - delete: [ - `${JS_DEST}/bundle.**`, - `${CSS_DEST}/bundle.**`, - `${BUILD_ASSETS}/bundle.**` - ] - }, - onEnd: { - copy: [ - { source: `${DEST}/bundle.*.js`, destination: JS_DEST }, - { source: `${DEST}/bundle.*.css`, destination: CSS_DEST }, - { source: `${DEST}/*.eot`, destination: IMAGES_DEST }, - { source: `${DEST}/*.svg`, destination: IMAGES_DEST }, - { source: `${DEST}/*.woff2`, destination: IMAGES_DEST }, - { source: `${DEST}/*.ttf`, destination: IMAGES_DEST }, - { source: `${DEST}/*.woff`, destination: IMAGES_DEST }, - { source: `${JS_DEST}/bundle.*.js`, destination: BUILD_ASSETS }, - { source: `${CSS_DEST}/bundle.*.css`, destination: BUILD_ASSETS } + events: { + onStart: { + delete: [ + // remove previous webpack output + `${JS_DEST}/bundle.*`, + `${CSS_DEST}/bundle.*`, + // remove previous asset-pipeline output + BUILD_ASSETS, + ], + }, + onEnd: [ + /* + * By providing a list of maps here (instead of a single map, + * like we do for `onStart`, above, we guarantee that the + * copy commands will complete before the delete commands + * begin. However, FileManagerPlugin is multithreaded and + * operations within each map will run in arbitrary order. + */ + { + copy: [ + { source: `${DEST}/bundle*.js`, destination: JS_DEST }, + { source: `${DEST}/bundle*.css`, destination: CSS_DEST }, + { source: `${DEST}/*.eot`, destination: IMAGES_DEST }, + { source: `${DEST}/*.svg`, destination: IMAGES_DEST }, + { source: `${DEST}/*.woff2`, destination: IMAGES_DEST }, + { source: `${DEST}/*.ttf`, destination: IMAGES_DEST }, + { source: `${DEST}/*.woff`, destination: IMAGES_DEST }, + ], + }, + { + delete: [ + `${DEST}/bundle.*`, + `${DEST}/*.eot`, + `${DEST}/*.svg`, + `${DEST}/*.woff2`, + `${DEST}/*.ttf`, + `${DEST}/*.woff` + ], + }, ], - delete: [ - `${DEST}/bundle.**`, - `${DEST}/*.eot`, - `${DEST}/*.svg`, - `${DEST}/*.woff2`, - `${DEST}/*.ttf`, - `${DEST}/*.woff` - ] - } + }, }), new MiniCssExtractPlugin({ filename: 'stylesheets/bundle.[hash].css',