From e4d906ca5e9a7fcc5db15a9dcb144335da6c6a09 Mon Sep 17 00:00:00 2001 From: Gregor Anders Date: Mon, 27 Dec 2021 16:09:32 +0100 Subject: [PATCH 01/16] [#1] Initial code Initial code including GitHub workflows and templates for issues, commits and PRs. Signed-off-by: Gregor Anders --- .gitattributes | 1 + .github/ISSUE_TEMPLATE/bug_report.md | 31 ++ .github/ISSUE_TEMPLATE/custom.md | 7 + .github/ISSUE_TEMPLATE/feature_request.md | 19 + .github/PULL_REQUEST_TEMPLATE.md | 45 ++ .github/dependabot.yml | 13 + .github/workflows/gradle.yml | 55 ++ CHANGELOG.md | 14 + CODE_OF_CONDUCT.md | 76 +++ CONTRIBUTING.md | 67 +++ SECURITY.md | 11 + build.gradle | 103 ++++ buildSrc/build.gradle | 12 + .../gradle/ProjectConfigurationPlugin.groovy | 279 +++++++++++ .../projectConfiguration.properties | 1 + config/checkstyle/checkstyle-header.txt | 23 + config/checkstyle/checkstyle-suppressions.xml | 29 ++ config/checkstyle/checkstyle.xml | 170 +++++++ config/checkstyle/configuration_1_3.dtd | 55 ++ config/checkstyle/suppressions_1_1.dtd | 16 + .../dependency-check-suppressions.xml | 33 ++ config/dependency-check/suppression.xsd | 70 +++ config/pmd/pmd-rules.xml | 65 +++ config/pmd/ruleset_2_0_0.xsd | 90 ++++ config/spotbugs/excludeFilter.xml | 38 ++ config/spotbugs/findbugsfilter.xsd | 472 ++++++++++++++++++ gradle.properties | 38 ++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59536 bytes gradle/wrapper/gradle-wrapper.properties | 5 + gradlew | 234 +++++++++ gradlew.bat | 89 ++++ settings.gradle | 8 + .../gregoranders/template/Application.java | 39 ++ .../gregoranders/template/package-info.java | 27 + src/main/java/module-info.java | 26 + src/main/resources/logback.xml | 34 ++ .../template/ApplicationSpec.groovy | 36 ++ src/test/resources/logback-test.xml | 13 + 38 files changed, 2344 insertions(+) create mode 100644 .gitattributes create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/custom.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/gradle.yml create mode 100644 CHANGELOG.md create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 SECURITY.md create mode 100644 build.gradle create mode 100644 buildSrc/build.gradle create mode 100644 buildSrc/src/main/groovy/com/github/gregoranders/template/gradle/ProjectConfigurationPlugin.groovy create mode 100644 buildSrc/src/main/resources/META-INF/gradle-plugins/projectConfiguration.properties create mode 100644 config/checkstyle/checkstyle-header.txt create mode 100644 config/checkstyle/checkstyle-suppressions.xml create mode 100644 config/checkstyle/checkstyle.xml create mode 100644 config/checkstyle/configuration_1_3.dtd create mode 100644 config/checkstyle/suppressions_1_1.dtd create mode 100644 config/dependency-check/dependency-check-suppressions.xml create mode 100644 config/dependency-check/suppression.xsd create mode 100644 config/pmd/pmd-rules.xml create mode 100644 config/pmd/ruleset_2_0_0.xsd create mode 100644 config/spotbugs/excludeFilter.xml create mode 100644 config/spotbugs/findbugsfilter.xsd create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle create mode 100644 src/main/java/com/github/gregoranders/template/Application.java create mode 100644 src/main/java/com/github/gregoranders/template/package-info.java create mode 100644 src/main/java/module-info.java create mode 100644 src/main/resources/logback.xml create mode 100644 src/test/groovy/com/github/gregoranders/template/ApplicationSpec.groovy create mode 100644 src/test/resources/logback-test.xml diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..17cafc9 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.bat text eol=crlf \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..86dd72f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,31 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: 'bug' +assignees: 'gregoranders' +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: + +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + +- OS: [e.g. Windows 10] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/custom.md b/.github/ISSUE_TEMPLATE/custom.md new file mode 100644 index 0000000..3f25027 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/custom.md @@ -0,0 +1,7 @@ +--- +name: Custom issue template +about: Describe this issue template's purpose here. +title: '' +labels: '' +assignees: 'gregoranders' +--- diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..ee4f3e0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,19 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: 'enhancement' +assignees: 'gregoranders' +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..9187ff4 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,45 @@ + + +## Description + + + +## Related Issue + + + + + + +## Motivation and Context + + + +## How Has This Been Tested? + + + + + +## Screenshots (if appropriate): + +## Types of changes + + + +- [ ] Dependencies (non-breaking change which updates dependencies) +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to change) + +## Checklist: + + + + +- [ ] My code follows the code style of this project. +- [ ] My change requires a change to the documentation. +- [ ] I have updated the documentation accordingly. +- [ ] I have read the **CONTRIBUTING** document. +- [ ] I have added tests to cover my changes. +- [ ] All new and existing tests passed. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..e714265 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +version: 2 +updates: + - package-ecosystem: 'gradle' + directory: '/' + schedule: + interval: 'weekly' + labels: + - 'gradle dependencies' + commit-message: + prefix: 'gradle' + assignees: + - 'gregoranders' + target-branch: 'development' diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml new file mode 100644 index 0000000..b891dc2 --- /dev/null +++ b/.github/workflows/gradle.yml @@ -0,0 +1,55 @@ +name: Gradle Build + +on: [push, pull_request] + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macOS-latest, windows-latest] + java: [ '17.0.1' ] + fail-fast: false + name: ${{ matrix.os }} JDK ${{ matrix.java }} + steps: + - name: Git checkout + uses: actions/checkout@v2 + - name: Set up JDK + uses: actions/setup-java@v1 + with: + java-version: ${{ matrix.java }} + - name: Echo JAVA_HOME + run: echo $JAVA_HOME + - name: Verify Gradle Wrapper + uses: gradle/wrapper-validation-action@v1 + - name: Execute build + run: ./gradlew --info --stacktrace build + - name: Execute jlink + run: ./gradlew --info --stacktrace jlink + - name: Execute jpackage + run: ./gradlew --info --stacktrace jpackage + - name: Upload DMG as an artifact + uses: actions/upload-artifact@v2 + with: + name: hellofx-jdk${{ matrix.java }}-${{ matrix.os }}-dmg + path: gui/build/jpackage/*.dmg + - name: Upload EXE as an artifact + uses: actions/upload-artifact@v2 + with: + name: hellofx-jdk${{ matrix.java }}-${{ matrix.os }}-exe + path: gui/build/jpackage/*.exe + - name: Upload MSI as an artifact + uses: actions/upload-artifact@v2 + with: + name: hellofx-jdk${{ matrix.java }}-${{ matrix.os }}-msi + path: gui/build/jpackage/*.msi + - name: Upload DEB as an artifact + uses: actions/upload-artifact@v2 + with: + name: hellofx-jdk${{ matrix.java }}-${{ matrix.os }}-deb + path: gui/build/jpackage/*.deb + - name: Upload RPM as an artifact + uses: actions/upload-artifact@v2 + with: + name: hellofx-jdk${{ matrix.java }}-${{ matrix.os }}-rpm + path: gui/build/jpackage/*.rpm \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..db566d2 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,14 @@ +# Changelog + +## [Unreleased] +### Added + +### Changed + +### Deprecated + +### Removed + +### Fixed + +### Security diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..164789f --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +- The use of sexualized language or imagery and unwelcome sexual attention or + advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic + address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team. All complaints will be reviewed and +investigated and will result in a response that is deemed necessary and +appropriate to the circumstances. The project team is obligated to maintain +confidentiality with regard to the reporter of an incident. Further details of +specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..20cba16 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,67 @@ +# Contributing Guide + +Contributing to `com.github.gregoranders.template` is fairly easy. This document shows you how to +get the project, run all provided tests and generate a production-ready build. + +It also covers provided tasks that help you develop with `com.github.gregoranders.template`. + +## Dependencies + +To make sure that the following instructions work, please install the following dependencies +on you machine: + +- JAVA 17 +- Git + +## Installation + +To get the source of `com.github.gregoranders.template`, clone the git repository via: + +``` +$ git clone https://github.com/gregoranders/com.github.gregoranders.template +``` + +This will clone the complete source to your local machine. Navigate to the project folder +and install all needed dependencies via **gradle**: + +``` +$ ./gradlew build +``` + +This commands installs everything which is required for building and testing the project. + +## Testing + +### Unit testing using [Spock][spock-url] + +`./gradle test` executes the unit tests. + +## Building + +`./gradle check build` executes the build. + +## Contributing/Submitting changes + +- Check out a new branch based on development and name it to what you intend to do: + - Example: + ``` + $ git checkout -b BRANCH_NAME origin/development + ``` + If you get an error, you may need to fetch development first by using + ``` + $ git remote update && git fetch + ``` + - Use one branch per fix/feature +- Make your changes + - Make sure to provide a spec for unit tests. + - Run your tests with ./gradlew clean test. + - Save integration time and run code quality checks locally with ./gradlew clean check + - When all tests pass, everything's fine. +- Commit your changes + - Please provide a git message that explains what you've done. + - Commit to the forked repository. +- Make a pull request + - Make sure you send the PR to the development branch. + - CI is watching you! + +[spock-url]: https://spockframework.org diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..d401fa5 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,11 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +|---------|--------------------| +| 0.0.1 | :white_check_mark: | + +## Reporting a Vulnerability + +[Create Issue](https://github.com/gregoranders/com.github.gregoranders.template/issues/new?labels=bug&template=bug_report.md&title=Security+Issue) diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..c838f7f --- /dev/null +++ b/build.gradle @@ -0,0 +1,103 @@ +import java.text.SimpleDateFormat + +buildscript { + repositories { + mavenCentral() + } +} + +plugins { + id 'java' + id 'groovy' + id 'idea' + id 'application' + id 'checkstyle' + id 'pmd' + id 'jacoco' + id 'project-report' + id 'build-dashboard' + id 'com.github.spotbugs' version "${spotbugsPluginVersion}" + id 'org.owasp.dependencycheck' version "${dependencyCheckVersion}" + id 'org.beryx.jlink' version "${jlinkPluginVersion}" + id 'org.javamodularity.moduleplugin' version "${modulePluginVersion}" + id 'org.jetbrains.changelog' version "${gitChangeLogPluginVersion}" + id 'projectConfiguration' +} + +repositories { + mavenCentral() +} + +sourceCompatibility = '17' +targetCompatibility = '17' + +application { + mainModule = project.property('mainModule') + mainClass = project.property('mainClass') +} + +test { + moduleOptions { + runOnClasspath = true + } +} + +changelog { + path = "${project.rootProject.projectDir}/CHANGELOG.md" + header = "[${-> version.get()}] - ${new SimpleDateFormat("yyyy-MM-dd").format(new Date())}" + headerParserRegex = ~/(\d+\.\d+)/ + itemPrefix = "-" + keepUnreleasedSection = true + unreleasedTerm = "[Unreleased]" + groups = ["Added", "Changed", "Deprecated", "Removed", "Fixed", "Security"] +} + +def pluginsCheck = false + +if (pluginsCheck) { + dependencies { + implementation( + [group: 'org.owasp', name: 'dependency-check-gradle', version: project.property('dependencyCheckVersion')], + [group: 'com.github.spotbugs', name: 'spotbugs', version: project.property('spotbugsVersion')], + [group: 'com.github.spotbugs.snom', name: 'spotbugs-gradle-plugin', version: project.property('spotbugsPluginVersion')], + [group: 'org.beryx', name: 'badass-jlink-plugin', version: project.property('jlinkPluginVersion')], + [group: 'org.javamodularity', name: 'moduleplugin', version: project.property('modulePluginVersion')] + ) + } +} + +dependencies { + implementation( + [group: 'org.slf4j', name: 'slf4j-api', version: project.property('slf4jVersion')], + ) + + runtimeOnly( + [group: 'ch.qos.logback', name: 'logback-core', version: project.property('logbackVersion')], + [group: 'ch.qos.logback', name: 'logback-classic', version: project.property('logbackVersion')], + + [group: 'javax.servlet', name: 'javax.servlet-api', version: project.property('servletApiVersion')], + ) + + testImplementation( + platform( + [group: 'org.codehaus.groovy', name: 'groovy-bom', version: project.property('groovyVersion')] + ), + platform( + [group: 'org.spockframework', name: 'spock-bom', version: project.property('spockVersion')] + ), + [group: 'org.spockframework', name: 'spock-core'], + [group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: project.property('junitVersion')] + ) + + testRuntimeOnly( + [group: 'ch.qos.logback', name: 'logback-core', version: project.property('logbackVersion')], + [group: 'ch.qos.logback', name: 'logback-classic', version: project.property('logbackVersion')], + ) +} + +test { + useJUnitPlatform() + testLogging { + events 'passed', 'skipped', 'failed' + } +} \ No newline at end of file diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle new file mode 100644 index 0000000..a89a0cc --- /dev/null +++ b/buildSrc/build.gradle @@ -0,0 +1,12 @@ +apply plugin: 'groovy' + +//noinspection GroovyAssignabilityCheck +repositories { + mavenCentral() +} + +dependencies { + implementation( + gradleApi() + ) +} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/com/github/gregoranders/template/gradle/ProjectConfigurationPlugin.groovy b/buildSrc/src/main/groovy/com/github/gregoranders/template/gradle/ProjectConfigurationPlugin.groovy new file mode 100644 index 0000000..75cd3ef --- /dev/null +++ b/buildSrc/src/main/groovy/com/github/gregoranders/template/gradle/ProjectConfigurationPlugin.groovy @@ -0,0 +1,279 @@ +/* + * MIT License + * + * Copyright (c) 2021 Gregor Anders + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.gregoranders.template.gradle + +import org.gradle.api.DefaultTask +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.tasks.TaskAction +import org.gradle.internal.os.OperatingSystem + +class ProjectConfigurationPlugin implements Plugin { + + static class CPDTask extends DefaultTask { + + @TaskAction + def cpd() { + File outDir = project.file("${project.buildDir}/reports/cpd") + outDir.mkdirs() + ant.taskdef(name: 'cpd', classname: 'net.sourceforge.pmd.cpd.CPDTask', + classpath: project.configurations.pmd.asPath) + ant.cpd(minimumTokenCount: '40', format: 'xml', + outputFile: new File(outDir, 'main.xml')) { + fileset(dir: "src/main/java") { + include(name: '**/*.java') + } + } + } + } + + @Override + void apply(Project project) { + processJava(project) + processIDEA(project) + processJaCoCo(project) + processCheckStyle(project) + processPMD(project) + processSpotBugs(project) + processDependencyCheck(project) + processJlink(project) + } + + def processJava(Project projectInternal) { + + if (projectInternal.plugins.hasPlugin('java')) { + + projectInternal.jar { + + archiveBaseName = "${projectInternal.group}.${projectInternal.name}" + archiveVersion = "${projectInternal.version}" + + def manifestAttributes = [ + 'Created-By' : "${projectInternal.properties['author']}", + 'Specification-Title' : "${projectInternal.properties['description']}", + 'Specification-Version' : "${projectInternal.version}", + 'Specification-Vendor' : "${projectInternal.properties['author']}", + 'Specification-Vendor-Id' : "${projectInternal.properties['author']} <${projectInternal.properties['email']}>", + 'Implementation-Title' : "${projectInternal.properties['description']} - Implementation", + 'Implementation-Version' : "${projectInternal.version}", + 'Implementation-Vendor' : "${projectInternal.properties['author']}", + 'Implementation-Vendor-Id': "${projectInternal.properties['author']} <${projectInternal.properties['email']}>" + ] + + if (projectInternal.properties['mainClass']) { + manifestAttributes.put('Main-Class', "${projectInternal.properties['mainClass']}") + } + + manifest { + attributes(manifestAttributes) + } + } + } + } + + def processIDEA(Project projectInternal) { + + if (projectInternal.plugins.hasPlugin('idea')) { + + projectInternal.idea { + + module { + downloadJavadoc = true + downloadSources = true + } + + project { + vcs = 'Git' + jdkName = "${projectInternal.sourceCompatibility}" + languageLevel = "${projectInternal.sourceCompatibility}" + } + } + } + } + + def processJaCoCo(Project projectInternal) { + if (projectInternal.plugins.hasPlugin('jacoco')) { + projectInternal.jacoco { + toolVersion = projectInternal.properties['jacocoVersion'] + reportsDirectory = projectInternal.layout.buildDirectory.dir('reports/jacoco').get().asFile + } + projectInternal.jacocoTestReport { + dependsOn projectInternal.test + reports { + xml.required = true + xml.destination projectInternal.layout.buildDirectory.file("reports/jacoco/${name}.xml").get().asFile + csv.required = false + html.destination projectInternal.layout.buildDirectory.dir('reports/jacoco/html').get().asFile + } + } + projectInternal.jacocoTestCoverageVerification { + violationRules { + rule { + limit { + counter = 'INSTRUCTION' + minimum = 1.0 + } + limit { + counter = 'BRANCH' + minimum = 1.0 + } + limit { + counter = 'LINE' + minimum = 1.0 + } + limit { + counter = 'METHOD' + minimum = 1.0 + } + limit { + counter = 'CLASS' + minimum = 1.0 + } + } + } + } + projectInternal.test { + jacoco { + destinationFile = projectInternal.layout.buildDirectory.file("results/jacoco/jacoco-${name}.exec").get().asFile + classDumpDir = projectInternal.layout.buildDirectory.dir('results/classpathdumps').get().asFile + excludes = ["**/Immutable*"] + } + finalizedBy projectInternal.jacocoTestReport + } + projectInternal.check { + dependsOn projectInternal.jacocoTestCoverageVerification + } + } + } + + def processCheckStyle(Project projectInternal) { + if (projectInternal.plugins.hasPlugin('checkstyle')) { + projectInternal.checkstyle { + toolVersion = projectInternal.properties['checkstyleVersion'] + ignoreFailures = false + configProperties = [ + 'checkstyle.header.file' : projectInternal.file("${projectInternal.rootProject.projectDir}/config/checkstyle/checkstyle-header.txt"), + 'checkstyle.suppressions.file': projectInternal.file("${projectInternal.rootProject.projectDir}/config/checkstyle/checkstyle-suppressions.xml") + ] + } + } + } + + def processPMD(Project projectInternal) { + if (projectInternal.plugins.hasPlugin('pmd')) { + projectInternal.pmd { + consoleOutput = true + incrementalAnalysis = true + toolVersion = projectInternal.properties['pmdVersion'] + ignoreFailures = false + ruleSets = [] + ruleSetConfig = projectInternal.resources.text.fromFile(projectInternal.file("$projectInternal.rootProject.projectDir/config/pmd/pmd-rules.xml")) + } + + def cpdTask = projectInternal.tasks.register('cpd', CPDTask) + + projectInternal.check.configure { + dependsOn cpdTask + } + } + } + + def processSpotBugs(Project projectInternal) { + if (projectInternal.plugins.hasPlugin('com.github.spotbugs')) { + projectInternal.spotbugs { + toolVersion = projectInternal.properties['spotbugsVersion'] + ignoreFailures = false + effort = 'max' + reportLevel = 'low' + excludeFilter = projectInternal.rootProject.file('config/spotbugs/excludeFilter.xml') + } + projectInternal.spotbugsMain { + reports { + html { + required = true + outputLocation = projectInternal.layout.buildDirectory.file('reports/spotbugs/main/spotbugs.html').get().asFile + stylesheet = 'fancy-hist.xsl' + } + xml { + required = true + outputLocation = projectInternal.layout.buildDirectory.file('reports/spotbugs/main/spotbugs.xml').get().asFile + } + } + } + projectInternal.spotbugsTest.enabled = false + } + } + + def processDependencyCheck(Project projectInternal) { + if (projectInternal.plugins.hasPlugin("org.owasp.dependencycheck")) { + projectInternal.dependencyCheck { + autoUpdate = true + failBuildOnCVSS = 1 + cveValidForHours = 1 + format = 'ALL' + outputDirectory = projectInternal.layout.buildDirectory.dir('reports/dependency-check').get().asFile + suppressionFile = projectInternal.file("${projectInternal.rootProject.projectDir}/config/dependency-check/dependency-check-suppressions.xml") + analyzers { + pyDistributionEnabled = false + pyPackageEnabled = false + rubygemsEnabled = false + opensslEnabled = false + cmakeEnabled = false + autoconfEnabled = false + composerEnabled = false + nodeEnabled = false + nuspecEnabled = false + assemblyEnabled = false + } + } + projectInternal.check.configure { + dependsOn projectInternal.dependencyCheckAnalyze + } + } + } + + def processJlink(Project projectInternal) { + if (projectInternal.plugins.hasPlugin('org.beryx.jlink')) { + projectInternal.jlink { + imageDir = projectInternal.layout.buildDirectory.dir("${projectInternal.rootProject.group}.${projectInternal.rootProject.name}").get().asFile + imageZip = projectInternal.layout.buildDirectory.file("distributions/${projectInternal.rootProject.group}.${projectInternal.rootProject.name}-${projectInternal.rootProject.version}.zip").get().asFile + options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages'] + launcher { + name = projectInternal.properties['jlinkExecutable'] + noConsole = OperatingSystem.current().windows + } + jpackage { + if (OperatingSystem.current().windows) { + installerOptions += ['--win-per-user-install', '--win-dir-chooser', '--win-menu', '--win-shortcut'] + imageOptions += ['--win-console'] + } + } + } + + projectInternal.jlinkZip { + group = 'distribution' + } + } + } +} diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/projectConfiguration.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/projectConfiguration.properties new file mode 100644 index 0000000..9330400 --- /dev/null +++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/projectConfiguration.properties @@ -0,0 +1 @@ +implementation-class=com.github.gregoranders.template.gradle.ProjectConfigurationPlugin \ No newline at end of file diff --git a/config/checkstyle/checkstyle-header.txt b/config/checkstyle/checkstyle-header.txt new file mode 100644 index 0000000..d0eebe7 --- /dev/null +++ b/config/checkstyle/checkstyle-header.txt @@ -0,0 +1,23 @@ +/* + * MIT License + * + * Copyright (c) 2021 Gregor Anders + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ \ No newline at end of file diff --git a/config/checkstyle/checkstyle-suppressions.xml b/config/checkstyle/checkstyle-suppressions.xml new file mode 100644 index 0000000..5ed81c5 --- /dev/null +++ b/config/checkstyle/checkstyle-suppressions.xml @@ -0,0 +1,29 @@ + + + + + + diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml new file mode 100644 index 0000000..31dbea0 --- /dev/null +++ b/config/checkstyle/checkstyle.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config/checkstyle/configuration_1_3.dtd b/config/checkstyle/configuration_1_3.dtd new file mode 100644 index 0000000..885bf38 --- /dev/null +++ b/config/checkstyle/configuration_1_3.dtd @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + diff --git a/config/checkstyle/suppressions_1_1.dtd b/config/checkstyle/suppressions_1_1.dtd new file mode 100644 index 0000000..54e4ead --- /dev/null +++ b/config/checkstyle/suppressions_1_1.dtd @@ -0,0 +1,16 @@ + + + + + + + diff --git a/config/dependency-check/dependency-check-suppressions.xml b/config/dependency-check/dependency-check-suppressions.xml new file mode 100644 index 0000000..8016195 --- /dev/null +++ b/config/dependency-check/dependency-check-suppressions.xml @@ -0,0 +1,33 @@ + + + + + + ^pkg:maven/commons\-io/commons\-io@.*$ + CVE-2021-29425 + + \ No newline at end of file diff --git a/config/dependency-check/suppression.xsd b/config/dependency-check/suppression.xsd new file mode 100644 index 0000000..604655d --- /dev/null +++ b/config/dependency-check/suppression.xsd @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + When specified the suppression will only be active when the specified date is still + in the future. On and after the 'until' date the suppression will no longer be + active. + + + + + + + + + diff --git a/config/pmd/pmd-rules.xml b/config/pmd/pmd-rules.xml new file mode 100644 index 0000000..4425994 --- /dev/null +++ b/config/pmd/pmd-rules.xml @@ -0,0 +1,65 @@ + + + + + PMD RuleSet + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/pmd/ruleset_2_0_0.xsd b/config/pmd/ruleset_2_0_0.xsd new file mode 100644 index 0000000..b6db5dc --- /dev/null +++ b/config/pmd/ruleset_2_0_0.xsd @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/spotbugs/excludeFilter.xml b/config/spotbugs/excludeFilter.xml new file mode 100644 index 0000000..71ae0f8 --- /dev/null +++ b/config/spotbugs/excludeFilter.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/config/spotbugs/findbugsfilter.xsd b/config/spotbugs/findbugsfilter.xsd new file mode 100644 index 0000000..dfa947d --- /dev/null +++ b/config/spotbugs/findbugsfilter.xsd @@ -0,0 +1,472 @@ + + + + + + + + + + + + This element specifies a particular bug pattern or patterns to match. + If more than one attribute is specified on the same Bug element, all bug patterns that match either one of specified + pattern names, abbreviations, or categories will be matched. + + + + + + + This element specifies a particular bug code or multiple bug codes to match. + + + + + + + This element specifies a particular bug pattern or multiple patterns to match. + + + + + + This element matches warnings with a particular priority. + This is deprecated, 'Confidence' should be used instead + + + + + + + This element matches warnings with a particular confidence. + + + + + + This element matches warnings with a particular rank. + + + + + + This element matches warnings associated with classes within the package specified using name + attribute. + + + + + + + This element matches warnings associated with a particular class. + + + + + + This element matches warnings associated with a particular type. + + + + + + This element matches warnings associated with a particular source file name. + + + + + + This element specifies a method. + + + + + + This element specifies a field. + + + + + + This element specifies a local variable. + + + + + + This element combines Match clauses as disjuncts. + I.e., you can put two Method elements in an Or clause in order to match either method. + + + + + + + This element combines Match clauses which both must evaluate to true. + I.e., you can put Bug and Confidence elements in an And clause in order to match specific bugs with given confidence only. + + + + + + + This element inverts the included child Match. + I.e., you can put a Bug element in a Not clause in order to match any bug excluding the given one. + + + + + + + + + + + + + + + + + + A comma-separated list of bug code types. You can find the bug code types for particular warnings by looking at the output produced by the -xml + output option (the type attribute of BugInstance elements), or from the bug descriptions document. + + + + + + + + + + + + A comma-separated list of bug pattern types. You can find the bug pattern types for particular warnings by looking at the output produced by the -xml + output option (the type attribute of BugInstance elements), or from the bug descriptions document. + + + + + + + + + + + + A comma-separated list of bug pattern types. You can find the bug pattern types for particular warnings by looking at the output produced by the -xml + output option (the type attribute of BugInstance elements), or from the bug descriptions document. + + + + + + A comma-separated list of bug abbreviations. + + + + + A comma separated list of bug category names. + + + + + + + + + + + The exact or regex match pattern for a class name. If the name starts with the ~ character the rest of attribute content is interpreted as a Java + regular expression. + + + + + + The class role + + + + + + + + + + + The exact or regex match pattern for type descriptor. If the descriptor starts with the ~ character the rest of attribute content is interpreted as a + Java regular expression. + + + + + + The type role + + + + + The type parameters + + + + + + + + + + + The exact or regex match pattern for a source file name. If the name starts with the ~ character the rest of attribute content is interpreted as a + Java regular expression. + + + + + + + + + + + + The exact or regex match pattern for a field name. If the name starts with the ~ character the rest of attribute content is interpreted as a Java + regular expression. + + + + + + Fully qualified type of the field + + + + + The field's role + + + + + + + + + + + The exact or regex match pattern for a local variable name. If the name starts with the ~ character the rest of attribute content is interpreted as a + Java regular expression. + + + + + + + + + + + + The exact or regex match pattern for a method name.. If the name starts with the ~ character the rest of attribute content is interpreted as a Java + regular expression. + + + + + + A comma-separated list of the fully qualified types of the method's parameters. + + + + + The method's fully qualified return type + + + + + The method's role + + + + + + + + + + + The exact or regex match pattern for a package name. Nested packages are not included (along the lines of Java import statement). If the name starts + with the ~ character the rest of attribute content is interpreted as a Java regular expression. + + + + + + + + Deprecated. Use ConfidenceType instead + + + + 1: high-priority warnings, 2: medium-priority warnings, 3: low-priority warnings + + + + + + + + + + + 1: high-priority warnings, 2: medium-priority warnings, 3: low-priority warnings + + + + + + + + + + + 1 to 4 are scariest, 5 to 9 scary, 10 to 14 troubling, and 15 to 20 of concern bugs. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..0d7db4b --- /dev/null +++ b/gradle.properties @@ -0,0 +1,38 @@ +org.gradle.daemon=true +org.gradle.parallel=true +org.gradle.configureondemand=true +org.gradle.warning.mode=summary + +group=com.github.gregoranders +description=JAVA Template +version=0.0.1-SNAPSHOT + +url=https://github.com/gregoranders/java-template + +author=Gregor Anders +email=gregor.anders@gmail.com + +license=The MIT License +licenseUrl=https://opensource.org/licenses/MIT + +mainModule=com.github.gregoranders.template +mainClass=com.github.gregoranders.template.Application +jlinkExecutable=template + +slf4jVersion=1.7.32 +logbackVersion=1.2.9 +servletApiVersion=4.0.1 + +junitVersion=5.8.2 +spockVersion=2.0-groovy-3.0 +groovyVersion=3.0.8 + +checkstyleVersion=9.2 +pmdVersion=6.41.0 +jacocoVersion=0.8.7 +dependencyCheckVersion=6.5.1 +spotbugsVersion=4.5.2 +spotbugsPluginVersion=5.0.3 +jlinkPluginVersion=2.24.1 +modulePluginVersion=1.8.9 +gitChangeLogPluginVersion=1.3.1 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..7454180f2ae8848c63b8b4dea2cb829da983f2fa GIT binary patch literal 59536 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 QuEJmfE|#`Dqx|px0L@K;Y5)KL literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..2e6e589 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..1b6c787 --- /dev/null +++ b/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original 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 +# +# https://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. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..48a1fe1 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,8 @@ +pluginManagement { + repositories { + mavenCentral() + gradlePluginPortal() + } +} + +rootProject.name = "template" \ No newline at end of file diff --git a/src/main/java/com/github/gregoranders/template/Application.java b/src/main/java/com/github/gregoranders/template/Application.java new file mode 100644 index 0000000..f60b2f8 --- /dev/null +++ b/src/main/java/com/github/gregoranders/template/Application.java @@ -0,0 +1,39 @@ +/* + * MIT License + * + * Copyright (c) 2021 Gregor Anders + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.gregoranders.template; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class Application { + + private static final Logger LOG = LoggerFactory.getLogger(Application.class); + + private Application() { + } + + public static void main(final String[] args) { + LOG.info("JAVA template"); + } +} diff --git a/src/main/java/com/github/gregoranders/template/package-info.java b/src/main/java/com/github/gregoranders/template/package-info.java new file mode 100644 index 0000000..0f56e48 --- /dev/null +++ b/src/main/java/com/github/gregoranders/template/package-info.java @@ -0,0 +1,27 @@ +/* + * MIT License + * + * Copyright (c) 2021 Gregor Anders + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/** + * Main entry point + */ +package com.github.gregoranders.template; \ No newline at end of file diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java new file mode 100644 index 0000000..267b78f --- /dev/null +++ b/src/main/java/module-info.java @@ -0,0 +1,26 @@ +/* + * MIT License + * + * Copyright (c) 2021 Gregor Anders + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +module com.github.gregoranders.template { + requires org.slf4j; +} \ No newline at end of file diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..49ca6d0 --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,34 @@ + + + + + + %d{"yyyy-MM-dd'T'HH:mm:ss,SSSXXX", UTC} [%thread] %-5level %logger - %msg%n + + + + + + \ No newline at end of file diff --git a/src/test/groovy/com/github/gregoranders/template/ApplicationSpec.groovy b/src/test/groovy/com/github/gregoranders/template/ApplicationSpec.groovy new file mode 100644 index 0000000..aeca180 --- /dev/null +++ b/src/test/groovy/com/github/gregoranders/template/ApplicationSpec.groovy @@ -0,0 +1,36 @@ +/* + * MIT License + * + * Copyright (c) 2021 Gregor Anders + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.gregoranders.template + +import spock.lang.Specification + +class ApplicationSpec extends Specification { + + def 'should not throw an exception'() { + when: + Application.main() + then: + noExceptionThrown() + } +} \ No newline at end of file diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml new file mode 100644 index 0000000..19a6c36 --- /dev/null +++ b/src/test/resources/logback-test.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n + + + + + + + + \ No newline at end of file From 062cd7359835e543744f860f2be574b4181fba7e Mon Sep 17 00:00:00 2001 From: Gregor Anders Date: Mon, 27 Dec 2021 16:23:32 +0100 Subject: [PATCH 02/16] [#1] Workflow fix Removed deb and rpm builds. Signed-off-by: Gregor Anders --- .github/workflows/gradle.yml | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index b891dc2..7a3096a 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -31,25 +31,15 @@ jobs: - name: Upload DMG as an artifact uses: actions/upload-artifact@v2 with: - name: hellofx-jdk${{ matrix.java }}-${{ matrix.os }}-dmg + name: template-jdk${{ matrix.java }}-${{ matrix.os }}-dmg path: gui/build/jpackage/*.dmg - name: Upload EXE as an artifact uses: actions/upload-artifact@v2 with: - name: hellofx-jdk${{ matrix.java }}-${{ matrix.os }}-exe + name: template-jdk${{ matrix.java }}-${{ matrix.os }}-exe path: gui/build/jpackage/*.exe - name: Upload MSI as an artifact uses: actions/upload-artifact@v2 with: - name: hellofx-jdk${{ matrix.java }}-${{ matrix.os }}-msi - path: gui/build/jpackage/*.msi - - name: Upload DEB as an artifact - uses: actions/upload-artifact@v2 - with: - name: hellofx-jdk${{ matrix.java }}-${{ matrix.os }}-deb - path: gui/build/jpackage/*.deb - - name: Upload RPM as an artifact - uses: actions/upload-artifact@v2 - with: - name: hellofx-jdk${{ matrix.java }}-${{ matrix.os }}-rpm - path: gui/build/jpackage/*.rpm \ No newline at end of file + name: template-jdk${{ matrix.java }}-${{ matrix.os }}-msi + path: gui/build/jpackage/*.msi \ No newline at end of file From 9790e9220eebbb43c32e088f56dfcce5e79fa691 Mon Sep 17 00:00:00 2001 From: Gregor Anders Date: Mon, 27 Dec 2021 16:43:27 +0100 Subject: [PATCH 03/16] [#1] Workflow fix Removed SNAPSHOT from version. Signed-off-by: Gregor Anders --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 0d7db4b..69749f1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,7 +5,7 @@ org.gradle.warning.mode=summary group=com.github.gregoranders description=JAVA Template -version=0.0.1-SNAPSHOT +version=0.0.1 url=https://github.com/gregoranders/java-template From a701fcc1a12824d386eeb9f6b3c2c483fe235fd8 Mon Sep 17 00:00:00 2001 From: Gregor Anders Date: Mon, 27 Dec 2021 17:03:52 +0100 Subject: [PATCH 04/16] [#1] Workflow fix Changed version to 1.0.0 as jpackage DMG build requires the first number in an app-version not to be zero or negative Signed-off-by: Gregor Anders --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 69749f1..a6ddd4c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,7 +5,7 @@ org.gradle.warning.mode=summary group=com.github.gregoranders description=JAVA Template -version=0.0.1 +version=1.0.0 url=https://github.com/gregoranders/java-template From 0b423284d2109272c1c908aa82d55df705b23635 Mon Sep 17 00:00:00 2001 From: Gregor Anders Date: Mon, 27 Dec 2021 17:04:55 +0100 Subject: [PATCH 05/16] [#1] Workflow fix Added jlinkZip to create an artifact to be uploaded. Signed-off-by: Gregor Anders --- .github/workflows/gradle.yml | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 7a3096a..6b0a1a1 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -26,20 +26,43 @@ jobs: run: ./gradlew --info --stacktrace build - name: Execute jlink run: ./gradlew --info --stacktrace jlink + - name: Execute jlinkZip + run: ./gradlew --info --stacktrace jlinkZip - name: Execute jpackage run: ./gradlew --info --stacktrace jpackage - name: Upload DMG as an artifact + if: matrix.os == 'macOS-latest' uses: actions/upload-artifact@v2 with: name: template-jdk${{ matrix.java }}-${{ matrix.os }}-dmg path: gui/build/jpackage/*.dmg - name: Upload EXE as an artifact + if: matrix.os == 'windows-latest' uses: actions/upload-artifact@v2 with: name: template-jdk${{ matrix.java }}-${{ matrix.os }}-exe - path: gui/build/jpackage/*.exe + path: build/jpackage/*.exe - name: Upload MSI as an artifact + if: matrix.os == 'windows-latest' uses: actions/upload-artifact@v2 with: name: template-jdk${{ matrix.java }}-${{ matrix.os }}-msi - path: gui/build/jpackage/*.msi \ No newline at end of file + path: build/jpackage/*.msi + - name: Upload DEB as an artifact + if: matrix.os == 'ubuntu-latest' + uses: actions/upload-artifact@v2 + with: + name: template-jdk${{ matrix.java }}-${{ matrix.os }}-deb + path: gui/build/jpackage/*.deb + - name: Upload RPM as an artifact + if: matrix.os == 'ubuntu-latest' + uses: actions/upload-artifact@v2 + with: + name: template-jdk${{ matrix.java }}-${{ matrix.os }}-rpm + path: gui/build/jpackage/*.rpm + - name: Upload ZIP as an artifact + if: matrix.os == 'ubuntu-latest' + uses: actions/upload-artifact@v2 + with: + name: template-jdk${{ matrix.java }}-${{ matrix.os }} + path: build/distributions/*.zip \ No newline at end of file From a63d90a409a8854e93d86b0baff4a0f6aabffbe8 Mon Sep 17 00:00:00 2001 From: Gregor Anders Date: Mon, 27 Dec 2021 17:06:29 +0100 Subject: [PATCH 06/16] [#1] Use constant for JAVA version Uses constant for JAVA version provided by gradle. Signed-off-by: Gregor Anders --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index c838f7f..56b0a5a 100644 --- a/build.gradle +++ b/build.gradle @@ -28,8 +28,8 @@ repositories { mavenCentral() } -sourceCompatibility = '17' -targetCompatibility = '17' +sourceCompatibility = JavaVersion.VERSION_17 +targetCompatibility = JavaVersion.VERSION_17 application { mainModule = project.property('mainModule') From 481cc22accc8f371ede665fa67184876e724678a Mon Sep 17 00:00:00 2001 From: Gregor Anders Date: Mon, 27 Dec 2021 17:13:46 +0100 Subject: [PATCH 07/16] [#1] Use correct jpackage output path Adjusted jpackage output directories. Signed-off-by: Gregor Anders --- .github/workflows/gradle.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 6b0a1a1..b782d5e 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -35,7 +35,7 @@ jobs: uses: actions/upload-artifact@v2 with: name: template-jdk${{ matrix.java }}-${{ matrix.os }}-dmg - path: gui/build/jpackage/*.dmg + path: build/jpackage/*.dmg - name: Upload EXE as an artifact if: matrix.os == 'windows-latest' uses: actions/upload-artifact@v2 @@ -53,16 +53,16 @@ jobs: uses: actions/upload-artifact@v2 with: name: template-jdk${{ matrix.java }}-${{ matrix.os }}-deb - path: gui/build/jpackage/*.deb + path: build/jpackage/*.deb - name: Upload RPM as an artifact if: matrix.os == 'ubuntu-latest' uses: actions/upload-artifact@v2 with: name: template-jdk${{ matrix.java }}-${{ matrix.os }}-rpm - path: gui/build/jpackage/*.rpm + path: build/jpackage/*.rpm - name: Upload ZIP as an artifact if: matrix.os == 'ubuntu-latest' uses: actions/upload-artifact@v2 with: - name: template-jdk${{ matrix.java }}-${{ matrix.os }} + name: template-jdk${{ matrix.java }}-${{ matrix.os }}-zip path: build/distributions/*.zip \ No newline at end of file From b14857b503bca4fd7a71ca24cd181889bbdc41da Mon Sep 17 00:00:00 2001 From: Gregor Anders Date: Mon, 27 Dec 2021 17:52:40 +0100 Subject: [PATCH 08/16] [#1] Code Coverage Upload JaCoCo code coverage to CodeClimate. Signed-off-by: Gregor Anders --- .github/workflows/gradle.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index b782d5e..d49e4fc 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -22,6 +22,21 @@ jobs: run: echo $JAVA_HOME - name: Verify Gradle Wrapper uses: gradle/wrapper-validation-action@v1 + - name: Execute clean + run: ./gradlew --info --stacktrace clean + - name: Execute check + run: ./gradlew --info --stacktrace check + - name: Execute test + run: ./gradlew --info --stacktrace test + - name: Publish code coverage + if: matrix.os == 'ubuntu-latest' + uses: paambaati/codeclimate-action@v3.0.0 + env: + CC_TEST_REPORTER_ID: ${{secrets.CC_TEST_REPORTER_ID}} + JACOCO_SOURCE_PATH: "${{github.workspace}}/src/main/java" + with: + coverageCommand: ./gradlew --info --stacktrace check + coverageLocations: ${{github.workspace}}/build/reports/jacoco/jacocoTestReport.xml:jacoco - name: Execute build run: ./gradlew --info --stacktrace build - name: Execute jlink From 1e84375b1df995e69f2763c4d04b3d4cfb9ece1c Mon Sep 17 00:00:00 2001 From: Gregor Anders Date: Mon, 27 Dec 2021 18:15:04 +0100 Subject: [PATCH 09/16] [#1] TravisCI and Coverall Adds support for TravisCI and Coverall. Signed-off-by: Gregor Anders --- .travis.yml | 23 +++++++++++++++++++++++ build.gradle | 3 ++- gradle.properties | 3 ++- 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..a324d23 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,23 @@ +os: linux +dist: focal +language: java +jdk: openjdk11 + +before_cache: + - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock + - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ + +cache: + directories: + - $HOME/.gradle/caches/ + - $HOME/.gradle/wrapper/ + +before_script: + - export CI=true + +after_success: + - ./gradlew jacocoTestReport coveralls + +script: + - /gradlew --info --stacktrace clean check + diff --git a/build.gradle b/build.gradle index 56b0a5a..5f67bd7 100644 --- a/build.gradle +++ b/build.gradle @@ -21,6 +21,7 @@ plugins { id 'org.beryx.jlink' version "${jlinkPluginVersion}" id 'org.javamodularity.moduleplugin' version "${modulePluginVersion}" id 'org.jetbrains.changelog' version "${gitChangeLogPluginVersion}" + id 'com.github.kt3k.coveralls' version "${coverallsPluginVersion}" id 'projectConfiguration' } @@ -100,4 +101,4 @@ test { testLogging { events 'passed', 'skipped', 'failed' } -} \ No newline at end of file +} diff --git a/gradle.properties b/gradle.properties index a6ddd4c..5997b71 100644 --- a/gradle.properties +++ b/gradle.properties @@ -35,4 +35,5 @@ spotbugsVersion=4.5.2 spotbugsPluginVersion=5.0.3 jlinkPluginVersion=2.24.1 modulePluginVersion=1.8.9 -gitChangeLogPluginVersion=1.3.1 \ No newline at end of file +gitChangeLogPluginVersion=1.3.1 +coverallsPluginVersion=2.12.0 From ed05ed4097234519065740047efd188a76184c2c Mon Sep 17 00:00:00 2001 From: Gregor Anders Date: Mon, 27 Dec 2021 18:25:13 +0100 Subject: [PATCH 10/16] [#1] Coveralls Includes coveralls in GitHub CI. Signed-off-by: Gregor Anders --- .github/workflows/gradle.yml | 9 +++++++-- build.gradle | 3 +++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index d49e4fc..1839028 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -28,7 +28,7 @@ jobs: run: ./gradlew --info --stacktrace check - name: Execute test run: ./gradlew --info --stacktrace test - - name: Publish code coverage + - name: Publish code coverage to codeclimate if: matrix.os == 'ubuntu-latest' uses: paambaati/codeclimate-action@v3.0.0 env: @@ -37,6 +37,11 @@ jobs: with: coverageCommand: ./gradlew --info --stacktrace check coverageLocations: ${{github.workspace}}/build/reports/jacoco/jacocoTestReport.xml:jacoco + - name: Publish code coverage to coveralls + if: matrix.os == 'ubuntu-latest' + env: + COVERALLS_REPO_TOKEN: ${{secrets.COVERALLS_REPO_TOKEN}} + run: ./gradlew --info --stacktrace jacocoTestReport coveralls - name: Execute build run: ./gradlew --info --stacktrace build - name: Execute jlink @@ -80,4 +85,4 @@ jobs: uses: actions/upload-artifact@v2 with: name: template-jdk${{ matrix.java }}-${{ matrix.os }}-zip - path: build/distributions/*.zip \ No newline at end of file + path: build/distributions/*.zip diff --git a/build.gradle b/build.gradle index 5f67bd7..9d4b7ac 100644 --- a/build.gradle +++ b/build.gradle @@ -52,6 +52,9 @@ changelog { unreleasedTerm = "[Unreleased]" groups = ["Added", "Changed", "Deprecated", "Removed", "Fixed", "Security"] } +coveralls { + jacocoReportPath 'build/reports/jacoco/jacocoTestReport.xml' +} def pluginsCheck = false From ed765a306bd4609fef03f953105ba02843177b1b Mon Sep 17 00:00:00 2001 From: Gregor Anders Date: Mon, 27 Dec 2021 18:46:56 +0100 Subject: [PATCH 11/16] [#1] Codacy Adds codacy support. Signed-off-by: Gregor Anders --- .github/workflows/gradle.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 1839028..f1171d9 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -42,6 +42,14 @@ jobs: env: COVERALLS_REPO_TOKEN: ${{secrets.COVERALLS_REPO_TOKEN}} run: ./gradlew --info --stacktrace jacocoTestReport coveralls + - name: Publish code coverage to codacy + if: matrix.os == 'ubuntu-latest' + env: + CODACY_PROJECT_TOKEN: ${{secrets.CODACY_PROJECT_TOKEN}} + CODACY_ORGANIZATION_PROVIDER: gh + CODACY_USERNAME: gregoranders + CODACY_PROJECT_NAME: "com.github.gregoranders.template" + run: bash <(curl -Ls https://coverage.codacy.com/get.sh) report -l Java -r "${{github.workspace}}/build/reports/jacoco/jacocoTestReport.xml" - name: Execute build run: ./gradlew --info --stacktrace build - name: Execute jlink From cd5c034e44505e984596289b1ccaab2596613ee3 Mon Sep 17 00:00:00 2001 From: Gregor Anders Date: Mon, 27 Dec 2021 19:09:01 +0100 Subject: [PATCH 12/16] [#1] Workflows Adds workflows for development/feature branches Signed-off-by: Gregor Anders --- .codeclimate.yml | 16 +++ .editorconfig | 26 +++++ .github/workflows/codacy-analysis.yml | 42 +++++++ .github/workflows/development.yml | 105 ++++++++++++++++++ .github/workflows/feature.yml | 64 +++++++++++ .github/workflows/master.yml | 99 +++++++++++++++++ .github/workflows/{gradle.yml => release.yml} | 0 README.md | 54 ++++++++- 8 files changed, 404 insertions(+), 2 deletions(-) create mode 100644 .codeclimate.yml create mode 100644 .editorconfig create mode 100644 .github/workflows/codacy-analysis.yml create mode 100644 .github/workflows/development.yml create mode 100644 .github/workflows/feature.yml create mode 100644 .github/workflows/master.yml rename .github/workflows/{gradle.yml => release.yml} (100%) diff --git a/.codeclimate.yml b/.codeclimate.yml new file mode 100644 index 0000000..c681fc0 --- /dev/null +++ b/.codeclimate.yml @@ -0,0 +1,16 @@ +version: '2' +plugins: + editorconfig: + enabled: true + fixme: + enabled: true + git-legal: + enabled: true +exclude_patterns: + - '**/.github' + - '**/.circleci' + - '**/.vscode' + - '**/build' + - '**/temp' + - '**/test' + - '**/docs' diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..ab19a94 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,26 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# editorconfig.org + +root = true + +[*] + +# Change these settings to your own preference +indent_style = space +indent_size = 2 + +# We recommend you to keep these unchanged +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false + +[*.java] +indent_size = 4 + +[*.groovy] +indent_size = 4 diff --git a/.github/workflows/codacy-analysis.yml b/.github/workflows/codacy-analysis.yml new file mode 100644 index 0000000..c6f335a --- /dev/null +++ b/.github/workflows/codacy-analysis.yml @@ -0,0 +1,42 @@ +# This workflow checks out code, performs a Codacy security scan +# and integrates the results with the +# GitHub Advanced Security code scanning feature. For more information on +# the Codacy security scan action usage and parameters, see +# https://github.com/codacy/codacy-analysis-cli-action. +# For more information on Codacy Analysis CLI in general, see +# https://github.com/codacy/codacy-analysis-cli. + +name: Codacy Security Scan + +on: + push: + branches: [ master, development ] + pull_request: + branches: [ master, development ] + +jobs: + codacy-security-scan: + name: Codacy Security Scan + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + with: + submodules: recursive + - name: Run Codacy Analysis CLI + uses: codacy/codacy-analysis-cli-action@master + with: + project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} + verbose: true + output: results.sarif + format: sarif + # Adjust severity of non-security issues + gh-code-scanning-compat: true + # Force 0 exit code to allow SARIF file generation + # This will handover control about PR rejection to the GitHub side + max-allowed-issues: 2147483647 + - name: Upload SARIF results file + uses: github/codeql-action/upload-sarif@v1 + with: + sarif_file: results.sarif diff --git a/.github/workflows/development.yml b/.github/workflows/development.yml new file mode 100644 index 0000000..db77c13 --- /dev/null +++ b/.github/workflows/development.yml @@ -0,0 +1,105 @@ +name: Development CI +on: + push: + branches: + - development + +env: + CI: true + GITHUB_BRANCH: ${{ github.ref }} + GITHUB_HEAD_REF: ${{ github.head_ref }} + GITHUB_BASE_REF: ${{ github.base_ref }} + GITHUB_COMMIT: ${{ github.sha }} + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macOS-latest, windows-latest] + java: [ '17.0.1' ] + fail-fast: false + name: ${{ matrix.os }} JDK ${{ matrix.java }} + steps: + - name: Git checkout + uses: actions/checkout@v2 + - name: Set up JDK + uses: actions/setup-java@v1 + with: + java-version: ${{ matrix.java }} + - name: Echo JAVA_HOME + run: echo $JAVA_HOME + - name: Verify Gradle Wrapper + uses: gradle/wrapper-validation-action@v1 + - name: Execute clean + run: ./gradlew --info --stacktrace clean + - name: Execute check + run: ./gradlew --info --stacktrace check + - name: Execute test + run: ./gradlew --info --stacktrace test + - name: Publish code coverage to codeclimate + if: matrix.os == 'ubuntu-latest' + uses: paambaati/codeclimate-action@v3.0.0 + env: + CC_TEST_REPORTER_ID: ${{secrets.CC_TEST_REPORTER_ID}} + JACOCO_SOURCE_PATH: "${{github.workspace}}/src/main/java" + with: + coverageCommand: ./gradlew --info --stacktrace check + coverageLocations: ${{github.workspace}}/build/reports/jacoco/jacocoTestReport.xml:jacoco + - name: Publish code coverage to coveralls + if: matrix.os == 'ubuntu-latest' + env: + COVERALLS_REPO_TOKEN: ${{secrets.COVERALLS_REPO_TOKEN}} + run: ./gradlew --info --stacktrace jacocoTestReport coveralls + - name: Publish code coverage to codacy + if: matrix.os == 'ubuntu-latest' + env: + CODACY_PROJECT_TOKEN: ${{secrets.CODACY_PROJECT_TOKEN}} + CODACY_ORGANIZATION_PROVIDER: gh + CODACY_USERNAME: gregoranders + CODACY_PROJECT_NAME: "com.github.gregoranders.template" + run: bash <(curl -Ls https://coverage.codacy.com/get.sh) report -l Java -r "${{github.workspace}}/build/reports/jacoco/jacocoTestReport.xml" + - name: Execute build + run: ./gradlew --info --stacktrace build + - name: Execute jlink + run: ./gradlew --info --stacktrace jlink + - name: Execute jlinkZip + run: ./gradlew --info --stacktrace jlinkZip + - name: Execute jpackage + run: ./gradlew --info --stacktrace jpackage + - name: Upload DMG as an artifact + if: matrix.os == 'macOS-latest' + uses: actions/upload-artifact@v2 + with: + name: template-jdk${{ matrix.java }}-${{ matrix.os }}-dmg + path: build/jpackage/*.dmg + - name: Upload EXE as an artifact + if: matrix.os == 'windows-latest' + uses: actions/upload-artifact@v2 + with: + name: template-jdk${{ matrix.java }}-${{ matrix.os }}-exe + path: build/jpackage/*.exe + - name: Upload MSI as an artifact + if: matrix.os == 'windows-latest' + uses: actions/upload-artifact@v2 + with: + name: template-jdk${{ matrix.java }}-${{ matrix.os }}-msi + path: build/jpackage/*.msi + - name: Upload DEB as an artifact + if: matrix.os == 'ubuntu-latest' + uses: actions/upload-artifact@v2 + with: + name: template-jdk${{ matrix.java }}-${{ matrix.os }}-deb + path: build/jpackage/*.deb + - name: Upload RPM as an artifact + if: matrix.os == 'ubuntu-latest' + uses: actions/upload-artifact@v2 + with: + name: template-jdk${{ matrix.java }}-${{ matrix.os }}-rpm + path: build/jpackage/*.rpm + - name: Upload ZIP as an artifact + if: matrix.os == 'ubuntu-latest' + uses: actions/upload-artifact@v2 + with: + name: template-jdk${{ matrix.java }}-${{ matrix.os }}-zip + path: build/distributions/*.zip diff --git a/.github/workflows/feature.yml b/.github/workflows/feature.yml new file mode 100644 index 0000000..897de8f --- /dev/null +++ b/.github/workflows/feature.yml @@ -0,0 +1,64 @@ +name: Feature CI + +on: + push: + branches: + - feature/* + +env: + CI: true + GITHUB_BRANCH: ${{ github.ref }} + GITHUB_HEAD_REF: ${{ github.head_ref }} + GITHUB_BASE_REF: ${{ github.base_ref }} + GITHUB_COMMIT: ${{ github.sha }} + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macOS-latest, windows-latest] + java: [ '17.0.1' ] + fail-fast: false + name: ${{ matrix.os }} JDK ${{ matrix.java }} + steps: + - name: Git checkout + uses: actions/checkout@v2 + - name: Set up JDK + uses: actions/setup-java@v1 + with: + java-version: ${{ matrix.java }} + - name: Echo JAVA_HOME + run: echo $JAVA_HOME + - name: Verify Gradle Wrapper + uses: gradle/wrapper-validation-action@v1 + - name: Execute clean + run: ./gradlew --info --stacktrace clean + - name: Execute check + run: ./gradlew --info --stacktrace check + - name: Execute test + run: ./gradlew --info --stacktrace test + - name: Publish code coverage to codeclimate + if: matrix.os == 'ubuntu-latest' + uses: paambaati/codeclimate-action@v3.0.0 + env: + CC_TEST_REPORTER_ID: ${{secrets.CC_TEST_REPORTER_ID}} + JACOCO_SOURCE_PATH: "${{github.workspace}}/src/main/java" + with: + coverageCommand: ./gradlew --info --stacktrace check + coverageLocations: ${{github.workspace}}/build/reports/jacoco/jacocoTestReport.xml:jacoco + - name: Publish code coverage to coveralls + if: matrix.os == 'ubuntu-latest' + env: + COVERALLS_REPO_TOKEN: ${{secrets.COVERALLS_REPO_TOKEN}} + run: ./gradlew --info --stacktrace jacocoTestReport coveralls + - name: Publish code coverage to codacy + if: matrix.os == 'ubuntu-latest' + env: + CODACY_PROJECT_TOKEN: ${{secrets.CODACY_PROJECT_TOKEN}} + CODACY_ORGANIZATION_PROVIDER: gh + CODACY_USERNAME: gregoranders + CODACY_PROJECT_NAME: "com.github.gregoranders.template" + run: bash <(curl -Ls https://coverage.codacy.com/get.sh) report -l Java -r "${{github.workspace}}/build/reports/jacoco/jacocoTestReport.xml" + - name: Execute build + run: ./gradlew --info --stacktrace build diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml new file mode 100644 index 0000000..e5a7fbd --- /dev/null +++ b/.github/workflows/master.yml @@ -0,0 +1,99 @@ +name: Master CI + +on: + push: + branches: + - master + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macOS-latest, windows-latest] + java: [ '17.0.1' ] + fail-fast: false + name: ${{ matrix.os }} JDK ${{ matrix.java }} + steps: + - name: Git checkout + uses: actions/checkout@v2 + - name: Set up JDK + uses: actions/setup-java@v1 + with: + java-version: ${{ matrix.java }} + - name: Echo JAVA_HOME + run: echo $JAVA_HOME + - name: Verify Gradle Wrapper + uses: gradle/wrapper-validation-action@v1 + - name: Execute clean + run: ./gradlew --info --stacktrace clean + - name: Execute check + run: ./gradlew --info --stacktrace check + - name: Execute test + run: ./gradlew --info --stacktrace test + - name: Publish code coverage to codeclimate + if: matrix.os == 'ubuntu-latest' + uses: paambaati/codeclimate-action@v3.0.0 + env: + CC_TEST_REPORTER_ID: ${{secrets.CC_TEST_REPORTER_ID}} + JACOCO_SOURCE_PATH: "${{github.workspace}}/src/main/java" + with: + coverageCommand: ./gradlew --info --stacktrace check + coverageLocations: ${{github.workspace}}/build/reports/jacoco/jacocoTestReport.xml:jacoco + - name: Publish code coverage to coveralls + if: matrix.os == 'ubuntu-latest' + env: + COVERALLS_REPO_TOKEN: ${{secrets.COVERALLS_REPO_TOKEN}} + run: ./gradlew --info --stacktrace jacocoTestReport coveralls + - name: Publish code coverage to codacy + if: matrix.os == 'ubuntu-latest' + env: + CODACY_PROJECT_TOKEN: ${{secrets.CODACY_PROJECT_TOKEN}} + CODACY_ORGANIZATION_PROVIDER: gh + CODACY_USERNAME: gregoranders + CODACY_PROJECT_NAME: "com.github.gregoranders.template" + run: bash <(curl -Ls https://coverage.codacy.com/get.sh) report -l Java -r "${{github.workspace}}/build/reports/jacoco/jacocoTestReport.xml" + - name: Execute build + run: ./gradlew --info --stacktrace build + - name: Execute jlink + run: ./gradlew --info --stacktrace jlink + - name: Execute jlinkZip + run: ./gradlew --info --stacktrace jlinkZip + - name: Execute jpackage + run: ./gradlew --info --stacktrace jpackage + - name: Upload DMG as an artifact + if: matrix.os == 'macOS-latest' + uses: actions/upload-artifact@v2 + with: + name: template-jdk${{ matrix.java }}-${{ matrix.os }}-dmg + path: build/jpackage/*.dmg + - name: Upload EXE as an artifact + if: matrix.os == 'windows-latest' + uses: actions/upload-artifact@v2 + with: + name: template-jdk${{ matrix.java }}-${{ matrix.os }}-exe + path: build/jpackage/*.exe + - name: Upload MSI as an artifact + if: matrix.os == 'windows-latest' + uses: actions/upload-artifact@v2 + with: + name: template-jdk${{ matrix.java }}-${{ matrix.os }}-msi + path: build/jpackage/*.msi + - name: Upload DEB as an artifact + if: matrix.os == 'ubuntu-latest' + uses: actions/upload-artifact@v2 + with: + name: template-jdk${{ matrix.java }}-${{ matrix.os }}-deb + path: build/jpackage/*.deb + - name: Upload RPM as an artifact + if: matrix.os == 'ubuntu-latest' + uses: actions/upload-artifact@v2 + with: + name: template-jdk${{ matrix.java }}-${{ matrix.os }}-rpm + path: build/jpackage/*.rpm + - name: Upload ZIP as an artifact + if: matrix.os == 'ubuntu-latest' + uses: actions/upload-artifact@v2 + with: + name: template-jdk${{ matrix.java }}-${{ matrix.os }}-zip + path: build/distributions/*.zip diff --git a/.github/workflows/gradle.yml b/.github/workflows/release.yml similarity index 100% rename from .github/workflows/gradle.yml rename to .github/workflows/release.yml diff --git a/README.md b/README.md index 1a7fa18..7bea659 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,56 @@ # JAVA Template +[![License][license-image]][license-url] +[![Issues][issues-image]][issues-url] +[![Code maintainability][code-maintainability-image]][code-maintainability-url] [![Code issues][code-issues-image]][code-issues-url] [![Code Technical Debt][code-tech-debt-image]][code-tech-debt-url] + +[![Codacy Badge][codacy-image]][codacy-url] + +[![Main Language][language-image]][code-metric-url] [![Languages][languages-image]][code-metric-url] [![Code Size][code-size-image]][code-metric-url] [![Repo-Size][repo-size-image]][code-metric-url] + ## Features -- Gradle -- GitHub CI Integration \ No newline at end of file + - Gradle + - GitHub CI Integration (feature, development, master, release) + - Code Quality via Code Climate and Codacy + +| GitHub | Coveralls | | +|------------------------------------------------------------------|----------------------------------------------------------------------------|------------------------------------------------------------------------------| +| [![ReleaseMaster Build][release-build-image]][release-url] | | [![Release][release-image]][release-url] | +| [![Master Build][master-build-image]][master-url] | [![Master Coverage][master-coveralls-image]][master-coveralls-url] | [![Master Version][master-version-image]][master-version-url] | +| [![Development Build][development-build-image]][development-url] | [![Test Coverage][development-coveralls-image]][development-coveralls-url] | [![Development Version][development-version-image]][development-version-url] | + + +[release-url]: https://github.com/gregoranders/com.github.gregoranders.template/releases +[master-url]: https://github.com/gregoranders/com.github.gregoranders.template/tree/master +[development-url]: https://github.com/gregoranders/com.github.gregoranders.template/tree/development +[repository-url]: https://github.com/gregoranders/com.github.gregoranders.template +[code-metric-url]: https://github.com/gregoranders/com.github.gregoranders.template/search?l=JAVA +[license-url]: https://github.com/gregoranders/com.github.gregoranders.template/blob/master/LICENSE +[license-image]: https://img.shields.io/github/license/gregoranders/com.github.gregoranders.template.svg +[master-version-url]: https://github.com/gregoranders/com.github.gregoranders.template/blob/master/package.json +[master-version-image]: https://img.shields.io/github/package-json/v/gregoranders/com.github.gregoranders.template/master +[development-version-url]: https://github.com/gregoranders/com.github.gregoranders.template/blob/development/package.json +[development-version-image]: https://img.shields.io/github/package-json/v/gregoranders/com.github.gregoranders.template/development +[issues-url]: https://github.com/gregoranders/com.github.gregoranders.template/issues +[issues-image]: https://img.shields.io/github/issues-raw/gregoranders/com.github.gregoranders.template.svg +[release-image]: https://img.shields.io/github/release/gregoranders/com.github.gregoranders.template +[release-build-image]: https://github.com/gregoranders/com.github.gregoranders.template/workflows/Release%20CI/badge.svg +[master-build-image]: https://github.com/gregoranders/com.github.gregoranders.template/workflows/Master%20CI/badge.svg +[development-build-image]: https://github.com/gregoranders/com.github.gregoranders.template/workflows/Development%20CI/badge.svg +[master-coveralls-url]: https://coveralls.io/github/gregoranders/com.github.gregoranders.template?branch=master +[master-coveralls-image]: https://img.shields.io/coveralls/github/gregoranders/com.github.gregoranders.template/master +[development-coveralls-image]: https://img.shields.io/coveralls/github/gregoranders/com.github.gregoranders.template/development +[development-coveralls-url]: https://coveralls.io/github/gregoranders/com.github.gregoranders.template?branch=development +[code-maintainability-url]: https://codeclimate.com/github/gregoranders/com.github.gregoranders.template/maintainability +[code-maintainability-image]: https://img.shields.io/codeclimate/maintainability/gregoranders/com.github.gregoranders.template +[code-issues-url]: https://codeclimate.com/github/gregoranders/com.github.gregoranders.template/maintainability +[code-issues-image]: https://img.shields.io/codeclimate/issues/gregoranders/com.github.gregoranders.template +[code-tech-debt-url]: https://codeclimate.com/github/gregoranders/com.github.gregoranders.template/maintainability +[code-tech-debt-image]: https://img.shields.io/codeclimate/tech-debt/gregoranders/com.github.gregoranders.template +[language-image]: https://img.shields.io/github/languages/top/gregoranders/com.github.gregoranders.template +[languages-image]: https://img.shields.io/github/languages/count/gregoranders/com.github.gregoranders.template +[code-size-image]: https://img.shields.io/github/languages/code-size/gregoranders/com.github.gregoranders.template +[repo-size-image]: https://img.shields.io/github/repo-size/gregoranders/com.github.gregoranders.template +[codacy-image]: https://app.codacy.com/project/badge/Grade/ba567567ab7c45eeab91ca4fe03011d4 +[codacy-url]: https://www.codacy.com/manual/gregoranders/com.github.gregoranders.template From cf01cb4d6aaa40eb4c58f40d015f879480594f58 Mon Sep 17 00:00:00 2001 From: Gregor Anders Date: Mon, 27 Dec 2021 19:27:43 +0100 Subject: [PATCH 13/16] [#1] Workflows Adds release workflow Signed-off-by: Gregor Anders --- .github/workflows/release.yml | 118 ++++++++++++++++++++-------------- 1 file changed, 70 insertions(+), 48 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f1171d9..29f4b8e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,6 +1,16 @@ -name: Gradle Build +name: Release CI -on: [push, pull_request] +on: + push: + tags: + - 'v*' + +env: + CI: true + GITHUB_BRANCH: ${{ github.ref }} + GITHUB_HEAD_REF: ${{ github.head_ref }} + GITHUB_BASE_REF: ${{ github.base_ref }} + GITHUB_COMMIT: ${{ github.sha }} jobs: build: @@ -28,28 +38,6 @@ jobs: run: ./gradlew --info --stacktrace check - name: Execute test run: ./gradlew --info --stacktrace test - - name: Publish code coverage to codeclimate - if: matrix.os == 'ubuntu-latest' - uses: paambaati/codeclimate-action@v3.0.0 - env: - CC_TEST_REPORTER_ID: ${{secrets.CC_TEST_REPORTER_ID}} - JACOCO_SOURCE_PATH: "${{github.workspace}}/src/main/java" - with: - coverageCommand: ./gradlew --info --stacktrace check - coverageLocations: ${{github.workspace}}/build/reports/jacoco/jacocoTestReport.xml:jacoco - - name: Publish code coverage to coveralls - if: matrix.os == 'ubuntu-latest' - env: - COVERALLS_REPO_TOKEN: ${{secrets.COVERALLS_REPO_TOKEN}} - run: ./gradlew --info --stacktrace jacocoTestReport coveralls - - name: Publish code coverage to codacy - if: matrix.os == 'ubuntu-latest' - env: - CODACY_PROJECT_TOKEN: ${{secrets.CODACY_PROJECT_TOKEN}} - CODACY_ORGANIZATION_PROVIDER: gh - CODACY_USERNAME: gregoranders - CODACY_PROJECT_NAME: "com.github.gregoranders.template" - run: bash <(curl -Ls https://coverage.codacy.com/get.sh) report -l Java -r "${{github.workspace}}/build/reports/jacoco/jacocoTestReport.xml" - name: Execute build run: ./gradlew --info --stacktrace build - name: Execute jlink @@ -58,39 +46,73 @@ jobs: run: ./gradlew --info --stacktrace jlinkZip - name: Execute jpackage run: ./gradlew --info --stacktrace jpackage - - name: Upload DMG as an artifact + - name: Create Release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref }} + release_name: Release ${{ github.ref }} + draft: false + prerelease: false + - name: Upload DMG Release Asset if: matrix.os == 'macOS-latest' - uses: actions/upload-artifact@v2 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - name: template-jdk${{ matrix.java }}-${{ matrix.os }}-dmg - path: build/jpackage/*.dmg - - name: Upload EXE as an artifact + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: build/jpackage/*.dmg + asset_name: template-jdk${{ matrix.java }}-${{ matrix.os }}-dmg + asset_content_type: application/dmg + - name: Upload EXE Release Asset if: matrix.os == 'windows-latest' - uses: actions/upload-artifact@v2 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - name: template-jdk${{ matrix.java }}-${{ matrix.os }}-exe - path: build/jpackage/*.exe - - name: Upload MSI as an artifact + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: build/jpackage/*.exe + asset_name: template-jdk${{ matrix.java }}-${{ matrix.os }}-exe + asset_content_type: application/exe + - name: Upload MSI Release Asset if: matrix.os == 'windows-latest' - uses: actions/upload-artifact@v2 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - name: template-jdk${{ matrix.java }}-${{ matrix.os }}-msi - path: build/jpackage/*.msi - - name: Upload DEB as an artifact + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: build/jpackage/*.msi + asset_name: template-jdk${{ matrix.java }}-${{ matrix.os }}-msi + asset_content_type: application/msi + - name: Upload DEB Release Asset if: matrix.os == 'ubuntu-latest' - uses: actions/upload-artifact@v2 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - name: template-jdk${{ matrix.java }}-${{ matrix.os }}-deb - path: build/jpackage/*.deb - - name: Upload RPM as an artifact + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: build/jpackage/*.deb + asset_name: template-jdk${{ matrix.java }}-${{ matrix.os }}-deb + asset_content_type: application/deb + - name: Upload RPM Release Asset if: matrix.os == 'ubuntu-latest' - uses: actions/upload-artifact@v2 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - name: template-jdk${{ matrix.java }}-${{ matrix.os }}-rpm - path: build/jpackage/*.rpm - - name: Upload ZIP as an artifact + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: build/jpackage/*.rpm + asset_name: template-jdk${{ matrix.java }}-${{ matrix.os }}-rpm + asset_content_type: application/rpm + - name: Upload ZIP Release Asset if: matrix.os == 'ubuntu-latest' - uses: actions/upload-artifact@v2 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - name: template-jdk${{ matrix.java }}-${{ matrix.os }}-zip - path: build/distributions/*.zip + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: build/distributions/*.zip + asset_name: template-jdk${{ matrix.java }}-${{ matrix.os }}-zip + asset_content_type: application/zip From 5ddcd3a7d578c15192c8f72a24430c4c4b5b2bf7 Mon Sep 17 00:00:00 2001 From: Gregor Anders Date: Mon, 27 Dec 2021 19:38:50 +0100 Subject: [PATCH 14/16] [#1] Code Quality fixes Adds gradle, gradlew and gradlew.bat to ignored files for CodeClimate. Signed-off-by: Gregor Anders --- .codeclimate.yml | 3 +++ LICENSE | 2 +- buildSrc/build.gradle | 2 +- config/checkstyle/checkstyle-header.txt | 2 +- config/checkstyle/checkstyle.xml | 2 +- src/main/java/module-info.java | 2 +- src/main/resources/logback.xml | 2 +- 7 files changed, 9 insertions(+), 6 deletions(-) diff --git a/.codeclimate.yml b/.codeclimate.yml index c681fc0..0a980f6 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -14,3 +14,6 @@ exclude_patterns: - '**/temp' - '**/test' - '**/docs' + - '**/gradle' + - '**/gradlew' + - '**/gradlew.bat' diff --git a/LICENSE b/LICENSE index 6102f85..68dbfb9 100644 --- a/LICENSE +++ b/LICENSE @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file +SOFTWARE. diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index a89a0cc..c8b4152 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -9,4 +9,4 @@ dependencies { implementation( gradleApi() ) -} \ No newline at end of file +} diff --git a/config/checkstyle/checkstyle-header.txt b/config/checkstyle/checkstyle-header.txt index d0eebe7..81dd0da 100644 --- a/config/checkstyle/checkstyle-header.txt +++ b/config/checkstyle/checkstyle-header.txt @@ -20,4 +20,4 @@ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. - */ \ No newline at end of file + */ diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 31dbea0..f015743 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -167,4 +167,4 @@ name="file" value="${checkstyle.suppressions.file}"/> - \ No newline at end of file + diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 267b78f..7a04fec 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -23,4 +23,4 @@ */ module com.github.gregoranders.template { requires org.slf4j; -} \ No newline at end of file +} diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index 49ca6d0..78409bb 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -31,4 +31,4 @@ - \ No newline at end of file + From 8a76fa4fd909898a4489d7d34b63d2456e4e4b32 Mon Sep 17 00:00:00 2001 From: Gregor Anders Date: Mon, 27 Dec 2021 19:46:02 +0100 Subject: [PATCH 15/16] [#1] Code Quality fixes Adds more fixes according to issues reported be codacy and codeclimate. Signed-off-by: Gregor Anders --- .codacy.yml | 25 +++++++++++++++++++ .codeclimate.yml | 1 + .../dependency-check-suppressions.xml | 2 +- settings.gradle | 2 +- .../gregoranders/template/package-info.java | 2 +- 5 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 .codacy.yml diff --git a/.codacy.yml b/.codacy.yml new file mode 100644 index 0000000..2fa0a9d --- /dev/null +++ b/.codacy.yml @@ -0,0 +1,25 @@ +--- +engines: + duplication: + exclude_paths: + - config/engines.yml + metric: + exclude_paths: + - config/engines.yml + remark-int: + exclude_paths: + - config/engines.yml + coverage: + exclude_paths: + - config/engines.yml +exclude_paths: + - '.circleci/**' + - '.github/**' + - '.vscode/**' + - 'gradle/**' + - 'gradlew' + - 'gradlew.bat' + - 'config/**' + - '**.json' + - '**.yml' + - '**.md' diff --git a/.codeclimate.yml b/.codeclimate.yml index 0a980f6..62777a8 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -17,3 +17,4 @@ exclude_patterns: - '**/gradle' - '**/gradlew' - '**/gradlew.bat' + - '**/config' diff --git a/config/dependency-check/dependency-check-suppressions.xml b/config/dependency-check/dependency-check-suppressions.xml index 8016195..0429eff 100644 --- a/config/dependency-check/dependency-check-suppressions.xml +++ b/config/dependency-check/dependency-check-suppressions.xml @@ -30,4 +30,4 @@ ^pkg:maven/commons\-io/commons\-io@.*$ CVE-2021-29425 - \ No newline at end of file + diff --git a/settings.gradle b/settings.gradle index 48a1fe1..0c6ea29 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,4 +5,4 @@ pluginManagement { } } -rootProject.name = "template" \ No newline at end of file +rootProject.name = "template" diff --git a/src/main/java/com/github/gregoranders/template/package-info.java b/src/main/java/com/github/gregoranders/template/package-info.java index 0f56e48..28bd69a 100644 --- a/src/main/java/com/github/gregoranders/template/package-info.java +++ b/src/main/java/com/github/gregoranders/template/package-info.java @@ -24,4 +24,4 @@ /** * Main entry point */ -package com.github.gregoranders.template; \ No newline at end of file +package com.github.gregoranders.template; From 96293fc516902ba5a6cded5eb31a693f7b41bc7d Mon Sep 17 00:00:00 2001 From: Gregor Anders Date: Mon, 27 Dec 2021 19:50:53 +0100 Subject: [PATCH 16/16] [#1] Code Quality fixes Adds more fixes according to issues reported be codacy and codeclimate. Signed-off-by: Gregor Anders --- .codacy.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.codacy.yml b/.codacy.yml index 2fa0a9d..59e5c74 100644 --- a/.codacy.yml +++ b/.codacy.yml @@ -20,6 +20,7 @@ exclude_paths: - 'gradlew' - 'gradlew.bat' - 'config/**' + - '**Spec.groovy' - '**.json' - '**.yml' - '**.md'