diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..6ef5d69 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,26 @@ +root = true + +[*] +trim_trailing_whitespace = true +insert_final_newline = true +charset = utf-8 +indent_style = space + +[{*.sh,gradlew}] +end_of_line = lf + +[{*.bat,*.cmd}] +end_of_line = crlf + +[{*.mustache,*.ftl}] +insert_final_newline = false + +[*.java] +indent_size = 4 +tab_width = 4 +max_line_length = 100 +# Import order can be configured with ij_java_imports_layout=... +# See documentation https://youtrack.jetbrains.com/issue/IDEA-170643#focus=streamItem-27-3708697.0-0 + +[*.xml] +indent_size = 4 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..2603050 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,22 @@ +# Auto detect text files and perform LF normalization +* text=auto + +*.java text eol=lf +*.groovy text eol=lf +*.html text eol=lf +*.kt text eol=lf +*.kts text eol=lf +*.md text diff=markdown eol=lf +*.py text diff=python executable +*.pl text diff=perl executable +*.pm text diff=perl +*.css text diff=css eol=lf +*.js text eol=lf +*.sql text eol=lf +*.q text eol=lf + +*.sh text eol=lf +gradlew text eol=lf + +*.bat text eol=crlf +*.cmd text eol=crlf diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml new file mode 100644 index 0000000..b30eafc --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -0,0 +1,59 @@ +name: Bug Report +description: File a bug report +body: + - type: markdown + attributes: + value: | + Thanks for reporting an issue, please review the task list below before submitting the issue. Your issue report will be closed if the issue is incomplete and the below tasks not completed. + + NOTE: If you are unsure about something and the issue is more of a question a better place to ask questions is on Github Discussions :arrow_up:, [Stack Overflow](https://stackoverflow.com/tags/micronaut) or [Gitter](https://gitter.im/micronautfw/). + - type: textarea + attributes: + label: Expected Behavior + description: A concise description of what you expected to happen. + placeholder: Tell us what should happen + validations: + required: false + - type: textarea + attributes: + label: Actual Behaviour + description: A concise description of what you're experiencing. + placeholder: Tell us what happens instead + validations: + required: false + - type: textarea + attributes: + label: Steps To Reproduce + description: Steps to reproduce the behavior. + placeholder: | + 1. In this environment... + 2. With this config... + 3. Run '...' + 4. See error... + validations: + required: false + - type: textarea + attributes: + label: Environment Information + description: Environment information where the problem occurs. + placeholder: | + - Operating System: + - JDK Version: + validations: + required: false + - type: input + id: example + attributes: + label: Example Application + description: Example application link. + placeholder: | + Link to GitHub repository with an example that reproduces the issue + validations: + required: false + - type: input + id: version + attributes: + label: Version + description: Micronaut version + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..e9d4552 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,13 @@ +contact_links: + - name: Micronaut Core Discussions + url: https://github.com/micronaut-projects/micronaut-core/discussions + about: Ask questions about Micronaut on Github + - name: Micronaut Data Discussions + url: https://github.com/micronaut-projects/micronaut-data/discussions + about: Ask Micronaut Data related questions on Github + - name: Stack Overflow + url: https://stackoverflow.com/tags/micronaut + about: Ask questions on Stack Overflow + - name: Chat + url: https://gitter.im/micronautfw/ + about: Chat with us on Gitter. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index bbcbbe7..0000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: '' -assignees: '' - ---- - -**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/ISSUE_TEMPLATE/new_feature.yaml b/.github/ISSUE_TEMPLATE/new_feature.yaml new file mode 100644 index 0000000..9bc2b1c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/new_feature.yaml @@ -0,0 +1,13 @@ +name: Feature request +description: Create a new feature request +body: + - type: markdown + attributes: + value: | + Please describe the feature you want for Micronaut to implement, before that check if there is already an existing issue to add it. + - type: textarea + attributes: + label: Feature description + placeholder: Tell us what feature you would like for Micronaut to have and what problem is it going to solve + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/other.yaml b/.github/ISSUE_TEMPLATE/other.yaml new file mode 100644 index 0000000..9bc2b1c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/other.yaml @@ -0,0 +1,13 @@ +name: Feature request +description: Create a new feature request +body: + - type: markdown + attributes: + value: | + Please describe the feature you want for Micronaut to implement, before that check if there is already an existing issue to add it. + - type: textarea + attributes: + label: Feature description + placeholder: Tell us what feature you would like for Micronaut to have and what problem is it going to solve + validations: + required: true diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 3073906..0000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,16 +0,0 @@ -version: 2 -updates: - - package-ecosystem: "gradle" - directory: "/" - schedule: - interval: "daily" - labels: - - "type: dependency-upgrade" - - "relates-to: build" - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "daily" - labels: - - "type: dependency-upgrade" - - "relates-to: build" \ No newline at end of file diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 0000000..a890b25 --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,33 @@ +changelog: + exclude: + authors: + - micronaut-build + categories: + - title: Breaking Changes 🛠 + labels: + - 'type: breaking' + - title: New Features 🎉 + labels: + - 'type: enhancement' + - title: Bug Fixes 🐞 + labels: + - 'type: bug' + - title: Improvements ⭐ + labels: + - 'type: improvement' + - title: Docs 📖 + labels: + - 'type: docs' + - title: Dependency updates 🚀 + labels: + - 'type: dependency-upgrade' + - 'dependency-upgrade' + - title: Regressions 🧐 + labels: + - 'type: regression' + - title: GraalVM 🏆 + labels: + - 'relates-to: graal' + - title: Other Changes 💡 + labels: + - "*" diff --git a/.github/renovate.json b/.github/renovate.json new file mode 100644 index 0000000..09c2a59 --- /dev/null +++ b/.github/renovate.json @@ -0,0 +1,26 @@ +{ + "extends": [ + "config:base" + ], + "addLabels": ["type: dependency-upgrade"], + "schedule": [ + "after 10pm every day" + ], + "prHourlyLimit": 1, + "prConcurrentLimit": 20, + "timezone": "Europe/Prague", + "packageRules": [ + { + "matchPackagePatterns": ["actions.*"], + "dependencyDashboardApproval": true, + "matchUpdateTypes": ["patch"], + "matchCurrentVersion": "!/^0/", + "automerge": true + }, + { + "matchUpdateTypes": ["patch"], + "matchCurrentVersion": "!/^0/", + "automerge": true + } + ] +} diff --git a/.github/workflows/.rsync-filter b/.github/workflows/.rsync-filter index ebd3041..691f3a1 100644 --- a/.github/workflows/.rsync-filter +++ b/.github/workflows/.rsync-filter @@ -1,4 +1,5 @@ - files-sync.yml - test-files-sync.yml - update-gradle-wrapper.yml -- .rsync-filter \ No newline at end of file +- .rsync-filter +- template-cleanup.yml diff --git a/.github/workflows/bintray-publish.yml b/.github/workflows/bintray-publish.yml deleted file mode 100644 index 80f9abb..0000000 --- a/.github/workflows/bintray-publish.yml +++ /dev/null @@ -1,31 +0,0 @@ -# WARNING: Do not edit this file directly. Instead, go to: -# -# https://github.com/micronaut-projects/micronaut-project-template/tree/master/.github/workflows -# -# and edit them there. Note that it will be sync'ed to all the Micronaut repos -name: Bintray Publish -on: - workflow_dispatch: - inputs: - release_version: - description: 'Release version (eg: 1.2.3)' - required: true -jobs: - release: - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v3 - with: - token: ${{ secrets.GH_TOKEN }} - ref: v${{ github.event.inputs.release_version }} - - uses: gradle/wrapper-validation-action@v1 - - name: Set up JDK - uses: actions/setup-java@v3 - with: - java-version: 1.8 - - name: Publish to Bintray - env: - BINTRAY_USER: ${{ secrets.BINTRAY_USER }} - BINTRAY_KEY: ${{ secrets.BINTRAY_KEY }} - run: ./gradlew bintrayPublish diff --git a/.github/workflows/central-sync.yml b/.github/workflows/central-sync.yml index 130c25c..23b80ba 100644 --- a/.github/workflows/central-sync.yml +++ b/.github/workflows/central-sync.yml @@ -15,14 +15,15 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: v${{ github.event.inputs.release_version }} - - uses: gradle/wrapper-validation-action@v1 + - uses: gradle/wrapper-validation-action@v3 - name: Set up JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: - java-version: 1.8 + distribution: 'temurin' + java-version: '17' - name: Publish to Sonatype OSSRH env: SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} @@ -30,11 +31,9 @@ jobs: GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }} GPG_PASSWORD: ${{ secrets.GPG_PASSWORD }} GPG_FILE: ${{ secrets.GPG_FILE }} - PUBLISH_IN_2_STEPS: ${{ secrets.PUBLISH_IN_2_STEPS }} + GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} + GRADLE_ENTERPRISE_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USERNAME }} + GRADLE_ENTERPRISE_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }} run: | echo $GPG_FILE | base64 -d > secring.gpg - if [ -z ${PUBLISH_IN_2_STEPS+x} ]; then - ./gradlew publish closeAndReleaseRepository - else - ./gradlew publish && ./gradlew closeAndReleaseRepository - fi + ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository diff --git a/.github/workflows/dependency-update.yml b/.github/workflows/dependency-update.yml deleted file mode 100644 index 21b0f4e..0000000 --- a/.github/workflows/dependency-update.yml +++ /dev/null @@ -1,40 +0,0 @@ -# WARNING: Do not edit this file directly. Instead, go to: -# -# https://github.com/micronaut-projects/micronaut-project-template/tree/master/.github/workflows -# -# and edit them there. Note that it will be sync'ed to all the Micronaut repos -name: Update Dependencies -on: - schedule: - - cron: '0 4 * * MON-FRI' -jobs: - dependency-updates: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/cache@v3 - with: - path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} - restore-keys: | - ${{ runner.os }}-gradle- - - name: Set up JDK - uses: actions/setup-java@v3 - with: - java-version: 1.8 - - name: Export Gradle Properties - uses: micronaut-projects/github-actions/export-gradle-properties@master - - name: Check Dependencies - run: ./gradlew useLatestVersions - - name: Create Pull Request - uses: peter-evans/create-pull-request@v4 - with: - token: ${{ secrets.GH_TOKEN }} - committer: micronaut-build <${{ secrets.MICRONAUT_BUILD_EMAIL }}> - author: micronaut-build <${{ secrets.MICRONAUT_BUILD_EMAIL }}> - commit-message: Update dependencies - title: 'Dependency upgrades' - body: Upgrades dependencies to their latest versions - labels: "type: dependency-upgrade" - base: ${{ env.githubBranch }} - branch: dependency-updates \ No newline at end of file diff --git a/.github/workflows/files-sync.yml b/.github/workflows/files-sync.yml index 76d6661..3f92ed8 100644 --- a/.github/workflows/files-sync.yml +++ b/.github/workflows/files-sync.yml @@ -1,152 +1,153 @@ name: Files sync on: - push: - branches: - - master + schedule: + - cron: '0 5 * * *' jobs: sync-files: if: github.repository == 'micronaut-projects/micronaut-project-template' runs-on: ubuntu-latest strategy: + fail-fast: false + max-parallel: 3 matrix: repo: - acme + - aot - aws - azure - cache - cassandra + - chatbots + - coherence + - control-panel - core - - couchbase + - crac - data - discovery-client + - eclipsestore - elasticsearch + - email - flyway + - fuzzing - gcp - - gradle-plugin - graphql - groovy + - graal-languages - grpc + - guice - hibernate-validator - - ignite - jackson-xml - jaxrs - jms - jmx + - json-schema - kafka - kotlin - kubernetes + - langchain4j - liquibase + - logging - micrometer + - microstream - mongodb - mqtt + - multitenancy - nats - neo4j - - netflix + - object-storage - openapi + - opensearch - oracle-cloud - picocli + - platform + - problem-json + - pulsar + - r2dbc - rabbitmq - - ratelimiter - reactor - redis - rss - - rxjava1 + - rxjava2 - rxjava3 - security + - serialization - servlet + - session + - sourcegen - spring - sql - test + - test-resources + - toml + - tracing + - validation - views steps: - name: Checkout source - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: source - - name: Checkout target - master - uses: actions/checkout@v3 + - name: Checkout target - default branch + uses: actions/checkout@v4 with: repository: micronaut-projects/micronaut-${{ matrix.repo }} path: target fetch-depth: 0 token: ${{ secrets.GH_TOKEN }} - - name: Determine latest maintenance branch + - name: Determine current branch id: branch working-directory: target run: | - branch=$(git --no-pager branch --list --remote "origin/*" | egrep '[1-9]+\.[0-9]+\.x$' | sed -e "s/.*origin\///" | sort -t. -k 1,1nr -k 2,2nr -k 3,3nr | head -1) - echo "Latest maintenance branch: ${branch}" - echo ::set-output name=branch::${branch} - - name: Checkout target - ${{ steps.branch.outputs.branch }} - if: steps.branch.outputs.branch != '' - uses: actions/checkout@v3 - with: - repository: micronaut-projects/micronaut-${{ matrix.repo }} - path: branch - ref: ${{ steps.branch.outputs.branch }} - token: ${{ secrets.GH_TOKEN }} + branch=$(git rev-parse --abbrev-ref HEAD) + echo "Current branch: ${branch}" + echo "branch=${branch}" >> $GITHUB_OUTPUT - name: Sync workflows run: | mkdir -p target/.github/workflows/ - rsync --verbose --verbose --delete --archive -F "source/.github/workflows/" "target/.github/workflows/" - if [ -d branch ]; then - mkdir -p branch/.github/workflows/ - rsync --verbose --verbose --delete --archive -F "source/.github/workflows/" "branch/.github/workflows/" - fi + rsync --verbose --verbose --archive -F "source/.github/workflows/" "target/.github/workflows/" + rm -f target/.github/dependabot.yml + rm -f target/.github/stale.yml + rm -f target/.github/release-drafter.yml + rm -f target/.github/workflows/release-notes.yml + rm -f target/.github/workflows/dependency-update.yml + rm -f target/.github/workflows/sonarqube.yml - name: Copy files from source to target branches run: | while IFS= read -r file; do - dest="$(dirname $file)" - mkdir -p target/$dest - cp -r source/$file target/$dest - if [ -d branch ]; then - mkdir -p branch/$dest - cp -r source/$file branch/$dest - fi + dest_dirname="$(dirname $file)" + dest_filename="$(basename $file)" + mkdir -p target/$dest_dirname + [ ! -f target/${dest_dirname}/${dest_filename}.lock ] && cp source/$file target/${dest_dirname}/${dest_filename} done <<< "$FILES" env: FILES: |- - .github/dependabot.yml - gradle/* - gradlew* + .editorconfig + .gitattributes .gitignore - ISSUE_TEMPLATE.md + .github/renovate.json + .github/release.yml + .github/ISSUE_TEMPLATE/bug_report.yaml + .github/ISSUE_TEMPLATE/config.yml + .github/ISSUE_TEMPLATE/new_feature.yaml + .github/ISSUE_TEMPLATE/other.yaml + gradle/wrapper/gradle-wrapper.jar + gradle/wrapper/gradle-wrapper.properties + gradlew + gradlew.bat + MAINTAINING.md + SECURITY.md LICENSE config/HEADER config/spotless.license.java config/checkstyle/checkstyle.xml config/checkstyle/suppressions.xml - - name: Create Pull Request - master - uses: peter-evans/create-pull-request@v4 - with: - path: target - token: ${{ secrets.GH_TOKEN }} - committer: micronaut-build <${{ secrets.MICRONAUT_BUILD_EMAIL }}> - author: micronaut-build <${{ secrets.MICRONAUT_BUILD_EMAIL }}> - commit-message: Update common files - title: "[${{ matrix.repo }}] Update common files for branch master" - body: Update common files - labels: "relates-to: build" - branch: sync-files-master - base: master - - - name: Determine whether to skip the branch ${{ steps.branch.outputs.branch }} - if: steps.branch.outputs.branch != '' - id: skip - working-directory: branch - run: | - sudo wget -O /usr/local/bin/yq https://github.com/mikefarah/yq/releases/download/3.3.0/yq_linux_amd64 - sudo chmod +x /usr/local/bin/yq - skip=false - if [ -f .github/micronaut-build.yml ]; then - skip=$(yq r .github/micronaut-build.yml files-sync.skip) - fi - echo ::set-output name=skip::${skip} + - name: Sleep for 3 minutes to avoid rate limiting + run: sleep 180s + shell: bash - name: Create Pull Request - ${{ steps.branch.outputs.branch }} - if: steps.branch.outputs.branch != '' && steps.skip.outputs.skip != 'true' - uses: peter-evans/create-pull-request@v4 + uses: peter-evans/create-pull-request@v7 with: - path: branch + path: target token: ${{ secrets.GH_TOKEN }} committer: micronaut-build <${{ secrets.MICRONAUT_BUILD_EMAIL }}> author: micronaut-build <${{ secrets.MICRONAUT_BUILD_EMAIL }}> @@ -156,6 +157,19 @@ jobs: labels: "relates-to: build" branch: sync-files-${{ steps.branch.outputs.branch }} base: ${{ steps.branch.outputs.branch }} - - - + add-paths: | + .editorconfig + .gitattributes + .gitignore + .github/* + .github/ISSUE_TEMPLATE/* + .github/workflows/* + gradle/* + gradlew* + MAINTAINING.md + SECURITY.md + LICENSE + config/HEADER + config/spotless.license.java + config/checkstyle/checkstyle.xml + config/checkstyle/suppressions.xml diff --git a/.github/workflows/graalvm-dev.yml b/.github/workflows/graalvm-dev.yml new file mode 100644 index 0000000..eb0203b --- /dev/null +++ b/.github/workflows/graalvm-dev.yml @@ -0,0 +1,65 @@ +# WARNING: Do not edit this file directly. Instead, go to: +# +# https://github.com/micronaut-projects/micronaut-project-template/tree/master/.github/workflows +# +# and edit them there. Note that it will be sync'ed to all the Micronaut repos +name: GraalVM Dev CI +on: + schedule: + - cron: "0 1 * * 1-5" # Mon-Fri at 1am UTC +jobs: + build_matrix: + if: github.repository != 'micronaut-projects/micronaut-project-template' + runs-on: ubuntu-latest + env: + GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} + GRADLE_ENTERPRISE_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USERNAME }} + GRADLE_ENTERPRISE_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }} + outputs: + matrix: ${{ steps.build-matrix.outputs.matrix }} + steps: + - uses: actions/checkout@v4 + - name: Build Matrix + uses: micronaut-projects/github-actions/graalvm/build-matrix@master + id: build-matrix + build: + needs: build_matrix + if: github.repository != 'micronaut-projects/micronaut-project-template' + runs-on: ubuntu-latest + strategy: + max-parallel: 6 + matrix: + java: ['dev', 'latest-ea'] + distribution: ['graalvm-community', 'graalvm'] + native_test_task: ${{ fromJson(needs.build_matrix.outputs.matrix).native_test_task }} + exclude: + - java: 'dev' + distribution: 'graalvm' + - java: 'latest-ea' + distribution: 'graalvm-community' + env: + GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} + GRADLE_ENTERPRISE_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USERNAME }} + GRADLE_ENTERPRISE_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }} + steps: + - uses: actions/checkout@v4 + - name: Pre-Build Steps + uses: micronaut-projects/github-actions/graalvm/pre-build@master + id: pre-build + with: + java: ${{ matrix.java }} + distribution: ${{ matrix.distribution }} + - name: Build Steps + uses: micronaut-projects/github-actions/graalvm/build@master + id: build + env: + GH_TOKEN_PUBLIC_REPOS_READONLY: ${{ secrets.GH_TOKEN_PUBLIC_REPOS_READONLY }} + GH_USERNAME: ${{ secrets.GH_USERNAME }} + GRAALVM_QUICK_BUILD: true + with: + nativeTestTask: ${{ matrix.native_test_task }} + - name: Post-Build Steps + uses: micronaut-projects/github-actions/graalvm/post-build@master + id: post-build + with: + java: ${{ matrix.java }} diff --git a/.github/workflows/graalvm-latest.yml b/.github/workflows/graalvm-latest.yml new file mode 100644 index 0000000..d150aa6 --- /dev/null +++ b/.github/workflows/graalvm-latest.yml @@ -0,0 +1,65 @@ +# WARNING: Do not edit this file directly. Instead, go to: +# +# https://github.com/micronaut-projects/micronaut-project-template/tree/master/.github/workflows +# +# and edit them there. Note that it will be sync'ed to all the Micronaut repos +name: GraalVM Latest CI +on: + push: + branches: + - master + - '[1-9]+.[0-9]+.x' + pull_request: + branches: + - master + - '[1-9]+.[0-9]+.x' +jobs: + build_matrix: + if: github.repository != 'micronaut-projects/micronaut-project-template' + runs-on: ubuntu-latest + env: + GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} + GRADLE_ENTERPRISE_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USERNAME }} + GRADLE_ENTERPRISE_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }} + outputs: + matrix: ${{ steps.build-matrix.outputs.matrix }} + steps: + - uses: actions/checkout@v4 + - name: Build Matrix + uses: micronaut-projects/github-actions/graalvm/build-matrix@master + id: build-matrix + build: + needs: build_matrix + if: github.repository != 'micronaut-projects/micronaut-project-template' + runs-on: ubuntu-latest + strategy: + max-parallel: 6 + matrix: + java: ['17', '21'] + native_test_task: ${{ fromJson(needs.build_matrix.outputs.matrix).native_test_task }} + env: + GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} + GRADLE_ENTERPRISE_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USERNAME }} + GRADLE_ENTERPRISE_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }} + steps: + - uses: actions/checkout@v4 + - name: Pre-Build Steps + uses: micronaut-projects/github-actions/graalvm/pre-build@master + id: pre-build + with: + distribution: 'graalvm' + java: ${{ matrix.java }} + - name: Build Steps + uses: micronaut-projects/github-actions/graalvm/build@master + id: build + env: + GH_TOKEN_PUBLIC_REPOS_READONLY: ${{ secrets.GH_TOKEN_PUBLIC_REPOS_READONLY }} + GH_USERNAME: ${{ secrets.GH_USERNAME }} + GRAALVM_QUICK_BUILD: true + with: + nativeTestTask: ${{ matrix.native_test_task }} + - name: Post-Build Steps + uses: micronaut-projects/github-actions/graalvm/post-build@master + id: post-build + with: + java: ${{ matrix.java }} diff --git a/.github/workflows/graalvm.yml b/.github/workflows/graalvm.yml deleted file mode 100644 index 8504a6b..0000000 --- a/.github/workflows/graalvm.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: GraalVM CE CI -on: - push: - branches: - - master - - '[1-9]+.[0-9]+.x' - pull_request: - branches: - - master - - '[1-9]+.[0-9]+.x' -jobs: - build: - if: github.repository != 'micronaut-projects/micronaut-project-template' - runs-on: ubuntu-latest - strategy: - matrix: - graalvm: ['20.2.0.java8', '20.2.0.java11'] - steps: - - uses: actions/checkout@v3 - - uses: actions/cache@v3 - with: - path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} - restore-keys: | - ${{ runner.os }}-gradle- - - name: Setup GraalVM CE - uses: DeLaGuardo/setup-graalvm@48f2bf339ab7d35e31029b1822a213681fdfc42e - with: - graalvm-version: ${{ matrix.graalvm }} - - name: Install Native Image - run: gu install native-image - - name: Build with Gradle - run: | - if ./gradlew tasks --all | grep -w "testNativeImage" - then - ./gradlew check testNativeImage --continue --no-daemon - else - ./gradlew check --continue --no-daemon - fi - env: - TESTCONTAINERS_RYUK_DISABLED: true - diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 59ab012..aa16a2b 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -19,51 +19,90 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - java: ['8', '11', '17'] + java: ['17', '21'] + env: + GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} + GRADLE_ENTERPRISE_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USERNAME }} + GRADLE_ENTERPRISE_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }} + GH_TOKEN_PUBLIC_REPOS_READONLY: ${{ secrets.GH_TOKEN_PUBLIC_REPOS_READONLY }} + GH_USERNAME: ${{ secrets.GH_USERNAME }} + TESTCONTAINERS_RYUK_DISABLED: true + PREDICTIVE_TEST_SELECTION: "${{ github.event_name == 'pull_request' && 'true' || 'false' }}" + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v3 - - uses: actions/cache@v3 + # https://github.com/actions/virtual-environments/issues/709 + - name: "🗑 Free disk space" + run: | + sudo rm -rf "/usr/local/share/boost" + sudo rm -rf "$AGENT_TOOLSDIRECTORY" + sudo apt-get clean + df -h + + - name: "📥 Checkout repository" + uses: actions/checkout@v4 with: - path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} - restore-keys: | - ${{ runner.os }}-gradle- - - name: Set up JDK - uses: actions/setup-java@v3 + fetch-depth: 0 + + - name: "🔧 Setup GraalVM CE" + uses: graalvm/setup-graalvm@v1.2.4 with: + distribution: 'graalvm' java-version: ${{ matrix.java }} - distribution: 'temurin' - - name: Optional setup step + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: "🔧 Setup Gradle" + uses: gradle/gradle-build-action@v3.5.0 + + - name: "❓ Optional setup step" run: | - [ -f ./setup.sh ] && ./setup.sh || true - - name: Build with Gradle - run: ./gradlew dependencyUpdates check --parallel --continue - env: - TESTCONTAINERS_RYUK_DISABLED: true - - name: Publish Test Report - uses: scacap/action-surefire-report@v1 + [ -f ./setup.sh ] && ./setup.sh || [ ! -f ./setup.sh ] + + - name: "🛠 Build with Gradle" + id: gradle + run: | + ./gradlew check --no-daemon --continue + + - name: "🔎 Run static analysis" + if: env.SONAR_TOKEN != '' && matrix.java == '17' + run: | + ./gradlew sonar + + - name: "📊 Publish Test Report" + if: always() + uses: mikepenz/action-junit-report@v4 with: - github_token: ${{ secrets.GITHUB_TOKEN }} + check_name: Java CI / Test Report (${{ matrix.java }}) report_paths: '**/build/test-results/test/TEST-*.xml' -# - name: Publish to JFrog OSS -# if: success() && github.event_name == 'push' && matrix.java == '8' -# env: -# BINTRAY_USER: ${{ secrets.BINTRAY_USER }} -# BINTRAY_KEY: ${{ secrets.BINTRAY_KEY }} -# run: ./gradlew publish docs --no-daemon - - name: Determine docs target repository + check_retries: 'true' + + - name: "📜 Upload binary compatibility check results" + if: matrix.java == '17' + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + with: + name: binary-compatibility-reports + path: "**/build/reports/binary-compatibility-*.html" + + - name: "📦 Publish to Sonatype Snapshots" + if: success() && github.event_name == 'push' && matrix.java == '17' + env: + SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} + SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} + run: ./gradlew publishToSonatype docs --no-daemon + + - name: "❓ Determine docs target repository" uses: haya14busa/action-cond@v1 id: docs_target with: cond: ${{ github.repository == 'micronaut-projects/micronaut-core' }} if_true: "micronaut-projects/micronaut-docs" if_false: ${{ github.repository }} -# - name: Publish to Github Pages -# if: success() && github.event_name == 'push' && matrix.java == '8' -# uses: micronaut-projects/github-pages-deploy-action@master -# env: -# TARGET_REPOSITORY: ${{ steps.docs_target.outputs.value }} -# GH_TOKEN: ${{ secrets.GH_TOKEN }} -# BASE_BRANCH: ${{ env.githubBranch }} -# BRANCH: gh-pages -# FOLDER: build/docs + + - name: "📑 Publish to Github Pages" + if: success() && github.event_name == 'push' && matrix.java == '17' + uses: micronaut-projects/github-pages-deploy-action@master + env: + TARGET_REPOSITORY: ${{ steps.docs_target.outputs.value }} + GH_TOKEN: ${{ secrets.GH_TOKEN }} + BRANCH: gh-pages + FOLDER: build/docs diff --git a/.github/workflows/publish-snapshot.yml b/.github/workflows/publish-snapshot.yml new file mode 100644 index 0000000..0875db9 --- /dev/null +++ b/.github/workflows/publish-snapshot.yml @@ -0,0 +1,33 @@ +# WARNING: Do not edit this file directly. Instead, go to: +# +# https://github.com/micronaut-projects/micronaut-project-template/tree/master/.github/workflows +# +# and edit them there. Note that it will be sync'ed to all the Micronaut repos +name: Publish snapshot release +on: [workflow_dispatch] +jobs: + build: + if: github.repository != 'micronaut-projects/micronaut-project-template' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/cache@v4 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} + restore-keys: | + ${{ runner.os }}-gradle- + - name: Set up JDK + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '17' + - name: Publish to Sonatype Snapshots + if: success() + env: + SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} + SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} + GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} + GRADLE_ENTERPRISE_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USERNAME }} + GRADLE_ENTERPRISE_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }} + run: ./gradlew publishToSonatype --no-daemon diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e8523e7..25c56f4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,59 +9,97 @@ on: types: [published] jobs: release: + outputs: + artifacts-sha256: ${{ steps.hash.outputs.artifacts-sha256 }} # Computed hashes for build artifacts. runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: token: ${{ secrets.GH_TOKEN }} - - uses: gradle/wrapper-validation-action@v1 + - uses: gradle/wrapper-validation-action@v3 - name: Set up JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: - java-version: 1.8 + distribution: 'temurin' + java-version: '17' - name: Set the current release version id: release_version - run: echo ::set-output name=release_version::${GITHUB_REF:11} + run: echo "release_version=${GITHUB_REF:11}" >> $GITHUB_OUTPUT - name: Run pre-release uses: micronaut-projects/github-actions/pre-release@master env: MICRONAUT_BUILD_EMAIL: ${{ secrets.MICRONAUT_BUILD_EMAIL }} with: token: ${{ secrets.GITHUB_TOKEN }} - - name: Upload to Bintray + - name: Publish to Sonatype OSSRH + id: publish env: - BINTRAY_USER: ${{ secrets.BINTRAY_USER }} - BINTRAY_KEY: ${{ secrets.BINTRAY_KEY }} - BINTRAY_PUBLISH: ${{ secrets.BINTRAY_PUBLISH }} - run: ./gradlew bintrayUpload docs + SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} + SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} + GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }} + GPG_PASSWORD: ${{ secrets.GPG_PASSWORD }} + GPG_FILE: ${{ secrets.GPG_FILE }} + GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} + GRADLE_ENTERPRISE_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USERNAME }} + GRADLE_ENTERPRISE_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }} + run: | + echo $GPG_FILE | base64 -d > secring.gpg + # Publish both locally and to Sonatype. + # The artifacts stored locally will be used to generate the SLSA provenance. + ./gradlew publishAllPublicationsToBuildRepository publishToSonatype closeAndReleaseSonatypeStagingRepository + # Read the current version from gradle.properties. + VERSION=$(./gradlew properties | grep 'version:' | awk '{print $2}') + # Read the project group from gradle.properties. + GROUP_PATH=$(./gradlew properties| grep "projectGroup" | awk '{print $2}' | sed 's/\./\//g') + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + echo "group=$GROUP_PATH" >> "$GITHUB_OUTPUT" + - name: Generate subject + id: hash + run: | + # Find the artifact JAR and POM files in the local repository. + ARTIFACTS=$(find build/repo/${{ steps.publish.outputs.group }}/*/${{ steps.publish.outputs.version }}/* \ + -type f \( \( -iname "*.jar" -not -iname "*-javadoc.jar" -not -iname "*-sources.jar" \) -or -iname "*.pom" \)) + # Compute the hashes for the artifacts. + # Set the hash as job output for debugging. + echo "artifacts-sha256=$(sha256sum $ARTIFACTS | base64 -w0)" >> "$GITHUB_OUTPUT" + # Store the hash in a file, which is uploaded as a workflow artifact. + sha256sum $ARTIFACTS | base64 -w0 > artifacts-sha256 + - name: Upload build artifacts + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + with: + name: gradle-build-outputs + path: build/repo/${{ steps.publish.outputs.group }}/*/${{ steps.publish.outputs.version }}/* + retention-days: 5 + - name: Upload artifacts-sha256 + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + with: + name: artifacts-sha256 + path: artifacts-sha256 + retention-days: 5 + - name: Generate docs + run: ./gradlew docs + env: + GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} + GRADLE_ENTERPRISE_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USERNAME }} + GRADLE_ENTERPRISE_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }} + GH_TOKEN_PUBLIC_REPOS_READONLY: ${{ secrets.GH_TOKEN_PUBLIC_REPOS_READONLY }} + GH_USERNAME: ${{ secrets.GH_USERNAME }} - name: Export Gradle Properties uses: micronaut-projects/github-actions/export-gradle-properties@master - name: Publish to Github Pages if: success() uses: micronaut-projects/github-pages-deploy-action@master env: - BETA: ${{ contains(steps.release_version.outputs.release_version, 'M') || contains(steps.release_version.outputs.release_version, 'RC') }} + BETA: ${{ !(github.event.release.target_commitish == github.event.repository.default_branch) || contains(steps.release_version.outputs.release_version, 'M') || contains(steps.release_version.outputs.release_version, 'RC') }} GH_TOKEN: ${{ secrets.GH_TOKEN }} - BASE_BRANCH: ${{ env.githubBranch }} BRANCH: gh-pages FOLDER: build/docs VERSION: ${{ steps.release_version.outputs.release_version }} - - name: Checkout micronaut-core - uses: actions/checkout@v3 - with: - token: ${{ secrets.GH_TOKEN }} - repository: micronaut-projects/micronaut-core - ref: ${{ env.githubCoreBranch }} - path: micronaut-core # Must be micronaut-core - continue-on-error: true - - name: Update BOM - uses: micronaut-projects/github-actions/update-bom@master - env: - MICRONAUT_BUILD_EMAIL: ${{ secrets.MICRONAUT_BUILD_EMAIL }} - with: - token: ${{ secrets.GH_TOKEN }} - continue-on-error: true + TARGET_REPOSITORY: ${{ github.repository == 'micronaut-projects/micronaut-core' && env.docsRepository || github.repository }} + GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} + GRADLE_ENTERPRISE_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USERNAME }} + GRADLE_ENTERPRISE_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }} - name: Run post-release if: success() uses: micronaut-projects/github-actions/post-release@master @@ -69,3 +107,59 @@ jobs: MICRONAUT_BUILD_EMAIL: ${{ secrets.MICRONAUT_BUILD_EMAIL }} with: token: ${{ secrets.GITHUB_TOKEN }} + + provenance-subject: + needs: [release] + runs-on: ubuntu-latest + outputs: + artifacts-sha256: ${{ steps.set-hash.outputs.artifacts-sha256 }} + steps: + - name: Download artifacts-sha256 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + with: + name: artifacts-sha256 + # The SLSA provenance generator expects the hash digest of artifacts to be passed as a job + # output. So we need to download the artifacts-sha256 and set it as job output. The hash of + # the artifacts should be set as output directly in the release job. But due to a known bug + # in GitHub Actions we have to use a workaround. + # See https://github.com/community/community/discussions/37942. + - name: Set artifacts-sha256 as output + id: set-hash + shell: bash + run: echo "artifacts-sha256=$(cat artifacts-sha256)" >> "$GITHUB_OUTPUT" + + provenance: + needs: [release, provenance-subject] + permissions: + actions: read # To read the workflow path. + id-token: write # To sign the provenance. + contents: write # To add assets to a release. + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0 + with: + base64-subjects: "${{ needs.provenance-subject.outputs.artifacts-sha256 }}" + upload-assets: true # Upload to a new release. + compile-generator: true # Build the generator from source. + + github_release: + needs: [release, provenance] + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/') + steps: + - name: Checkout repository + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - name: Download artifacts + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + with: + name: gradle-build-outputs + path: build/repo + - name: Create artifacts archive + shell: bash + run: | + find build/repo -type f \( \( -iname "*.jar" -not -iname "*-javadoc.jar" -not \ + -iname "*-sources.jar" \) -or -iname "*.pom" \) | xargs zip artifacts.zip + - name: Upload assets + # Upload the artifacts to the existing release. Note that the SLSA provenance will + # attest to each artifact file and not the aggregated ZIP file. + uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191 # v2.0.8 + with: + files: artifacts.zip diff --git a/.github/workflows/template-cleanup.yml b/.github/workflows/template-cleanup.yml new file mode 100644 index 0000000..64fdf30 --- /dev/null +++ b/.github/workflows/template-cleanup.yml @@ -0,0 +1,52 @@ +# GitHub Actions Workflow responsible for template-clean like updating CLA contract url. This workflow is supposed to be triggered automatically +# when a new template-based repository has been created. + +name: Template Clean Up +on: + push: + +jobs: + + # Run cleaning process only if workflow is triggered by the non micronaut-project/micronaut-project-template repository. + template-cleanup: + name: Template Cleanup + runs-on: ubuntu-latest + if: github.event.repository.name != 'micronaut-project-template' + steps: + + # Check out current repository + - name: Fetch Sources + uses: actions/checkout@v4 + + # Cleanup project + - name: Cleanup + run: | + # Update CLA url in CONTRIBUTING.md + sed -i "s|micronaut-projects/micronaut-project-template|$GITHUB_REPOSITORY|" CONTRIBUTING.md + sed -i "s|project-template|${GITHUB_REPOSITORY:29}|" README.md + sed -i "s|project-template|${GITHUB_REPOSITORY:29}|" gradle.properties + sed -i "s|project-template|${GITHUB_REPOSITORY:29}|" CONTRIBUTING.md + sed -i "s|project-template|${GITHUB_REPOSITORY:29}|" MAINTAINING.md + sed -i "s|micronaut-projects/micronaut-project-template|$GITHUB_REPOSITORY|" SECURITY.md + sed -i "s|project-template|${GITHUB_REPOSITORY:29}|" project-template/build.gradle + sed -i "s|project-template|${GITHUB_REPOSITORY:29}|" project-template-bom/build.gradle + sed -i "s|project-template|${GITHUB_REPOSITORY:29}|" buildSrc/src/main/groovy/io.micronaut.build.internal.project-template-module.gradle + git mv project-template/ "micronaut-${GITHUB_REPOSITORY:29}/" + git mv project-template-bom/ "micronaut-${GITHUB_REPOSITORY:29}-bom/" + git mv buildSrc/src/main/groovy/io.micronaut.build.internal.project-template-module.gradle "buildSrc/src/main/groovy/io.micronaut.build.internal.${GITHUB_REPOSITORY:29}-module.gradle" + git mv buildSrc/src/main/groovy/io.micronaut.build.internal.project-template-base.gradle "buildSrc/src/main/groovy/io.micronaut.build.internal.${GITHUB_REPOSITORY:29}-base.gradle" + # Remove clean up template + rm -rf .github/workflows/template-cleanup.yml + # Commit modified files + - name: Commit files + run: | + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + git add . + git commit -m "Template cleanup" + # Push changes + - name: Push changes + uses: ad-m/github-push-action@master + with: + branch: ${{ github.ref }} + github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/update-gradle-wrapper.yml b/.github/workflows/update-gradle-wrapper.yml index 5dcf49f..dcbc78c 100644 --- a/.github/workflows/update-gradle-wrapper.yml +++ b/.github/workflows/update-gradle-wrapper.yml @@ -1,25 +1,34 @@ +# WARNING: Do not edit this file directly. Instead, go to: +# +# https://github.com/micronaut-projects/micronaut-project-template/tree/master/.github/workflows +# +# and edit them there. Note that it will be sync'ed to all the Micronaut repos name: Update Gradle Wrapper on: schedule: - - cron: '0 0 * * MON' + - cron: '0 3 * * SAT' jobs: update-wrapper: if: github.repository == 'micronaut-projects/micronaut-project-template' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: token: ${{ secrets.GH_TOKEN }} - name: "Update Gradle Wrapper" id: update + env: + GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} + GRADLE_ENTERPRISE_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USERNAME }} + GRADLE_ENTERPRISE_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }} run: | latest=`curl -s https://services.gradle.org/versions/current | jq -cr ".version"` - echo ::set-output name=latest_version::${latest} + echo "latest_version=${latest}" >> $GITHUB_OUTPUT ./gradlew wrapper --gradle-version $latest - - uses: gradle/wrapper-validation-action@v1 - - uses: stefanzweifel/git-auto-commit-action@v4.15.4 + - uses: gradle/wrapper-validation-action@v3 + - uses: stefanzweifel/git-auto-commit-action@v5 with: commit_message: Upgrade Gradle Wrapper to ${{ steps.update.outputs.latest_version }} commit_user_name: micronaut-build commit_user_email: ${{ secrets.MICRONAUT_BUILD_EMAIL }} - commit_author: micronaut-build <${{ secrets.MICRONAUT_BUILD_EMAIL }}> \ No newline at end of file + commit_author: micronaut-build <${{ secrets.MICRONAUT_BUILD_EMAIL }}> diff --git a/.gitignore b/.gitignore index e01c9ee..f585fc1 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ target/ .gradle/ .idea/ build/ +!build-logic/src/main/java/io/micronaut/build classes/ out/ *.db @@ -29,3 +30,6 @@ src/main/docs/resources/css/*.css src/main/docs/resources/js/*.js src/main/docs/resources/style/*.html src/main/docs/resources/img/micronaut-logo-white.svg + +# Ignore files generated by test-resources +**/.micronaut/test-resources/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4e4c496..f2e1956 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,44 +1,53 @@ # Contributing Code or Documentation to Micronaut +Sign the [Contributor License Agreement (CLA)](https://cla-assistant.io/micronaut-projects/micronaut-project-template). This is required before any of your code or pull-requests are accepted. + ## Finding Issues to Work on -If you are interested in contributing to Micronaut and are looking for issues to work on, take a look at the issues tagged with [help wanted](https://github.com/micronaut-projects/micronaut-data/issues?q=is%3Aopen+is%3Aissue+label%3A%22status%3A+help+wanted%22). +If you are interested in contributing to Micronaut and are looking for issues to work on, take a look at the issues tagged with [help wanted](https://github.com/micronaut-projects/micronaut-xxx/issues?q=is%3Aopen+is%3Aissue+label%3A%22status%3A+help+wanted%22). ## JDK Setup -Micronaut Data currently requires JDK 8 +Micronaut project-template currently requires JDK 17. ## IDE Setup -Micronaut Data can be imported into IntelliJ IDEA by opening the `build.gradle` file. +Micronaut project-template can be imported into IntelliJ IDEA by opening the `build.gradle` file. ## Docker Setup -Micronaut Data tests currently require docker to be installed. - +Micronaut project-template tests currently require Docker to be installed. + ## Running Tests -To run the tests use `./gradlew check`. +To run the tests, use `./gradlew check`. ## Building Documentation The documentation sources are located at `src/main/docs/guide`. -To build the documentation run `./gradlew publishGuide` or `./gradlew pG` then open `build/docs/index.html` +To build the documentation, run `./gradlew publishGuide` (or `./gradlew pG`), then open `build/docs/index.html` -To also build the javadocs instead run `./gradlew docs`. +To also build the Javadocs, run `./gradlew docs`. ## Working on the code base -If you are working with the IntelliJ IDEA development environment, you can import the project using the Intellij Gradle Tooling ( "File / Import Project" and select the "settings.gradle" file). +If you use IntelliJ IDEA, you can import the project using the Intellij Gradle Tooling ("File / Import Project" and selecting the "settings.gradle" file). -To get a local development version of Micronaut Data working, first run the `publishToMavenLocal` task. +To get a local development version of Micronaut XXX working, first run the `publishToMavenLocal` task. ``` ./gradlew pTML ``` -You can then reference the version specified with `projectVersion` in `gradle.properties` in a test project's `build.gradle` or `pom.xml`. +You can then reference the version specified with `projectVersion` in `gradle.properties` in a test project's `build.gradle` or `pom.xml`. If you use Gradle, add the `mavenLocal` repository (Maven automatically does this): + +``` +repositories { + mavenLocal() + mavenCentral() +} +``` ## Creating a pull request @@ -48,19 +57,34 @@ Once you are satisfied with your changes: - Push your changes to your remote branch on GitHub - Send us a [pull request](https://help.github.com/articles/creating-a-pull-request) +## Merging a pull request + +Before we merge into a module's `master` branch a PR, we have to consider. + +Can this PR be merged into a patch release (e.g. documentation fixes, bug fix, patch transitive dependency upgrade, breaking change due to security, GitHub actions sync, Micronaut Build Plugin upgrade)? + +Should this PR be merged into the next minor version of the module? For example, a new feature, a new module, or a minor transitive dependency upgrade. + +If the PR is going into the next minor version of the module, we need to release a patch version, and branch off `master` a new branch for the current minor module's version. If the `gradle.properties`'s `projectVersion` is 3.1.2-SNAPSHOT the branch should be named 3.1.x, and we push it to GitHub. If `master` contains only commits such as GitHub actions sync (no commits with benefits to users), we can branch off without doing a patch release. + +When you merge a PR which will go into the next Module's minor. + +- Update `gradle.properties`'s `githubCoreBranch` to point to the next minor branch of Micronaut Core. +- Update `gradle.properties`'s `projectVersion` to the next minor snapshot. +- Upgrade the module to the latest version of Micronaut. + ## Checkstyle -We want to keep the code clean, following good practices about organization, javadoc and style as much as possible. +We want to keep the code clean, following good practices about organization, Javadoc, and style as much as possible. + +Micronaut XXX uses [Checkstyle](https://checkstyle.sourceforge.io/) to make sure that the code follows those standards. The configuration is defined in `config/checkstyle/checkstyle.xml`. To execute Checkstyle, run: -Micronaut Data uses [Checkstyle](https://checkstyle.sourceforge.io/) to make sure that all the code follows those standards. The configuration file is defined in `config/checkstyle/checkstyle.xml` and to execute the Checkstyle you -need to run: - ``` ./gradlew :checkstyleMain ``` -Before start contributing with new code it is recommended to install IntelliJ [CheckStyle-IDEA](https://plugins.jetbrains.com/plugin/1065-checkstyle-idea) plugin and configure it to use Micronaut's checkstyle configuration file. - +Before starting to contribute new code we recommended that you install the IntelliJ [CheckStyle-IDEA](https://plugins.jetbrains.com/plugin/1065-checkstyle-idea) plugin and configure it to use Micronaut's checkstyle configuration file. + IntelliJ will mark in red the issues Checkstyle finds. For example: ![](https://github.com/micronaut-projects/micronaut-core/raw/master/src/main/docs/resources/img/checkstyle-issue.png) @@ -69,7 +93,6 @@ In this case, to fix the issues, we need to: - Add one empty line before `package` in line 16 - Add the Javadoc for the constructor in line 27 -- Add an space after `if` in line 34 +- Add a space after `if` in line 34 -The plugin also adds a new tab in the bottom to run checkstyle report and see all the errors and warnings. It is recommended -to run the report and fixing all the issues before submitting a pull request. +The plugin also adds a new tab in the bottom of the IDE to run Checkstyle and show errors and warnings. We recommend that you run the report and fix all issues before submitting a pull request. diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md deleted file mode 100644 index 3fcd4c6..0000000 --- a/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,36 +0,0 @@ -Thanks for reporting an issue, please review the task list below before submitting the -issue. Your issue report will be closed if the issue is incomplete and the below tasks not completed. - -NOTE: If you are unsure about something and the issue is more of a question a better place to ask questions is on Stack Overflow (https://stackoverflow.com/tags/micronaut) or Gitter (https://gitter.im/micronautfw/). DO NOT use the issue tracker to ask questions. - -### Task List - -- [ ] Steps to reproduce provided -- [ ] Stacktrace (if present) provided -- [ ] Example that reproduces the problem uploaded to Github -- [ ] Full description of the issue provided (see below) - -### Steps to Reproduce - -1. TODO -2. TODO -3. TODO - -### Expected Behaviour - -Tell us what should happen - -### Actual Behaviour - -Tell us what happens instead - -### Environment Information - -- **Operating System**: TODO -- **Micronaut Version:** TODO -- **JDK Version:** TODO - -### Example Application - -- TODO: link to github repository with example that reproduces the issue - diff --git a/MAINTAINING.md b/MAINTAINING.md new file mode 100644 index 0000000..4cbc7b9 --- /dev/null +++ b/MAINTAINING.md @@ -0,0 +1,210 @@ +# Micronaut module maintenance tasks + +## Triage incoming issues + +New issues need to be categorised. At least with one of the following labels: + +* `type: bug`: when something is not working as designed. +* `type: improvement`: a minor improvement over an existing feature. +* `type: enhancement`: a completely new feature. +* `type: docs`: documentation change. + +There are other labels that are useful for changelog generation: + +* `type: breaking`. +* `type: deprecated`. +* `type: removed`. + +Issues with the above labels will show up in their own section in the changelog. + +Sometimes, before accepting bugs, we need to ask more information to the requester, or need to validate ourselves that it +is actually a bug. There are some labels to help with these situations: + +* `status: awaiting feedback`: used to mark that we are waiting for more information to the user. +* `status: awaiting validation`: we need to validate ourselves that it is actually an issue. +* `status: awaiting third-party`: the issue is blocked by another bug in a third-party library + +Note that when the blockers are cleared, the awaiting labels need to be manually removed. There are some other labels +around this: + +* `status: validated`: the issue is ready to be being worked on. +* `status: acknowledged` (possibly duplicate?). +* `status: in progress`: (could be removed, we assign issues to mark them being worked on) + +There are sometimes where we are not sure whether we want or can solve an issue. The labels about this are: + +* `status: under consideration`: the issue is being considered, but has not been accepted yet. +* `status: future consideration`: we won't fix it now (because either we can't or we don't want to), but this can be + revisited in the future. +* `status: next major version`: it is a breaking change and therefore needs to be implemented in the next major version. + +There are also a bunch of `relates-to` labels that can be used to further categorise issues. This is helpful in projects +with a lot of issues, or projects where different people work on different parts or modules. + +The majority of the issues are defined in the +[management](https://github.com/micronaut-projects/management/blob/master/labels.tf) repo, and propagated via Terraform. +If you want new labels: + +* If they can be beneficial to several repos, send a pull request to the management repo. +* If they are repo-specific, just go ahead and create them with the GitHub UI. + +Finally, issues (especially bugs) should be prioritised with either `priority: high`, `priority: medium` or +`priority: low`. Checkout the +[Issue Priority Labels](https://github.com/micronaut-projects/micronaut-core/wiki/Issue-Priority-Labels) document for +guidelines about when to use each of them. + +## Review pull requests + +Pull requests, regardless of whether they are created by internal or external contributors, should meet the following +criteria: + +* All the GitHub checks are passing (CLA signed and builds passing). +* Code has a minimum quality, it uses the Micronaut APIs correctly, doesn't contain bad smells, etc. Essentially, the + type of things you would review in every other software project. +* Contains tests. +* Includes documentation. +* If it closes any issues, + [they should be linked](https://docs.github.com/en/free-pro-team@latest/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue) + either using closing keywords, or manually. + +Regarding the target branch, backwards-compatible bug fixes and improvements typically target the default branch, +backwards-compatible enhancements target the next minor version branch, and breaking changes target the next major version +branch. Check the +[Micronaut Module Versioning](https://github.com/micronaut-projects/micronaut-core/wiki/Micronaut-Module-Versioning) +document for more information. + +Before merging pull requests, it is really important to ensure they target the correct branch, so that in the next +patch/minor release we don't leak breaking changes. Check the +[Micronaut Module Branch Naming](https://github.com/micronaut-projects/micronaut-core/wiki/Micronaut-Module-Branch-Naming) +document for more information. + +Note that +[Micronaut Core and Starter](https://github.com/micronaut-projects/micronaut-core/wiki/Micronaut-Core-and-Starter-Branching-Strategy) +follow a slightly different strategy. + +### Automated pull requests + +#### Dependency upgrades + +All Micronaut repos have 2 dependency upgrade checking mechanism: + +1. Renovate: it has the advantage that it performs dependency upgrades not only on build dependencies, but also on + GitHub Actions workflows. On the other hand, its biggest downside is that it's unable to find newer versions for + those defined in `gradle.properties`. It will also send different PRs for the same version upgrade if the artifact ID + is different. For example, if you have `com.example:client:1.0` and `com.example:server:1.0`, and a new 1.1 version + arrives for both, it will send 2 PRs, where they should both be upgraded at the same time. + +2. To overcome those disadvantages, we have our own dependency upgrade solution based on the + [Gradle Use Latest Versions Plugin](https://github.com/patrikerdes/gradle-use-latest-versions-plugin). It runs daily + during weekdays. + +The consequence of having both approaches in place is that we get multiple dependency upgrade PRs: one created by +`micronaut-build` via our automation, and one or many (one per dependency) created by Renovate. When merging those, it +is better to prefer the `micronaut-build` ones, if possible, for 2 reasons: a) they attempt to upgrade multiple dependencies +in a single PR, which creates less noise in the Git history; b) Once you merge that, Renovate will react and automatically +close its own PRs if the dependency is up-to-date. + +When an upgrade to a new version arrives, we need to be careful when merging, so that we don't introduce an +unnecessary upgrade burden on our users. Read the +[Module Upgrade Strategy](https://github.com/micronaut-projects/micronaut-core/wiki/Module-Upgrade-Strategy) for more +information. + +Note that if a new version arrives, and we are not ready yet to do the upgrade, you need to +[pin the old version](https://github.com/micronaut-projects/micronaut-build/#configuration-options), because otherwise, +Renovate and our workflow will keep sending PRs. You should also create an issue to upgrade so that it's not forgotten. + +#### Files sync + +We have a [template repo](https://github.com/micronaut-projects/micronaut-project-template) that we use as the single +source of truth for certain files. It is used as a template to create new repos, and changes to certain files in the +template repo will get propagated automatically. The files propagated are: + +* Workflow files (`.github/workflows/*`). They are copied using rsync" + * `central-sync.yml`. + * `dependency-update.yml`. + * `graalvm.yml`. + * `gradle.yml`. + * `release.yml`. + * `release-notes.yml`. +* Renovate configuration (`.github/renovate.json`). +* Gradle wrapper. +* `.gitignore`. +* `ISSUE_TEMPLATE.md`, `LICENSE`, `MAINTAINING.md`, `config/HEADER` and `config/spotless.license.java`. +* Checkstyle's `config/checkstyle/checkstyle.xml` and `config/checkstyle/suppressions.xml`. + +Regarding the Gradle wrapper, the template repo checks every week if there is a new Gradle version. If there is, it will +upgrade the wrapper in the template repo itself, and via the files sync workflow this gets propagated to all repos. This +way we make sure we stay up-to-date regarding Gradle versions in all repos. + +##### Customised workflow files + +Due to limitations in the GitHub Actions design (such that they don't allow including snippets or any other kind of +reusability), for the sync'ed workflow files listed above, it is not possible to have custom steps and still be part of +the sync process, since any modification to those files will be overwritten the next time the files sync workflow is +executed. + +The "Java CI" (`gradle.yml`) workflow does have the ability to have an optional setup step, though. If there is a `setup.sh` +file in the project root, it will be executed before invoking Gradle. + +There are projects, such as micronaut-gcp and micronaut-kubernetes, that have made customisations to sync'ed workflows +because it's absolutely necessary. In those projects, the sync pull requests are manually merged so that the customisations +aren't lost. + +Note that it is perfectly possible to have new workflows that aren't part of the sync process. + +## Releases + +The release process is highly automated and normally involves just publishing a GitHub release. But before you get there, +there are some parts you need to understand first. + +First of all, all the repos have an automatic changelog generation mechanism: when a change is made to the repo +(a push event), it creates (or updates if there is already one) a draft release, calculating the next patch version. The +release notes will contain pull requests merged and issues closed since the last release. + +When the module is ready for a new release, check the generated release notes, and make changes if needed (for example, +you can add an introduction paragraph highlighting some items included in the release). If the version you are going to +publish is not a new patch version, but a new minor or major, update the release notes text to reflect the new version. +If you are publishing a milestone or release candidate, check the pre-release checkbox. + +Note that the release tags must be preceded with `v`, e.g.: `v1.2.3`. + +Once you publish the GitHub release, the +[Release GitHub Action workflow](https://github.com/micronaut-projects/micronaut-project-template/blob/master/.github/workflows/release.yml) +will kick off, performing the following steps: + +* Pre-release: sets the `projectVersion` property in `gradle.properties` to the release version, and commit and pushes + the result. +* Generates documentation guide and publishes it to the `gh-pages` branch. +* Sends a pull request to Core to update the BOM. +* Post-release: + * Determines the next patch version, and sets it as a `SNAPSHOT` version. + * Closes the milestone that matches the release version, and creates a new one for the next patch. + +If everything goes well, you now need to manually trigger the Maven Central publishing workflow via the GitHub UI. + +If there is an issue with the release, it's important not to trigger the Maven Central publishing workflow because once +we publish a version to Maven Central we cannot change or remove it anymore. + +There are some properties in `gradle.properties` that affect the release process: + +* `githubBranch`: the current branch, usually `master`. +* `githubCoreBranch`: the Micronaut Core branch where the BOM update pull requests will be sent to. +* `bomProperty`: in Micronaut Core's `gradle.properties`, the property that represents this module's version. +* `bomProperties`: if needed, additional properties for the BOM pull request. + +For example, assuming a module has the release `1.0.0` as the latest version published, which was included in the +Micronaut `2.2.0` BOM. If the next version you want to publish is: + +* A new patch release (`1.0.1`): simply publish the existing draft release. +* A new minor release (`1.1.0`): + * Before the release, push a `1.0.x` branch off `master`. + * Bump the version in master to `1.1.0-SNAPSHOT`. + * Set the `githubCoreBranch` property to `2.3.x` (or `3.0.x` if it will be the next one). + * Edit the draft release setting the version to `1.1.0` in the release title, body, tag, etc. + * Publish the release. +* A new major release (`2.0.0`): + * Before the release, push a `1.0.x` branch off `master`. + * Bump the version in master to `2.0.0-SNAPSHOT`. + * Set the `githubCoreBranch` property to `3.0.x` (or `2.3.x` if this new major version doesn't introduce breaking changes). + * Edit the draft release setting the version to `2.0.0` in the release title, body, tag, etc. + * Publish the release. diff --git a/README.md b/README.md index 1458c71..ef9e86a 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,12 @@ + + # Micronaut etcd [![Codacy Badge](https://api.codacy.com/project/badge/Grade/f7fe9398e9014a09970e5b2e18e39b62)](https://app.codacy.com/gh/marcosflobo/micronaut-etcd?utm_source=github.com&utm_medium=referral&utm_content=marcosflobo/micronaut-etcd&utm_campaign=Badge_Grade) [![Maven Central](https://img.shields.io/maven-central/v/io.micronaut.etcd/micronaut-etcd.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22io.micronaut.etcd%22%20AND%20a:%22micronaut-etcd%22) [![Build Status](https://github.com/marcosflobo/micronaut-etcd/workflows/Java%20CI/badge.svg)](https://github.com/marcosflobo/micronaut-etcd/actions) +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=micronaut-projects_micronaut-template&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=micronaut-projects_micronaut-template) +[![Revved up by Develocity](https://img.shields.io/badge/Revved%20up%20by-Develocity-06A0CE?logo=Gradle&labelColor=02303A)](https://ge.micronaut.io/scans) This project integrates [etcd](https://etcd.io/) and [Micronaut](https://micronaut.io) @@ -39,9 +43,11 @@ PENDING More info at https://etcd.io/docs/v3.4.0/learning/api/ +Micronaut etcd + ## Documentation -See the [Documentation](https://micronaut-projects.github.io/micronaut-etcd/latest/guide/) for more information. +See the [Documentation](https://micronaut-projects.github.io/micronaut-etcd/latest/guide/) for more information. See the [Snapshot Documentation](https://micronaut-projects.github.io/micronaut-etcd/snapshot/guide/) for the current development docs. @@ -51,14 +57,15 @@ Examples can be found in the [examples](https://github.com/marcosflobo/micronaut ## Snapshots and Releases -Snaphots are automatically published to [JFrog OSS](https://oss.jfrog.org/artifactory/oss-snapshot-local/) using [Github Actions](https://github.com/micronaut-projects/micronaut-etcd/actions). +Snapshots are automatically published to [Sonatype Snapshots](https://s01.oss.sonatype.org/content/repositories/snapshots/io/micronaut/) using [GitHub Actions](https://github.com/marcosflobo/micronaut-etcd/actions). See the documentation in the [Micronaut Docs](https://docs.micronaut.io/latest/guide/index.html#usingsnapshots) for how to configure your build to use snapshots. -Releases are published to JCenter and Maven Central via [Github Actions](https://github.com/micronaut-projects/micronaut-etcd/actions). +Releases are published to Maven Central via [GitHub Actions](https://github.com/marcosflobo/micronaut-etcd/actions). Releases are completely automated. To perform a release use the following steps: * [Publish the draft release](https://github.com/marcosflobo/micronaut-etcd/releases). There should be already a draft release created, edit and publish it. The Git Tag should start with `v`. For example `v1.0.0`. * [Monitor the Workflow](https://github.com/marcosflobo/micronaut-etcd/actions?query=workflow%3ARelease) to check it passed successfully. +* If everything went fine, [publish to Maven Central](https://github.com/marcosflobo/micronaut-etcd/actions?query=workflow%3A"Maven+Central+Sync"). * Celebrate! diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..794aaf7 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,16 @@ +# Security Policy + +We release patches for security vulnerabilities. Which versions are eligible +receiving such patches depend on the CVSS v3.0 Rating: + +| CVSS v3.0 | Supported Versions | +|-----------|-------------------------------------------| +| 9.0-10.0 | Releases within the previous three months | +| 4.0-8.9 | Most recent release | + +## Reporting a Vulnerability + +Please responsibly disclose (suspected) security vulnerabilities to +**[The Micronaut Foundation](foundation@micronaut.io)**. You will receive a response from +us within 48 hours. If the issue is confirmed, we will release a patch as soon +as possible depending on complexity but historically within a few days. diff --git a/build.gradle b/build.gradle index e5e0085..5cdc7d1 100644 --- a/build.gradle +++ b/build.gradle @@ -1,25 +1,4 @@ -buildscript { - repositories { - gradlePluginPortal() - jcenter() - maven { url "https://dl.bintray.com/micronaut/core-releases-local" } - maven { url "https://repo.grails.org/grails/core" } - } - dependencies { - classpath "io.micronaut.build:micronaut-gradle-plugins:2.0.16" - classpath 'com.github.jengelman.gradle.plugins:shadow:6.1.0' - } +plugins { + id "io.micronaut.build.internal.docs" + id "io.micronaut.build.internal.quality-reporting" } - -subprojects { Project subproject -> - group "io.micronaut.etcd" - - apply plugin: "io.micronaut.build.common" - apply plugin: "io.micronaut.build.dependency-updates" - - apply plugin: "io.micronaut.build.publishing" -} - -apply plugin: "io.micronaut.build.docs" -apply plugin: "io.micronaut.build.dependency-updates" -apply plugin: 'com.github.johnrengelman.shadow' diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle new file mode 100644 index 0000000..6784052 --- /dev/null +++ b/buildSrc/build.gradle @@ -0,0 +1,3 @@ +plugins { + id 'groovy-gradle-plugin' +} diff --git a/buildSrc/src/main/groovy/io.micronaut.build.internal.etcd-base.gradle b/buildSrc/src/main/groovy/io.micronaut.build.internal.etcd-base.gradle new file mode 100644 index 0000000..d648e17 --- /dev/null +++ b/buildSrc/src/main/groovy/io.micronaut.build.internal.etcd-base.gradle @@ -0,0 +1 @@ +// If you don't need any common settings/dependencies/... for everything, remove this convention plugin and the reference to it in `io.micronaut.build.internal.project-template-module.gradle` file diff --git a/buildSrc/src/main/groovy/io.micronaut.build.internal.etcd-module.gradle b/buildSrc/src/main/groovy/io.micronaut.build.internal.etcd-module.gradle new file mode 100644 index 0000000..73a6819 --- /dev/null +++ b/buildSrc/src/main/groovy/io.micronaut.build.internal.etcd-module.gradle @@ -0,0 +1,4 @@ +plugins { + id 'io.micronaut.build.internal.etcd-base' + id "io.micronaut.build.internal.module" +} diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 38c71ad..ef0b79e 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -82,6 +82,10 @@ + + + + @@ -92,11 +96,13 @@ - + - + + + @@ -114,7 +120,7 @@ - + @@ -165,8 +171,8 @@ - - + + diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml index 73f71b3..5c5bc68 100644 --- a/config/checkstyle/suppressions.xml +++ b/config/checkstyle/suppressions.xml @@ -6,7 +6,7 @@ - + diff --git a/etcd-bom/build.gradle b/etcd-bom/build.gradle new file mode 100644 index 0000000..7b133f5 --- /dev/null +++ b/etcd-bom/build.gradle @@ -0,0 +1,4 @@ +plugins { + id 'io.micronaut.build.internal.etcd-base' + id "io.micronaut.build.internal.bom" +} diff --git a/etcd/build.gradle b/etcd/build.gradle index 7519faa..e406eda 100644 --- a/etcd/build.gradle +++ b/etcd/build.gradle @@ -1,38 +1,25 @@ +plugins { + id 'io.micronaut.build.internal.etcd-module' +} + dependencies { - annotationProcessor "io.micronaut:micronaut-inject-java" - annotationProcessor "io.micronaut.docs:micronaut-docs-asciidoc-config-props:$micronautDocsVersion" + annotationProcessor mn.micronaut.inject.java - implementation "io.micronaut:micronaut-inject" - implementation "io.micronaut:micronaut-inject-java" - implementation "io.etcd:jetcd-core:$jetcdVersion" + implementation mn.micronaut.inject + implementation mn.micronaut.inject.java + implementation libs.etcd - compileOnly "io.micronaut.micrometer:micronaut-micrometer-core" - compileOnly "io.micronaut:micronaut-management" + compileOnly mnMicrometer.micronaut.micrometer.core + compileOnly mn.micronaut.management - testImplementation("org.spockframework:spock-core:${spockVersion}") { - exclude module:'groovy-all' + testImplementation(libs.spock.core) { + exclude group: "org.codehaus.groovy", module:'groovy-all' } - testImplementation "io.micronaut.test:micronaut-test-spock:$micronautTestVersion" - testImplementation "io.micronaut:micronaut-inject-groovy" - testImplementation "io.micronaut:micronaut-inject-java" - testImplementation "org.testcontainers:spock:$spockTestConainersVersion" - testImplementation "io.micronaut:micronaut-management" -} + testImplementation mnTest.micronaut.test.spock + testImplementation mn.micronaut.inject.groovy + testImplementation mn.micronaut.inject.java + testImplementation libs.testcontainers.spock + testImplementation mn.micronaut.management -tasks.withType(Test) { - useJUnitPlatform() + testRuntimeOnly(mnLogging.logback.classic) } - - -task fatJar(type: Jar) { - manifest.from jar.manifest - classifier = 'all' - from { - configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } - } { - exclude "META-INF/*.SF" - exclude "META-INF/*.DSA" - exclude "META-INF/*.RSA" - } - with jar -} \ No newline at end of file diff --git a/etcd/src/main/java/io/micronaut/etcd/client/ClientFactory.java b/etcd/src/main/java/io/micronaut/etcd/client/ClientFactory.java index d8688e0..d49ddc5 100644 --- a/etcd/src/main/java/io/micronaut/etcd/client/ClientFactory.java +++ b/etcd/src/main/java/io/micronaut/etcd/client/ClientFactory.java @@ -20,9 +20,10 @@ import io.etcd.jetcd.ClientBuilder; import io.etcd.jetcd.KV; import io.micronaut.etcd.config.EtcdFactoryConfig; + import java.net.URI; import java.util.Collection; -import javax.inject.Singleton; +import jakarta.inject.Singleton; /** * Client factory for jetcd clients. @@ -30,101 +31,103 @@ @Singleton public class ClientFactory { - /** - * Create a KV client {@link KV} base on the configuration injected. - * @param config The configuration to connect to the etcd server - * @return {@link KV} - */ - public KV etcdKVClient(EtcdFactoryConfig config) { - Client client = getClient(config); - return client.getKVClient(); - } - - /** - * Create a singleton {@link KV} client, based on the string endpoints. - * - * @param endpoints Array of String endpoints - * @return {@link KV} - */ - @Singleton - public KV etcdKVClient(String... endpoints) { - Client client = Client.builder().endpoints(endpoints).build(); - return client.getKVClient(); - } - - /** - * Create a singleton {@link KV} client, based on the URI endpoints. - * - * @param endpoints Array of URI endpoints - * @return {@link KV} - */ - @Singleton - public KV etcdKVClient(URI... endpoints) { - Client client = Client.builder().endpoints(endpoints).build(); - return client.getKVClient(); - } - - /** - * Create a singleton {@link KV} client, based on the Collection of URI endpoints. - * - * @param endpoints Collection of URI endpoints - * @return {@link KV} - */ - @Singleton - public KV etcdKVClient(Collection endpoints) { - Client client = Client.builder().endpoints(endpoints).build(); - return client.getKVClient(); - } - - /** - * Gets a generic etcd client factory to obtain any of the available etcd clients. - * @param config The configuration to connect to the etcd server - * @return {@link Client} - */ - private Client getClient(EtcdFactoryConfig config) { - ClientBuilder clientBuilder = Client.builder().endpoints(config.getEndpoints()); - if (config.getUser() != null) { - clientBuilder.user(ByteSequence.from(config.getUser().getBytes())); - } - if (config.getPassword() != null) { - clientBuilder.password(ByteSequence.from(config.getPassword().getBytes())); - } - if (config.getExecutorService() != null) { - clientBuilder.executorService(config.getExecutorService()); - } - if (config.getLoadBalancerPolicy() != null) { - clientBuilder.loadBalancerPolicy(config.getLoadBalancerPolicy()); + /** + * Create a KV client {@link KV} base on the configuration injected. + * + * @param config The configuration to connect to the etcd server + * @return {@link KV} + */ + public KV etcdKVClient(EtcdFactoryConfig config) { + Client client = getClient(config); + return client.getKVClient(); } - if (config.getSslContext() != null) { - clientBuilder.sslContext(config.getSslContext()); - } - if (config.getAuthority() != null) { - clientBuilder.authority(config.getAuthority()); - } - if (config.getMaxInboundMessageSize() != null) { - clientBuilder.maxInboundMessageSize(config.getMaxInboundMessageSize()); - } - if (config.getHeaders() != null) { - clientBuilder.headers(config.getHeaders()); + + /** + * Create a singleton {@link KV} client, based on the string endpoints. + * + * @param endpoints Array of String endpoints + * @return {@link KV} + */ + @Singleton + public KV etcdKVClient(String... endpoints) { + Client client = Client.builder().endpoints(endpoints).build(); + return client.getKVClient(); } - if (config.getInterceptors() != null) { - clientBuilder.interceptors(config.getInterceptors()); + + /** + * Create a singleton {@link KV} client, based on the URI endpoints. + * + * @param endpoints Array of URI endpoints + * @return {@link KV} + */ + @Singleton + public KV etcdKVClient(URI... endpoints) { + Client client = Client.builder().endpoints(endpoints).build(); + return client.getKVClient(); } - clientBuilder.namespace(config.getNamespace()); - clientBuilder.retryDelay(config.getRetryDelay()); - clientBuilder.retryMaxDelay(config.getRetryMaxDelay()); - clientBuilder.keepaliveTimeMs(config.getKeepaliveTimeMs()); - clientBuilder.keepaliveTimeoutMs(config.getKeepaliveTimeoutMs()); - clientBuilder.keepaliveWithoutCalls(config.getKeepaliveWithoutCalls()); - clientBuilder.retryChronoUnit(config.getRetryChronoUnit()); - if (!config.getRetryMaxDuration().isEmpty()) { - clientBuilder.retryMaxDuration(config.getRetryMaxDuration()); + + /** + * Create a singleton {@link KV} client, based on the Collection of URI endpoints. + * + * @param endpoints Collection of URI endpoints + * @return {@link KV} + */ + @Singleton + public KV etcdKVClient(Collection endpoints) { + Client client = Client.builder().endpoints(endpoints).build(); + return client.getKVClient(); } - if (config.getConnectTimeoutMs() != null) { - clientBuilder.connectTimeoutMs(config.getConnectTimeoutMs()); + + /** + * Gets a generic etcd client factory to obtain any of the available etcd clients. + * + * @param config The configuration to connect to the etcd server + * @return {@link Client} + */ + private Client getClient(EtcdFactoryConfig config) { + ClientBuilder clientBuilder = Client.builder().endpoints(config.getEndpoints()); + if (config.getUser() != null) { + clientBuilder.user(ByteSequence.from(config.getUser().getBytes())); + } + if (config.getPassword() != null) { + clientBuilder.password(ByteSequence.from(config.getPassword().getBytes())); + } + if (config.getExecutorService() != null) { + clientBuilder.executorService(config.getExecutorService()); + } + if (config.getLoadBalancerPolicy() != null) { + clientBuilder.loadBalancerPolicy(config.getLoadBalancerPolicy()); + } + if (config.getSslContext() != null) { + clientBuilder.sslContext(config.getSslContext()); + } + if (config.getAuthority() != null) { + clientBuilder.authority(config.getAuthority()); + } + if (config.getMaxInboundMessageSize() != null) { + clientBuilder.maxInboundMessageSize(config.getMaxInboundMessageSize()); + } + if (config.getHeaders() != null) { + clientBuilder.headers(config.getHeaders()); + } + if (config.getInterceptors() != null) { + clientBuilder.interceptors(config.getInterceptors()); + } + clientBuilder.namespace(config.getNamespace()); + clientBuilder.retryDelay(config.getRetryDelay()); + clientBuilder.retryMaxDelay(config.getRetryMaxDelay()); + clientBuilder.keepaliveTime(config.getKeepaliveTime()); + clientBuilder.keepaliveTimeout(config.getKeepaliveTimeout()); + clientBuilder.keepaliveWithoutCalls(config.getKeepaliveWithoutCalls()); + clientBuilder.retryChronoUnit(config.getRetryChronoUnit()); + if (config.getRetryMaxDuration() != null) { + clientBuilder.retryMaxDuration(config.getRetryMaxDuration()); + } + if (config.getConnectTimeout() != null) { + clientBuilder.connectTimeout(config.getConnectTimeout()); + } + clientBuilder.waitForReady(config.waitForReady()); + return clientBuilder.build(); } - clientBuilder.discovery(config.isDiscovery()); - return clientBuilder.build(); - } } diff --git a/etcd/src/main/java/io/micronaut/etcd/config/EtcdFactoryConfig.java b/etcd/src/main/java/io/micronaut/etcd/config/EtcdFactoryConfig.java index 26b91ff..71bbf9d 100644 --- a/etcd/src/main/java/io/micronaut/etcd/config/EtcdFactoryConfig.java +++ b/etcd/src/main/java/io/micronaut/etcd/config/EtcdFactoryConfig.java @@ -16,10 +16,14 @@ package io.micronaut.etcd.config; import io.etcd.jetcd.ByteSequence; +import io.etcd.jetcd.ClientBuilder; import io.grpc.ClientInterceptor; import io.grpc.Metadata.Key; +import io.grpc.netty.GrpcSslContexts; import io.micronaut.context.annotation.Parameter; import io.netty.handler.ssl.SslContext; + +import java.time.Duration; import java.time.temporal.ChronoUnit; import java.util.List; import java.util.Map; @@ -42,13 +46,13 @@ public abstract class EtcdFactoryConfig { private ByteSequence namespace = ByteSequence.EMPTY; private long retryDelay = 500; private long retryMaxDelay = 2500; - private Long keepaliveTimeMs = 30000L; - private Long keepaliveTimeoutMs = 10000L; + private Duration keepaliveTime = Duration.ofSeconds(30); + private Duration keepaliveTimeout = Duration.ofSeconds(10); private Boolean keepaliveWithoutCalls = true; private ChronoUnit retryChronoUnit = ChronoUnit.MILLIS; - private String retryMaxDuration = ""; - private Integer connectTimeoutMs; - private boolean discovery; + private Duration retryMaxDuration; + private Duration connectTimeout; + private boolean waitForReady = true; /** * Constructor. @@ -250,33 +254,33 @@ public void setRetryMaxDelay(long retryMaxDelay) { /** * @return The interval for gRPC keepalives */ - public Long getKeepaliveTimeMs() { - return keepaliveTimeMs; + public Duration getKeepaliveTime() { + return keepaliveTime; } /** * The interval for gRPC keepalives. * The current minimum allowed by gRPC is 10s * - * @param keepaliveTimeMs time in ms between keepalives + * @param keepaliveTime duration between keepalives */ - public void setKeepaliveTimeMs(Long keepaliveTimeMs) { - this.keepaliveTimeMs = keepaliveTimeMs; + public void setKeepaliveTime(Duration keepaliveTime) { + this.keepaliveTime = keepaliveTime; } /** * @return The timeout for gRPC keepalives */ - public Long getKeepaliveTimeoutMs() { - return keepaliveTimeoutMs; + public Duration getKeepaliveTimeout() { + return keepaliveTimeout; } /** * The timeout for gRPC keepalives. - * @param keepaliveTimeoutMs The gRPC keep alive timeout in milliseconds. + * @param keepaliveTimeout The gRPC keep alive timeout duration. */ - public void setKeepaliveTimeoutMs(Long keepaliveTimeoutMs) { - this.keepaliveTimeoutMs = keepaliveTimeoutMs; + public void setKeepaliveTimeout(Duration keepaliveTimeout) { + this.keepaliveTimeout = keepaliveTimeout; } /** @@ -311,22 +315,22 @@ public void setRetryChronoUnit(ChronoUnit retryChronoUnit) { /** * @return the retries max duration. */ - public String getRetryMaxDuration() { + public Duration getRetryMaxDuration() { return retryMaxDuration; } /** * @param retryMaxDuration the retries max duration. */ - public void setRetryMaxDuration(String retryMaxDuration) { + public void setRetryMaxDuration(Duration retryMaxDuration) { this.retryMaxDuration = retryMaxDuration; } /** - * @return the connect timeout in milliseconds. + * @return the connect timeout duration. */ - public Integer getConnectTimeoutMs() { - return connectTimeoutMs; + public Duration getConnectTimeout() { + return connectTimeout; } /** @@ -334,23 +338,27 @@ public Integer getConnectTimeoutMs() { * Clients connecting to fault tolerant etcd clusters (eg, clusters with >= 3 etcd server * peers/endpoints) should consider a value that will allow switching timely from a * crashed/partitioned peer to a consensus peer. - * @param connectTimeoutMs config the connect timeout in milliseconds. + * @param connectTimeout config the connect timeout duration. */ - public void setConnectTimeoutMs(Integer connectTimeoutMs) { - this.connectTimeoutMs = connectTimeoutMs; + public void setConnectTimeout(Duration connectTimeout) { + this.connectTimeout = connectTimeout; } /** - * @return if the endpoint represent a discovery address using dns+srv. + * Enable gRPC's wait for ready semantics. + * + * @return if this client uses gRPC's wait for ready semantics. */ - public boolean isDiscovery() { - return discovery; + public boolean waitForReady() { + return waitForReady; } /** - * @param discovery if the endpoint represent a discovery address using dns+srv. + * Configure the gRPC's wait for ready semantics. + * + * @param waitForReady if this client should use gRPC's wait for ready semantics. Enabled by default. */ - public void setDiscovery(boolean discovery) { - this.discovery = discovery; + public void waitForReady(boolean waitForReady) { + this.waitForReady = waitForReady; } } diff --git a/etcd/src/main/java/io/micronaut/etcd/config/SingleEtcdFactoryConfig.java b/etcd/src/main/java/io/micronaut/etcd/config/SingleEtcdFactoryConfig.java index 4a12700..fadffc1 100644 --- a/etcd/src/main/java/io/micronaut/etcd/config/SingleEtcdFactoryConfig.java +++ b/etcd/src/main/java/io/micronaut/etcd/config/SingleEtcdFactoryConfig.java @@ -18,8 +18,8 @@ import io.micronaut.context.annotation.ConfigurationProperties; import io.micronaut.context.annotation.Requires; -import javax.inject.Named; -import javax.inject.Singleton; +import jakarta.inject.Named; +import jakarta.inject.Singleton; /** * The default etcd configuration class. diff --git a/etcd/src/test/groovy/io/micronaut/etcd/kv/ConfigurationSpec.groovy b/etcd/src/test/groovy/io/micronaut/etcd/kv/ConfigurationSpec.groovy index 92d9012..f3d1e58 100644 --- a/etcd/src/test/groovy/io/micronaut/etcd/kv/ConfigurationSpec.groovy +++ b/etcd/src/test/groovy/io/micronaut/etcd/kv/ConfigurationSpec.groovy @@ -16,7 +16,6 @@ class ConfigurationSpec extends Specification { ,"etcd.endpoints": [endpoints] ,"etcd.user": dummyValue ,"etcd.password": dummyValue - ,"etcd.retryMaxDuration": dummyValue ,"etcd.authority": dummyValue ] ) diff --git a/etcd/src/test/groovy/io/micronaut/etcd/kv/KVServiceSpec.groovy b/etcd/src/test/groovy/io/micronaut/etcd/kv/KVServiceSpec.groovy index e1f4546..c648a49 100644 --- a/etcd/src/test/groovy/io/micronaut/etcd/kv/KVServiceSpec.groovy +++ b/etcd/src/test/groovy/io/micronaut/etcd/kv/KVServiceSpec.groovy @@ -1,28 +1,30 @@ package io.micronaut.etcd.kv -import io.etcd.jetcd.ByteSequence import io.micronaut.etcd.config.EtcdFactoryConfig import io.micronaut.etcd.config.SingleEtcdFactoryConfig import io.micronaut.etcd.util.DummyObject import org.testcontainers.containers.GenericContainer import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy -import org.testcontainers.shaded.org.apache.commons.lang.SerializationUtils +import org.testcontainers.shaded.org.apache.commons.lang3.SerializationUtils +import org.testcontainers.spock.Testcontainers +import org.testcontainers.utility.DockerImageName import spock.lang.Shared import spock.lang.Specification import static com.google.common.base.Charsets.UTF_8 - +@Testcontainers class KVServiceSpec extends Specification { + private static final DockerImageName ETCD_IMAGE = DockerImageName.parse("quay.io/coreos/etcd:v3.4.34") + int originalPort = 2379 @Shared - GenericContainer etcdContainer = - new GenericContainer("quay.io/coreos/etcd:v3.4.9") - .withExposedPorts(2379, 4001) - .withCommand("/usr/local/bin/etcd -advertise-client-urls http://0.0.0.0:2379 -listen-client-urls http://0.0.0.0:2379") - .waitingFor(new LogMessageWaitStrategy().withRegEx("(?s).*ready to serve client requests.*")) + GenericContainer etcdContainer = new GenericContainer(ETCD_IMAGE) + .withExposedPorts(2379, 4001) + .withCommand("/usr/local/bin/etcd -advertise-client-urls http://0.0.0.0:2379 -listen-client-urls http://0.0.0.0:2379") + .waitingFor(new LogMessageWaitStrategy().withRegEx("(?s).*ready to serve client requests.*")) def "test Get service works with empty storage"() { given: @@ -39,17 +41,17 @@ class KVServiceSpec extends Specification { byte[] ret = kvService.get(key) then: - expected == ret + expected == ret cleanup: etcdContainer.stop() } - def "test Put single integer" () { + def "test Put single integer"() { given: etcdContainer.start() String key = "foo" - Integer value = new Integer(69) + Integer value = Integer.valueOf(69) and: EtcdFactoryConfig config = new SingleEtcdFactoryConfig() @@ -62,14 +64,14 @@ class KVServiceSpec extends Specification { byte[] ret = kvService.get(key) then: - expectedFromPut == retFromPut + expectedFromPut == retFromPut BigInteger.valueOf(value).toByteArray() == ret cleanup: etcdContainer.stop() } - def "test Put byte array" () { + def "test Put byte array"() { given: etcdContainer.start() String key = "foo" @@ -91,7 +93,7 @@ class KVServiceSpec extends Specification { etcdContainer.stop() } - def "test Put single string" () { + def "test Put single string"() { given: etcdContainer.start() String key = "foo" @@ -115,7 +117,7 @@ class KVServiceSpec extends Specification { etcdContainer.stop() } - def "test Put several String values" () { + def "test Put several String values"() { given: etcdContainer.start() String key = "foo" @@ -144,7 +146,7 @@ class KVServiceSpec extends Specification { etcdContainer.stop() } - def "test Put single Object" () { + def "test Put single Object"() { given: etcdContainer.start() String key = "foo" @@ -169,7 +171,7 @@ class KVServiceSpec extends Specification { etcdContainer.stop() } - def "test delete element from etcd" () { + def "test delete element from etcd"() { given: etcdContainer.start() String key = "foo" diff --git a/etcd/src/test/groovy/io/micronaut/etcd/util/DummyObject.java b/etcd/src/test/groovy/io/micronaut/etcd/util/DummyObject.java index 13a8ab7..550f026 100644 --- a/etcd/src/test/groovy/io/micronaut/etcd/util/DummyObject.java +++ b/etcd/src/test/groovy/io/micronaut/etcd/util/DummyObject.java @@ -1,7 +1,7 @@ package io.micronaut.etcd.util; import java.io.Serializable; -import javax.inject.Singleton; +import jakarta.inject.Singleton; /** * Class to be used for testing. diff --git a/etcd/src/test/resources/logback.xml b/etcd/src/test/resources/logback.xml new file mode 100644 index 0000000..44b79c4 --- /dev/null +++ b/etcd/src/test/resources/logback.xml @@ -0,0 +1,14 @@ + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + diff --git a/gradle.properties b/gradle.properties index fd7d8ed..b809520 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,14 +1,5 @@ projectVersion=1.0.0.BUILD-SNAPSHOT -micronautDocsVersion=1.0.24 -micronautVersion=2.0.2 -micronautTestVersion=2.2.1 -groovyVersion=3.0.5 -spockVersion=2.0-M3-groovy-3.0 -# Or: -#groovyVersion=2.5.11 -#spockVersion=1.3-groovy-2.5 -spockTestConainersVersion=1.15.0 -jetcdVersion=0.5.4 +projectGroup=io.micronaut.etcd title=Micronaut etcd projectDesc=This project includes integration between Micronaut and etcd @@ -16,14 +7,5 @@ projectUrl=https://micronaut.io githubSlug=marcosflobo/micronaut-etcd developers=Marcos F. Lobo -# This project's branch -githubBranch=master - -# Micronaut core branch for BOM pull requests -githubCoreBranch=master - -bomProperty=micronautetcdVersion -# If needed, set additional properties -bomProperties=hibernateVersion,tomcatJdbcVersion - org.gradle.caching=true +org.gradle.jvmargs=-Xmx1g diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..7984da1 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,25 @@ +[versions] +micronaut = "4.7.0" +micronaut-docs = "2.0.0" +micronaut-test = "4.2.1" +micronaut-micrometer = "5.8.0" +micronaut-logging = "1.4.0" +groovy = "4.0.17" +spock = "2.3-groovy-4.0" +spock-testcontainers = "1.20.2" +etcd = "0.8.3" + +[libraries] +# Core +micronaut-core = { module = 'io.micronaut:micronaut-core-bom', version.ref = 'micronaut' } +micronaut-logging = { module = "io.micronaut.logging:micronaut-logging-bom", version.ref = "micronaut-logging" } +micronaut-micrometer = { module = "io.micronaut.micrometer:micronaut-micrometer-bom", version.ref = "micronaut-micrometer" } +micronaut-test = { module = "io.micronaut.test:micronaut-test-bom", version.ref = "micronaut-test" } + +etcd = { module = "io.etcd:jetcd-core", version.ref = "etcd" } +spock-core = { module = "org.spockframework:spock-core", version.ref = "spock" } +testcontainers-spock = { module = "org.testcontainers:spock", version.ref = "spock-testcontainers" } + +[bundles] + +[plugins] diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e708b1c..a4b76b9 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index be52383..df97d72 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 4f906e0..f5feea6 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# 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. @@ -15,69 +15,104 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## -## -## Gradle start up script for UN*X -## +# +# 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/HEAD/platforms/jvm/plugins-application/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 -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +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 -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$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"' +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +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 - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +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 @@ -87,9 +122,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 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" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,88 +133,120 @@ 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. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + 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 fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -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" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +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 - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + 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 - i=`expr $i + 1` + # 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 - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +# 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"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# 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 index ac1b06f..9d21a21 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,89 +1,94 @@ -@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 +@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 +@rem SPDX-License-Identifier: Apache-2.0 +@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=. +@rem This is normally unused +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% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +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% equ 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! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle index 8945869..162f42b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,23 @@ -rootProject.name = 'etcd' +pluginManagement { + repositories { + gradlePluginPortal() + mavenCentral() + } +} + +plugins { + id 'io.micronaut.build.shared.settings' version '7.2.1' +} + +rootProject.name = 'etcd-parent' include 'etcd' +include 'etcd-bom' + +enableFeaturePreview 'TYPESAFE_PROJECT_ACCESSORS' + +micronautBuild { + useStandardizedProjectNames = true + importMicronautCatalog() + importMicronautCatalog("micronaut-micrometer") +}