diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml new file mode 100644 index 0000000..38a91ce --- /dev/null +++ b/.github/release-drafter.yml @@ -0,0 +1,134 @@ +name-template: $RESOLVED_VERSION +tag-template: v$RESOLVED_VERSION +pull-request: + title-templates: + fix: '🐛 $TITLE (#$NUMBER)' + feat: '🚀 $TITLE (#$NUMBER)' + default: '$TITLE (#$NUMBER)' +autolabeler: + - label: 'bug' + branch: + - '/fix\/.+/' + title: + - '/fix/i' + - label: 'improvement' + branch: + - '/improv\/.+/' + title: + - '/improv/i' + - label: 'feature' + branch: + - '/feature\/.+/' + title: + - '/feat/i' + - label: 'documentation' + branch: + - '/docs\/.+/' + title: + - '/docs/i' + - label: 'maintenance' + branch: + - '/(chore|refactor|style|test|ci|perf|build)\/.+/' + title: + - '/(chore|refactor|style|test|ci|perf|build)/i' + - label: 'chore' + branch: + - '/chore\/.+/' + title: + - '/chore/i' + - label: 'refactor' + branch: + - '/refactor\/.+/' + title: + - '/refactor/i' + - label: 'style' + branch: + - '/style\/.+/' + title: + - '/style/i' + - label: 'test' + branch: + - '/test\/.+/' + title: + - '/test/i' + - label: 'ci' + branch: + - '/ci\/.+/' + title: + - '/ci/i' + - label: 'perf' + branch: + - '/perf\/.+/' + title: + - '/perf/i' + - label: 'build' + branch: + - '/build\/.+/' + title: + - '/build/i' + - label: 'deps' + branch: + - '/deps\/.+/' + title: + - '/deps/i' + - label: 'revert' + branch: + - '/revert\/.+/' + title: + - '/revert/i' +categories: + - title: '🚀 Features' + labels: + - 'feature' + - "type: enhancement" + - "type: new feature" + - "type: major" + - "type: minor" + - title: '💡 Improvements' + labels: + - 'improvement' + - "type: improvement" + + - title: '🐛 Bug Fixes' + labels: + - 'fix' + - 'bug' + - "type: bug" + - title: '📚 Documentation' + labels: + - 'docs' + - title: '🔧 Maintenance' + labels: + - 'maintenance' + - 'chore' + - 'refactor' + - 'style' + - 'test' + - 'ci' + - 'perf' + - 'build' + - "type: ci" + - "type: build" + - title: '⏪ Reverts' + labels: + - 'revert' +change-template: '- $TITLE @$AUTHOR (#$NUMBER)' +version-resolver: + major: + labels: + - 'type: major' + minor: + labels: + - 'type: minor' + patch: + labels: + - 'type: patch' + default: patch +template: | + ## What's Changed + + $CHANGES + + ## Contributors + + $CONTRIBUTORS \ No newline at end of file diff --git a/.github/renovate.json b/.github/renovate.json new file mode 100644 index 0000000..30740f8 --- /dev/null +++ b/.github/renovate.json @@ -0,0 +1,61 @@ +{ + "extends": [ + "config:base" + ], + "labels": ["type: dependency upgrade"], + "packageRules": [ + { + "matchUpdateTypes": ["major"], + "enabled": false + }, + { + "matchPackagePatterns": ["*"], + "allowedVersions": "!/SNAPSHOT$/" + }, + { + "matchPackagePatterns": [ + "^org\\.codehaus\\.groovy" + ], + "groupName": "groovy monorepo" + }, + { + "matchPackageNames": [ + "org.grails:grails-bom", + "org.grails:grails-bootstrap", + "org.grails:grails-codecs", + "org.grails:grails-console", + "org.grails:grails-core", + "org.grails:grails-databinding", + "org.grails:grails-dependencies", + "org.grails:grails-docs", + "org.grails:grails-encoder", + "org.grails:grails-gradle-model", + "org.grails:grails-logging", + "org.grails:grails-plugin-codecs", + "org.grails:grails-plugin-controllers", + "org.grails:grails-plugin-databinding", + "org.grails:grails-plugin-datasource", + "org.grails:grails-plugin-domain-class", + "org.grails:grails-plugin-i18n", + "org.grails:grails-plugin-interceptors", + "org.grails:grails-plugin-mimetypes", + "org.grails:grails-plugin-rest", + "org.grails:grails-plugin-services", + "org.grails:grails-plugin-url-mappings", + "org.grails:grails-plugin-url-validation", + "org.grails:grails-shell", + "org.grails:grails-spring", + "org.grails:grails-test", + "org.grails:grails-validation", + "org.grails:grails-web", + "org.grails:grails-web-boot", + "org.grails:grails-web-common", + "org.grails:grails-web-databinding", + "org.grails:grails-web-fileupload", + "org.grails:grails-web-mvc", + "org.grails:grails-web-url-mappings" + ], + "groupName": "grails monorepo" + } + ] +} \ No newline at end of file diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml new file mode 100644 index 0000000..ffef9ac --- /dev/null +++ b/.github/workflows/gradle.yml @@ -0,0 +1,83 @@ +name: Java CI +on: + push: + branches: + - '[4-9]+.[0-9]+.x' + pull_request: + branches: + - '[4-9]+.[0-9]+.x' +env: + GIT_USER_NAME: puneetbehl + GIT_USER_EMAIL: behlp@unityfoundation.io + +jobs: + + test_project: + name: Test Project + if: github.event_name == 'pull_request' + runs-on: ubuntu-latest + strategy: + fail-fast: true + matrix: + java: [11, 17] + + steps: + - uses: actions/checkout@v4 + - uses: gradle/wrapper-validation-action@v2 + - uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: ${{ matrix.java }} + - uses: gradle/actions/setup-gradle@v3 + env: + DEVELOCITY_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} + with: + arguments: check + + publish_snapshot: + name: Build Project and Publish Snapshot release + runs-on: ubuntu-latest + if: github.event_name == 'push' + + steps: + - uses: actions/checkout@v4 + - uses: gradle/wrapper-validation-action@v2 + - uses: actions/setup-java@v4 + with: { java-version: 11, distribution: temurin } + + - name: Build Project + uses: gradle/actions/setup-gradle@v3 + env: + DEVELOCITY_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} + with: + arguments: build + + - name: Publish Snapshot version to Artifactory (repo.grails.org) + if: success() + uses: gradle/actions/setup-gradle@v3 + env: + DEVELOCITY_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} + ORG_GRADLE_PROJECT_artifactoryPublishUsername: ${{ secrets.ARTIFACTORY_USERNAME }} + ORG_GRADLE_PROJECT_artifactoryPublishPassword: ${{ secrets.ARTIFACTORY_PASSWORD }} + with: + arguments: | + -Dorg.gradle.internal.publish.checksums.insecure=true + publish + + - name: Generate Snapshot Documentation + if: success() + uses: gradle/actions/setup-gradle@v3 + env: + DEVELOCITY_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} + with: + arguments: docs + + - name: Publish Snapshot Documentation to Github Pages + if: success() + uses: micronaut-projects/github-pages-deploy-action@grails + env: + BRANCH: gh-pages + COMMIT_EMAIL: ${{ env.GIT_USER_EMAIL }} + COMMIT_NAME: ${{ env.GIT_USER_NAME }} + FOLDER: build/docs/manual + GH_TOKEN: ${{ secrets.GH_TOKEN }} diff --git a/.github/workflows/release-notes.yml b/.github/workflows/release-notes.yml new file mode 100644 index 0000000..2491496 --- /dev/null +++ b/.github/workflows/release-notes.yml @@ -0,0 +1,51 @@ +name: Changelog +on: + issues: + types: [closed,reopened] + push: + branches: + - '[4-9]+.[0-9]+.x' + pull_request: + types: [opened, reopened, synchronize, labeled] + pull_request_target: + types: [opened, reopened, synchronize, labeled] + workflow_dispatch: +jobs: + release_notes: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Check if it has release drafter config file + id: check_release_drafter + run: | + has_release_drafter=$([ -f .github/release-drafter.yml ] && echo "true" || echo "false") + echo "has_release_drafter=${has_release_drafter}" >> $GITHUB_OUTPUT + - name: Extract branch name + id: extract_branch + run: echo "value=${GITHUB_REF:11}" >> $GITHUB_OUTPUT + # If it has release drafter: + - uses: release-drafter/release-drafter@v5 + if: steps.check_release_drafter.outputs.has_release_drafter == 'true' + env: + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} + with: + commitish: ${{ steps.extract_branch.outputs.value }} + # Otherwise: + - name: Export Gradle Properties + if: steps.check_release_drafter.outputs.has_release_drafter == 'false' + uses: micronaut-projects/github-actions/export-gradle-properties@master + - uses: micronaut-projects/github-actions/release-notes@master + if: steps.check_release_drafter.outputs.has_release_drafter == 'false' + id: release_notes + with: + token: ${{ secrets.GH_TOKEN }} + - uses: ncipollo/release-action@v1 + if: steps.check_release_drafter.outputs.has_release_drafter == 'false' && steps.release_notes.outputs.generated_changelog == 'true' + with: + allowUpdates: true + commit: ${{ steps.release_notes.outputs.current_branch }} + draft: true + name: "${{ env.title }} ${{ steps.release_notes.outputs.next_version }}" + tag: v${{ steps.release_notes.outputs.next_version }} + bodyFile: CHANGELOG.md + token: ${{ secrets.GH_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..046de3c --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,68 @@ +name: Release +on: + release: + types: [published] +env: + GIT_USER_NAME: puneetbehl + GIT_USER_EMAIL: behlp@unityfoundation.io + +jobs: + release: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: gradle/wrapper-validation-action@v2 + - uses: actions/setup-java@v4 + with: { java-version: 11, distribution: temurin } + + - name: Get the current release version + id: release_version + run: echo "release_version=${GITHUB_REF:11}" >> $GITHUB_OUTPUT + + - name: Run pre-release + uses: micronaut-projects/github-actions/pre-release@master + + - name: Generate secring file + env: + SECRING_FILE: ${{ secrets.SECRING_FILE }} + run: echo $SECRING_FILE | base64 -d > ${{ github.workspace }}/secring.gpg + + - name: Publish artifacts to Sonatype + id: publish_to_sonatype + uses: gradle/actions/setup-gradle@v3 + env: + DEVELOCITY_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} + ORG_GRADLE_PROJECT_sonatypeUsername: ${{ secrets.SONATYPE_USERNAME }} + ORG_GRADLE_PROJECT_sonatypePassword: ${{ secrets.SONATYPE_PASSWORD }} + ORG_GRADLE_PROJECT_sonatypeStagingProfileId: ${{ secrets.SONATYPE_STAGING_PROFILE_ID }} + SIGNING_KEY: ${{ secrets.SIGNING_KEY }} + SIGNING_PASSPHRASE: ${{ secrets.SIGNING_PASSPHRASE }} + with: + arguments: | + -Psigning.secretKeyRingFile=${{ github.workspace }}/secring.gpg + publishToSonatype + closeAndReleaseSonatypeStagingRepository + + - name: Generate Documentation + if: success() + uses: gradle/actions/setup-gradle@v3 + env: + DEVELOCITY_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} + with: + arguments: docs + + - name: Publish Documentation to Github Pages + if: success() + uses: micronaut-projects/github-pages-deploy-action@grails + env: + BRANCH: gh-pages + COMMIT_EMAIL: ${{ env.GIT_USER_EMAIL }} + COMMIT_NAME: ${{ env.GIT_USER_NAME }} + FOLDER: build/docs/manual + GH_TOKEN: ${{ secrets.GH_TOKEN }} + VERSION: ${{ steps.release_version.outputs.release_version }} + + - name: Run post-release + if: steps.publish_to_sonatype.outcome == 'success' + uses: micronaut-projects/github-actions/post-release@master \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 859a45d..0000000 --- a/.travis.yml +++ /dev/null @@ -1,16 +0,0 @@ -language: groovy -jdk: -- openjdk8 -- openjdk11 -before_script: -- rm -rf target -script: "./travis-build.sh" -env: - global: - - GIT_NAME="Jeff Scott Brown" - - GIT_EMAIL="brownj@objectcomputing.com" - - secure: cCZD9HmATbdJDohqSUVTk/2J6WgcsrRoUpEynwBOx2zc7n95XB48B+hhtOEJ998B33Pky4u5gb04VpaSXJqOambmVHreGwYl1OtA3QWz9tXuohgnSyP8qdp6Dzo3Jb+91yURQAErftvZyBJo3fVANPHkaFb4L2FG+oGrWZ7KsMA= - - secure: IU68RJFNFmr2NA9WJUavnIK+8PESBrX7eee3Z5xQtXPMW+GcpK6Xb4jr10YmBuiLH3rWJMryTz/i2C8fLO/hxYgf6MCWI+WZHxL2KW6U6V0rdID+hH1MVVLQVpWFyOH3KOmtcLHn36Ix6ZZiNn+mjfF9ocHRCo8Jw49hr6+sQAc= - - secure: ePY48Cu0eV28K++86JVz0BImE4f+x2LLIPsYA7BR3lsqQJS3IheFQviJr/DpIMEtZYEC6/Pzmtl/1tpqPsIesMnEvn7Z7v230mWQW4SaXgCsD0c80rj3nPvPoPEyWpveD5+Ayo8AzkTvV/9zFlwDJloVDG5NWyTdglOlZMc4dno= - - secure: JmNcdO2oUyJJBLXRnoeLb1orrURKGQ2jEp8LaG2YolZDSbyoKKwNVPmymfCwCPHzdMCdspJJjRCL7O6l2J/irgG8LzsKwS6snOmeFiDq8EXCREdcMjKeVjrVUsKB0OZQpHKnmwwpEfpVlgJ5rkR5IVjTwJxRfJaCUFZSRZ5IXtI= - - secure: ThHW0nEmx0fyAaYzYmCC7pw6TUaZsjyA3stw9rWHC40hkRW9J/tUilzzGbqFKRu0JI/G8oOKHuJ11iYb8W7gmxAewd0KAsdxZCVU12/CxCH6TYGhiNuszuU0N4e2zRbg1jkQOicSiRmIu0klBi2//59RuyPu6oOMwyJzuWylBiM= diff --git a/README.md b/README.md index ad69a83..889f4fa 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,43 @@ -The Grails mail plugin provides a convenient DSL for _sending_ email. It supports plain text, html, attachments, inline resources and i18n among other features. -[![Build Status](https://travis-ci.org/grails3-plugins/mail.svg?branch=master)](https://travis-ci.org/grails3-plugins/mail) +# Grails Mail Plugin + +[![Maven Central](https://img.shields.io/maven-central/v/org.grails.plugins/mail.svg?label=Maven%20Central)](https://central.sonatype.com/artifact/org.grails.plugins/mail) +[![Java CI](https://github.com/grails/grails-mail/actions/workflows/gradle.yml/badge.svg?event=push)](https://github.com/grails/grails-mail/actions/workflows/gradle.yml) -Mail can be sent using the @mailService@ via the @sendMail@ method. Here is an example… +## About - mailService.sendMail { - to "fred@gmail.com","ginger@gmail.com" - from "john@gmail.com" - cc "marge@gmail.com", "ed@gmail.com" - bcc "joe@gmail.com" - subject "Hello John" - text 'this is some text' - } +The Grails mail plugin provides a convenient DSL for _sending_ email. It supports plain text, html, attachments, inline resources and i18n among other features. -Please see the [User Guide](https://grails3-plugins.github.io/mail/ "Grails Mail Plugin @ GitHub") for more information. +Mail can be sent using the `mailService.sendMail` method. Here is an example… +```groovy +mailService.sendMail { + to 'fred@gmail.com', 'ginger@gmail.com' + from 'john@gmail.com' + cc 'marge@gmail.com', 'ed@gmail.com' + bcc 'joe@gmail.com' + subject 'Hello John' + text 'this is some text' +} +``` -The plugin is released under the [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html "Apache License, Version 2.0 - The Apache Software Foundation"). +## Documentation + +[Latest documentation](https://grails.github.io/grails-mail/latest/) and [snapshots](https://grails.github.io/grails-mail/snapshot/) are available. ## Versions -* 3.x - Compatible with Grails 4 -* 2.x - Compatible with Grails 3 -* 1.x - Compatible with Grails 2 +| Branch | Grails Version | +|--------|----------------| +| 1.x | 2 | +| 2.x | 3 | +| 3.x | 4-5 | +| 4.x | 6 | ## Issues -Issues can be raised via [GitHub Issues](https://github.com/grails3-plugins/mail/issues). +Issues can be raised via [GitHub Issues](https://github.com/grails/grails-mail/issues). ## Contributing Pull requests are the preferred method for submitting contributions. Please open an issue via that issue tracker link above and create an issue describing what your contribution addresses. -If you are contributing documentation, raising an issue is not necessary. - +If you are contributing documentation, raising an issue is not necessary. \ No newline at end of file diff --git a/build.gradle b/build.gradle index ffe8c69..91f0082 100644 --- a/build.gradle +++ b/build.gradle @@ -1,67 +1,63 @@ -buildscript { - ext { - grailsVersion = project.grailsVersion - } - repositories { - mavenLocal() - maven { url "https://repo.grails.org/grails/core" } - } - dependencies { - classpath "org.grails:grails-gradle-plugin:$grailsVersion" - classpath "org.jfrog.buildinfo:build-info-extractor-gradle:latest.release" - } +plugins { + id 'groovy' + id 'java-library' + id 'io.github.gradle-nexus.publish-plugin' + id 'maven-publish' + id 'signing' } -version "3.0.1.BUILD-SNAPSHOT" -group "org.grails.plugins" - - -apply plugin: 'eclipse' -apply plugin: 'idea' -apply plugin: "org.grails.grails-plugin" -apply plugin: "org.grails.grails-plugin-publish" -apply plugin: "org.grails.grails-gsp" -apply plugin: "org.grails.grails-doc" -apply plugin: "com.jfrog.artifactory" - - -ext { - grailsVersion = project.grailsVersion -} - -sourceCompatibility = 1.8 -targetCompatibility = 1.8 +version = projectVersion +group = 'org.grails.plugins' +ext.set('grailsVersion', libs.versions.grails.asProvider().get()) +ext.set('isReleaseVersion', !version.toString().endsWith('-SNAPSHOT')) +ext.set('isSnapshot', !isReleaseVersion) +apply plugin: 'org.grails.grails-plugin' // Needs to be applied after grailsVersion has been set repositories { - mavenLocal() mavenCentral() - maven { url "https://repo.grails.org/grails/core" } -} - -dependencyManagement { - imports { - mavenBom "org.grails:grails-bom:$grailsVersion" - } - applyMavenExclusions false + maven { url = 'https://repo.grails.org/grails/core' } } dependencies { - provided 'org.springframework.boot:spring-boot-starter-logging' - provided "org.springframework.boot:spring-boot-starter-actuator" - provided "org.springframework.boot:spring-boot-autoconfigure" - provided "org.springframework.boot:spring-boot-starter-tomcat" - provided "org.grails:grails-web-boot" - provided "org.grails:grails-dependencies" - provided 'javax.servlet:javax.servlet-api:3.1.0' - - testCompile 'org.grails:grails-web-testing-support:2.0.0' - testCompile "com.icegreen:greenmail:1.5.10" + api libs.groovy.core // Used in public api + api libs.javamail.api // Used in public api + api libs.spring.context // Used in public api + api libs.spring.context.support // Used in public api + + // These three libraries are used in public api, but not in a way + // that is meant to be consumed by users of the plugin. + // Therefore they are set to implementation to not expose unnecessarily + // to the compileClasspath of plugin users. + implementation libs.grails.core + implementation libs.grails.gsp + implementation libs.grails.web.common + + implementation libs.grails.web.urlmappings + implementation libs.javamail.impl + implementation libs.spring.beans + implementation libs.springboot.autoconfigure + + testImplementation libs.grails.testing.support.core + testImplementation libs.spock.core + + integrationTestImplementation libs.greenmail + integrationTestImplementation libs.spring.web + + integrationTestRuntimeOnly libs.grails.testing.support.web + integrationTestRuntimeOnly libs.slf4j.nop // Get rid of warning about missing slf4j implementation during test task + integrationTestRuntimeOnly libs.springboot.starter.tomcat +} - compile "javax.mail:javax.mail-api:1.6.2" - compile "com.sun.mail:javax.mail:1.6.2" +tasks.withType(Test).configureEach { + useJUnitPlatform() + testLogging { + events 'passed', 'skipped', 'failed' + } } -apply from: "${rootProject.projectDir}/gradle/grailsPublish.gradle" -apply from: "${rootProject.projectDir}/gradle/artifactoryPublish.gradle" \ No newline at end of file +apply from: layout.projectDirectory.file('gradle/java-config.gradle') +apply from: layout.projectDirectory.file('gradle/grails-plugin-config.gradle') +apply from: layout.projectDirectory.file('gradle/documentation-config.gradle') +apply from: layout.projectDirectory.file('gradle/publishing.gradle') diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle new file mode 100644 index 0000000..61d9189 --- /dev/null +++ b/buildSrc/build.gradle @@ -0,0 +1,8 @@ +repositories { + mavenCentral() + maven { url = 'https://repo.grails.org/grails/core' } +} +dependencies { + implementation buildsrcLibs.nexus.publish.gradle.plugin + implementation buildsrcLibs.grails.gradle.plugin +} \ No newline at end of file diff --git a/buildSrc/settings.gradle b/buildSrc/settings.gradle new file mode 100644 index 0000000..6cd9ab1 --- /dev/null +++ b/buildSrc/settings.gradle @@ -0,0 +1,7 @@ +dependencyResolutionManagement { + versionCatalogs { + buildsrcLibs { + from(files('../gradle/buildsrc.libs.versions.toml')) + } + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index af15de3..0e8d2d9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,9 @@ -grailsVersion=4.0.0 -vcsUrl=https://github.com/grails3-plugins/mail/ \ No newline at end of file +projectVersion=4.0.0-SNAPSHOT + +# This prevents the Grails Gradle Plugin from unnecessarily excluding slf4j-simple in the generated POMs +# https://github.com/grails/grails-gradle-plugin/issues/222 +slf4jPreventExclusion=true + +org.gradle.caching=true +org.gradle.daemon=true +org.gradle.parallel=true diff --git a/gradle/artifactoryPublish.gradle b/gradle/artifactoryPublish.gradle deleted file mode 100644 index 8c216b1..0000000 --- a/gradle/artifactoryPublish.gradle +++ /dev/null @@ -1,13 +0,0 @@ -artifactory { - contextUrl = 'http://oss.jfrog.org' - publish { - repository { - repoKey = 'oss-snapshot-local' - username = System.getenv("BINTRAY_USER") ?: project.hasProperty("bintrayUser") ? project.bintrayUser : '' - password = System.getenv("BINTRAY_KEY") ?: project.hasProperty("bintrayKey") ? project.bintrayKey : '' - } - defaults { - publications('maven') - } - } -} diff --git a/gradle/buildsrc.libs.versions.toml b/gradle/buildsrc.libs.versions.toml new file mode 100644 index 0000000..3374bdb --- /dev/null +++ b/gradle/buildsrc.libs.versions.toml @@ -0,0 +1,7 @@ +[versions] +grails-gradle-plugin = '6.2.0' +nexus-publish-gradle-plugin = '1.3.0' + +[libraries] +grails-gradle-plugin = { module = 'org.grails:grails-gradle-plugin', version.ref = 'grails-gradle-plugin' } +nexus-publish-gradle-plugin = { module = 'io.github.gradle-nexus:publish-plugin', version.ref = 'nexus-publish-gradle-plugin' } diff --git a/gradle/documentation-config.gradle b/gradle/documentation-config.gradle new file mode 100644 index 0000000..f12f550 --- /dev/null +++ b/gradle/documentation-config.gradle @@ -0,0 +1,32 @@ +import org.grails.gradle.plugin.doc.PublishGuideTask + +apply plugin: 'org.grails.grails-doc' + +configurations.register('groovydocConfiguration') +configurations.register('guideConfiguration') + +dependencies { + + add('groovydocConfiguration', localGroovy(), { + because 'groovydoc needs to run with the same version as Gradle' + }) + + add('guideConfiguration', libs.grails.docs) + add('guideConfiguration', libs.groovy.templates) + add('guideConfiguration', libs.slf4j.nop) // Get rid of warning about missing slf4j implementation during docs task +} + +tasks.withType(Groovydoc).configureEach { + access = GroovydocAccess.PRIVATE + processScripts = false + includeMainForScripts = false + includeAuthor = true + classpath = configurations.groovydocConfiguration + groovyClasspath = configurations.groovydocConfiguration +} + +tasks.withType(PublishGuideTask).configureEach { + classpath = configurations.guideConfiguration + javadocDir = null + propertiesFile = layout.projectDirectory.file('src/docs/guide.properties').asFile +} \ No newline at end of file diff --git a/gradle/grails-plugin-config.gradle b/gradle/grails-plugin-config.gradle new file mode 100644 index 0000000..e516cd9 --- /dev/null +++ b/gradle/grails-plugin-config.gradle @@ -0,0 +1,8 @@ +tasks.named('bootJar') { + enabled = false // Plugins should not create a bootJar +} +tasks.named('jar', Jar) { + enabled = true // Enable the jar task again, as the bootJar task has been disabled + archiveClassifier = '' // Remove '-plain' suffix from jar file name + exclude('_testemails', 'messages*.properties') +} \ No newline at end of file diff --git a/gradle/grailsPublish.gradle b/gradle/grailsPublish.gradle deleted file mode 100644 index 7cf69d4..0000000 --- a/gradle/grailsPublish.gradle +++ /dev/null @@ -1,23 +0,0 @@ -def setIfNotSet = { String name, value -> - if (!project.ext.has(name)) { - project.ext[name] = value - } -} -setIfNotSet 'issueTrackerUrl', project.vcsUrl + '/issues' -setIfNotSet 'websiteUrl', project.vcsUrl - -grailsPublish { - user = System.getenv("BINTRAY_USER") ?: project.hasProperty("bintrayUser") ? project.bintrayUser : '' - key = System.getenv("BINTRAY_KEY") ?: project.hasProperty("bintrayKey") ? project.bintrayKey : '' - userOrg = project.hasProperty('userOrg') ? project.userOrg : 'grails' - repo = project.hasProperty('repo') ? project.repo : 'plugins' - websiteUrl = project.hasProperty('websiteUrl') ? project.websiteUrl : "https://grails.org/plugin/$project.name" - license { - name = project.hasProperty('license') ? [project.license] : ['Apache-2.0'] - } - issueTrackerUrl = project.hasProperty('issueTrackerUrl') ? project.issueTrackerUrl : "https://github.com/grails-plugins/$project.name/issues" - vcsUrl = project.hasProperty('vcsUrl') ? project.vcsUrl : "https://github.com/grails-plugins/$project.name" - title = 'Grails mail plugin' - desc = '' - developers = [jeffbrown:"Jeff Brown"] -} diff --git a/gradle/java-config.gradle b/gradle/java-config.gradle new file mode 100644 index 0000000..f536319 --- /dev/null +++ b/gradle/java-config.gradle @@ -0,0 +1,5 @@ +java { + sourceCompatibility = JavaVersion.VERSION_11 + withSourcesJar() + withJavadocJar() +} \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..a4d9491 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,33 @@ +[versions] +grails = '6.2.0' +grails-testing-support = '3.2.1' +greenmail = '1.6.15' +groovy = '3.0.21' +gsp = '6.2.1' +javamail = '1.6.2' +slf4j = '1.7.36' +spring = '5.3.34' +springboot = '2.7.18' +spock = '2.3-groovy-3.0' + +[libraries] +grails-core = { module = 'org.grails:grails-core', version.ref = 'grails' } +grails-gsp = { module = 'org.grails:grails-gsp', version.ref = 'gsp' } +grails-testing-support-core = { module = 'org.grails:grails-testing-support', version.ref = 'grails-testing-support' } +grails-testing-support-web = { module = 'org.grails:grails-web-testing-support', version.ref = 'grails-testing-support' } +grails-web-common = { module = 'org.grails:grails-web-common', version.ref = 'grails' } +grails-web-urlmappings = { module = 'org.grails:grails-web-url-mappings', version.ref = 'grails' } +greenmail = { module = 'com.icegreen:greenmail', version.ref = 'greenmail' } +groovy-core = { module = 'org.codehaus.groovy:groovy', version.ref = 'groovy' } +grails-docs = { module = 'org.grails:grails-docs', version.ref = 'grails' } +groovy-templates = { module = 'org.codehaus.groovy:groovy-templates', version.ref = 'groovy' } +javamail-api = { module = 'javax.mail:javax.mail-api', version.ref = 'javamail' } +javamail-impl = { module = 'com.sun.mail:javax.mail', version.ref = 'javamail' } +slf4j-nop = { module = 'org.slf4j:slf4j-nop', version.ref = 'slf4j' } +spring-beans = { module = 'org.springframework:spring-beans', version.ref = 'spring' } +spring-context = { module = 'org.springframework:spring-context', version.ref = 'spring' } +spring-context-support = { module = 'org.springframework:spring-context-support', version.ref = 'spring' } +spring-web = { module = 'org.springframework:spring-web', version.ref = 'spring' } +springboot-autoconfigure = { module = 'org.springframework.boot:spring-boot-autoconfigure', version.ref = 'springboot' } +springboot-starter-tomcat = { module = 'org.springframework.boot:spring-boot-starter-tomcat', version.ref = 'springboot' } +spock-core = { module = 'org.spockframework:spock-core', version.ref = 'spock' } \ No newline at end of file diff --git a/gradle/publishing.gradle b/gradle/publishing.gradle new file mode 100644 index 0000000..df06f69 --- /dev/null +++ b/gradle/publishing.gradle @@ -0,0 +1,125 @@ +import io.github.gradlenexus.publishplugin.InitializeNexusStagingRepository + +ext.set('signing.keyId', findProperty('signing.keyId') ?: System.getenv('SIGNING_KEY')) +ext.set('signing.password', findProperty('signing.password') ?: System.getenv('SIGNING_PASSPHRASE')) + +def javaComponent = components.named('java') +publishing { + publications { + register('grailsMailPlugin', MavenPublication) { + from javaComponent.get() + versionMapping { + usage('java-api') { fromResolutionOf('runtimeClasspath') } + usage('java-runtime') { fromResolutionResult() } + } + pom { + name = 'Grails Mail plugin' + description = 'Provides Mail support to a running Grails application' + url = 'https://github.com/grails/grails-mail' + licenses { + license { + name = 'The Apache License, Version 2.0' + url = 'https://www.apache.org/licenses/LICENSE-2.0.txt' + } + } + developers { + developer { + id = 'candrews' + name = 'Craig Andrews' + email = 'candrews@integralblue.com' + } + developer { + id = 'ldaley' + name = 'Luke Daley' + email = 'ld@ldaley.com' + } + developer { + id = 'pledbrook' + name = 'Peter Ledbrook' + email = 'p.ledbrook@cacoethes.co.uk' + } + developer { + id = 'osscontributor' + name = 'Jeff Brown' + email = 'brownj@ociweb.com' + } + developer { + id = 'graemerocher' + name = 'Graeme Rocher' + email = 'graeme.rocher@gmail.com' + } + developer { + id = 'marcpalmer' + name = 'Marc Palmer' + email = 'marc@grailsrocks.com' + } + developer { + id = 'sbglasius' + name = 'Søren Berg Glasius' + email = 'soeren@glasius.dk' + } + developer { + id = 'matrei' + name = 'Mattias Reichel' + email = 'mattias.reichel@gmail.com' + } + } + scm { + connection = 'scm:git:git://github.com/grails/grails-mail.git' + developerConnection = 'scm:git:ssh://github.com:grails/grails-mail.git' + url = 'https://github.com/grails/grails-mail' + } + } + // dependency management shouldn't be included + pom.withXml { + def root = it.asElement() + root.getElementsByTagName('dependencyManagement').each { root.removeChild(it) } + } + } + } + + if (isSnapshot) { + repositories { + maven { + credentials { + username = findProperty('artifactoryPublishUsername') ?: '' + password = findProperty('artifactoryPublishPassword') ?: '' + } + url = uri('https://repo.grails.org/grails/plugins3-snapshots-local') + } + } + } +} + +def mavenPublication = extensions.findByType(PublishingExtension).publications.named('grailsMailPlugin') +tasks.withType(Sign).configureEach { + onlyIf { isReleaseVersion } +} +afterEvaluate { + signing { + required = { isReleaseVersion } + sign(mavenPublication.get()) + } +} + +if (isReleaseVersion) { + nexusPublishing { + String sonatypeUsername = findProperty('sonatypeUsername') ?: '' + String sonatypePassword = findProperty('sonatypePassword') ?: '' + String sonatypeStagingProfileId = findProperty('sonatypeStagingProfileId') ?: '' + repositories { + sonatype { + nexusUrl = uri('https://s01.oss.sonatype.org/service/local/') + username = sonatypeUsername + password = sonatypePassword + stagingProfileId = sonatypeStagingProfileId + } + } + } +} + + +//do not generate extra load on Nexus with new staging repository if signing fails +tasks.withType(InitializeNexusStagingRepository).configureEach { + shouldRunAfter = tasks.withType(Sign) +} \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 7c4388a..3994438 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.4-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 8e25e6c..83f2acf 100755 --- a/gradlew +++ b/gradlew @@ -125,8 +125,8 @@ if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` JAVACMD=`cygpath --unix "$JAVACMD"` diff --git a/grails-app/conf/application.yml b/grails-app/conf/application.yml deleted file mode 100644 index d73204b..0000000 --- a/grails-app/conf/application.yml +++ /dev/null @@ -1,93 +0,0 @@ ---- -grails: - profile: web-plugin - codegen: - defaultPackage: mail -info: - app: - name: '@info.app.name@' - version: '@info.app.version@' - grailsVersion: '@info.app.grailsVersion@' -spring: - groovy: - template: - check-template-location: false - ---- -grails: - doc: - title: "Grails Mail Plugin" - subtitle: "Send email from Grails applications" - authors: "Grails Plugin Collective" - copyright: "Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically." - footer: "Developed by the Grails Plugin Collective" - mime: - disable: - accept: - header: - userAgents: - - Gecko - - WebKit - - Presto - - Trident - types: - all: '*/*' - atom: application/atom+xml - css: text/css - csv: text/csv - form: application/x-www-form-urlencoded - html: - - text/html - - application/xhtml+xml - js: text/javascript - json: - - application/json - - text/json - multipartForm: multipart/form-data - rss: application/rss+xml - text: text/plain - hal: - - application/hal+json - - application/hal+xml - xml: - - text/xml - - application/xml - urlmapping: - cache: - maxsize: 1000 - controllers: - defaultScope: singleton - converters: - encoding: UTF-8 - hibernate: - cache: - queries: false - views: - default: - codec: html - gsp: - encoding: UTF-8 - htmlcodec: xml - codecs: - expression: html - scriptlets: html - taglib: none - staticparts: none - ---- -dataSource: - pooled: true - jmxExport: true - driverClassName: org.h2.Driver - username: sa - password: - -environments: - development: - dataSource: - dbCreate: create-drop - url: jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE - test: - dataSource: - dbCreate: update - url: jdbc:h2:mem:testDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE diff --git a/grails-app/conf/logback.groovy b/grails-app/conf/logback.groovy deleted file mode 100644 index 5b2d1e3..0000000 --- a/grails-app/conf/logback.groovy +++ /dev/null @@ -1,28 +0,0 @@ -import grails.util.BuildSettings -import grails.util.Environment - - -// See http://logback.qos.ch/manual/groovy.html for details on configuration -appender('STDOUT', ConsoleAppender) { - encoder(PatternLayoutEncoder) { - pattern = "%level %logger - %msg%n" - } -} - -root(ERROR, ['STDOUT']) - -if(Environment.current == Environment.DEVELOPMENT) { - def targetDir = BuildSettings.TARGET_DIR - if(targetDir) { - - appender("FULL_STACKTRACE", FileAppender) { - - file = "${targetDir}/stacktrace.log" - append = true - encoder(PatternLayoutEncoder) { - pattern = "%level %logger - %msg%n" - } - } - logger("StackTrace", ERROR, ['FULL_STACKTRACE'], false ) - } -} diff --git a/grails-app/init/grails/plugins/mail/Application.groovy b/grails-app/init/grails/plugins/mail/Application.groovy index 65e9e38..9476c01 100644 --- a/grails-app/init/grails/plugins/mail/Application.groovy +++ b/grails-app/init/grails/plugins/mail/Application.groovy @@ -2,7 +2,9 @@ package grails.plugins.mail import grails.boot.GrailsApp import grails.boot.config.GrailsAutoConfiguration +import grails.plugins.metadata.PluginSource +@PluginSource class Application extends GrailsAutoConfiguration { static void main(String[] args) { GrailsApp.run(Application) diff --git a/grails-app/services/grails/plugins/mail/MailService.groovy b/grails-app/services/grails/plugins/mail/MailService.groovy index 238c16f..2a0dd6e 100644 --- a/grails-app/services/grails/plugins/mail/MailService.groovy +++ b/grails-app/services/grails/plugins/mail/MailService.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2008 the original author or authors. + * Copyright 2008-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,13 +20,10 @@ import groovy.transform.CompileStatic import groovy.util.logging.Slf4j import org.springframework.beans.factory.DisposableBean import org.springframework.beans.factory.InitializingBean -import org.springframework.boot.context.properties.ConfigurationProperties import org.springframework.boot.context.properties.bind.Bindable import org.springframework.boot.context.properties.bind.Binder -import org.springframework.boot.context.properties.source.ConfigurationPropertySource import org.springframework.boot.context.properties.source.ConfigurationPropertySources import org.springframework.core.env.PropertiesPropertySource -import org.springframework.core.env.PropertySource import org.springframework.mail.MailMessage import java.util.concurrent.LinkedBlockingQueue @@ -40,27 +37,23 @@ import java.util.concurrent.TimeUnit @CompileStatic class MailService implements InitializingBean, DisposableBean { - static transactional = false - MailConfigurationProperties mailConfigurationProperties MailMessageBuilderFactory mailMessageBuilderFactory - ThreadPoolExecutor mailExecutorService - private static final Integer DEFAULT_POOL_SIZE = 5 + private ThreadPoolExecutor mailExecutorService + private static final Integer DEFAULT_POOL_SIZE = 5 private static final Bindable CONFIG_BINDABLE = Bindable.of(MailConfigurationProperties) MailMessage sendMail(MailConfigurationProperties properties, @DelegatesTo(strategy = Closure.DELEGATE_FIRST, value = MailMessageBuilder) Closure callable) { - if (isDisabled()) { - log.warn("Sending emails disabled by configuration option") - return + if (disabled) { + log.warn('Sending emails disabled by configuration option') + return null } - - MailMessageBuilder messageBuilder = mailMessageBuilderFactory.createBuilder(properties) + def messageBuilder = mailMessageBuilderFactory.createBuilder(properties) callable.delegate = messageBuilder callable.resolveStrategy = Closure.DELEGATE_FIRST callable.call(messageBuilder) - return messageBuilder.sendMessage(mailExecutorService) } @@ -73,9 +66,9 @@ class MailService implements InitializingBean, DisposableBean { } private static MailConfigurationProperties toMailProperties(Config config) { - PropertySource propertySource = new PropertiesPropertySource('mailProperties', config.toProperties()) - Iterable configurationPropertySources = ConfigurationPropertySources.from(propertySource) - Binder binder = new Binder(configurationPropertySources) + def propertySource = new PropertiesPropertySource('mailProperties', config.toProperties()) + def configurationPropertySources = ConfigurationPropertySources.from(propertySource) + def binder = new Binder(configurationPropertySources) return binder.bind(MailConfigurationProperties.PREFIX, CONFIG_BINDABLE).get() } @@ -89,21 +82,15 @@ class MailService implements InitializingBean, DisposableBean { } @Override - public void destroy() throws Exception { + void destroy() throws Exception { mailExecutorService.shutdown() - mailExecutorService.awaitTermination(10, TimeUnit.SECONDS); + mailExecutorService.awaitTermination(10, TimeUnit.SECONDS) } @Override - public void afterPropertiesSet() throws Exception { + void afterPropertiesSet() throws Exception { mailExecutorService = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, new LinkedBlockingQueue()) - - Integer poolSize = mailConfigurationProperties.poolSize - try{ - ((ThreadPoolExecutor)mailExecutorService).allowCoreThreadTimeOut(true) - }catch(MissingMethodException e){ - log.info("ThreadPoolExecutor.allowCoreThreadTimeOut method is missing; Java < 6 must be running. The thread pool size will never go below ${poolSize}, which isn't harmful, just a tiny bit wasteful of resources.", e) - } - setPoolSize(poolSize) + mailExecutorService.allowCoreThreadTimeOut(true) + setPoolSize(mailConfigurationProperties.poolSize) } } diff --git a/plugins/for-plugin-view-resolution/ForPluginViewResolutionGrailsPlugin.groovy b/plugins/for-plugin-view-resolution/ForPluginViewResolutionGrailsPlugin.groovy deleted file mode 100644 index ca1d411..0000000 --- a/plugins/for-plugin-view-resolution/ForPluginViewResolutionGrailsPlugin.groovy +++ /dev/null @@ -1,50 +0,0 @@ -class ForPluginViewResolutionGrailsPlugin { - // the plugin version - def version = "0.1" - // the version or versions of Grails the plugin is designed for - def grailsVersion = "1.3.5 > *" - // the other plugins this plugin depends on - def dependsOn = [:] - // resources that are excluded from plugin packaging - def pluginExcludes = [ - "grails-app/views/error.gsp" - ] - - // TODO Fill in these fields - def author = "Your name" - def authorEmail = "" - def title = "Plugin summary/headline" - def description = '''\\ -Brief description of the plugin. -''' - - // URL to the plugin's documentation - def documentation = "http://grails.org/plugin/for-plugin-view-resolution" - - def doWithWebDescriptor = { xml -> - // TODO Implement additions to web.xml (optional), this event occurs before - } - - def doWithSpring = { - // TODO Implement runtime spring config (optional) - } - - def doWithDynamicMethods = { ctx -> - // TODO Implement registering dynamic methods to classes (optional) - } - - def doWithApplicationContext = { applicationContext -> - // TODO Implement post initialization spring config (optional) - } - - def onChange = { event -> - // TODO Implement code that is executed when any artefact that this plugin is - // watching is modified and reloaded. The event contains: event.source, - // event.application, event.manager, event.ctx, and event.plugin. - } - - def onConfigChange = { event -> - // TODO Implement code that is executed when the project configuration changes. - // The event is the same as for 'onChange'. - } -} diff --git a/plugins/for-plugin-view-resolution/application.properties b/plugins/for-plugin-view-resolution/application.properties deleted file mode 100644 index e6bdc55..0000000 --- a/plugins/for-plugin-view-resolution/application.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Grails Metadata file -#Tue Jan 04 14:44:20 EST 2011 -app.grails.version=1.3.5 -app.name=for-plugin-view-resolution -plugins.hibernate=1.3.5 -plugins.tomcat=1.3.5 diff --git a/plugins/for-plugin-view-resolution/grails-app/conf/BuildConfig.groovy b/plugins/for-plugin-view-resolution/grails-app/conf/BuildConfig.groovy deleted file mode 100644 index 453f400..0000000 --- a/plugins/for-plugin-view-resolution/grails-app/conf/BuildConfig.groovy +++ /dev/null @@ -1,31 +0,0 @@ -grails.project.class.dir = "target/classes" -grails.project.test.class.dir = "target/test-classes" -grails.project.test.reports.dir = "target/test-reports" -//grails.project.war.file = "target/${appName}-${appVersion}.war" -grails.project.dependency.resolution = { - // inherit Grails' default dependencies - inherits("global") { - // uncomment to disable ehcache - // excludes 'ehcache' - } - log "warn" // log level of Ivy resolver, either 'error', 'warn', 'info', 'debug' or 'verbose' - repositories { - grailsPlugins() - grailsHome() - grailsCentral() - - // uncomment the below to enable remote dependency resolution - // from public Maven repositories - //mavenLocal() - //mavenCentral() - //mavenRepo "http://snapshots.repository.codehaus.org" - //mavenRepo "http://repository.codehaus.org" - //mavenRepo "http://download.java.net/maven/2/" - //mavenRepo "http://repository.jboss.com/maven2/" - } - dependencies { - // specify dependencies here under either 'build', 'compile', 'runtime', 'test' or 'provided' scopes eg. - - // runtime 'mysql:mysql-connector-java:5.1.5' - } -} diff --git a/plugins/for-plugin-view-resolution/grails-app/conf/Config.groovy b/plugins/for-plugin-view-resolution/grails-app/conf/Config.groovy deleted file mode 100644 index 2e57c6d..0000000 --- a/plugins/for-plugin-view-resolution/grails-app/conf/Config.groovy +++ /dev/null @@ -1,24 +0,0 @@ -// configuration for plugin testing - will not be included in the plugin zip - -log4j = { - // Example of changing the log pattern for the default console - // appender: - // - //appenders { - // console name:'stdout', layout:pattern(conversionPattern: '%c{2} %m%n') - //} - - error 'org.codehaus.groovy.grails.web.servlet', // controllers - 'org.codehaus.groovy.grails.web.pages', // GSP - 'org.codehaus.groovy.grails.web.sitemesh', // layouts - 'org.codehaus.groovy.grails.web.mapping.filter', // URL mapping - 'org.codehaus.groovy.grails.web.mapping', // URL mapping - 'org.codehaus.groovy.grails.commons', // core / classloading - 'org.codehaus.groovy.grails.plugins', // plugins - 'org.codehaus.groovy.grails.orm.hibernate', // hibernate integration - 'org.springframework', - 'org.hibernate', - 'net.sf.ehcache.hibernate' - - warn 'org.mortbay.log' -} diff --git a/plugins/for-plugin-view-resolution/grails-app/conf/DataSource.groovy b/plugins/for-plugin-view-resolution/grails-app/conf/DataSource.groovy deleted file mode 100644 index 91143e7..0000000 --- a/plugins/for-plugin-view-resolution/grails-app/conf/DataSource.groovy +++ /dev/null @@ -1,32 +0,0 @@ -dataSource { - pooled = true - driverClassName = "org.hsqldb.jdbcDriver" - username = "sa" - password = "" -} -hibernate { - cache.use_second_level_cache = true - cache.use_query_cache = true - cache.provider_class = 'net.sf.ehcache.hibernate.EhCacheProvider' -} -// environment specific settings -environments { - development { - dataSource { - dbCreate = "create-drop" // one of 'create', 'create-drop','update' - url = "jdbc:hsqldb:mem:devDB" - } - } - test { - dataSource { - dbCreate = "update" - url = "jdbc:hsqldb:mem:testDb" - } - } - production { - dataSource { - dbCreate = "update" - url = "jdbc:hsqldb:file:prodDb;shutdown=true" - } - } -} diff --git a/plugins/for-plugin-view-resolution/grails-app/conf/UrlMappings.groovy b/plugins/for-plugin-view-resolution/grails-app/conf/UrlMappings.groovy deleted file mode 100644 index 8c597d6..0000000 --- a/plugins/for-plugin-view-resolution/grails-app/conf/UrlMappings.groovy +++ /dev/null @@ -1,13 +0,0 @@ -class UrlMappings { - - static mappings = { - "/$controller/$action?/$id?"{ - constraints { - // apply constraints here - } - } - - "/"(view:"/index") - "500"(view:'/error') - } -} diff --git a/plugins/for-plugin-view-resolution/grails-app/views/email/email.gsp b/plugins/for-plugin-view-resolution/grails-app/views/email/email.gsp deleted file mode 100644 index e8c39c1..0000000 --- a/plugins/for-plugin-view-resolution/grails-app/views/email/email.gsp +++ /dev/null @@ -1 +0,0 @@ -This is from a plugin!!! \ No newline at end of file diff --git a/plugins/for-plugin-view-resolution/grails-app/views/error.gsp b/plugins/for-plugin-view-resolution/grails-app/views/error.gsp deleted file mode 100644 index cfc512a..0000000 --- a/plugins/for-plugin-view-resolution/grails-app/views/error.gsp +++ /dev/null @@ -1,54 +0,0 @@ - - - Grails Runtime Exception - - - - -

Grails Runtime Exception

-

Error Details

- -
- Error ${request.'javax.servlet.error.status_code'}: ${request.'javax.servlet.error.message'.encodeAsHTML()}
- Servlet: ${request.'javax.servlet.error.servlet_name'}
- URI: ${request.'javax.servlet.error.request_uri'}
- - Exception Message: ${exception.message?.encodeAsHTML()}
- Caused by: ${exception.cause?.message?.encodeAsHTML()}
- Class: ${exception.className}
- At Line: [${exception.lineNumber}]
- Code Snippet:
-
- - ${cs?.encodeAsHTML()}
-
-
-
-
- -

Stack Trace

-
-
${it.encodeAsHTML()}
-
-
- - \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 325ab70..9916886 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,24 @@ +plugins { + id 'com.gradle.develocity' version '3.17.1' + id 'com.gradle.common-custom-user-data-gradle-plugin' version '2.0' +} + +def isCI = System.getenv('CI') == 'true' + +develocity { + server = 'https://ge.grails.org' + buildScan { + publishing.onlyIf { isCI } + uploadInBackground = !isCI + } +} + +buildCache { + local { enabled = !isCI } + remote(develocity.buildCache) { + enabled = true + push = isCI && System.getenv('DEVELOCITY_ACCESS_KEY') + } +} + rootProject.name = 'mail' diff --git a/src/integration-test/groovy/grails/plugins/mail/MailServiceSpec.groovy b/src/integration-test/groovy/grails/plugins/mail/MailServiceSpec.groovy index 96f9486..e0d7817 100644 --- a/src/integration-test/groovy/grails/plugins/mail/MailServiceSpec.groovy +++ b/src/integration-test/groovy/grails/plugins/mail/MailServiceSpec.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 the original author or authors. + * Copyright 2004-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,9 +18,8 @@ package grails.plugins.mail import com.icegreen.greenmail.util.GreenMail import com.icegreen.greenmail.util.ServerSetupTest -import grails.core.GrailsApplication import grails.testing.mixin.integration.Integration -import org.springframework.beans.factory.annotation.Autowired +import org.grails.io.support.ClassPathResource import org.springframework.core.io.FileSystemResource import org.springframework.mail.MailMessage import org.springframework.mail.MailSender @@ -41,28 +40,23 @@ import javax.mail.internet.MimeMultipart @Integration class MailServiceSpec extends Specification { - static transactional = false - MailService mimeCapableMailService MailService nonMimeCapableMailService - @Autowired - MailMessageContentRenderer mailMessageContentRenderer // autowired - @Autowired - GrailsApplication grailsApplication // autowired + MailMessageContentRenderer mailMessageContentRenderer @Shared - public GreenMail greenMail = new GreenMail(ServerSetupTest.SMTP) - + GreenMail greenMail = new GreenMail(ServerSetupTest.SMTP) def setupSpec() { greenMail.start() - Thread.sleep(3000) } + def cleanupSpec() { greenMail.stop() } + def setup() { - MailSender mimeMailSender = new JavaMailSenderImpl(host: "localhost", port: ServerSetupTest.SMTP.port) + def mimeMailSender = new JavaMailSenderImpl(host: "localhost", port: ServerSetupTest.SMTP.port) MailMessageBuilderFactory mimeMessageBuilderFactor = new MailMessageBuilderFactory( mailSender: mimeMailSender, mailMessageContentRenderer: mailMessageContentRenderer @@ -453,7 +447,7 @@ class MailServiceSpec extends Specification { void testInlineAttachment() { when: - byte[] bytes = new File("src/integration-test/groovy/grails/plugins/mail/grailslogo.png").bytes + byte[] bytes = new ClassPathResource('assets/grailslogo.png').inputStream.bytes MailMessage message = mimeCapableMailService.sendMail { multipart true @@ -556,7 +550,7 @@ class MailServiceSpec extends Specification { MimeMailMessage message = mimeCapableMailService.sendMail { to "fred@g2one.com" subject "Hello John" - body(view: '/_testemails/test', model: [msg: 'hello']) + body(view: '/test', model: [msg: 'hello']) } then: message.getMimeMessage().getSubject() == "Hello John" diff --git a/src/integration-test/groovy/grails/plugins/mail/grailslogo.png b/src/integration-test/resources/assets/grailslogo.png similarity index 100% rename from src/integration-test/groovy/grails/plugins/mail/grailslogo.png rename to src/integration-test/resources/assets/grailslogo.png diff --git a/src/integration-test/resources/logback-test.xml b/src/integration-test/resources/logback-test.xml new file mode 100644 index 0000000..2f57334 --- /dev/null +++ b/src/integration-test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + + + + UTF-8 + %clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n%wex + + + + + + \ No newline at end of file diff --git a/src/main/groovy/grails/plugins/mail/MailConfiguration.groovy b/src/main/groovy/grails/plugins/mail/MailConfiguration.groovy index 780a929..4e0c1f1 100644 --- a/src/main/groovy/grails/plugins/mail/MailConfiguration.groovy +++ b/src/main/groovy/grails/plugins/mail/MailConfiguration.groovy @@ -1,3 +1,18 @@ +/* + * Copyright 2022-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package grails.plugins.mail import grails.core.GrailsApplication @@ -30,7 +45,7 @@ class MailConfiguration { @ConditionalOnMissingBean(name = 'mailSession') @ConditionalOnProperty(prefix = 'grails.mail', name = 'jndiName') JndiObjectFactoryBean mailSession(MailConfigurationProperties mailProperties) { - JndiObjectFactoryBean factory = new JndiObjectFactoryBean() + def factory = new JndiObjectFactoryBean() factory.jndiName = mailProperties.jndiName return factory } @@ -40,7 +55,7 @@ class MailConfiguration { @Autowired(required = false) @Qualifier('mailSession') Session mailSession, MailConfigurationProperties mailProperties) { - JavaMailSenderImpl mailSender = new JavaMailSenderImpl() + def mailSender = new JavaMailSenderImpl() if (mailProperties.host) { mailSender.host = mailProperties.host } else if (!mailProperties.jndiName) { @@ -81,10 +96,7 @@ class MailConfiguration { MailMessageBuilderFactory mailMessageBuilderFactory( MailSender mailSender, MailMessageContentRenderer mailMessageContentRenderer) { - MailMessageBuilderFactory factory = new MailMessageBuilderFactory() - factory.mailSender = mailSender - factory.mailMessageContentRenderer = mailMessageContentRenderer - return factory + return new MailMessageBuilderFactory(mailSender, mailMessageContentRenderer) } @Bean @@ -93,11 +105,6 @@ class MailConfiguration { GroovyPagesUriService groovyPagesUriService, GrailsApplication grailsApplication, GrailsPluginManager pluginManager) { - MailMessageContentRenderer renderer = new MailMessageContentRenderer() - renderer.groovyPagesTemplateEngine = groovyPagesTemplateEngine - renderer.groovyPagesUriService = groovyPagesUriService - renderer.grailsApplication = grailsApplication - renderer.pluginManager = pluginManager - return renderer + return new MailMessageContentRenderer(groovyPagesTemplateEngine, groovyPagesUriService, grailsApplication, pluginManager) } } diff --git a/src/main/groovy/grails/plugins/mail/MailConfigurationProperties.groovy b/src/main/groovy/grails/plugins/mail/MailConfigurationProperties.groovy index a5ae670..e445819 100644 --- a/src/main/groovy/grails/plugins/mail/MailConfigurationProperties.groovy +++ b/src/main/groovy/grails/plugins/mail/MailConfigurationProperties.groovy @@ -1,8 +1,23 @@ +/* + * Copyright 2022-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package grails.plugins.mail import org.springframework.boot.context.properties.ConfigurationProperties -@ConfigurationProperties(MailConfigurationProperties.PREFIX) +@ConfigurationProperties(PREFIX) class MailConfigurationProperties { public static final String PREFIX = 'grails.mail' diff --git a/src/main/groovy/grails/plugins/mail/MailGrailsPlugin.groovy b/src/main/groovy/grails/plugins/mail/MailGrailsPlugin.groovy index 4159e63..2fb7483 100644 --- a/src/main/groovy/grails/plugins/mail/MailGrailsPlugin.groovy +++ b/src/main/groovy/grails/plugins/mail/MailGrailsPlugin.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2008 the original author or authors. + * Copyright 2008-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,17 +16,15 @@ package grails.plugins.mail import grails.plugins.Plugin -import groovy.util.logging.Commons -@Commons class MailGrailsPlugin extends Plugin { - def grailsVersion = "3.0 > *" - - def author = "Grails Plugin Collective" - def authorEmail = "grails.plugin.collective@gmail.com" - def title = "Provides Mail support to a running Grails application" + + def grailsVersion = '6.0.0 > *' + def author = 'The Grails team' + def authorEmail = 'info@grails.org' + def title = 'Provides Mail support to a running Grails application' def description = '''\ -This plug-in provides a MailService class as well as configuring the necessary beans within +This plugin provides a MailService class as well as configuring the necessary beans within the Spring ApplicationContext. It also adds a "sendMail" method to all controller classes. A typical example usage is: @@ -39,34 +37,35 @@ sendMail { subject "Hello John" text "this is some text" } - ''' - def documentation = "http://grails.org/plugins/mail" + def documentation = 'https://grails.github.io/grails-mail/' - def license = "APACHE" - def organization = [ name: "Grails Plugin Collective", url: "http://github.com/gpc" ] + def license = 'Apache 2.0 License' + def organization = [name: 'Grails', url: 'https://grails.org'] def developers = [ - [ name: "Craig Andrews", email: "candrews@integralblue.com" ], - [ name: "Luke Daley", email: "ld@ldaley.com" ], - [ name: "Peter Ledbrook", email: "p.ledbrook@cacoethes.co.uk" ], - [ name: "Jeff Brown", email: "brownj@ociweb.com" ], - [ name: "Graeme Rocher", email: "rocherg@ociweb.com" ], - [ name: "Marc Palmer", email: "marc@grailsrocks.com" ], - [ name: "Søren Berg Glasius", email: "glasiuss@ociweb.com" ], - + [name: 'Craig Andrews', email: 'candrews@integralblue.com'], + [name: 'Luke Daley', email: 'ld@ldaley.com'], + [name: 'Peter Ledbrook', email: 'p.ledbrook@cacoethes.co.uk'], + [name: 'Jeff Brown', email: 'brownj@ociweb.com'], + [name: 'Graeme Rocher', email: 'rocherg@ociweb.com'], + [name: 'Marc Palmer', email: 'marc@grailsrocks.com'], + [name: 'Søren Berg Glasius', email: 'soeren@glasius.dk'], + [name: 'Mattias Reichel', email: 'mattias.reichel@gmail.com'] ] - def issueManagement = [ system: "GitHub", url: "https://github.com/gpc/mail/issues" ] - def scm = [ url: "http://github.com/gpc/grails-mail" ] + def issueManagement = [system: 'GitHub', url: 'https://github.com/grails/grails-mail/issues'] + def scm = [url: 'https://github.com/grails/grails-mail'] - def observe = ['controllers','services'] + def observe = ['controllers', 'services'] - def pluginExcludes = [ - "grails-app/views/_testemails/*.gsp" + def pluginExcludes = [ + 'grails-app/i18n/*.properties', + 'grails-app/views/_testemails/*.gsp' ] + @Override Closure doWithSpring() { - { -> + return { mailConfiguration(MailConfiguration) } } diff --git a/src/main/groovy/grails/plugins/mail/MailMessageBuilder.groovy b/src/main/groovy/grails/plugins/mail/MailMessageBuilder.groovy index 423c9aa..3153fec 100644 --- a/src/main/groovy/grails/plugins/mail/MailMessageBuilder.groovy +++ b/src/main/groovy/grails/plugins/mail/MailMessageBuilder.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2008 the original author or authors. + * Copyright 2008-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,8 +16,9 @@ package grails.plugins.mail import com.sun.mail.smtp.SMTPMessage -import org.slf4j.Logger -import org.slf4j.LoggerFactory +import groovy.transform.CompileDynamic +import groovy.transform.CompileStatic +import groovy.util.logging.Slf4j import org.springframework.core.io.ByteArrayResource import org.springframework.core.io.FileSystemResource import org.springframework.core.io.InputStreamSource @@ -28,6 +29,7 @@ import org.springframework.mail.javamail.JavaMailSender import org.springframework.mail.javamail.MimeMailMessage import org.springframework.mail.javamail.MimeMessageHelper import org.springframework.util.Assert +import org.springframework.util.StringUtils import javax.mail.Message import javax.mail.internet.MimeMessage @@ -40,10 +42,10 @@ import java.util.concurrent.ExecutorService * If the builder is constructed without a MailMessageContentRenderer, it is incapable * of rendering GSP views into message content. */ +@Slf4j +@CompileStatic class MailMessageBuilder { - private static final Logger log = LoggerFactory.getLogger(MailMessageBuilder.class) - final MailSender mailSender final MailMessageContentRenderer mailMessageContentRenderer @@ -73,7 +75,6 @@ class MailMessageBuilder { MailMessageBuilder(MailSender mailSender, MailConfigurationProperties properties, MailMessageContentRenderer mailMessageContentRenderer = null) { this.mailSender = mailSender this.mailMessageContentRenderer = mailMessageContentRenderer - this.overrideAddress = properties.overrideAddress this.defaultFrom = overrideAddress ?: properties.default.from this.defaultTo = overrideAddress ?: properties.default.to @@ -82,180 +83,174 @@ class MailMessageBuilder { private MailMessage getMessage() { if (!message) { if (mimeCapable) { - helper = new MimeMessageHelper(mailSender.createMimeMessage(), multipart) + helper = new MimeMessageHelper((mailSender as JavaMailSender).createMimeMessage(), multipart) message = new MimeMailMessage(helper) } else { message = new SimpleMailMessage() } - if (defaultFrom) { message.from = defaultFrom } - if (defaultTo) { message.setTo(defaultTo) } } - message } MailMessage sendMessage(ExecutorService executorService) { - MailMessage message = finishMessage() + def message = finishMessage() - if (log.traceEnabled) { - log.trace("Sending mail ${getDescription(message)}} ...") - } + log.trace('Sending mail {} ...', getDescription(message as Message)) - def sendingMsg = message instanceof MimeMailMessage ? message.mimeMessage : message - if(envelopeFrom) { - if(!mimeCapable) { - throw new GrailsMailException("You must use a JavaMailSender to set the envelopeFrom.") - } + def sendingMsg = (message instanceof MimeMailMessage) ? message.mimeMessage : message - sendingMsg = new SMTPMessage(sendingMsg) + if (envelopeFrom) { + if (!mimeCapable) { + throw new GrailsMailException('You must use a JavaMailSender to set the envelopeFrom.') + } + sendingMsg = new SMTPMessage(sendingMsg as MimeMessage) sendingMsg.envelopeFrom = envelopeFrom } - if(async){ + if (async) { executorService.execute({ - try{ - mailSender.send(sendingMsg) - }catch(Throwable t){ - if(log.errorEnabled) log.error("Failed to send email", t) + try { + send(sendingMsg) + } catch(Throwable t) { + log.error('Failed to send email', t) } } as Runnable) - }else{ - mailSender.send(sendingMsg) + } else { + send(sendingMsg) } - if (log.traceEnabled) { - log.trace("Sent mail ${getDescription(message)}} ...") - } + log.trace('Sent mail {} ...', getDescription(message as Message)) message } - void multipart(boolean multipart) { - this.multipart = MimeMessageHelper.MULTIPART_MODE_MIXED_RELATED + /** + * Method to send messages of any type. + * This method is dynamically compiled to avoid the need to cast the mail sender and message to the correct types. + * @param message Any type of message + */ + @CompileDynamic + private void send(Object message) { + mailSender.send(message) } - void async(boolean async) { - this.async = async + void multipart(boolean multipart) { + this.multipart = multipart ? + MimeMessageHelper.MULTIPART_MODE_MIXED_RELATED : + MimeMessageHelper.MULTIPART_MODE_NO } void multipart(int multipartMode) { this.multipart = multipartMode } - void headers(Map hdrs) { - Assert.notEmpty(hdrs, "headers cannot be null") + void async(boolean async) { + this.async = async + } + + void headers(Map headers) { + Assert.notEmpty(headers, 'headers cannot be null') // The message must be of type MimeMailMessage to add headers. if (!mimeCapable) { - throw new GrailsMailException("You must use a JavaMailSender to customise the headers.") + throw new GrailsMailException('You must use a JavaMailSender to customise the headers.') } MailMessage msg = getMessage() - if(msg instanceof MimeMailMessage){ - MimeMessage mimeMessage = ((MimeMailMessage)msg).mimeMessageHelper.mimeMessage - hdrs.each { name, value -> + if (msg instanceof MimeMailMessage) { + MimeMessage mimeMessage = (msg as MimeMailMessage).mimeMessageHelper.mimeMessage + headers.each { name, value -> String nameString = name?.toString() String valueString = value?.toString() - Assert.hasText(nameString, "header names cannot be null or empty") + Assert.hasText(nameString, 'header names cannot be null or empty') Assert.hasText(valueString, "header value for '$nameString' cannot be null") mimeMessage.setHeader(nameString, valueString) } - }else{ - throw new GrailsMailException("mail message builder is not mime capable so headers cannot be set") + } else { + throw new GrailsMailException('Mail message builder is not mime capable so headers cannot be set') } } void to(Object[] args) { - Assert.notEmpty(args, "to cannot be null or empty") - Assert.noNullElements(args, "to cannot contain null elements") - + Assert.notEmpty(args, 'to cannot be null or empty') + Assert.noNullElements(args, 'to cannot contain null elements') getMessage().setTo(toDestinationAddresses(args)) } void to(List args) { - Assert.notEmpty(args, "to cannot be null or empty") - Assert.noNullElements(args.toArray(), "to cannot contain null elements") - - to(*args) + Assert.notEmpty(args, 'to cannot be null or empty') + Assert.noNullElements(args, 'to cannot contain null elements') + to(args.toArray()) } void bcc(Object[] args) { - Assert.notEmpty(args, "bcc cannot be null or empty") - Assert.noNullElements(args, "bcc cannot contain null elements") - + Assert.notEmpty(args, 'bcc cannot be null or empty') + Assert.noNullElements(args, 'bcc cannot contain null elements') getMessage().setBcc(toDestinationAddresses(args)) } void bcc(List args) { - Assert.notEmpty(args, "bcc cannot be null or empty") - Assert.noNullElements(args.toArray(), "bcc cannot contain null elements") - - bcc(*args) + Assert.notEmpty(args, 'bcc cannot be null or empty') + Assert.noNullElements(args, 'bcc cannot contain null elements') + bcc(args.toArray()) } void cc(Object[] args) { - Assert.notEmpty(args, "cc cannot be null or empty") - Assert.noNullElements(args, "cc cannot contain null elements") - + Assert.notEmpty(args, 'cc cannot be null or empty') + Assert.noNullElements(args, 'cc cannot contain null elements') getMessage().setCc(toDestinationAddresses(args)) } void cc(List args) { - Assert.notEmpty(args, "cc cannot be null or empty") - Assert.noNullElements(args.toArray(), "cc cannot contain null elements") - - cc(*args) + Assert.notEmpty(args, 'cc cannot be null or empty') + Assert.noNullElements(args, 'cc cannot contain null elements') + cc(args.toArray()) } void replyTo(CharSequence replyTo) { - Assert.hasText(replyTo, "replyTo cannot be null or 0 length") - - getMessage().replyTo = replyTo.toString() + def value = replyTo.toString() + Assert.hasText(value, 'replyTo cannot be null or 0 length') + getMessage().replyTo = value } void from(CharSequence from) { - Assert.hasText(from, "from cannot be null or 0 length") - - getMessage().from = from.toString() + def value = from.toString() + Assert.hasText(value, 'from cannot be null or 0 length') + getMessage().from = value } void envelopeFrom(CharSequence envFrom) { - Assert.hasText(envFrom, "envelope from cannot be null or 0 length") - - envelopeFrom = envFrom.toString() + def value = envFrom.toString() + Assert.hasText(value, 'envelope from cannot be null or 0 length') + envelopeFrom = value } void title(CharSequence title) { - Assert.notNull(title, "title cannot be null") - + Assert.notNull(title, 'title cannot be null') subject(title) } void subject(CharSequence title) { - Assert.notNull(title, "subject cannot be null") - + Assert.notNull(title, 'subject cannot be null') getMessage().subject = title.toString() } void body(CharSequence body) { - Assert.notNull(body, "body cannot be null") - + Assert.notNull(body, 'body cannot be null') text(body) } void body(Map params) { - Assert.notEmpty(params, "body cannot be null or empty") - - MailMessageContentRender render = doRender(params) - + Assert.notEmpty(params, 'body cannot be null or empty') + def render = doRender(params) if (render.html) { html(render.out.toString()) // @todo Spring mail helper will not set correct mime type if we give it XHTML } else { @@ -265,53 +260,45 @@ class MailMessageBuilder { protected MailMessageContentRender doRender(Map params) { if (mailMessageContentRenderer == null) { - throw new GrailsMailException("mail message builder was constructed without a message content render so cannot render views") + throw new GrailsMailException('mail message builder was constructed without a message content render so cannot render views') } - if (!params.view) { - throw new GrailsMailException("no view specified") + throw new GrailsMailException('no view specified') } - - mailMessageContentRenderer.render(new StringWriter(), params.view, params.model, locale, params.plugin) + mailMessageContentRenderer.render(new StringWriter(), params.view as String, params.model as Map, locale, params.plugin as String) } void text(Map params) { - Assert.notEmpty(params, "text cannot be null or empty") - + Assert.notEmpty(params, 'params cannot be null or empty') text(doRender(params).out.toString()) } void text(CharSequence text) { - Assert.notNull(text, "text cannot be null") - + Assert.notNull(text, 'text cannot be null') textContent = text.toString() } void html(Map params) { - Assert.notEmpty(params, "html cannot be null or empty") - + Assert.notEmpty(params, 'params cannot be null or empty') html(doRender(params).out.toString()) } void html(CharSequence text) { - Assert.notNull(text, "html cannot be null") - + Assert.notNull(text, 'html cannot be null') if (mimeCapable) { htmlContent = text.toString() } else { - throw new GrailsMailException("mail sender is not mime capable, try configuring a JavaMailSender") + throw new GrailsMailException('mail sender is not mime capable, try configuring a JavaMailSender') } } void locale(String localeStr) { - Assert.hasText(localeStr, "locale cannot be null or empty") - - locale(new Locale(*localeStr.split('_', 3))) + Assert.hasText(localeStr, 'locale cannot be null or empty') + locale(StringUtils.parseLocale(localeStr)) } void locale(Locale locale) { - Assert.notNull(locale, "locale cannot be null") - + Assert.notNull(locale, 'locale cannot be null') this.locale = locale } @@ -332,9 +319,8 @@ class MailMessageBuilder { void attach(String fileName, File file) { if (!mimeCapable) { - throw new GrailsMailException("Message is not an instance of org.springframework.mail.javamail.MimeMessage, cannot attach bytes!") + throw new GrailsMailException('Message is not an instance of org.springframework.mail.javamail.MimeMessage, cannot attach bytes!') } - attach(fileName, helper.fileTypeMap.getContentType(file), file) } @@ -342,7 +328,6 @@ class MailMessageBuilder { if (!file.exists()) { throw new FileNotFoundException("cannot use $file as an attachment as it does not exist") } - attach(fileName, contentType, new FileSystemResource(file)) } @@ -360,9 +345,8 @@ class MailMessageBuilder { void inline(String fileName, File file) { if (!mimeCapable) { - throw new GrailsMailException("Message is not an instance of org.springframework.mail.javamail.MimeMessage, cannot attach bytes!") + throw new GrailsMailException('Message is not an instance of org.springframework.mail.javamail.MimeMessage, cannot attach bytes!') } - inline(fileName, helper.fileTypeMap.getContentType(file), file) } @@ -370,7 +354,6 @@ class MailMessageBuilder { if (!file.exists()) { throw new FileNotFoundException("cannot use $file as an attachment as it does not exist") } - inline(contentId, contentType, new FileSystemResource(file)) } @@ -380,12 +363,11 @@ class MailMessageBuilder { protected doAdd(String id, String contentType, InputStreamSource toAdd, boolean isAttachment) { if (!mimeCapable) { - throw new GrailsMailException("Message is not an instance of org.springframework.mail.javamail.MimeMessage, cannot attach bytes!") + throw new GrailsMailException('Message is not an instance of org.springframework.mail.javamail.MimeMessage, cannot attach bytes!') } + assert multipart, 'message is not marked as "multipart"; use "multipart true" as the first line in your builder DSL' - assert multipart, "message is not marked as 'multipart'; use 'multipart true' as the first line in your builder DSL" - - getMessage() //ensure that helper is initialized + getMessage() // ensure that helper is initialized if (isAttachment) { helper.addAttachment(MimeUtility.encodeWord(id), toAdd, contentType) } else { @@ -401,25 +383,23 @@ class MailMessageBuilder { if (overrideAddress) { addresses = addresses.collect { overrideAddress } } - addresses.collect { it?.toString() } as String[] } - protected getDescription(SimpleMailMessage message) { + static protected getDescription(SimpleMailMessage message) { "[${message.subject}] from [${message.from}] to ${message.to}" } - protected getDescription(Message message) { + static protected getDescription(Message message) { "[${message.subject}] from [${message.from}] to ${message.getRecipients(Message.RecipientType.TO)*.toString()}" } - protected getDescription(MimeMailMessage message) { + static protected getDescription(MimeMailMessage message) { getDescription(message.mimeMessage) } MailMessage finishMessage() { - MailMessage message = getMessage() - + def message = getMessage() if (htmlContent) { if (textContent) { helper.setText(textContent, htmlContent) @@ -428,17 +408,14 @@ class MailMessageBuilder { } } else { if (!textContent) { - throw new GrailsMailException("message has no content, use text(), html() or body() methods to set content") + throw new GrailsMailException('message has no content, use text(), html() or body() methods to set content') } - message.text = textContent } - inlines.each { doAdd(it.id, it.contentType, it.toAdd, false) } - message.sentDate = new Date() message } -} +} \ No newline at end of file diff --git a/src/main/groovy/grails/plugins/mail/MailMessageBuilderFactory.groovy b/src/main/groovy/grails/plugins/mail/MailMessageBuilderFactory.groovy index c39a239..c030813 100644 --- a/src/main/groovy/grails/plugins/mail/MailMessageBuilderFactory.groovy +++ b/src/main/groovy/grails/plugins/mail/MailMessageBuilderFactory.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2008 the original author or authors. + * Copyright 2008-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,6 +29,18 @@ class MailMessageBuilderFactory { MailSender mailSender MailMessageContentRenderer mailMessageContentRenderer + MailMessageBuilderFactory() {} + + /** + * @param mailSender + * @param mailMessageContentRenderer + * @since 4.0.0 + */ + MailMessageBuilderFactory(MailSender mailSender, MailMessageContentRenderer mailMessageContentRenderer) { + this.mailSender = mailSender + this.mailMessageContentRenderer = mailMessageContentRenderer + } + MailMessageBuilder createBuilder(MailConfigurationProperties properties) { new MailMessageBuilder(mailSender, properties, mailMessageContentRenderer) } diff --git a/src/main/groovy/grails/plugins/mail/MailMessageContentRenderer.groovy b/src/main/groovy/grails/plugins/mail/MailMessageContentRenderer.groovy index 6529aad..daa43e5 100644 --- a/src/main/groovy/grails/plugins/mail/MailMessageContentRenderer.groovy +++ b/src/main/groovy/grails/plugins/mail/MailMessageContentRenderer.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2010 the original author or authors. + * Copyright 2010-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,8 +26,6 @@ import org.grails.gsp.GroovyPageTemplate import org.grails.gsp.GroovyPagesTemplateEngine import org.grails.web.servlet.WrappedResponseHolder import org.grails.web.servlet.mvc.GrailsWebRequest -import org.slf4j.Logger -import org.slf4j.LoggerFactory import org.springframework.context.ApplicationContext import org.springframework.web.context.request.RequestContextHolder import org.springframework.web.servlet.DispatcherServlet @@ -41,18 +39,37 @@ import java.lang.reflect.InvocationHandler import java.lang.reflect.Method import java.lang.reflect.Proxy import java.util.concurrent.ConcurrentHashMap + /** * Renders a GSP into the content of a mail message. */ @CompileStatic class MailMessageContentRenderer { - private static final Logger log = LoggerFactory.getLogger(MailMessageContentRenderer.class) GroovyPagesTemplateEngine groovyPagesTemplateEngine GroovyPagesUriService groovyPagesUriService GrailsApplication grailsApplication GrailsPluginManager pluginManager + MailMessageContentRenderer() {} + + /** + * @param groovyPagesTemplateEngine The GSP template engine to use + * @param groovyPagesUriService The GSP URI service to use + * @param grailsApplication The Grails application + * @param pluginManager The plugin manager + * @since 4.0.0 + */ + MailMessageContentRenderer(GroovyPagesTemplateEngine groovyPagesTemplateEngine, + GroovyPagesUriService groovyPagesUriService, + GrailsApplication grailsApplication, + GrailsPluginManager pluginManager) { + this.groovyPagesTemplateEngine = groovyPagesTemplateEngine + this.groovyPagesUriService = groovyPagesUriService + this.grailsApplication = grailsApplication + this.pluginManager = pluginManager + } + MailMessageContentRender render(Writer out, String templateName, Map model, Locale locale, String pluginName = null) { RenderEnvironment.with(grailsApplication.mainContext, out, locale) { RenderEnvironment env -> Template template = createTemplate(templateName, env.controllerName, pluginName) @@ -61,33 +78,27 @@ class MailMessageContentRenderer { } else { template.make().writeTo(out) } - new MailMessageContentRender(out, template.metaInfo.contentType) } as MailMessageContentRender } protected GroovyPageTemplate createTemplate(String templateName, String controllerName, String pluginName) { - if (templateName.startsWith("/")) { + if (templateName.startsWith('/')) { if (!controllerName) { - controllerName = "" + controllerName = '' } } else { if (!controllerName) { - throw new IllegalArgumentException("Mail views cannot be loaded from relative view paths where there is no current HTTP request") + throw new IllegalArgumentException('Mail views cannot be loaded from relative view paths when there is no current HTTP request') } } String contextPath = getContextPath(pluginName) + String templateUri = contextPath ? + contextPath + groovyPagesUriService.getViewURI(controllerName, templateName) : + groovyPagesUriService.getDeployedViewURI(controllerName, templateName) - String templateUri - if (contextPath) { - templateUri = contextPath + groovyPagesUriService.getViewURI(controllerName, templateName) - } else { - templateUri = groovyPagesUriService.getDeployedViewURI(controllerName, templateName) - } - - GroovyPageTemplate template = groovyPagesTemplateEngine.createTemplateForUri(templateUri) as GroovyPageTemplate - + def template = groovyPagesTemplateEngine.createTemplateForUri(templateUri) if (!template) { if (pluginName) { throw new IllegalArgumentException("Could not locate email view ${templateName} in plugin [$pluginName]") @@ -95,24 +106,22 @@ class MailMessageContentRenderer { throw new IllegalArgumentException("Could not locate mail body ${templateName}. Is it in a plugin? If so you must pass the plugin name in the [plugin] variable") } } - - template + template as GroovyPageTemplate } protected String getContextPath(String pluginName) { - String contextPath = "" - + String contextPath = '' if (pluginName) { def plugin = pluginManager.getGrailsPlugin(pluginName) if (plugin && !plugin.isBasePlugin()) { - contextPath = plugin.pluginPath + "/grails-app/views" + contextPath = "${plugin.pluginPath}/grails-app/views" } } - contextPath } private static class RenderEnvironment { + final PrintWriter out final Locale locale final ApplicationContext applicationContext @@ -126,7 +135,7 @@ class MailMessageContentRenderer { this.out = out instanceof PrintWriter ? out as PrintWriter : new PrintWriter(out) this.locale = locale this.applicationContext = applicationContext - this.grailsLinkGenerator = applicationContext.getBean('grailsLinkGenerator', LinkGenerator.class) + this.grailsLinkGenerator = applicationContext.getBean('grailsLinkGenerator', LinkGenerator) } private void init() { @@ -140,36 +149,39 @@ class MailMessageContentRenderer { renderLocale = RequestContextUtils.getLocale(originalRequestAttributes.request) } - renderRequestAttributes = new GrailsWebRequest(PageRenderRequestCreator.createInstance(grailsLinkGenerator.serverBaseURL, "/mail/render", renderLocale), - PageRenderResponseCreator.createInstance(out, renderLocale), null, applicationContext) + renderRequestAttributes = new GrailsWebRequest( + PageRenderRequestCreator.createInstance(grailsLinkGenerator.serverBaseURL, '/mail/render', renderLocale), + PageRenderResponseCreator.createInstance(out, renderLocale), + null, + applicationContext + ) if (originalRequestAttributes) { renderRequestAttributes.controllerName = originalRequestAttributes.controllerName } - RequestContextHolder.setRequestAttributes(renderRequestAttributes) - + RequestContextHolder.requestAttributes = renderRequestAttributes renderRequestAttributes.request.setAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE, new FixedLocaleResolver(defaultLocale: renderLocale)) renderRequestAttributes.setOut(out) WrappedResponseHolder.wrappedResponse = renderRequestAttributes.currentResponse } private void close() { - RequestContextHolder.setRequestAttributes(originalRequestAttributes) // null ok + RequestContextHolder.requestAttributes = originalRequestAttributes // null ok WrappedResponseHolder.wrappedResponse = originalWrappedResponse } /** * Establish an environment inheriting the locale of the current request if there is one */ - static with(ApplicationContext applicationContext, Writer out, Closure block) { + static Object with(ApplicationContext applicationContext, Writer out, Closure block) { with(applicationContext, out, null, block) } /** * Establish an environment with a specific locale */ - static with(ApplicationContext applicationContext, Writer out, Locale locale, Closure block) { + static Object with(ApplicationContext applicationContext, Writer out, Locale locale, Closure block) { def env = new RenderEnvironment(applicationContext, out, locale) env.init() try { @@ -191,15 +203,15 @@ class MailMessageContentRenderer { static class PageRenderRequestCreator { static HttpServletRequest createInstance(final String serverBaseURL, final String requestURI, Locale localeToUse = Locale.getDefault()) { - final URI serverBaseURI = serverBaseURL!=null? new URI(serverBaseURL):null + final URI serverBaseURI = serverBaseURL != null ? new URI(serverBaseURL) : null def params = new ConcurrentHashMap() def attributes = new ConcurrentHashMap() String contentType = null - String characterEncoding = "UTF-8" + String characterEncoding = 'UTF-8' - (HttpServletRequest)Proxy.newProxyInstance(HttpServletRequest.classLoader, [HttpServletRequest] as Class[], new InvocationHandler() { + Proxy.newProxyInstance(HttpServletRequest.classLoader, [HttpServletRequest] as Class[], new InvocationHandler() { Object invoke(proxy, Method method, Object[] args) { String methodName = method.name @@ -216,21 +228,20 @@ class MailMessageContentRenderer { } if (methodName == 'setCharacterEncoding') { characterEncoding = args[0] + return null } - if (methodName == 'getRealPath') { return requestURI } if (methodName == 'getLocalName') { - return "localhost" + return 'localhost' } if (methodName == 'getLocalAddr') { - return "127.0.0.1" + return '127.0.0.1' } if (methodName == 'getLocalPort') { return 80 } - if (methodName == 'getCookies') { return ([] as Cookie[]) } @@ -243,18 +254,15 @@ class MailMessageContentRenderer { if (methodName == 'getContextPath' || methodName == 'getServletPath') { return '/' } - if (methodName in ['getPathInfo', 'getPathTranslated', 'getQueryString']) { return '' } - if (methodName == 'getRequestURL') { return new StringBuffer(requestURI) } if (methodName == 'getRequestURI') { return requestURI } - if (methodName == 'isRequestedSessionIdValid') { return true } @@ -263,71 +271,61 @@ class MailMessageContentRenderer { 'authenticate', 'isUserInRole', 'isSecure', 'isAsyncStarted', 'isAsyncSupported']) { return false } - if (methodName == 'getSession') { - throw new UnsupportedOperationException("You cannot use the session in non-request rendering operations") + throw new UnsupportedOperationException('You cannot use the session in non-request rendering operations') } if (methodName == 'getInputStream') { - throw new UnsupportedOperationException("You cannot read the input stream in non-request rendering operations") + throw new UnsupportedOperationException('You cannot read the input stream in non-request rendering operations') } if (methodName == 'getProtocol') { - throw new UnsupportedOperationException("You cannot read the protocol in non-request rendering operations") + throw new UnsupportedOperationException('You cannot read the protocol in non-request rendering operations') } if (methodName == 'getScheme') { - if(serverBaseURI == null){ - throw new UnsupportedOperationException("You cannot read the scheme in non-request rendering operations") + if (serverBaseURI == null) { + throw new UnsupportedOperationException('You cannot read the scheme in non-request rendering operations') } - else{ - return serverBaseURI.scheme - } + return serverBaseURI.scheme } if (methodName == 'getServerName') { - if(serverBaseURI == null){ - throw new UnsupportedOperationException("You cannot read the servername in non-request rendering operations") - } - else{ - return serverBaseURI.host + if(serverBaseURI == null) { + throw new UnsupportedOperationException('You cannot read the servername in non-request rendering operations') } + return serverBaseURI.host } if (methodName == 'getServerPort') { - if(serverBaseURI == null){ - throw new UnsupportedOperationException("You cannot read the server port in non-request rendering operations") + if (serverBaseURI == null) { + throw new UnsupportedOperationException('You cannot read the server port in non-request rendering operations') } - else{ - int port = serverBaseURI?.port - if(port == -1){ - switch(serverBaseURI?.scheme?.toLowerCase()){ - case 'http': - port = 80 - break - case 'https': - port = 443 - break - } + int port = serverBaseURI.port + if (port == -1) { + switch (serverBaseURI.scheme?.toLowerCase()) { + case 'https': + port = 443 + break + default: + port = 80 } - return port } + return port } if (methodName == 'getReader') { - throw new UnsupportedOperationException("You cannot read input in non-request rendering operations") + throw new UnsupportedOperationException('You cannot read input in non-request rendering operations') } if (methodName == 'getRemoteAddr') { - throw new UnsupportedOperationException("You cannot read the remote address in non-request rendering operations") + throw new UnsupportedOperationException('You cannot read the remote address in non-request rendering operations') } if (methodName == 'getRemoteHost') { - throw new UnsupportedOperationException("You cannot read the remote host in non-request rendering operations") + throw new UnsupportedOperationException('You cannot read the remote host in non-request rendering operations') } if (methodName == 'getRequestDispatcher') { - throw new UnsupportedOperationException("You cannot use the request dispatcher in non-request rendering operations") + throw new UnsupportedOperationException('You cannot use the request dispatcher in non-request rendering operations') } if (methodName == 'getRemotePort') { - throw new UnsupportedOperationException("You cannot read the remote port in non-request rendering operations") + throw new UnsupportedOperationException('You cannot read the remote port in non-request rendering operations') } - if (methodName == 'getParts') { return [] } - if (methodName == 'getAttribute') { return attributes[args[0]] } @@ -338,26 +336,24 @@ class MailMessageContentRenderer { String name = args[0] Object o = args[1] if (o == null) { - attributes.remove name + attributes.remove(name) } else { attributes[name] = o } return null } if (methodName == 'removeAttribute') { - attributes.remove args[0] + attributes.remove(args[0]) return null } - if (methodName == 'getLocale') { return localeToUse } if (methodName == 'getLocales') { def iterator = [localeToUse].iterator() //noinspection UnnecessaryQualifiedReference - PageRenderRequestCreator.iteratorAsEnumeration(iterator) + return PageRenderRequestCreator.iteratorAsEnumeration(iterator) } - if (methodName == 'getParameter') { return params[args[0]] } @@ -370,18 +366,15 @@ class MailMessageContentRenderer { if (methodName == 'getParameterMap') { return params } - if (methodName == 'getContentLength') { return 0 } - - if ('getHeaderNames'.equals(methodName) || 'getHeaders'.equals(methodName)) { + if ('getHeaderNames' == methodName || 'getHeaders' == methodName) { return Collections.enumeration(Collections.emptySet()) } - return null } - }) + }) as HttpServletRequest } private static Enumeration iteratorAsEnumeration(Iterator iterator) { @@ -403,11 +396,11 @@ class MailMessageContentRenderer { static HttpServletResponse createInstance(final PrintWriter writer, Locale localeToUse = Locale.getDefault()) { - String characterEncoding = "UTF-8" + String characterEncoding = 'UTF-8' String contentType = null int bufferSize = 0 - (HttpServletResponse)Proxy.newProxyInstance(HttpServletResponse.classLoader, [HttpServletResponse] as Class[], new InvocationHandler() { + Proxy.newProxyInstance(HttpServletResponse.classLoader, [HttpServletResponse] as Class[], new InvocationHandler() { Object invoke(proxy, Method method, Object[] args) { String methodName = method.name @@ -433,38 +426,30 @@ class MailMessageContentRenderer { bufferSize = args[0] as Integer return null } - if (methodName == 'containsHeader' || methodName == 'isCommitted') { return false } - if (methodName in ['encodeURL', 'encodeRedirectURL', 'encodeUrl', 'encodeRedirectUrl']) { return args[0] } - if (methodName == 'getWriter') { - writer + return writer } - if (methodName == 'getOutputStream') { - throw new UnsupportedOperationException("You cannot use the OutputStream in non-request rendering operations. Use getWriter() instead") + throw new UnsupportedOperationException('You cannot use the OutputStream in non-request rendering operations. Use getWriter() instead') } - if (methodName == 'getHeaderNames') { return [] } - if (methodName == 'getLocale') { return localeToUse } - if (methodName == 'getStatus') { return 0 } - return null } - }) + }) as HttpServletResponse } } } diff --git a/src/main/groovy/grails/plugins/mail/SendMail.groovy b/src/main/groovy/grails/plugins/mail/SendMail.groovy index 7521c53..6f97ca7 100644 --- a/src/main/groovy/grails/plugins/mail/SendMail.groovy +++ b/src/main/groovy/grails/plugins/mail/SendMail.groovy @@ -21,13 +21,16 @@ import org.grails.core.DefaultGrailsControllerClass import org.grails.core.DefaultGrailsServiceClass import org.springframework.beans.factory.annotation.Autowired import org.springframework.context.ApplicationContext +import org.springframework.mail.MailMessage -@Enhances([DefaultGrailsServiceClass.SERVICE, DefaultGrailsControllerClass.CONTROLLER]) @CompileStatic +@Enhances([DefaultGrailsServiceClass.SERVICE, DefaultGrailsControllerClass.CONTROLLER]) trait SendMail { + @Autowired ApplicationContext applicationContext - public sendMail(@DelegatesTo(strategy = Closure.DELEGATE_FIRST, value = MailMessageBuilder) Closure dsl) { + + MailMessage sendMail(@DelegatesTo(strategy = Closure.DELEGATE_FIRST, value = MailMessageBuilder) Closure dsl) { applicationContext.getBean('mailService', MailService).sendMail(dsl) } } \ No newline at end of file diff --git a/src/test/groovy/grails/plugins/mail/MailMessageBuilderSpec.groovy b/src/test/groovy/grails/plugins/mail/MailMessageBuilderSpec.groovy index 05baa04..ca2a431 100644 --- a/src/test/groovy/grails/plugins/mail/MailMessageBuilderSpec.groovy +++ b/src/test/groovy/grails/plugins/mail/MailMessageBuilderSpec.groovy @@ -41,17 +41,17 @@ class MailMessageBuilderSpec extends Specification implements GrailsUnitTest { private static String defaultTo = "to@grailsplugin.com" def setup() { - MailConfigurationProperties properties = new MailConfigurationProperties() + def properties = new MailConfigurationProperties() properties.default.from = defaultFrom properties.default.to = defaultTo - MailSender mockJavaMailSender = Stub(JavaMailSender) { + def mockJavaMailSender = Stub(JavaMailSender) { createMimeMessage() >> new MimeMessage(Session.getInstance(new Properties())) } testJavaMailSenderBuilder = new MailMessageBuilder(mockJavaMailSender, properties) - MailSender mockBasicMailSender = Stub(MailSender) + def mockBasicMailSender = Stub(MailSender) testBasicMailSenderBuilder = new MailMessageBuilder(mockBasicMailSender, properties) } diff --git a/travis-build.sh b/travis-build.sh deleted file mode 100755 index 53df1d4..0000000 --- a/travis-build.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash -set -e -rm -rf *.zip -./gradlew clean check assemble || EXIT_STATUS=$? - -if [ "${TRAVIS_JDK_VERSION}" == "openjdk11" ] ; then - exit $EXIT_STATUS -fi - -filename=$(find build/libs -name "*.jar" | head -1) -filename=$(basename "$filename") - -EXIT_STATUS=0 -echo "Publishing archives for branch $TRAVIS_BRANCH" -if [[ -n $TRAVIS_TAG ]] || [[ $TRAVIS_BRANCH == 'master' && $TRAVIS_PULL_REQUEST == 'false' ]]; then - - echo "Publishing archives" - - if [[ -n $TRAVIS_TAG ]]; then - ./gradlew bintrayUpload || EXIT_STATUS=$? - else - ./gradlew publish || EXIT_STATUS=$? - fi - -fi - -exit $EXIT_STATUS \ No newline at end of file