1
0
mirror of synced 2026-07-08 20:30:04 +00:00

Compare commits

..

78 Commits

Author SHA1 Message Date
Josh Cummings bdc3feaa6d Release 5.5.2 2021-08-16 11:43:06 -06:00
Josh Cummings 134f8b0c5d Update org.springframework.data to 2021.0.4
Closes gh-10195
2021-08-16 10:02:27 -06:00
Josh Cummings 835ee559d7 Update org.springframework to 5.3.9
Closes gh-10194
2021-08-16 10:02:25 -06:00
Josh Cummings cfe48556d4 Update org.slf4j to 1.7.32
Closes gh-10193
2021-08-16 10:02:22 -06:00
Josh Cummings c7b73d7b3b Update org.jetbrains.kotlinx to 1.5.1
Closes gh-10192
2021-08-16 10:02:20 -06:00
Josh Cummings 618edc2e12 Update org.jetbrains.kotlin to 1.5.21
Closes gh-10191
2021-08-16 10:02:18 -06:00
Josh Cummings f7fef100c0 Update org.eclipse.jetty to 9.4.43.v20210629
Closes gh-10190
2021-08-16 10:02:15 -06:00
Josh Cummings 9be97e76dc Update org.aspectj to 1.9.7
Closes gh-10189
2021-08-16 10:02:13 -06:00
Josh Cummings 603e0a4140 Update io.projectreactor to 2020.0.10
Closes gh-10187
2021-08-16 10:02:08 -06:00
Josh Cummings b081627f52 Update com.nimbusds to 9.9.1
Closes gh-10186
2021-08-16 10:02:05 -06:00
Josh Cummings 10a0bda63f Update jackson-bom to 2.12.4
Closes gh-10183
2021-08-16 10:01:58 -06:00
Josh Cummings 7db5149163 Update logback-classic to 1.2.5
Closes gh-10182
2021-08-16 10:01:56 -06:00
Josh Cummings b206670245 Exclude Kotlin RC and M releases 2021-08-16 09:59:59 -06:00
Fabio Guenci b067aa4653 Preserve Null Claim Values
Prior to this commit ClaimTypeConverter returned the claims with the
original value for all the claims with a null converted value.
The changes allows ClaimTypeConverter to overwrite and return claims
with converted value of null.

Closes gh-10135
2021-08-16 08:22:31 -06:00
Abdul Al-Faraj ba16d91971 Improve OpenSAML Version Check
Closes gh-10077
2021-07-26 10:51:31 -06:00
Steve Riesenberg dfebd6d9d4 Revert "URL encode client credentials"
This reverts commit e6c268add0.

Issue gh-9610 gh-9858
Closes gh-10018
Closes gh-10121
2021-07-20 12:59:44 -05:00
Eleftheria Stein bd703ff4ac Fix release instructions for generating changelog 2021-07-19 13:42:35 +02:00
dmitrilc 7abaefda10 Update oauth2-resourceserver.adoc
fix the name of the parameter, from failure to badCredentials

Replaces AuthenticationFailureEvent

Remove AuthenticationFailureEvent Reference

Closes gh-10062
2021-07-16 11:58:34 -06:00
Marcus Da Coregio 4440020217 Update SAML docs to point to correct api url
Closes gh-9953
2021-07-12 15:47:28 -03:00
Marcus Da Coregio c2b9c0856d Use springFrameworkVersion property in docs links
Closes gh-9987
2021-07-12 15:47:09 -03:00
Marcus Da Coregio a06f47fac3 Add springFrameworkVersion property in gradle
Closes gh-9954
2021-07-12 15:45:01 -03:00
Marcus Da Coregio 8c0103498a Ensure line endings for .bat are not modified
Closes gh-10039
2021-07-12 15:37:29 -03:00
Luke Quinane e269e5cb91 Fix typos
Closes gh-10050
2021-07-08 09:20:50 -03:00
Eleftheria Stein ed8b08fa24 Fix README local Maven install command
Switching from the maven to maven-publish plugin means users should use publishToMavenLocal to install jars into their local Maven cache.

Closes gh-10047
2021-07-07 13:26:28 +02:00
Marcus Da Coregio 208e327629 Update docs links to point to minor version branches
Closes gh-9986
2021-07-01 09:08:53 -03:00
Marcus Da Coregio 51dfae1b91 Add samplesBranch property
Closes gh-10019
2021-07-01 09:08:30 -03:00
Daniel Garnier-Moiroux 2fd94752c9 Fix Saml2WebSsoAuthenticationRequestFilter javadoc
Closes gh-10025
2021-06-30 13:51:29 +02:00
/usr/local/ΕΨΗΕΛΩΝ 61284ce22d Improve AuthenticationManagerBeanDefinitionParser XML parsing
Closes gh-7282
2021-06-28 11:55:05 +02:00
Eleftheria Stein fdd017d935 Apply DefaultLoginPageConfigurer before logout
If they are not applied in this order, then the LogoutConfigurer cannot
set the logoutSuccessUrl, because the DefaultLoginPageGeneratingFilter
does not exist yet.
This impacts users that inject the default HttpSecurity bean.

Closes gh-9973
2021-06-24 10:28:19 +02:00
Josh Cummings bfeb6bd756 Next Development Version 2021-06-21 12:59:19 -06:00
Josh Cummings e41360b4a3 Release 5.5.1 2021-06-21 11:00:32 -06:00
Josh Cummings e2e06539fc Remove commons-codec constraint
Closes gh-9977
2021-06-21 10:41:22 -06:00
Josh Cummings 93f59a228b Update to OpenSAML 4.1.1
Closes gh-9976
2021-06-21 10:41:11 -06:00
Josh Cummings b2bb014492 Update to nimbus-jose-jwt 9.10
Closes gh-9975
2021-06-21 10:41:06 -06:00
Josh Cummings 062910c2c4 Update to oauth2-oidc-sdk 9.9
Closes gh-9974
2021-06-21 10:40:59 -06:00
Josh Cummings 40fdb5a60d Update org.springframework to 5.3.8
Closes gh-9984
2021-06-21 10:40:06 -06:00
Josh Cummings 2fa0da5cde Update org.slf4j to 1.7.31
Closes gh-9983
2021-06-21 10:40:06 -06:00
Josh Cummings c5f4ae5c0a Update org.jetbrains.kotlin to 1.5.10
Closes gh-9982
2021-06-21 10:39:54 -06:00
Josh Cummings c68c1c55ff Update hibernate-entitymanager to 5.4.32.Final
Closes gh-9981
2021-06-21 10:37:30 -06:00
Josh Cummings be2595bc66 Update org.eclipse.jetty to 9.4.42.v20210604
Closes gh-9980
2021-06-21 10:37:28 -06:00
Josh Cummings dddd71439f Update io.rsocket to 1.1.1
Closes gh-9979
2021-06-21 10:37:25 -06:00
Marcus Hert da Coregio 95a1ccb52c Fix Broken Links in Docs
Closes gh-9869
2021-06-21 10:58:44 -03:00
Marcus Hert da Coregio 4060f83261 Add a link checker to docs build
Closes gh-9818
2021-06-21 10:58:44 -03:00
Marcus Da Coregio f9a7ae0a6f Update links to point to migrated samples
Closes gh-9816
2021-06-21 10:58:43 -03:00
Marcus Hert da Coregio 425d008f1d Add messaging to documentation about sample migration
Closes gh-9815
2021-06-21 10:58:43 -03:00
Eleftheria Stein b73104c9d1 Add missing WebFlux CORS Reference
Closes gh-9951
2021-06-18 16:33:01 +02:00
Eleftheria Stein 895ef6cf76 Remove non-existent class from RSocket reference docs
Closes gh-9949
2021-06-18 14:18:31 +02:00
Eleftheria Stein cb4bb463da Disable default logout page when logout disabled
Closes gh-9475
2021-06-17 17:09:34 +02:00
Arnaud Mergey 5fd81eeaf1 fix typo preventing full exception to be displayed in log
closes gh-9901
2021-06-17 08:38:24 -06:00
Steve Riesenberg a332e2a728 Support additional client authentication methods
Closes gh-9780
2021-06-16 16:03:13 -05:00
Steve Riesenberg 9daf058a6e Handle missing authorization endpoint uri
Closes gh-9795
2021-06-16 16:00:53 -05:00
Steve Riesenberg 839cc5e851 Remove validation for unsupported grant types
Closes gh-9828
2021-06-16 15:55:45 -05:00
Christian Frommeyer 0087128be8 Replace StringUtils from oauth2-oidc-sdk
SecurityMockServerConfigurers.java previously used the StringUtils from
the optional oauth2-oidc-sdk dependency. Replacing this with the
StringUtils from the spring framework this should not force adding the
dependency in cases where it is not actually used.

Closes gh-9923
2021-06-16 13:22:49 -06:00
Josh Cummings bfc9c5e18f Use stack-workflow-status Action
Closes gh-9792
2021-06-16 13:21:20 -06:00
Joe Grandja 6fbd038111 Jwt client authentication converter detects new key
Closes gh-9814
2021-06-16 12:58:01 -04:00
Steve Riesenberg 700bda68b7 Store one request by default in WebSessionOAuth2ServerAuthorizationRequestRepository
Related to gh-9649
Closes gh-9857
2021-06-15 11:32:35 -05:00
Marcus Hert da Coregio 53870ab3de Fix Adding Filter Relative to Custom Filter
Closes gh-9787
2021-06-14 15:51:27 -03:00
Josh Cummings fe13b488a1 Anonymous Authentication Argument Resolution Docs
Closes gh-3338
2021-06-08 16:12:38 -06:00
Josh Cummings c38495bfaf Change Getting Started Link
Point to 5.5.x reference guide

Issue gh-6502
2021-06-08 13:56:58 -06:00
Josh Cummings c4b210b580 Fix Getting Started Link
Closes gh-6502
2021-06-08 13:44:06 -06:00
Josh Cummings 1a28b4f849 Format PayloadInterceptorRSocket
Issue gh-9345
2021-06-04 12:47:25 -06:00
Josh Cummings 63cd52d1a6 PayloadInterceptorRSocket retains all payloads
Flux#skip discards its corresponding elements, meaning that they
aren't intended for reuse. When using RSocket's ByteBufPayloads,
this means that the bytes are releaseed back into RSocket's pool.

Since the downstream request may still need the skipped payload,
we should construct the publisher in a different way so as to
avoid the preemptive release.

Deferring Spring JavaFormat to clarify what changed.

Closes gh-9345
2021-06-04 12:47:22 -06:00
Eleftheria Stein 895ae0ac55 Remove hard dependency on Kotlin
Closes gh-9811
2021-06-03 18:34:52 +03:00
Steve Riesenberg e6c268add0 URL encode client credentials
Closes gh-9610
2021-06-03 09:12:18 -05:00
Eleftheria Stein 82d471a592 Fix Resource Server clock skew default value in docs
Closes gh-6611
2021-06-02 12:22:42 +03:00
Josh Cummings f48a006034 Polish postLogoutRedirectUri encoding
Issue gh-9511
2021-05-26 13:51:26 -06:00
Hans Hosea Schaefer b7a0959ede Encode postLogoutRedirectUri query params
Now encodes already encoded queryparameters in postLogoutRedirectUrl
correctly

Closes gh-9511
2021-05-26 13:51:15 -06:00
Marcus Hert da Coregio 29f4193529 Adjust createNewSessionIfAllowed to prevent NPE
Ensure that isTransientAuthentication reuses the same authentication object from saveContext

Closes gh-8947
2021-05-26 13:46:08 -03:00
Steve Riesenberg ab59adbfd2 Handle encoded spaces in the root dn
Fixes an issue where provider URLs passed to the constructor of the
DefaultSpringSecurityContextSource can be URL encoded, resulting in
an invalid base dn. Additionally adds support for list constructor
to support spaces in base dn.

Closes gh-9742
2021-05-26 10:29:49 -05:00
Steve Riesenberg de4b3a4310 Handle custom status codes in error handler
Fixes an issue where custom status codes in the error response cause an
IllegalArgumentException to be thrown when resolving an HttpStatus.

Closes gh-9741
2021-05-25 13:41:04 -05:00
Marcus Hert da Coregio e691906dbc Combine multiple OS builds into one
Closes gh-9790
2021-05-25 14:19:46 -03:00
Marcus Hert da Coregio 5a06fbd984 Update Env Variables in Build Windows Job
Closes gh-9761
2021-05-25 11:07:37 -06:00
Eleftheria Stein 34b55242fe Ensure Kotlin 1.3 compatibility
Closes gh-9765
2021-05-19 10:15:24 +02:00
Rob Winch 26e34368c0 Use GPG_PRIVATE_KEY directly
Closes gh-9776
2021-05-18 17:19:24 -05:00
Rob Winch 0fb7c24cbb core depends on crypto
Issue gh-9767
2021-05-18 17:19:24 -05:00
Josh Cummings 0351883dfa Include all configured branches in CI
Closes gh-9775
2021-05-18 15:59:40 -06:00
Rob Winch 95132d9fe3 Remove spring-security-crypto from spring-core pom
Instead of having api extend included configuration, we should use the
*Classpath configurations.

Closes gh-9767
2021-05-18 15:32:17 -05:00
Rob Winch bf9f1de6e1 Artifactory defaults to publish mavenJava Publication
Closes gh-9772
2021-05-18 15:32:17 -05:00
2178 changed files with 24504 additions and 90103 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
# EditorConfig for Spring Security
# see https://github.com/spring-projects/spring-security/blob/master/CONTRIBUTING.adoc#mind-the-whitespace
# see https://github.com/spring-projects/spring-security/blob/master/CONTRIBUTING.md#mind-the-whitespace
root = true
-1
View File
@@ -14,4 +14,3 @@
*.odg binary
*.otg binary
*.png binary
*.hsx binary
+1 -1
View File
@@ -1,5 +1,5 @@
<!--
For Security Vulnerabilities, please use https://spring.io/security-policy
For Security Vulnerabilities, please use https://pivotal.io/security#reporting
-->
### Summary
-20
View File
@@ -1,20 +0,0 @@
{
"index_name": "security-docs",
"start_urls": [
"https://docs.spring.io/spring-security/reference/"
],
"selectors": {
"lvl0": {
"selector": "//nav[@class='crumbs']//li[@class='crumb'][last()-1]",
"type": "xpath",
"global": true,
"default_value": "Home"
},
"lvl1": ".doc h1",
"lvl2": ".doc h2",
"lvl3": ".doc h3",
"lvl4": ".doc h4",
"text": ".doc p, .doc td.content, .doc th.tableblock"
}
}
-20
View File
@@ -1,20 +0,0 @@
#!/bin/bash
HOST="$1"
HOST_PATH="$2"
SSH_PRIVATE_KEY="$3"
SSH_KNOWN_HOST="$4"
if [ "$#" -ne 4 ]; then
echo -e "not enough arguments USAGE:\n\n$0 \$HOST \$HOST_PATH \$SSH_PRIVATE_KEY \$SSH_KNOWN_HOSTS \n\n" >&2
exit 1
fi
# Use a non-default path to avoid overriding when testing locally
SSH_PRIVATE_KEY_PATH=~/.ssh/github-actions-docs
install -m 600 -D /dev/null "$SSH_PRIVATE_KEY_PATH"
echo "$SSH_PRIVATE_KEY" > "$SSH_PRIVATE_KEY_PATH"
echo "$SSH_KNOWN_HOST" > ~/.ssh/known_hosts
rsync --delete -avze "ssh -i $SSH_PRIVATE_KEY_PATH" docs/build/site/ "$HOST:$HOST_PATH"
rm -f "$SSH_PRIVATE_KEY_PATH"
@@ -1,21 +0,0 @@
#!/bin/bash
###
# Docs
# config.json https://docsearch.algolia.com/docs/config-file
# Run the crawler https://docsearch.algolia.com/docs/run-your-own/#run-the-crawl-from-the-docker-image
### USAGE
if [ "$#" -ne 3 ]; then
echo -e "not enough arguments USAGE:\n\n$0 \$ALGOLIA_APPLICATION_ID \$ALGOLIA_API_KEY \$CONFIG_FILE\n\n" >&2
exit 1
fi
# Script Parameters
APPLICATION_ID=$1
API_KEY=$2
CONFIG_FILE=$3
#### Script
script_dir=$(dirname $0)
docker run -e "APPLICATION_ID=$APPLICATION_ID" -e "API_KEY=$API_KEY" -e "CONFIG=$(cat $CONFIG_FILE | jq -r tostring)" algolia/docsearch-scraper
-5
View File
@@ -1,5 +0,0 @@
REPOSITORY_REF="$1"
TOKEN="$2"
curl -H "Accept: application/vnd.github.everest-preview+json" -H "Authorization: token ${TOKEN}" --request POST --data '{"event_type": "request-build-reference"}' https://api.github.com/repos/${REPOSITORY_REF}/dispatches
echo "Requested Build for $REPOSITORY_REF"
-20
View File
@@ -1,20 +0,0 @@
name: Update Algolia Index
on:
schedule:
- cron: '0 10 * * *' # Once per day at 10am UTC
workflow_dispatch: # Manual trigger
permissions:
contents: read
jobs:
update:
name: Update Algolia Index
runs-on: ubuntu-latest
if: ${{ github.repository == 'spring-projects/spring-security' }}
steps:
- name: Checkout Source
uses: actions/checkout@v2
- name: Update Index
run: ${GITHUB_WORKSPACE}/.github/actions/algolia-docsearch-scraper.sh "${{ secrets.ALGOLIA_APPLICATION_ID }}" "${{ secrets.ALGOLIA_WRITE_API_KEY }}" "${GITHUB_WORKSPACE}/.github/actions/algolia-config.json"
-41
View File
@@ -1,41 +0,0 @@
name: Generate Antora Files and Request Build
on:
workflow_dispatch:
push:
branches-ignore:
- 'gh-pages'
tags: '**'
env:
GH_ACTIONS_REPO_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
if: ${{ github.repository == 'spring-projects/spring-security' }}
steps:
- name: Checkout Source
uses: actions/checkout@v2
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
with:
java-version: '11'
distribution: 'adopt'
- name: Generate antora.yml
run: ./gradlew :spring-security-docs:generateAntora
- name: Extract Branch Name
id: extract_branch_name
run: echo "##[set-output name=generated_branch_name;]$(echo ${GITHUB_REPOSITORY}/${GITHUB_REF##*/})"
- name: Push generated antora files to the spring-generated-docs
uses: JamesIves/github-pages-deploy-action@4.1.4
with:
branch: ${{ steps.extract_branch_name.outputs.generated_branch_name }} # The branch the action should deploy to.
folder: "docs/build/generateAntora" # The folder the action should deploy.
repository-name: "spring-io/spring-generated-docs"
token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
- name: Dispatch Build Request
run: ${GITHUB_WORKSPACE}/.github/actions/dispatch.sh 'spring-projects/spring-security' "$GH_ACTIONS_REPO_TOKEN"
-33
View File
@@ -1,33 +0,0 @@
name: Backport Bot
on:
issues:
types: [labeled]
pull_request:
types: [labeled]
push:
branches:
- '*.x'
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
if: ${{ github.repository == 'spring-projects/spring-security' }}
permissions:
contents: read
issues: write
pull-requests: write
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'
- name: Download BackportBot
run: wget https://github.com/spring-io/backport-bot/releases/download/latest/backport-bot-0.0.1-SNAPSHOT.jar
- name: Backport
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_EVENT: ${{ toJSON(github.event) }}
run: java -jar backport-bot-0.0.1-SNAPSHOT.jar --github.accessToken="$GITHUB_TOKEN" --github.event_name "$GITHUB_EVENT_NAME" --github.event "$GITHUB_EVENT"
@@ -3,15 +3,9 @@ on:
schedule:
- cron: '0 10 * * *' # Once per day at 10am UTC
permissions:
contents: read
jobs:
main:
runs-on: ubuntu-latest
if: ${{ github.repository == 'spring-projects/spring-security' }}
permissions:
contents: none
steps:
- name: Delete artifacts in cron job
env:
@@ -2,8 +2,6 @@ name: CI
on:
push:
branches:
- '**'
schedule:
- cron: '0 10 * * *' # Once per day at 10am UTC
workflow_dispatch: # Manual trigger
@@ -15,31 +13,21 @@ env:
GRADLE_ENTERPRISE_SECRET_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }}
COMMIT_OWNER: ${{ github.event.pusher.name }}
COMMIT_SHA: ${{ github.sha }}
STRUCTURE101_LICENSEID: ${{ secrets.STRUCTURE101_LICENSEID }}
ARTIFACTORY_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }}
ARTIFACTORY_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}
permissions:
contents: read
RUN_JOBS: ${{ github.repository == 'spring-projects/spring-security' }}
jobs:
prerequisites:
name: Pre-requisites for building
runs-on: ubuntu-latest
if: ${{ github.repository == 'spring-projects/spring-security' }}
outputs:
runjobs: ${{ steps.continue.outputs.runjobs }}
project_version: ${{ steps.continue.outputs.project_version }}
steps:
- uses: actions/checkout@v2
- id: continue
name: Determine if should continue
run: |
# Run jobs if in upstream repository
echo "::set-output name=runjobs::true"
# Extract version from gradle.properties
version=$(cat gradle.properties | grep "version=" | awk -F'=' '{print $2}')
echo "::set-output name=project_version::$version"
if: env.RUN_JOBS == 'true'
run: echo "::set-output name=runjobs::true"
build_jdk_11:
name: Build JDK 11
needs: [prerequisites]
@@ -51,14 +39,18 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v2
uses: actions/setup-java@v1
with:
java-version: '11'
distribution: 'adopt'
- name: Set up Gradle
uses: gradle/gradle-build-action@v2
- name: Set up gradle user name
run: echo 'systemProp.user.name=spring-builds+github' >> gradle.properties
- name: Setup gradle user name
run: |
mkdir -p ~/.gradle
echo 'systemProp.user.name=spring-builds' >> ~/.gradle/gradle.properties
- name: Cache Gradle packages
uses: actions/cache@v2
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
- name: Build with Gradle
env:
GRADLE_ENTERPRISE_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USER }}
@@ -72,68 +64,67 @@ jobs:
if: needs.prerequisites.outputs.runjobs
steps:
- uses: actions/checkout@v2
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
- name: Set up JDK
uses: actions/setup-java@v1
with:
java-version: '11'
distribution: 'adopt'
- name: Setup gradle user name
run: |
mkdir -p ~/.gradle
echo 'systemProp.user.name=spring-builds' >> ~/.gradle/gradle.properties
- name: Snapshot Tests
run: |
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD"
export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY"
./gradlew test --refresh-dependencies -PartifactoryUsername="$ARTIFACTORY_USERNAME" -PartifactoryPassword="$ARTIFACTORY_PASSWORD" -PforceMavenRepositories=snapshot -PspringVersion='5.+' -PreactorVersion='20+' -PspringDataVersion='Neumann-BUILD-SNAPSHOT' -PrsocketVersion=1.1.0-SNAPSHOT -PspringBootVersion=2.4.0-SNAPSHOT -PlocksDisabled --stacktrace
check_samples:
name: Check Samples project
sonar_analysis:
name: Static Code Analysis
needs: [prerequisites]
runs-on: ubuntu-latest
if: needs.prerequisites.outputs.runjobs
env:
SONAR_URL: ${{ secrets.SONAR_URL }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
steps:
- uses: actions/checkout@v2
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
- name: Set up JDK
uses: actions/setup-java@v1
with:
java-version: '11'
distribution: 'adopt'
- name: Check samples project
env:
LOCAL_REPOSITORY_PATH: ${{ github.workspace }}/build/publications/repos
SAMPLES_INIT_SCRIPT: ${{ github.workspace }}/build/includeRepo/spring-security-ci.gradle
- name: Setup gradle user name
run: |
mkdir -p ~/.gradle
echo 'systemProp.user.name=spring-builds' >> ~/.gradle/gradle.properties
- name: Run Sonar on given (non-main) branch
if: ${{ github.ref != 'refs/heads/main' }}
run: |
export BRANCH=${GITHUB_REF#refs/heads/}
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD"
export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY"
./gradlew sonarqube -PartifactoryUsername="$ARTIFACTORY_USERNAME" -PartifactoryPassword="$ARTIFACTORY_PASSWORD" -PexcludeProjects='**/samples/**' -Dsonar.projectKey="spring-security-${GITHUB_REF#refs/heads/}" -Dsonar.projectName="spring-security-${GITHUB_REF#refs/heads/}" -Dsonar.host.url="$SONAR_URL" -Dsonar.login="$SONAR_TOKEN" --stacktrace
- name: Run Sonar on main
if: ${{ github.ref == 'refs/heads/main' }}
run: |
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD"
export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY"
./gradlew publishMavenJavaPublicationToLocalRepository
./gradlew checkSamples -PsamplesInitScript="$SAMPLES_INIT_SCRIPT" -PlocalRepositoryPath="$LOCAL_REPOSITORY_PATH" --stacktrace
check_tangles:
name: Check for Package Tangles
needs: [ prerequisites ]
runs-on: ubuntu-latest
if: needs.prerequisites.outputs.runjobs
steps:
- uses: actions/checkout@v2
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
with:
java-version: '11'
distribution: 'adopt'
- name: Check for package tangles
run: |
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD"
export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY"
./gradlew check s101 -Ps101.licenseId="$STRUCTURE101_LICENSEID" --stacktrace
./gradlew sonarqube -PartifactoryUsername="$ARTIFACTORY_USERNAME" -PartifactoryPassword="$ARTIFACTORY_PASSWORD" -PexcludeProjects='**/samples/**' -Dsonar.host.url="$SONAR_URL" -Dsonar.login="$SONAR_TOKEN" --stacktrace
deploy_artifacts:
name: Deploy Artifacts
needs: [build_jdk_11, snapshot_tests, check_samples, check_tangles]
needs: [build_jdk_11, snapshot_tests, sonar_analysis]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
- name: Set up JDK
uses: actions/setup-java@v1
with:
java-version: '11'
distribution: 'adopt'
- name: Setup gradle user name
run: |
mkdir -p ~/.gradle
echo 'systemProp.user.name=spring-builds' >> ~/.gradle/gradle.properties
- name: Deploy artifacts
run: |
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
@@ -149,15 +140,18 @@ jobs:
ARTIFACTORY_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}
deploy_docs:
name: Deploy Docs
needs: [build_jdk_11, snapshot_tests, check_samples, check_tangles]
needs: [build_jdk_11, snapshot_tests, sonar_analysis]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
- name: Set up JDK
uses: actions/setup-java@v1
with:
java-version: '11'
distribution: 'adopt'
- name: Setup gradle user name
run: |
mkdir -p ~/.gradle
echo 'systemProp.user.name=spring-builds' >> ~/.gradle/gradle.properties
- name: Deploy Docs
run: |
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
@@ -170,15 +164,18 @@ jobs:
DOCS_HOST: ${{ secrets.DOCS_HOST }}
deploy_schema:
name: Deploy Schema
needs: [build_jdk_11, snapshot_tests, check_samples, check_tangles]
needs: [build_jdk_11, snapshot_tests, sonar_analysis]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
- name: Set up JDK
uses: actions/setup-java@v1
with:
java-version: '11'
distribution: 'adopt'
- name: Setup gradle user name
run: |
mkdir -p ~/.gradle
echo 'systemProp.user.name=spring-builds' >> ~/.gradle/gradle.properties
- name: Deploy Schema
run: |
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
@@ -189,122 +186,14 @@ jobs:
DOCS_USERNAME: ${{ secrets.DOCS_USERNAME }}
DOCS_SSH_KEY: ${{ secrets.DOCS_SSH_KEY }}
DOCS_HOST: ${{ secrets.DOCS_HOST }}
perform_release:
name: Perform release
needs: [prerequisites, deploy_artifacts, deploy_docs, deploy_schema]
runs-on: ubuntu-latest
permissions:
contents: write
timeout-minutes: 90
if: ${{ !endsWith(needs.prerequisites.outputs.project_version, '-SNAPSHOT') }}
env:
REPO: ${{ github.repository }}
BRANCH: ${{ github.ref_name }}
TOKEN: ${{ github.token }}
VERSION: ${{ needs.prerequisites.outputs.project_version }}
steps:
- uses: actions/checkout@v2
with:
token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
with:
java-version: '11'
distribution: 'adopt'
- name: Wait for Artifactory Artifacts
if: ${{ contains(needs.prerequisites.outputs.project_version, '-RC') || contains(needs.prerequisites.outputs.project_version, '-M') }}
run: |
echo "Wait for artifacts of $REPO@$VERSION to appear on Artifactory."
until curl -f -s https://repo.spring.io/artifactory/milestone/org/springframework/security/spring-security-core/$VERSION/ > /dev/null
do
sleep 30
echo "."
done
echo "Artifacts for $REPO@$VERSION have been released to Artifactory."
- name: Wait for Maven Central Artifacts
if: ${{ !contains(needs.prerequisites.outputs.project_version, '-RC') && !contains(needs.prerequisites.outputs.project_version, '-M') }}
run: |
echo "Wait for artifacts of $REPO@$VERSION to appear on Maven Central."
until curl -f -s https://repo1.maven.org/maven2/org/springframework/security/spring-security-core/$VERSION/ > /dev/null
do
sleep 30
echo "."
done
echo "Artifacts for $REPO@$VERSION have been released to Maven Central."
- name: Create GitHub Release
run: |
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD"
export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY"
echo "Tagging and publishing $REPO@$VERSION release on GitHub."
./gradlew createGitHubRelease -PnextVersion=$VERSION -Pbranch=$BRANCH -PcreateRelease=true -PgitHubAccessToken=$TOKEN
- name: Announce Release on Slack
id: spring-security-announcing
uses: slackapi/slack-github-action@v1.19.0
with:
payload: |
{
"text": "spring-security-announcing `${{ env.VERSION }}` is available now",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "spring-security-announcing `${{ env.VERSION }}` is available now"
}
}
]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SPRING_RELEASE_SLACK_WEBHOOK_URL }}
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
- name: Setup git config
run: |
git config user.name 'github-actions[bot]'
git config user.email 'github-actions[bot]@users.noreply.github.com'
- name: Update to next Snapshot Version
run: |
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD"
export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY"
echo "Updating $REPO@$VERSION to next snapshot version."
./gradlew :updateToSnapshotVersion
./gradlew :spring-security-docs:antoraUpdateVersion
git commit -am "Next development version"
git push
perform_post_release:
name: Perform post-release
needs: [prerequisites, deploy_artifacts, deploy_docs, deploy_schema]
runs-on: ubuntu-latest
permissions:
contents: read
issues: write
timeout-minutes: 90
if: ${{ endsWith(needs.prerequisites.outputs.project_version, '-SNAPSHOT') }}
env:
TOKEN: ${{ github.token }}
VERSION: ${{ needs.prerequisites.outputs.project_version }}
steps:
- uses: actions/checkout@v2
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
with:
java-version: '11'
distribution: 'adopt'
- name: Schedule next release (if not already scheduled)
run: ./gradlew scheduleNextRelease -PnextVersion=$VERSION -PgitHubAccessToken=$TOKEN
notify_result:
name: Check for failures
needs: [perform_release, perform_post_release]
needs: [build_jdk_11, snapshot_tests, sonar_analysis, deploy_artifacts, deploy_docs, deploy_schema]
if: failure()
runs-on: ubuntu-latest
permissions:
actions: read
steps:
- name: Send Slack message
# Workaround while waiting for Gamesight/slack-workflow-status#38 to be fixed
# See https://github.com/Gamesight/slack-workflow-status/issues/38
uses: sjohnr/slack-workflow-status@v1-beta
uses: Gamesight/slack-workflow-status@v1.0.1
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}
-34
View File
@@ -1,34 +0,0 @@
name: Build & Deploy Reference
on:
repository_dispatch:
types: request-build-reference
schedule:
- cron: '0 10 * * *' # Once per day at 10am UTC
workflow_dispatch: # Manual trigger
permissions:
contents: read
jobs:
deploy:
name: deploy
runs-on: ubuntu-latest
if: ${{ github.repository == 'spring-projects/spring-security' }}
steps:
- uses: actions/checkout@v2
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
with:
java-version: '11'
distribution: 'adopt'
- name: Cleanup Gradle Cache
# Remove some files from the Gradle cache, so they aren't cached by GitHub Actions.
# Restoring these files from a GitHub Actions cache might cause problems for future builds.
run: |
rm -f /home/runner/.gradle/caches/modules-2/modules-2.lock
rm -f /home/runner/.gradle/caches/modules-2/gc.properties
- name: Build with Gradle
run: ./gradlew :spring-security-docs:antora --stacktrace
- name: Deploy
run: ${GITHUB_WORKSPACE}/.github/actions/algolia-deploy.sh "${{ secrets.DOCS_USERNAME }}@${{ secrets.DOCS_HOST }}" "/opt/www/domains/spring.io/docs/htdocs/spring-security/reference/" "${{ secrets.DOCS_SSH_KEY }}" "${{ secrets.DOCS_SSH_HOST_KEY }}"
@@ -1,40 +0,0 @@
name: Check Milestone
on:
milestone:
types: [created, opened, edited]
env:
DUE_ON: ${{ github.event.milestone.due_on }}
TITLE: ${{ github.event.milestone.title }}
permissions:
contents: read
jobs:
spring-releasetrain-checks:
name: Check DueOn is on a Release Date
runs-on: ubuntu-latest
if: ${{ github.repository == 'spring-projects/spring-security' }}
permissions:
contents: none
steps:
- name: Print Milestone Being Checked
run: echo "Validating DueOn '$DUE_ON' for milestone '$TITLE'"
- name: Validate DueOn
if: env.DUE_ON != ''
run: |
export TOOL_VERSION=0.1.1
wget "https://repo.maven.apache.org/maven2/io/spring/releasetrain/spring-release-train-tools/$TOOL_VERSION/spring-release-train-tools-$TOOL_VERSION.jar"
java -cp "spring-release-train-tools-$TOOL_VERSION.jar" io.spring.releasetrain.CheckMilestoneDueOnMain --dueOn "$DUE_ON" --expectedDayOfWeek MONDAY --expectedMondayCount 3
notify_result:
name: Check for failures
needs: [spring-releasetrain-checks]
if: failure()
runs-on: ubuntu-latest
permissions:
actions: read
steps:
- name: Send Slack message
uses: Gamesight/slack-workflow-status@v1.0.1
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}
channel: '#spring-security-ci'
name: 'CI Notifier'
+14 -7
View File
@@ -2,20 +2,27 @@ name: PR Build
on: pull_request
permissions:
contents: read
env:
RUN_JOBS: ${{ github.repository == 'spring-projects/spring-security' }}
jobs:
build:
name: Build
runs-on: ubuntu-latest
if: ${{ github.repository == 'spring-projects/spring-security' }}
steps:
- uses: actions/checkout@v2
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
- if: env.RUN_JOBS == 'true'
uses: actions/checkout@v2
- name: Set up JDK
if: env.RUN_JOBS == 'true'
uses: actions/setup-java@v1
with:
java-version: '11'
distribution: 'adopt'
- name: Cache Gradle packages
if: env.RUN_JOBS == 'true'
uses: actions/cache@v2
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
- name: Build with Gradle
if: env.RUN_JOBS == 'true'
run: ./gradlew clean build --continue --scan
@@ -1,81 +0,0 @@
name: Update Scheduled Release Version
on:
workflow_dispatch: # Manual trigger only. Triggered by release-scheduler.yml on main.
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
GRADLE_ENTERPRISE_CACHE_USER: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USER }}
GRADLE_ENTERPRISE_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }}
GRADLE_ENTERPRISE_SECRET_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }}
permissions:
contents: read
jobs:
update_scheduled_release_version:
name: Initiate Release If Scheduled
if: ${{ github.repository == 'spring-projects/spring-security' }}
runs-on: ubuntu-latest
permissions:
contents: read
actions: read
steps:
- id: checkout-source
name: Checkout Source Code
uses: actions/checkout@v2
with:
token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v1
with:
java-version: '11'
distribution: 'adopt'
- id: check-release-due
name: Check Release Due
run: |
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD"
export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY"
./gradlew gitHubCheckNextVersionDueToday
echo "::set-output name=is_due_today::$(cat build/github/milestones/is-due-today)"
- id: check-open-issues
name: Check for open issues
if: steps.check-release-due.outputs.is_due_today == 'true'
run: |
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD"
export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY"
./gradlew gitHubCheckMilestoneHasNoOpenIssues
echo "::set-output name=is_open_issues::$(cat build/github/milestones/is-open-issues)"
- id: validate-release-state
name: Validate State of Release
if: steps.check-release-due.outputs.is_due_today == 'true' && steps.check-open-issues.outputs.is_open_issues == 'true'
run: |
echo "The release is due today but there are open issues"
exit 1
- id: update-version-and-push
name: Update version and push
if: steps.check-release-due.outputs.is_due_today == 'true' && steps.check-open-issues.outputs.is_open_issues == 'false'
run: |
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD"
export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY"
git config user.name 'github-actions[bot]'
git config user.email 'github-actions[bot]@users.noreply.github.com'
./gradlew :updateProjectVersion
./gradlew :spring-security-docs:antoraUpdateVersion
updatedVersion=$(cat gradle.properties | grep "version=" | awk -F'=' '{print $2}')
git commit -am "Release $updatedVersion"
git tag $updatedVersion
git push
git push origin $updatedVersion
- id: send-slack-notification
name: Send Slack message
if: failure()
uses: Gamesight/slack-workflow-status@v1.0.1
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}
channel: '#spring-security-ci'
name: 'CI Notifier'
-6
View File
@@ -1,6 +0,0 @@
# Use sdkman to run "sdk env" to initialize with correct JDK version
# Enable auto-env through the sdkman_auto_env config
# See https://sdkman.io/usage#config
# A summary is to add the following to ~/.sdkman/etc/config
# sdkman_auto_env=true
java=11.0.14-tem
+1 -1
View File
@@ -22,7 +22,7 @@ Be sure to read the https://docs.spring.io/spring-security/site/docs/current/ref
Extensive JavaDoc for the Spring Security code is also available in the https://docs.spring.io/spring-security/site/docs/current/api/[Spring Security API Documentation].
== Quick Start
See https://docs.spring.io/spring-security/site/docs/current/reference/html5/#servlet-hello[Hello Spring Security] to get started with a "Hello, World" application.
See https://docs.spring.io/spring-security/site/docs/5.5.x/reference/html5/#servlet-hello[Hello Spring Security] to get started with a "Hello, World" application.
== Building from Source
Spring Security uses a https://gradle.org[Gradle]-based build system.
+2 -12
View File
@@ -78,16 +78,6 @@ Alternatively, you can manually check using https://github.com/spring-projects/s
Update the version number in `gradle.properties` for the release, for example `5.5.0-M1`, `5.5.0-RC1`, `5.5.0`
= Update Antora Version
You will need to update the antora.yml version.
If you are unsure of what the values should be, the following task will instruct you what the expected values are:
[source,bash]
----
./gradlew :spring-security-docs:antoraCheckVersion
----
= Build Locally
Run the build using
@@ -129,13 +119,13 @@ git push origin 5.4.0-RC1
== 7. Update to Next Development Version
* Update `gradle.properties` version to next `+SNAPSHOT+` version, update antora.yml, and then push
* Update `gradle.properties` version to next `+SNAPSHOT+` version and then push
== 8. Update version on project page
The following command will update https://spring.io/projects/spring-security#learn with the new release version using the following parameters
<github-personal-access-token> - Replace with a https://github.com/settings/tokens[GitHub personal access token] that has a scope of `read:org` as https://spring.io/restdocs/index.html#authentication[documented for spring.io api]
<github-personal-access-token> - Replace with a https://github.com/settings/tokens[GitHub personal access token] that has a scope of `public_repo`
<next-version> - Replace with the milestone you are releasing now (i.e. 5.5.0-RC1)
<previous-version> - Replace with the previous release which will be removed from the listed versions (i.e. 5.5.0-M3)
+1 -7
View File
@@ -11,15 +11,9 @@ dependencies {
optional 'net.sf.ehcache:ehcache'
testImplementation "org.assertj:assertj-core"
testImplementation "org.junit.jupiter:junit-jupiter-api"
testImplementation "org.junit.jupiter:junit-jupiter-params"
testImplementation "org.junit.jupiter:junit-jupiter-engine"
testImplementation "org.mockito:mockito-core"
testImplementation "org.mockito:mockito-junit-jupiter"
testImplementation 'org.springframework:spring-beans'
testImplementation 'org.springframework:spring-context-support'
testImplementation "org.springframework:spring-test"
testImplementation 'org.springframework:spring-test'
testRuntimeOnly 'org.hsqldb:hsqldb'
}
@@ -37,9 +37,7 @@ import org.springframework.util.Assert;
* {@link PermissionGrantingStrategy} and {@link AclAuthorizationStrategy} instances.
*
* @author Ben Alex
* @deprecated since 5.6. In favor of JCache based implementations
*/
@Deprecated
public class EhCacheBasedAclCache implements AclCache {
private final Ehcache cache;
@@ -42,7 +42,7 @@ import org.springframework.security.acls.domain.AuditLogger;
import org.springframework.security.acls.domain.DefaultPermissionFactory;
import org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy;
import org.springframework.security.acls.domain.GrantedAuthoritySid;
import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.domain.PermissionFactory;
import org.springframework.security.acls.domain.PrincipalSid;
import org.springframework.security.acls.model.AccessControlEntry;
@@ -51,7 +51,6 @@ import org.springframework.security.acls.model.AclCache;
import org.springframework.security.acls.model.MutableAcl;
import org.springframework.security.acls.model.NotFoundException;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.acls.model.ObjectIdentityGenerator;
import org.springframework.security.acls.model.Permission;
import org.springframework.security.acls.model.PermissionGrantingStrategy;
import org.springframework.security.acls.model.Sid;
@@ -74,8 +73,8 @@ import org.springframework.util.Assert;
* one in <tt>lookupObjectIdentities</tt>. These are built from the same select and "order
* by" clause, using a different where clause in each case. In order to use custom schema
* or column names, each of these SQL clauses can be customized, but they must be
* consistent with each other and with the expected result set generated by the default
* values.
* consistent with each other and with the expected result set generated by the the
* default values.
*
* @author Ben Alex
*/
@@ -110,8 +109,6 @@ public class BasicLookupStrategy implements LookupStrategy {
private final AclAuthorizationStrategy aclAuthorizationStrategy;
private ObjectIdentityGenerator objectIdentityGenerator;
private PermissionFactory permissionFactory = new DefaultPermissionFactory();
private final AclCache aclCache;
@@ -165,7 +162,6 @@ public class BasicLookupStrategy implements LookupStrategy {
this.aclCache = aclCache;
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
this.grantingStrategy = grantingStrategy;
this.objectIdentityGenerator = new ObjectIdentityRetrievalStrategyImpl();
this.aclClassIdUtils = new AclClassIdUtils();
this.fieldAces.setAccessible(true);
this.fieldAcl.setAccessible(true);
@@ -492,11 +488,6 @@ public class BasicLookupStrategy implements LookupStrategy {
}
}
public final void setObjectIdentityGenerator(ObjectIdentityGenerator objectIdentityGenerator) {
Assert.notNull(objectIdentityGenerator, "objectIdentityGenerator cannot be null");
this.objectIdentityGenerator = objectIdentityGenerator;
}
public final void setConversionService(ConversionService conversionService) {
this.aclClassIdUtils = new AclClassIdUtils(conversionService);
}
@@ -578,8 +569,7 @@ public class BasicLookupStrategy implements LookupStrategy {
// target id type, e.g. UUID.
Serializable identifier = (Serializable) rs.getObject("object_id_identity");
identifier = BasicLookupStrategy.this.aclClassIdUtils.identifierFrom(identifier, rs);
ObjectIdentity objectIdentity = BasicLookupStrategy.this.objectIdentityGenerator
.createObjectIdentity(identifier, rs.getString("class"));
ObjectIdentity objectIdentity = new ObjectIdentityImpl(rs.getString("class"), identifier);
Acl parentAcl = null;
long parentAclId = rs.getLong("parent_object");
@@ -31,12 +31,11 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.core.convert.ConversionService;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.model.Acl;
import org.springframework.security.acls.model.AclService;
import org.springframework.security.acls.model.NotFoundException;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.acls.model.ObjectIdentityGenerator;
import org.springframework.security.acls.model.Sid;
import org.springframework.util.Assert;
@@ -82,8 +81,6 @@ public class JdbcAclService implements AclService {
private AclClassIdUtils aclClassIdUtils;
private ObjectIdentityGenerator objectIdentityGenerator;
public JdbcAclService(DataSource dataSource, LookupStrategy lookupStrategy) {
this(new JdbcTemplate(dataSource), lookupStrategy);
}
@@ -94,7 +91,6 @@ public class JdbcAclService implements AclService {
this.jdbcOperations = jdbcOperations;
this.lookupStrategy = lookupStrategy;
this.aclClassIdUtils = new AclClassIdUtils();
this.objectIdentityGenerator = new ObjectIdentityRetrievalStrategyImpl();
}
@Override
@@ -109,7 +105,7 @@ public class JdbcAclService implements AclService {
String javaType = rs.getString("class");
Serializable identifier = (Serializable) rs.getObject("obj_id");
identifier = this.aclClassIdUtils.identifierFrom(identifier, rs);
return this.objectIdentityGenerator.createObjectIdentity(identifier, javaType);
return new ObjectIdentityImpl(javaType, identifier);
}
@Override
@@ -169,11 +165,6 @@ public class JdbcAclService implements AclService {
this.aclClassIdUtils = new AclClassIdUtils(conversionService);
}
public void setObjectIdentityGenerator(ObjectIdentityGenerator objectIdentityGenerator) {
Assert.notNull(objectIdentityGenerator, "objectIdentityGenerator cannot be null");
this.objectIdentityGenerator = objectIdentityGenerator;
}
protected boolean isAclClassIdSupported() {
return this.aclClassIdSupported;
}
@@ -16,7 +16,7 @@
package org.springframework.security.acls;
import org.junit.jupiter.api.Test;
import org.junit.Test;
import org.springframework.security.acls.domain.AclFormattingUtils;
import org.springframework.security.acls.model.Permission;
@@ -20,7 +20,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.junit.Test;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.model.AclService;
@@ -18,7 +18,7 @@ package org.springframework.security.acls;
import java.util.Locale;
import org.junit.jupiter.api.Test;
import org.junit.Test;
import org.springframework.security.acls.model.Acl;
import org.springframework.security.acls.model.AclService;
@@ -21,7 +21,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.junit.Test;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
@@ -20,7 +20,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.junit.Test;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
@@ -16,7 +16,7 @@
package org.springframework.security.acls.domain;
import org.junit.jupiter.api.Test;
import org.junit.Test;
import org.springframework.security.acls.model.AccessControlEntry;
import org.springframework.security.acls.model.Acl;
@@ -18,12 +18,12 @@ package org.springframework.security.acls.domain;
import java.util.Arrays;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.security.acls.model.Acl;
import org.springframework.security.authentication.TestingAuthenticationToken;
@@ -37,7 +37,7 @@ import static org.mockito.BDDMockito.given;
* @author Rob Winch
*
*/
@ExtendWith(MockitoExtension.class)
@RunWith(MockitoJUnitRunner.class)
public class AclAuthorizationStrategyImplTests {
@Mock
@@ -47,7 +47,7 @@ public class AclAuthorizationStrategyImplTests {
AclAuthorizationStrategyImpl strategy;
@BeforeEach
@Before
public void setup() {
this.authority = new SimpleGrantedAuthority("ROLE_AUTH");
TestingAuthenticationToken authentication = new TestingAuthenticationToken("foo", "bar",
@@ -56,7 +56,7 @@ public class AclAuthorizationStrategyImplTests {
SecurityContextHolder.getContext().setAuthentication(authentication);
}
@AfterEach
@After
public void cleanup() {
SecurityContextHolder.clearContext();
}
@@ -22,9 +22,9 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.security.acls.model.AccessControlEntry;
import org.springframework.security.acls.model.Acl;
@@ -83,7 +83,7 @@ public class AclImplTests {
private DefaultPermissionFactory permissionFactory;
@BeforeEach
@Before
public void setUp() {
SecurityContextHolder.getContext().setAuthentication(this.auth);
this.authzStrategy = mock(AclAuthorizationStrategy.class);
@@ -93,7 +93,7 @@ public class AclImplTests {
this.permissionFactory = new DefaultPermissionFactory();
}
@AfterEach
@After
public void tearDown() {
SecurityContextHolder.clearContext();
}
@@ -16,9 +16,9 @@
package org.springframework.security.acls.domain;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.acls.model.Acl;
@@ -43,12 +43,12 @@ public class AclImplementationSecurityCheckTests {
private static final String TARGET_CLASS = "org.springframework.security.acls.TargetObject";
@BeforeEach
@Before
public void setUp() {
SecurityContextHolder.clearContext();
}
@AfterEach
@After
public void tearDown() {
SecurityContextHolder.clearContext();
}
@@ -19,9 +19,9 @@ package org.springframework.security.acls.domain;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.security.acls.model.AccessControlEntry;
import org.springframework.security.acls.model.AuditableAccessControlEntry;
@@ -45,7 +45,7 @@ public class AuditLoggerTests {
private AuditableAccessControlEntry ace;
@BeforeEach
@Before
public void setUp() {
this.logger = new ConsoleAuditLogger();
this.ace = mock(AuditableAccessControlEntry.class);
@@ -53,7 +53,7 @@ public class AuditLoggerTests {
System.setOut(new PrintStream(this.bytes));
}
@AfterEach
@After
public void tearDown() {
System.setOut(this.console);
this.bytes.reset();
@@ -16,7 +16,7 @@
package org.springframework.security.acls.domain;
import org.junit.jupiter.api.Test;
import org.junit.Test;
import org.springframework.security.acls.model.ObjectIdentity;
@@ -16,7 +16,7 @@
package org.springframework.security.acls.domain;
import org.junit.jupiter.api.Test;
import org.junit.Test;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.acls.model.ObjectIdentityRetrievalStrategy;
@@ -16,8 +16,8 @@
package org.springframework.security.acls.domain;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.Before;
import org.junit.Test;
import org.springframework.security.acls.model.Permission;
@@ -32,7 +32,7 @@ public class PermissionTests {
private DefaultPermissionFactory permissionFactory;
@BeforeEach
@Before
public void createPermissionfactory() {
this.permissionFactory = new DefaultPermissionFactory();
}
@@ -26,11 +26,11 @@ import javax.sql.DataSource;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.acls.TargetObject;
@@ -81,19 +81,19 @@ public abstract class AbstractBasicLookupStrategyTests {
public abstract DataSource getDataSource();
@BeforeAll
@BeforeClass
public static void initCacheManaer() {
cacheManager = CacheManager.create();
cacheManager.addCache(new Cache("basiclookuptestcache", 500, false, false, 30, 30));
}
@AfterAll
@AfterClass
public static void shutdownCacheManager() {
cacheManager.removalAll();
cacheManager.shutdown();
}
@BeforeEach
@Before
public void populateDatabase() {
String query = "INSERT INTO acl_sid(ID,PRINCIPAL,SID) VALUES (1,1,'ben');"
+ "INSERT INTO acl_class(ID,CLASS) VALUES (2,'" + TARGET_CLASS + "');"
@@ -107,7 +107,7 @@ public abstract class AbstractBasicLookupStrategyTests {
getJdbcTemplate().execute(query);
}
@BeforeEach
@Before
public void initializeBeans() {
this.strategy = new BasicLookupStrategy(getDataSource(), aclCache(), aclAuthStrategy(),
new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger()));
@@ -123,7 +123,7 @@ public abstract class AbstractBasicLookupStrategyTests {
new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_USER")));
}
@AfterEach
@After
public void emptyDatabase() {
String query = "DELETE FROM acl_entry;" + "DELETE FROM acl_object_identity WHERE ID = 9;"
+ "DELETE FROM acl_object_identity WHERE ID = 8;" + "DELETE FROM acl_object_identity WHERE ID = 7;"
@@ -318,13 +318,4 @@ public abstract class AbstractBasicLookupStrategyTests {
assertThat(((GrantedAuthoritySid) result).getGrantedAuthority()).isEqualTo("sid");
}
@Test
public void setObjectIdentityGeneratorWhenNullThenThrowsIllegalArgumentException() {
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> this.strategy.setObjectIdentityGenerator(null))
.withMessage("objectIdentityGenerator cannot be null");
// @formatter:on
}
}
@@ -22,11 +22,11 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.UUID;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.core.convert.ConversionService;
@@ -39,7 +39,7 @@ import static org.mockito.BDDMockito.given;
*
* @author paulwheeler
*/
@ExtendWith(MockitoExtension.class)
@RunWith(MockitoJUnitRunner.class)
public class AclClassIdUtilsTests {
private static final Long DEFAULT_IDENTIFIER = 999L;
@@ -56,7 +56,7 @@ public class AclClassIdUtilsTests {
private AclClassIdUtils aclClassIdUtils;
@BeforeEach
@Before
public void setUp() {
this.aclClassIdUtils = new AclClassIdUtils();
}
@@ -18,8 +18,8 @@ package org.springframework.security.acls.jdbc;
import javax.sql.DataSource;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -33,12 +33,12 @@ public class BasicLookupStrategyTests extends AbstractBasicLookupStrategyTests {
private static final BasicLookupStrategyTestsDbHelper DATABASE_HELPER = new BasicLookupStrategyTestsDbHelper();
@BeforeAll
@BeforeClass
public static void createDatabase() throws Exception {
DATABASE_HELPER.createDatabase();
}
@AfterAll
@AfterClass
public static void dropDatabase() {
DATABASE_HELPER.getDataSource().destroy();
}
@@ -21,10 +21,11 @@ import java.util.Map;
import javax.sql.DataSource;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import junit.framework.Assert;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.support.DefaultConversionService;
@@ -36,7 +37,6 @@ import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.model.Acl;
import org.springframework.security.acls.model.ObjectIdentity;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
@@ -60,18 +60,18 @@ public class BasicLookupStrategyWithAclClassTypeTests extends AbstractBasicLooku
return DATABASE_HELPER.getDataSource();
}
@BeforeAll
@BeforeClass
public static void createDatabase() throws Exception {
DATABASE_HELPER.createDatabase();
}
@AfterAll
@AfterClass
public static void dropDatabase() {
DATABASE_HELPER.getDataSource().destroy();
}
@Override
@BeforeEach
@Before
public void initializeBeans() {
super.initializeBeans();
this.uuidEnabledStrategy = new BasicLookupStrategy(getDataSource(), aclCache(), aclAuthStrategy(),
@@ -81,7 +81,7 @@ public class BasicLookupStrategyWithAclClassTypeTests extends AbstractBasicLooku
this.uuidEnabledStrategy.setConversionService(new DefaultConversionService());
}
@BeforeEach
@Before
public void populateDatabaseForAclClassTypeTests() {
String query = "INSERT INTO acl_class(ID,CLASS,CLASS_ID_TYPE) VALUES (3,'" + TARGET_CLASS_WITH_UUID
+ "', 'java.util.UUID');"
@@ -99,8 +99,8 @@ public class BasicLookupStrategyWithAclClassTypeTests extends AbstractBasicLooku
ObjectIdentity oid = new ObjectIdentityImpl(TARGET_CLASS_WITH_UUID, OBJECT_IDENTITY_UUID);
Map<ObjectIdentity, Acl> foundAcls = this.uuidEnabledStrategy.readAclsById(Arrays.asList(oid),
Arrays.asList(BEN_SID));
assertThat(foundAcls).hasSize(1);
assertThat(foundAcls.get(oid)).isNotNull();
Assert.assertEquals(1, foundAcls.size());
Assert.assertNotNull(foundAcls.get(oid));
}
@Test
@@ -108,8 +108,8 @@ public class BasicLookupStrategyWithAclClassTypeTests extends AbstractBasicLooku
ObjectIdentity oid = new ObjectIdentityImpl(TARGET_CLASS, 100L);
Map<ObjectIdentity, Acl> foundAcls = this.uuidEnabledStrategy.readAclsById(Arrays.asList(oid),
Arrays.asList(BEN_SID));
assertThat(foundAcls).hasSize(1);
assertThat(foundAcls.get(oid)).isNotNull();
Assert.assertEquals(1, foundAcls.size());
Assert.assertNotNull(foundAcls.get(oid));
}
@Test
@@ -26,14 +26,14 @@ import java.util.List;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.security.acls.domain.AclAuthorizationStrategy;
import org.springframework.security.acls.domain.AclAuthorizationStrategyImpl;
@@ -62,7 +62,7 @@ import static org.mockito.Mockito.verify;
*
* @author Andrei Stefan
*/
@ExtendWith(MockitoExtension.class)
@RunWith(MockitoJUnitRunner.class)
public class EhCacheBasedAclCacheTests {
private static final String TARGET_CLASS = "org.springframework.security.acls.TargetObject";
@@ -77,7 +77,7 @@ public class EhCacheBasedAclCacheTests {
private MutableAcl acl;
@BeforeEach
@Before
public void setup() {
this.myCache = new EhCacheBasedAclCache(this.cache,
new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger()),
@@ -89,7 +89,7 @@ public class EhCacheBasedAclCacheTests {
this.acl = new AclImpl(identity, 1L, aclAuthorizationStrategy, new ConsoleAuditLogger());
}
@AfterEach
@After
public void cleanup() {
SecurityContextHolder.clearContext();
}
@@ -25,12 +25,12 @@ import java.util.UUID;
import javax.sql.DataSource;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.RowMapper;
@@ -45,7 +45,6 @@ import org.springframework.security.acls.model.Sid;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.anyString;
@@ -57,7 +56,7 @@ import static org.mockito.BDDMockito.given;
*
* @author Nena Raab
*/
@ExtendWith(MockitoExtension.class)
@RunWith(MockitoJUnitRunner.class)
public class JdbcAclServiceTests {
private EmbeddedDatabase embeddedDatabase;
@@ -75,20 +74,23 @@ public class JdbcAclServiceTests {
private JdbcAclService aclService;
@BeforeEach
@Before
public void setUp() {
this.aclService = new JdbcAclService(this.jdbcOperations, this.lookupStrategy);
this.aclServiceIntegration = new JdbcAclService(this.embeddedDatabase, this.lookupStrategy);
}
@Before
public void setUpEmbeddedDatabase() {
// @formatter:off
this.embeddedDatabase = new EmbeddedDatabaseBuilder()
.addScript("createAclSchemaWithAclClassIdType.sql")
.addScript("db/sql/test_data_hierarchy.sql")
.build();
// @formatter:on
this.aclService = new JdbcAclService(this.jdbcOperations, this.lookupStrategy);
this.aclServiceIntegration = new JdbcAclService(this.embeddedDatabase, this.lookupStrategy);
}
@AfterEach
@After
public void tearDownEmbeddedDatabase() {
this.embeddedDatabase.shutdown();
}
@@ -171,26 +173,6 @@ public class JdbcAclServiceTests {
.isEqualTo(UUID.fromString("25d93b3f-c3aa-4814-9d5e-c7c96ced7762"));
}
@Test
public void setObjectIdentityGeneratorWhenNullThenThrowsIllegalArgumentException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> this.aclServiceIntegration.setObjectIdentityGenerator(null))
.withMessage("objectIdentityGenerator cannot be null");
}
@Test
public void findChildrenWhenObjectIdentityGeneratorSetThenUsed() {
this.aclServiceIntegration
.setObjectIdentityGenerator((id, type) -> new ObjectIdentityImpl(type, "prefix:" + id));
ObjectIdentity objectIdentity = new ObjectIdentityImpl("location", "US");
this.aclServiceIntegration.setAclClassIdSupported(true);
List<ObjectIdentity> objectIdentities = this.aclServiceIntegration.findChildren(objectIdentity);
assertThat(objectIdentities.size()).isEqualTo(1);
assertThat(objectIdentities.get(0).getType()).isEqualTo("location");
assertThat(objectIdentities.get(0).getIdentifier()).isEqualTo("prefix:US-PAL");
}
class MockLongIdDomainObject {
private Object id;
@@ -22,8 +22,7 @@ import java.util.Map;
import javax.sql.DataSource;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
@@ -50,7 +49,7 @@ import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
import org.springframework.test.context.transaction.AfterTransaction;
import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.transaction.annotation.Transactional;
@@ -67,10 +66,8 @@ import static org.mockito.Mockito.spy;
* @author Ben Alex
* @author Andrei Stefan
*/
@Transactional
@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = { "/jdbcMutableAclServiceTests-context.xml" })
public class JdbcMutableAclServiceTests {
public class JdbcMutableAclServiceTests extends AbstractTransactionalJUnit4SpringContextTests {
private static final String TARGET_CLASS = TargetObject.class.getName();
@@ -18,7 +18,7 @@ package org.springframework.security.acls.jdbc;
import java.util.UUID;
import org.junit.jupiter.api.Test;
import org.junit.Test;
import org.springframework.security.acls.TargetObjectWithUUID;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
@@ -18,9 +18,9 @@ package org.springframework.security.acls.jdbc;
import java.util.Map;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.After;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
@@ -56,7 +56,7 @@ public class SpringCacheBasedAclCacheTests {
private static CacheManager cacheManager;
@BeforeAll
@BeforeClass
public static void initCacheManaer() {
cacheManager = new ConcurrentMapCacheManager();
// Use disk caching immediately (to test for serialization issue reported in
@@ -64,7 +64,7 @@ public class SpringCacheBasedAclCacheTests {
cacheManager.getCache("springcasebasedacltests");
}
@AfterEach
@After
public void clearContext() {
SecurityContextHolder.clearContext();
}
@@ -18,7 +18,7 @@ package org.springframework.security.acls.sid;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.junit.Test;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.acls.domain.GrantedAuthoritySid;
@@ -19,7 +19,7 @@ package org.springframework.security.acls.sid;
import java.util.Collection;
import java.util.Collections;
import org.junit.jupiter.api.Test;
import org.junit.Test;
import org.springframework.security.acls.domain.GrantedAuthoritySid;
import org.springframework.security.acls.domain.PrincipalSid;
+4 -7
View File
@@ -10,13 +10,6 @@ dependencies {
api 'org.springframework:spring-core'
testImplementation 'org.springframework:spring-aop'
testImplementation "org.assertj:assertj-core"
testImplementation "org.junit.jupiter:junit-jupiter-api"
testImplementation "org.junit.jupiter:junit-jupiter-params"
testImplementation "org.junit.jupiter:junit-jupiter-engine"
testImplementation "org.mockito:mockito-core"
testImplementation "org.mockito:mockito-junit-jupiter"
testImplementation "org.springframework:spring-test"
testAspect sourceSets.main.output
}
@@ -27,3 +20,7 @@ sourceSets.test.aspectj.srcDir "src/test/java"
sourceSets.test.java.srcDirs = files()
compileAspectj.ajcOptions.outxmlfile = "META-INF/aop.xml"
aspectj {
version = aspectjVersion
}
@@ -20,9 +20,9 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -74,7 +74,7 @@ public class AnnotationSecurityAspectTests {
private PrePostSecured prePostSecured = new PrePostSecured();
@BeforeEach
@Before
public final void setUp() {
MockitoAnnotations.initMocks(this);
this.interceptor = new AspectJMethodSecurityInterceptor();
@@ -88,7 +88,7 @@ public class AnnotationSecurityAspectTests {
secAspect.setSecurityInterceptor(this.interceptor);
}
@AfterEach
@After
public void clearContext() {
SecurityContextHolder.clearContext();
}
+15 -82
View File
@@ -1,28 +1,25 @@
buildscript {
dependencies {
classpath "io.spring.javaformat:spring-javaformat-gradle-plugin:$springJavaformatVersion"
classpath 'io.spring.nohttp:nohttp-gradle:0.0.10'
classpath "io.freefair.gradle:aspectj-plugin:6.4.3.1"
classpath 'io.spring.nohttp:nohttp-gradle:0.0.8'
classpath "io.freefair.gradle:aspectj-plugin:5.3.3.3"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
classpath "com.netflix.nebula:nebula-project-plugin:8.2.0"
classpath "com.netflix.nebula:nebula-project-plugin:8.0.0"
}
repositories {
gradlePluginPortal()
maven { url 'https://repo.spring.io/plugins-snapshot' }
maven { url 'https://plugins.gradle.org/m2/' }
}
}
apply plugin: 'io.spring.nohttp'
apply plugin: 'locks'
apply plugin: 's101'
apply plugin: 'io.spring.convention.root'
apply plugin: 'io.spring.convention.include-check-remote'
apply plugin: 'org.jetbrains.kotlin.jvm'
apply plugin: 'org.springframework.security.update-dependencies'
apply plugin: 'org.springframework.security.update-version'
apply plugin: 'org.springframework.security.sagan'
apply plugin: 'org.springframework.github.milestone'
apply plugin: 'org.springframework.github.changelog'
apply plugin: 'org.springframework.github.release'
group = 'org.springframework.security'
description = 'Spring Security'
@@ -36,7 +33,7 @@ repositories {
}
tasks.named("saganCreateRelease") {
referenceDocUrl = "https://docs.spring.io/spring-security/reference/{version}/index.html"
referenceDocUrl = "https://docs.spring.io/spring-security/site/docs/{version}/reference/html5/"
apiDocUrl = "https://docs.spring.io/spring-security/site/docs/{version}/api/"
}
@@ -47,43 +44,6 @@ tasks.named("gitHubCheckMilestoneHasNoOpenIssues") {
}
}
tasks.named("gitHubNextReleaseMilestone") {
repository {
owner = "spring-projects"
name = "spring-security"
}
}
tasks.named("gitHubCheckNextVersionDueToday") {
repository {
owner = "spring-projects"
name = "spring-security"
}
}
tasks.named("scheduleNextRelease") {
repository {
owner = "spring-projects"
name = "spring-security"
}
weekOfMonth = 3
dayOfWeek = 1
}
tasks.named("createGitHubRelease") {
repository {
owner = "spring-projects"
name = "spring-security"
}
}
tasks.named("dispatchGitHubWorkflow") {
repository {
owner = "spring-projects"
name = "spring-security"
}
}
tasks.named("updateDependencies") {
// we aren't Gradle 7 compatible yet
checkForGradleUpdate = false
@@ -96,23 +56,18 @@ updateDependenciesSettings {
}
addFiles({
return [
project.file("buildSrc/src/main/java/io/spring/gradle/convention/AsciidoctorConventionPlugin.java"),
project.file("buildSrc/src/main/groovy/io/spring/gradle/convention/CheckstylePlugin.groovy")
]
})
dependencyExcludes {
majorVersionBump()
minorVersionBump()
alphaBetaVersions()
releaseCandidatesVersions()
milestoneVersions()
alphaBetaVersions()
snapshotVersions()
addRule { components ->
components.withModule("commons-codec:commons-codec") { selection ->
ModuleComponentIdentifier candidate = selection.getCandidate();
if (!candidate.getVersion().equals(selection.getCurrentVersion())) {
selection.reject("commons-codec updates break saml tests");
}
}
components.withModule("org.python:jython") { selection ->
ModuleComponentIdentifier candidate = selection.getCandidate();
if (!candidate.getVersion().equals(selection.getCurrentVersion())) {
@@ -132,17 +87,13 @@ updateDependenciesSettings {
if (candidate.getGroup().equals("org.opensaml")) {
selection.reject("org.opensaml maintains two different versions, so it must be updated manually");
}
}
components.withModule("io.spring.javaformat:spring-javaformat-gradle-plugin") { selection ->
ModuleComponentIdentifier candidate = selection.getCandidate();
if (!candidate.getVersion().equals(selection.getCurrentVersion())) {
selection.reject("spring-javaformat-gradle-plugin updates break checkstyle");
}
}
components.withModule("io.spring.javaformat:spring-javaformat-checkstyle") { selection ->
ModuleComponentIdentifier candidate = selection.getCandidate();
if (!candidate.getVersion().equals(selection.getCurrentVersion())) {
selection.reject("spring-javaformat-checkstyle updates break checkstyle");
if (candidate.getGroup().equals("org.jetbrains.kotlin")) {
if (candidate.getVersion().endsWith("-RC")) {
selection.reject("On a maintenance branch, we should not take RC versions")
}
if (candidate.getVersion().contains("-M")) {
selection.reject("On a maintenance branch, we should not take milestone versions")
}
}
}
}
@@ -155,8 +106,6 @@ subprojects {
}
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
options.compilerArgs.add("-parameters")
options.release = 8
}
}
@@ -199,19 +148,3 @@ nohttp {
source.exclude "buildSrc/build/**"
}
tasks.register('checkSamples') {
includeCheckRemote {
repository = 'spring-projects/spring-security-samples'
ref = samplesBranch
if (project.hasProperty("samplesInitScript")) {
initScripts = [samplesInitScript]
projectProperties = ["localRepositoryPath": localRepositoryPath, "springSecurityVersion": project.version]
}
}
dependsOn checkRemote
}
s101 {
configurationDirectory = project.file("etc/s101")
}
+14 -36
View File
@@ -5,9 +5,11 @@ plugins {
id 'com.apollographql.apollo' version '2.4.5'
}
sourceCompatibility = 1.8
repositories {
jcenter()
gradlePluginPortal()
mavenCentral()
maven { url 'https://repo.spring.io/plugins-release/' }
@@ -26,10 +28,6 @@ sourceSets {
gradlePlugin {
plugins {
checkAntoraVersion {
id = "org.springframework.antora.check-version"
implementationClass = "org.springframework.gradle.antora.AntoraVersionPlugin"
}
trang {
id = "trang"
implementationClass = "trang.TrangPlugin"
@@ -46,10 +44,6 @@ gradlePlugin {
id = "org.springframework.security.update-dependencies"
implementationClass = "org.springframework.security.convention.versions.UpdateDependenciesPlugin"
}
updateProjectVersion {
id = "org.springframework.security.update-version"
implementationClass = "org.springframework.security.convention.versions.UpdateProjectVersionPlugin"
}
sagan {
id = "org.springframework.security.sagan"
implementationClass = "org.springframework.gradle.sagan.SaganPlugin"
@@ -62,14 +56,6 @@ gradlePlugin {
id = "org.springframework.github.changelog"
implementationClass = "org.springframework.gradle.github.changelog.GitHubChangelogPlugin"
}
githubRelease {
id = "org.springframework.github.release"
implementationClass = "org.springframework.gradle.github.release.GitHubReleasePlugin"
}
s101 {
id = "s101"
implementationClass = "s101.S101Plugin"
}
}
}
@@ -83,39 +69,31 @@ dependencies {
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.thaiopensource:trang:20091111'
implementation 'net.sourceforge.saxon:saxon:9.1.0.8'
implementation 'org.yaml:snakeyaml:1.30'
implementation localGroovy()
implementation 'io.github.gradle-nexus:publish-plugin:1.1.0'
implementation 'io.projectreactor:reactor-core:3.5.0-M1'
implementation 'io.projectreactor:reactor-core:3.4.9'
implementation 'gradle.plugin.org.gretty:gretty:3.0.1'
implementation 'com.apollographql.apollo:apollo-runtime:2.4.5'
implementation 'com.github.ben-manes:gradle-versions-plugin:0.38.0'
implementation 'com.github.spullara.mustache.java:compiler:0.9.4'
implementation 'io.spring.gradle:docbook-reference-plugin:0.3.1'
implementation 'io.spring.gradle:propdeps-plugin:0.0.10.RELEASE'
implementation 'io.spring.javaformat:spring-javaformat-gradle-plugin:0.0.15'
implementation 'io.spring.nohttp:nohttp-gradle:0.0.10'
implementation 'net.sourceforge.htmlunit:htmlunit:2.37.0'
implementation 'io.spring.nohttp:nohttp-gradle:0.0.8'
implementation 'org.aim42:htmlSanityCheck:1.1.6'
implementation 'org.asciidoctor:asciidoctor-gradle-jvm:3.1.0'
implementation 'org.asciidoctor:asciidoctor-gradle-jvm-pdf:3.1.0'
implementation 'org.hidetake:gradle-ssh-plugin:2.10.1'
implementation 'org.jfrog.buildinfo:build-info-extractor-gradle:4.29.0'
implementation 'org.jfrog.buildinfo:build-info-extractor-gradle:4.9.10'
implementation 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.7.1'
testImplementation platform('org.junit:junit-bom:5.8.2')
testImplementation "org.junit.jupiter:junit-jupiter-api"
testImplementation "org.junit.jupiter:junit-jupiter-params"
testImplementation "org.junit.jupiter:junit-jupiter-engine"
testImplementation 'junit:junit:4.12'
testImplementation 'org.apache.commons:commons-io:1.3.2'
testImplementation 'org.assertj:assertj-core:3.13.2'
testImplementation 'org.mockito:mockito-core:3.12.4'
testImplementation 'org.mockito:mockito-junit-jupiter:3.12.4'
testImplementation 'org.mockito:mockito-core:3.0.0'
testImplementation 'org.spockframework:spock-core:1.3-groovy-2.5'
testImplementation "com.squareup.okhttp3:mockwebserver:3.14.9"
}
tasks.named('test', Test).configure {
onlyIf { !project.hasProperty("buildSrc.skipTests") }
useJUnitPlatform()
jvmArgs(
'--add-opens', 'java.base/java.lang=ALL-UNNAMED',
'--add-opens', 'java.base/java.util=ALL-UNNAMED'
)
}
test.onlyIf { !project.hasProperty("buildSrc.skipTests") }
Binary file not shown.
+1 -1
View File
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
@@ -1,104 +0,0 @@
/*
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package io.spring.gradle
import groovy.transform.CompileStatic
import groovy.transform.TypeChecked
import groovy.transform.TypeCheckingMode
import org.gradle.api.DefaultTask
import org.gradle.api.Task
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction
/**
* Checkout a project template from a git repository.
*
* @author Marcus Da Coregio
*/
@CompileStatic
abstract class IncludeRepoTask extends DefaultTask {
private static final String DEFAULT_URI_PREFIX = 'https://github.com/'
/**
* Git repository to use. Will be prefixed with {@link #DEFAULT_URI_PREFIX} if it isn't already
* @return
*/
@Input
abstract Property<String> getRepository();
/**
* Git reference to use.
*/
@Input
abstract Property<String> getRef()
/**
* Directory where the project template should be copied.
*/
@OutputDirectory
final File outputDirectory = project.file("$project.buildDir/$name")
@TaskAction
void checkoutAndCopy() {
outputDirectory.deleteDir()
File checkoutDir = checkout(this, getRemoteUri(), ref.get())
moveToOutputDir(checkoutDir, outputDirectory)
}
private static File cleanTemporaryDir(Task task, File tmpDir) {
if (tmpDir.exists()) {
task.project.delete(tmpDir)
}
return tmpDir
}
static File checkout(Task task, String remoteUri, String ref) {
checkout(task, remoteUri, ref, task.getTemporaryDir())
}
@TypeChecked(TypeCheckingMode.SKIP)
static File checkout(Task task, String remoteUri, String ref, File checkoutDir) {
cleanTemporaryDir(task, checkoutDir)
task.project.exec {
commandLine = ["git", "clone", "--no-checkout", remoteUri, checkoutDir.absolutePath]
errorOutput = System.err
}
task.project.exec {
commandLine = ["git", "checkout", ref]
workingDir = checkoutDir
errorOutput = System.err
}
return checkoutDir
}
private static void moveToOutputDir(File tmpDir, File outputDirectory) {
File baseDir = tmpDir
baseDir.renameTo(outputDirectory)
}
private String getRemoteUri() {
String remoteUri = this.repository.get()
if (remoteUri.startsWith(DEFAULT_URI_PREFIX)) {
return remoteUri
}
return DEFAULT_URI_PREFIX + remoteUri
}
}
@@ -16,17 +16,20 @@
package io.spring.gradle.convention;
import io.spring.gradle.propdeps.PropDepsMavenPlugin;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.plugins.GroovyPlugin;
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.MavenPlugin;
import org.gradle.api.plugins.PluginManager;
import org.gradle.internal.impldep.org.apache.maven.Maven;
import org.gradle.plugins.ide.eclipse.EclipseWtpPlugin;
import org.gradle.plugins.ide.idea.IdeaPlugin;
import org.springframework.gradle.CopyPropertiesPlugin
import org.springframework.gradle.propdeps.PropDepsEclipsePlugin
import org.springframework.gradle.propdeps.PropDepsIdeaPlugin
import org.springframework.gradle.propdeps.PropDepsPlugin;
import io.spring.gradle.propdeps.PropDepsEclipsePlugin;
import io.spring.gradle.propdeps.PropDepsIdeaPlugin;
import io.spring.gradle.propdeps.PropDepsPlugin
import org.springframework.gradle.CopyPropertiesPlugin;
/**
* @author Rob Winch
@@ -37,7 +40,7 @@ public abstract class AbstractSpringJavaPlugin implements Plugin<Project> {
public final void apply(Project project) {
PluginManager pluginManager = project.getPluginManager();
pluginManager.apply(JavaPlugin.class);
pluginManager.apply(ManagementConfigurationPlugin.class)
pluginManager.apply(ManagementConfigurationPlugin.class);
if (project.file("src/main/groovy").exists()
|| project.file("src/test/groovy").exists()
|| project.file("src/integration-test/groovy").exists()) {
@@ -49,8 +52,12 @@ public abstract class AbstractSpringJavaPlugin implements Plugin<Project> {
pluginManager.apply(PropDepsPlugin);
pluginManager.apply(PropDepsEclipsePlugin);
pluginManager.apply(PropDepsIdeaPlugin);
project.getPlugins().withType(MavenPlugin) {
pluginManager.apply(PropDepsMavenPlugin);
}
pluginManager.apply("io.spring.convention.tests-configuration");
pluginManager.apply("io.spring.convention.integration-test");
pluginManager.apply("io.spring.convention.dependency-set");
pluginManager.apply("io.spring.convention.javadoc-options");
pluginManager.apply("io.spring.convention.checkstyle");
pluginManager.apply(CopyPropertiesPlugin);
@@ -62,9 +69,6 @@ public abstract class AbstractSpringJavaPlugin implements Plugin<Project> {
manifest.attributes["Implementation-Version"] = project.version
manifest.attributes["Automatic-Module-Name"] = project.name.replace('-', '.')
}
project.test {
useJUnitPlatform()
}
additionalPlugins(project);
}
@@ -17,7 +17,6 @@ package io.spring.gradle.convention
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.publish.maven.plugins.MavenPublishPlugin
class ArtifactoryPlugin implements Plugin<Project> {
@@ -37,14 +36,8 @@ class ArtifactoryPlugin implements Plugin<Project> {
password = artifactoryPassword
}
}
}
}
project.plugins.withType(MavenPublishPlugin) {
project.artifactory {
publish {
defaults {
publications('mavenJava')
}
defaults {
publications('mavenJava')
}
}
}
@@ -36,7 +36,7 @@ class CheckstylePlugin implements Plugin<Project> {
if (checkstyleDir.exists() && checkstyleDir.directory) {
project.getPluginManager().apply('checkstyle')
project.dependencies.add('checkstyle', 'io.spring.javaformat:spring-javaformat-checkstyle:0.0.15')
project.dependencies.add('checkstyle', 'io.spring.nohttp:nohttp-checkstyle:0.0.10')
project.dependencies.add('checkstyle', 'io.spring.nohttp:nohttp-checkstyle:0.0.8')
project.checkstyle {
configDirectory = checkstyleDir
@@ -0,0 +1,126 @@
/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package io.spring.gradle.convention;
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPlugin
/**
* Adds sets of dependencies to make it easy to add a grouping of dependencies. The
* dependencies added are:
*
* <ul>
* <li>sockDependencies</li>
* <li>seleniumDependencies</li>
* <li>gebDependencies</li>
* <li>powerMockDependencies</li>
* <li>slf4jDependencies</li>
* <li>jstlDependencies</li>
* <li>apachedsDependencies</li>
* </ul>
*
* @author Rob Winch
*/
public class DependencySetPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
project.ext.spockDependencies = [
project.dependencies.create("org.spockframework:spock-spring") {
exclude group: 'junit', module: 'junit-dep'
},
project.dependencies.create("org.spockframework:spock-core") {
exclude group: 'junit', module: 'junit-dep'
}
]
project.ext.seleniumDependencies = [
"org.seleniumhq.selenium:htmlunit-driver",
"org.seleniumhq.selenium:selenium-support"
]
project.ext.gebDependencies = project.spockDependencies +
project.seleniumDependencies + [
"org.gebish:geb-spock",
'commons-httpclient:commons-httpclient',
"org.codehaus.groovy:groovy",
"org.codehaus.groovy:groovy-all"
]
project.ext.powerMockDependencies = [
"org.powermock:powermock-core",
"org.powermock:powermock-api-support",
"org.powermock:powermock-module-junit4-common",
"org.powermock:powermock-module-junit4",
project.dependencies.create("org.powermock:powermock-api-mockito") {
exclude group: 'org.mockito', module: 'mockito-all'
},
"org.powermock:powermock-reflect"
]
project.ext.powerMock2Dependencies = [
"org.powermock:powermock-core",
"org.powermock:powermock-api-support",
"org.powermock:powermock-module-junit4-common",
"org.powermock:powermock-module-junit4",
project.dependencies.create("org.powermock:powermock-api-mockito2") {
exclude group: 'org.mockito', module: 'mockito-all'
},
"org.powermock:powermock-reflect"
]
project.ext.slf4jDependencies = [
"org.slf4j:slf4j-api",
"org.slf4j:jcl-over-slf4j",
"org.slf4j:log4j-over-slf4j",
"ch.qos.logback:logback-classic"
]
project.ext.springCoreDependency = [
project.dependencies.create("org.springframework:spring-core") {
exclude(group: 'commons-logging', module: 'commons-logging')
}
]
project.ext.testDependencies = [
"junit:junit",
"org.mockito:mockito-core",
"org.springframework:spring-test",
"org.assertj:assertj-core"
]
project.ext.jstlDependencies = [
"javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api",
"org.apache.taglibs:taglibs-standard-jstlel"
]
project.ext.apachedsDependencies = [
"org.apache.directory.server:apacheds-core",
"org.apache.directory.server:apacheds-core-entry",
"org.apache.directory.server:apacheds-protocol-shared",
"org.apache.directory.server:apacheds-protocol-ldap",
"org.apache.directory.server:apacheds-server-jndi",
'org.apache.directory.shared:shared-ldap'
]
project.plugins.withType(JavaPlugin) {
project.dependencies {
testImplementation project.testDependencies
}
}
}
}
@@ -1,9 +1,12 @@
package io.spring.gradle.convention
import org.aim42.htmlsanitycheck.HtmlSanityCheckPlugin
import org.aim42.htmlsanitycheck.HtmlSanityCheckTask
import org.aim42.htmlsanitycheck.check.BrokenHttpLinksChecker
import org.asciidoctor.gradle.jvm.AbstractAsciidoctorTask
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.plugins.BasePlugin
import org.gradle.api.plugins.PluginManager
import org.gradle.api.tasks.bundling.Zip
@@ -16,18 +19,54 @@ public class DocsPlugin implements Plugin<Project> {
public void apply(Project project) {
PluginManager pluginManager = project.getPluginManager();
pluginManager.apply(BasePlugin);
pluginManager.apply("org.asciidoctor.jvm.convert");
pluginManager.apply("org.asciidoctor.jvm.pdf");
pluginManager.apply(AsciidoctorConventionPlugin);
pluginManager.apply(DeployDocsPlugin);
pluginManager.apply(JavadocApiPlugin);
pluginManager.apply(HtmlSanityCheckPlugin)
String projectName = Utils.getProjectName(project);
String pdfFilename = projectName + "-reference.pdf";
project.tasks.withType(AbstractAsciidoctorTask) { t ->
project.configure(t) {
sources {
include "**/*.adoc"
exclude '_*/**'
}
}
}
project.tasks.withType(HtmlSanityCheckTask) { HtmlSanityCheckTask t ->
project.configure(t) {
t.dependsOn 'asciidoctor'
t.checkerClasses = [BrokenHttpLinksChecker]
t.checkingResultsDir = new File(project.getBuildDir(), "/report/htmlchecks")
t.failOnErrors = false
t.httpConnectionTimeout = 3000
t.sourceDir = new File(project.getBuildDir(), "/docs/asciidoc/")
t.sourceDocuments = project.files(new File(project.getBuildDir(), "/docs/asciidoc/index.html"))
}
}
Task docsZip = project.tasks.create('docsZip', Zip) {
dependsOn 'api'
dependsOn 'api', 'asciidoctor'
group = 'Distribution'
archiveBaseName = project.rootProject.name
archiveClassifier = 'docs'
description = "Builds -${archiveClassifier.get()} archive containing all " +
description = "Builds -${classifier} archive containing all " +
"Docs for deployment at docs.spring.io"
from(project.tasks.asciidoctor.outputs) {
into 'reference/html5'
include '**'
}
from(project.tasks.asciidoctorPdf.outputs) {
into 'reference/pdf'
include '**'
rename "index.pdf", pdfFilename
}
from(project.tasks.api.outputs) {
into 'api'
}
@@ -1,80 +0,0 @@
/*
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package io.spring.gradle.convention
import io.spring.gradle.IncludeRepoTask
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.tasks.GradleBuild
import org.gradle.api.tasks.TaskProvider
/**
* Adds a set of tasks that make easy to clone a remote repository and perform some task
*
* @author Marcus Da Coregio
*/
class IncludeCheckRemotePlugin implements Plugin<Project> {
@Override
void apply(Project project) {
IncludeCheckRemoteExtension extension = project.extensions.create('includeCheckRemote', IncludeCheckRemoteExtension)
TaskProvider<IncludeRepoTask> includeRepoTask = project.tasks.register('includeRepo', IncludeRepoTask) { IncludeRepoTask it ->
it.repository = extension.repository
it.ref = extension.ref
}
project.tasks.register('checkRemote', GradleBuild) {
it.dependsOn 'includeRepo'
it.dir = includeRepoTask.get().outputDirectory
it.tasks = extension.getTasks()
extension.getInitScripts().forEach {script ->
it.startParameter.addInitScript(new File(script))
}
extension.getProjectProperties().entrySet().forEach { entry ->
it.startParameter.projectProperties.put(entry.getKey(), entry.getValue())
}
}
}
abstract static class IncludeCheckRemoteExtension {
/**
* Git repository to clone
*/
String repository;
/**
* Git ref to checkout
*/
String ref
/**
* Task to run in the repository
*/
List<String> tasks = ['check']
/**
* Init scripts for the build
*/
List<String> initScripts = []
/**
* Map of properties for the build
*/
Map<String, String> projectProperties = [:]
}
}
@@ -15,6 +15,7 @@
*/
package io.spring.gradle.convention
import io.spring.gradle.propdeps.PropDepsPlugin
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
@@ -23,7 +24,6 @@ import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.tasks.testing.Test
import org.gradle.plugins.ide.eclipse.EclipsePlugin
import org.gradle.plugins.ide.idea.IdeaPlugin
import org.springframework.gradle.propdeps.PropDepsPlugin
/**
*
@@ -54,27 +54,19 @@ public class IntegrationTestPlugin implements Plugin<Project> {
}
project.configurations {
integrationTestCompile {
extendsFrom testImplementation
extendsFrom testCompile, testImplementation
}
integrationTestRuntime {
extendsFrom integrationTestCompile, testRuntime, testRuntimeOnly
}
integrationTestCompileClasspath {
extendsFrom integrationTestCompile
canBeResolved = true
}
integrationTestRuntimeClasspath {
extendsFrom integrationTestRuntime
canBeResolved = true
}
}
project.sourceSets {
integrationTest {
java.srcDir project.file('src/integration-test/java')
resources.srcDir project.file('src/integration-test/resources')
compileClasspath = project.sourceSets.main.output + project.sourceSets.test.output + project.configurations.integrationTestCompileClasspath
runtimeClasspath = output + compileClasspath + project.configurations.integrationTestRuntimeClasspath
compileClasspath = project.sourceSets.main.output + project.sourceSets.test.output + project.configurations.integrationTestCompile
runtimeClasspath = output + compileClasspath + project.configurations.integrationTestRuntime
}
}
@@ -85,7 +77,6 @@ public class IntegrationTestPlugin implements Plugin<Project> {
testClassesDirs = project.sourceSets.integrationTest.output.classesDirs
classpath = project.sourceSets.integrationTest.runtimeClasspath
shouldRunAfter project.tasks.test
useJUnitPlatform()
}
project.tasks.check.dependsOn integrationTestTask
@@ -93,7 +84,7 @@ public class IntegrationTestPlugin implements Plugin<Project> {
project.idea {
module {
testSourceDirs += project.file('src/integration-test/java')
scopes.TEST.plus += [ project.configurations.integrationTestCompileClasspath ]
scopes.TEST.plus += [ project.configurations.integrationTestCompile ]
}
}
}
@@ -123,7 +114,7 @@ public class IntegrationTestPlugin implements Plugin<Project> {
project.plugins.withType(EclipsePlugin) {
project.eclipse.classpath {
plusConfigurations += [ project.configurations.integrationTestCompileClasspath ]
plusConfigurations += [ project.configurations.integrationTestCompile ]
}
}
}
@@ -1,21 +1,7 @@
/*
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.spring.gradle.convention;
import io.spring.gradle.propdeps.PropDepsPlugin;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.ConfigurationContainer;
@@ -26,8 +12,6 @@ import org.gradle.api.publish.PublishingExtension;
import org.gradle.api.publish.maven.MavenPublication;
import org.gradle.api.publish.maven.plugins.MavenPublishPlugin;
import org.springframework.gradle.propdeps.PropDepsPlugin;
/**
* Creates a Management configuration that is appropriate for adding a platform to that is not exposed externally. If
* the JavaPlugin is applied, the compileClasspath, runtimeClasspath, testCompileClasspath, and testRuntimeClasspath
@@ -71,4 +55,5 @@ public class ManagementConfigurationPlugin implements Plugin<Project> {
}));
});
}
}
}
@@ -0,0 +1,26 @@
package io.spring.gradle.convention
import org.gradle.api.Plugin
import org.gradle.api.Project
public class OssrhPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
if(project.hasProperty('ossrhUsername')) {
project.uploadArchives {
repositories {
mavenDeployer {
repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
authentication(userName: project.ossrhUsername, password: project.ossrhPassword)
}
snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") {
authentication(userName: project.ossrhUsername, password: project.ossrhPassword)
}
}
}
}
}
}
}
@@ -35,6 +35,11 @@ class RepositoryConventionPlugin implements Plugin<Project> {
mavenLocal()
}
mavenCentral()
jcenter() {
content {
includeGroup "org.gretty"
}
}
if (isSnapshot) {
maven {
name = 'artifactory-snapshot'
@@ -21,7 +21,6 @@ import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.BasePlugin
import org.gradle.api.plugins.PluginManager
import org.springframework.gradle.classpath.CheckProhibitedDependenciesLifecyclePlugin
import org.springframework.gradle.maven.SpringNexusPublishPlugin
class RootProjectPlugin implements Plugin<Project> {
@@ -33,8 +32,6 @@ class RootProjectPlugin implements Plugin<Project> {
pluginManager.apply(SchemaPlugin)
pluginManager.apply(NoHttpPlugin)
pluginManager.apply(SpringNexusPublishPlugin)
pluginManager.apply(CheckProhibitedDependenciesLifecyclePlugin)
pluginManager.apply(ArtifactoryPlugin)
pluginManager.apply("org.sonarqube")
project.repositories.mavenCentral()
@@ -20,7 +20,6 @@ import org.gradle.api.Project
import org.gradle.api.plugins.JavaLibraryPlugin;
import org.gradle.api.plugins.MavenPlugin;
import org.gradle.api.plugins.PluginManager
import org.springframework.gradle.classpath.CheckClasspathForProhibitedDependenciesPlugin;
import org.springframework.gradle.maven.SpringMavenPlugin;
/**
@@ -33,13 +32,15 @@ class SpringModulePlugin extends AbstractSpringJavaPlugin {
PluginManager pluginManager = project.getPluginManager();
pluginManager.apply(JavaLibraryPlugin.class)
pluginManager.apply(SpringMavenPlugin.class);
pluginManager.apply(CheckClasspathForProhibitedDependenciesPlugin.class);
pluginManager.apply("io.spring.convention.jacoco");
def deployArtifacts = project.task("deployArtifacts")
deployArtifacts.group = 'Deploy tasks'
deployArtifacts.description = "Deploys the artifacts to either Artifactory or Maven Central"
if (!Utils.isRelease(project)) {
if (Utils.isRelease(project)) {
deployArtifacts.dependsOn project.tasks.uploadArchives
}
else {
deployArtifacts.dependsOn project.tasks.artifactoryPublish
}
}
@@ -0,0 +1,208 @@
/*
* Copyright 2019-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.spring.gradle.convention;
import org.asciidoctor.gradle.base.AsciidoctorAttributeProvider;
import org.asciidoctor.gradle.jvm.AbstractAsciidoctorTask;
import org.asciidoctor.gradle.jvm.AsciidoctorJExtension;
import org.asciidoctor.gradle.jvm.AsciidoctorJPlugin;
import org.asciidoctor.gradle.jvm.AsciidoctorTask;
import org.gradle.api.Action;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.DependencySet;
import org.gradle.api.artifacts.dsl.RepositoryHandler;
import org.gradle.api.file.CopySpec;
import org.gradle.api.file.FileTree;
import org.gradle.api.tasks.Sync;
import java.io.File;
import java.net.URI;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.function.Consumer;
/**
* Conventions that are applied in the presence of the {@link AsciidoctorJPlugin}. When
* the plugin is applied:
*
* <ul>
* <li>All warnings are made fatal.
* <li>A task is created to resolve and unzip our documentation resources (CSS and
* Javascript).
* <li>For each {@link AsciidoctorTask} (HTML only):
* <ul>
* <li>A configuration named asciidoctorExtensions is ued to add the
* <a href="https://github.com/spring-io/spring-asciidoctor-extensions#block-switch">block
* switch</a> extension
* <li>{@code doctype} {@link AsciidoctorTask#options(Map) option} is configured.
* <li>{@link AsciidoctorTask#attributes(Map) Attributes} are configured for syntax
* highlighting, CSS styling, docinfo, etc.
* </ul>
* <li>For each {@link AbstractAsciidoctorTask} (HTML and PDF):
* <ul>
* <li>{@link AsciidoctorTask#attributes(Map) Attributes} are configured to enable
* warnings for references to missing attributes, the year is added as @{code today-year},
* etc
* <li>{@link AbstractAsciidoctorTask#baseDirFollowsSourceDir() baseDirFollowsSourceDir()}
* is enabled.
* </ul>
* </ul>
*
* @author Andy Wilkinson
* @author Rob Winch
*/
public class AsciidoctorConventionPlugin implements Plugin<Project> {
public void apply(Project project) {
project.getPlugins().withType(AsciidoctorJPlugin.class, (asciidoctorPlugin) -> {
createDefaultAsciidoctorRepository(project);
makeAllWarningsFatal(project);
Sync unzipResources = createUnzipDocumentationResourcesTask(project);
project.getTasks().withType(AbstractAsciidoctorTask.class, (asciidoctorTask) -> {
asciidoctorTask.dependsOn(unzipResources);
configureExtensions(project, asciidoctorTask);
configureCommonAttributes(project, asciidoctorTask);
configureOptions(asciidoctorTask);
asciidoctorTask.baseDirFollowsSourceDir();
asciidoctorTask.useIntermediateWorkDir();
asciidoctorTask.resources(new Action<CopySpec>() {
@Override
public void execute(CopySpec resourcesSpec) {
resourcesSpec.from(unzipResources);
resourcesSpec.from(asciidoctorTask.getSourceDir(), new Action<CopySpec>() {
@Override
public void execute(CopySpec resourcesSrcDirSpec) {
// https://github.com/asciidoctor/asciidoctor-gradle-plugin/issues/523
// For now copy the entire sourceDir over so that include files are
// available in the intermediateWorkDir
// resourcesSrcDirSpec.include("images/**");
}
});
}
});
if (asciidoctorTask instanceof AsciidoctorTask) {
configureHtmlOnlyAttributes(project, asciidoctorTask);
}
});
});
}
private void createDefaultAsciidoctorRepository(Project project) {
project.getGradle().afterProject(new Action<Project>() {
@Override
public void execute(Project project) {
RepositoryHandler repositories = project.getRepositories();
if (repositories.isEmpty()) {
repositories.mavenCentral();
repositories.maven(repo -> {
repo.setUrl(URI.create("https://repo.spring.io/release"));
});
}
}
});
}
private void makeAllWarningsFatal(Project project) {
project.getExtensions().getByType(AsciidoctorJExtension.class).fatalWarnings(".*");
}
private void configureExtensions(Project project, AbstractAsciidoctorTask asciidoctorTask) {
Configuration extensionsConfiguration = project.getConfigurations().maybeCreate("asciidoctorExtensions");
extensionsConfiguration.defaultDependencies(new Action<DependencySet>() {
@Override
public void execute(DependencySet dependencies) {
dependencies.add(project.getDependencies().create("io.spring.asciidoctor:spring-asciidoctor-extensions-block-switch:0.4.2.RELEASE"));
}
});
asciidoctorTask.configurations(extensionsConfiguration);
}
private Sync createUnzipDocumentationResourcesTask(Project project) {
Configuration documentationResources = project.getConfigurations().maybeCreate("documentationResources");
documentationResources.getDependencies()
.add(project.getDependencies().create("io.spring.docresources:spring-doc-resources:0.2.5"));
Sync unzipResources = project.getTasks().create("unzipDocumentationResources",
Sync.class, new Action<Sync>() {
@Override
public void execute(Sync sync) {
sync.dependsOn(documentationResources);
sync.from(new Callable<List<FileTree>>() {
@Override
public List<FileTree> call() throws Exception {
List<FileTree> result = new ArrayList<>();
documentationResources.getAsFileTree().forEach(new Consumer<File>() {
@Override
public void accept(File file) {
result.add(project.zipTree(file));
}
});
return result;
}
});
File destination = new File(project.getBuildDir(), "docs/resources");
sync.into(project.relativePath(destination));
}
});
return unzipResources;
}
private void configureOptions(AbstractAsciidoctorTask asciidoctorTask) {
asciidoctorTask.options(Collections.singletonMap("doctype", "book"));
}
private void configureHtmlOnlyAttributes(Project project, AbstractAsciidoctorTask asciidoctorTask) {
Map<String, Object> attributes = new HashMap<>();
attributes.put("source-highlighter", "highlight.js");
attributes.put("highlightjsdir", "js/highlight");
attributes.put("highlightjs-theme", "github");
attributes.put("linkcss", true);
attributes.put("icons", "font");
attributes.put("stylesheet", "css/spring.css");
asciidoctorTask.getAttributeProviders().add(new AsciidoctorAttributeProvider() {
@Override
public Map<String, Object> getAttributes() {
Object version = project.getVersion();
Map<String, Object> attrs = new HashMap<>();
if (version != null && version.toString() != Project.DEFAULT_VERSION) {
attrs.put("revnumber", version);
}
return attrs;
}
});
asciidoctorTask.attributes(attributes);
}
private void configureCommonAttributes(Project project, AbstractAsciidoctorTask asciidoctorTask) {
Map<String, Object> attributes = new HashMap<>();
attributes.put("attribute-missing", "warn");
attributes.put("icons", "font");
attributes.put("idprefix", "");
attributes.put("idseparator", "-");
attributes.put("docinfo", "shared");
attributes.put("sectanchors", "");
attributes.put("sectnums", "");
attributes.put("today-year", LocalDate.now().getYear());
asciidoctorTask.attributes(attributes);
}
}
@@ -1,71 +0,0 @@
package org.springframework.gradle.antora;
import org.gradle.api.Action;
import org.gradle.api.GradleException;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.language.base.plugins.LifecycleBasePlugin;
public class AntoraVersionPlugin implements Plugin<Project> {
public static final String ANTORA_CHECK_VERSION_TASK_NAME = "antoraCheckVersion";
@Override
public void apply(Project project) {
TaskProvider<CheckAntoraVersionTask> antoraCheckVersion = project.getTasks().register(ANTORA_CHECK_VERSION_TASK_NAME, CheckAntoraVersionTask.class, new Action<CheckAntoraVersionTask>() {
@Override
public void execute(CheckAntoraVersionTask antoraCheckVersion) {
antoraCheckVersion.setGroup(LifecycleBasePlugin.VERIFICATION_GROUP);
antoraCheckVersion.setDescription("Checks the antora.yml version properties match the Gradle version");
antoraCheckVersion.getAntoraVersion().convention(project.provider(() -> getDefaultAntoraVersion(project)));
antoraCheckVersion.getAntoraPrerelease().convention(project.provider(() -> getDefaultAntoraPrerelease(project)));
antoraCheckVersion.getAntoraDisplayVersion().convention(project.provider(() -> getDefaultAntoraDisplayVersion(project)));
antoraCheckVersion.getAntoraYmlFile().fileProvider(project.provider(() -> project.file("antora.yml")));
}
});
project.getPlugins().withType(LifecycleBasePlugin.class, new Action<LifecycleBasePlugin>() {
@Override
public void execute(LifecycleBasePlugin lifecycleBasePlugin) {
project.getTasks().named(LifecycleBasePlugin.CHECK_TASK_NAME).configure(new Action<Task>() {
@Override
public void execute(Task check) {
check.dependsOn(antoraCheckVersion);
}
});
}
});
project.getTasks().register("antoraUpdateVersion", UpdateAntoraVersionTask.class, new Action<UpdateAntoraVersionTask>() {
@Override
public void execute(UpdateAntoraVersionTask antoraUpdateVersion) {
antoraUpdateVersion.setGroup("Release");
antoraUpdateVersion.setDescription("Updates the antora.yml version properties to match the Gradle version");
antoraUpdateVersion.getAntoraYmlFile().fileProvider(project.provider(() -> project.file("antora.yml")));
}
});
}
private static String getDefaultAntoraVersion(Project project) {
String projectVersion = getProjectVersion(project);
return AntoraVersionUtils.getDefaultAntoraVersion(projectVersion);
}
private static String getDefaultAntoraPrerelease(Project project) {
String projectVersion = getProjectVersion(project);
return AntoraVersionUtils.getDefaultAntoraPrerelease(projectVersion);
}
private static String getDefaultAntoraDisplayVersion(Project project) {
String projectVersion = getProjectVersion(project);
return AntoraVersionUtils.getDefaultAntoraDisplayVersion(projectVersion);
}
private static String getProjectVersion(Project project) {
Object projectVersion = project.getVersion();
if (projectVersion == null) {
throw new GradleException("Please define antoraVersion and antoraPrerelease on " + ANTORA_CHECK_VERSION_TASK_NAME + " or provide a Project version so they can be defaulted");
}
return String.valueOf(projectVersion);
}
}
@@ -1,55 +0,0 @@
/*
* Copyright 2019-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.gradle.antora;
public class AntoraVersionUtils {
public static String getDefaultAntoraVersion(String projectVersion) {
int preReleaseIndex = getSnapshotIndex(projectVersion);
return isSnapshot(projectVersion) ? projectVersion.substring(0, preReleaseIndex) : projectVersion;
}
public static String getDefaultAntoraPrerelease(String projectVersion) {
if (isSnapshot(projectVersion)) {
int preReleaseIndex = getSnapshotIndex(projectVersion);
return projectVersion.substring(preReleaseIndex);
}
if (isPreRelease(projectVersion)) {
return Boolean.TRUE.toString();
}
return null;
}
public static String getDefaultAntoraDisplayVersion(String projectVersion) {
if (!isSnapshot(projectVersion) && isPreRelease(projectVersion)) {
return getDefaultAntoraVersion(projectVersion);
}
return null;
}
private static boolean isSnapshot(String projectVersion) {
return getSnapshotIndex(projectVersion) >= 0;
}
private static int getSnapshotIndex(String projectVersion) {
return projectVersion.lastIndexOf("-SNAPSHOT");
}
private static boolean isPreRelease(String projectVersion) {
return projectVersion.lastIndexOf("-") >= 0;
}
}
@@ -1,96 +0,0 @@
package org.springframework.gradle.antora;
import org.gradle.api.DefaultTask;
import org.gradle.api.GradleException;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.TaskAction;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.representer.Representer;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public abstract class CheckAntoraVersionTask extends DefaultTask {
@TaskAction
public void check() throws FileNotFoundException {
File antoraYmlFile = getAntoraYmlFile().getAsFile().get();
String expectedAntoraVersion = getAntoraVersion().get();
String expectedAntoraPrerelease = getAntoraPrerelease().getOrElse(null);
String expectedAntoraDisplayVersion = getAntoraDisplayVersion().getOrElse(null);
Representer representer = new Representer();
representer.getPropertyUtils().setSkipMissingProperties(true);
Yaml yaml = new Yaml(new Constructor(AntoraYml.class), representer);
AntoraYml antoraYml = yaml.load(new FileInputStream(antoraYmlFile));
String actualAntoraPrerelease = antoraYml.getPrerelease();
boolean preReleaseMatches = antoraYml.getPrerelease() == null && expectedAntoraPrerelease == null ||
(actualAntoraPrerelease != null && actualAntoraPrerelease.equals(expectedAntoraPrerelease));
String actualAntoraDisplayVersion = antoraYml.getDisplay_version();
boolean displayVersionMatches = antoraYml.getDisplay_version() == null && expectedAntoraDisplayVersion == null ||
(actualAntoraDisplayVersion != null && actualAntoraDisplayVersion.equals(expectedAntoraDisplayVersion));
String actualAntoraVersion = antoraYml.getVersion();
if (!preReleaseMatches ||
!displayVersionMatches ||
!expectedAntoraVersion.equals(actualAntoraVersion)) {
throw new GradleException("The Gradle version of '" + getProject().getVersion() + "' should have version: '"
+ expectedAntoraVersion + "' prerelease: '" + expectedAntoraPrerelease + "' display_version: '"
+ expectedAntoraDisplayVersion + "' defined in " + antoraYmlFile + " but got version: '"
+ actualAntoraVersion + "' prerelease: '" + actualAntoraPrerelease + "' display_version: '" + actualAntoraDisplayVersion + "'");
}
}
@InputFile
public abstract RegularFileProperty getAntoraYmlFile();
@Input
public abstract Property<String> getAntoraVersion();
@Input
@Optional
public abstract Property<String> getAntoraPrerelease();
@Input
@Optional
public abstract Property<String> getAntoraDisplayVersion();
public static class AntoraYml {
private String version;
private String prerelease;
private String display_version;
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getPrerelease() {
return prerelease;
}
public void setPrerelease(String prerelease) {
this.prerelease = prerelease;
}
public String getDisplay_version() {
return display_version;
}
public void setDisplay_version(String display_version) {
this.display_version = display_version;
}
}
}
@@ -1,138 +0,0 @@
/*
* Copyright 2019-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.gradle.antora;
import org.gradle.api.DefaultTask;
import org.gradle.api.GradleException;
import org.gradle.api.Project;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.TaskAction;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.nodes.NodeTuple;
import org.yaml.snakeyaml.nodes.Tag;
import org.yaml.snakeyaml.representer.Representer;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import org.springframework.gradle.github.milestones.NextVersionYml;
public abstract class UpdateAntoraVersionTask extends DefaultTask {
@TaskAction
public void update() throws IOException {
String projectVersion = getProject().getVersion().toString();
File antoraYmlFile = getAntoraYmlFile().getAsFile().get();
String updatedAntoraVersion = AntoraVersionUtils.getDefaultAntoraVersion(projectVersion);
String updatedAntoraPrerelease = AntoraVersionUtils.getDefaultAntoraPrerelease(projectVersion);
String updatedAntoraDisplayVersion = AntoraVersionUtils.getDefaultAntoraDisplayVersion(projectVersion);
Representer representer = new Representer();
representer.getPropertyUtils().setSkipMissingProperties(true);
Yaml yaml = new Yaml(new Constructor(AntoraYml.class), representer);
AntoraYml antoraYml = yaml.load(new FileInputStream(antoraYmlFile));
System.out.println("Updating the version parameters in " + antoraYmlFile.getName() + " to version: "
+ updatedAntoraVersion + ", prerelease: " + updatedAntoraPrerelease + ", display_version: "
+ updatedAntoraDisplayVersion);
antoraYml.setVersion(updatedAntoraVersion);
antoraYml.setPrerelease(updatedAntoraPrerelease);
antoraYml.setDisplay_version(updatedAntoraDisplayVersion);
FileWriter outputWriter = new FileWriter(antoraYmlFile);
getYaml().dump(antoraYml, outputWriter);
}
@InputFile
public abstract RegularFileProperty getAntoraYmlFile();
public static class AntoraYml {
private String name;
private String version;
private String prerelease;
private String display_version;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getPrerelease() {
return prerelease;
}
public void setPrerelease(String prerelease) {
this.prerelease = prerelease;
}
public String getDisplay_version() {
return display_version;
}
public void setDisplay_version(String display_version) {
this.display_version = display_version;
}
}
private Yaml getYaml() {
Representer representer = new Representer() {
@Override
protected NodeTuple representJavaBeanProperty(Object javaBean,
org.yaml.snakeyaml.introspector.Property property, Object propertyValue, Tag customTag) {
// Don't write out null values
if (propertyValue == null) {
return null;
}
else {
return super.representJavaBeanProperty(javaBean, property, propertyValue, customTag);
}
}
};
representer.addClassTag(AntoraYml.class, Tag.MAP);
DumperOptions ymlOptions = new DumperOptions();
ymlOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
ymlOptions.setDefaultScalarStyle(DumperOptions.ScalarStyle.SINGLE_QUOTED);
return new Yaml(representer, ymlOptions);
}
}
@@ -1,99 +0,0 @@
/*
* Copyright 2012-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.gradle.classpath;
import org.gradle.api.DefaultTask;
import org.gradle.api.GradleException;
import org.gradle.api.Task;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.ModuleVersionIdentifier;
import org.gradle.api.artifacts.ResolvedConfiguration;
import org.gradle.api.file.FileCollection;
import org.gradle.api.tasks.Classpath;
import org.gradle.api.tasks.TaskAction;
import java.io.IOException;
import java.util.TreeSet;
import java.util.stream.Collectors;
/**
* A {@link Task} for checking the classpath for prohibited dependencies.
*
* @author Andy Wilkinson
*/
public class CheckClasspathForProhibitedDependencies extends DefaultTask {
private Configuration classpath;
public CheckClasspathForProhibitedDependencies() {
getOutputs().upToDateWhen((task) -> true);
}
public void setClasspath(Configuration classpath) {
this.classpath = classpath;
}
@Classpath
public FileCollection getClasspath() {
return this.classpath;
}
@TaskAction
public void checkForProhibitedDependencies() throws IOException {
ResolvedConfiguration resolvedConfiguration = this.classpath.getResolvedConfiguration();
TreeSet<String> prohibited = resolvedConfiguration.getResolvedArtifacts().stream()
.map((artifact) -> artifact.getModuleVersion().getId()).filter(this::prohibited)
.map((id) -> id.getGroup() + ":" + id.getName()).collect(Collectors.toCollection(TreeSet::new));
if (!prohibited.isEmpty()) {
StringBuilder message = new StringBuilder(String.format("Found prohibited dependencies in '%s':%n", this.classpath.getName()));
for (String dependency : prohibited) {
message.append(String.format(" %s%n", dependency));
}
throw new GradleException(message.toString());
}
}
private boolean prohibited(ModuleVersionIdentifier id) {
String group = id.getGroup();
if (group.equals("javax.batch")) {
return false;
}
if (group.equals("javax.cache")) {
return false;
}
if (group.equals("javax.money")) {
return false;
}
if (group.startsWith("javax")) {
return true;
}
if (group.equals("commons-logging")) {
return true;
}
if (group.equals("org.slf4j") && id.getName().equals("jcl-over-slf4j")) {
return true;
}
if (group.startsWith("org.jboss.spec")) {
return true;
}
if (group.equals("org.apache.geronimo.specs")) {
return true;
}
return false;
}
}
@@ -1,67 +0,0 @@
/*
* Copyright 2012-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.gradle.classpath;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.ConfigurationContainer;
import org.gradle.api.plugins.JavaBasePlugin;
import org.gradle.api.tasks.SourceSetContainer;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.language.base.plugins.LifecycleBasePlugin;
import org.springframework.util.StringUtils;
/**
* @author Andy Wilkinson
* @author Rob Winch
*/
public class CheckClasspathForProhibitedDependenciesPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
project.getPlugins().apply(CheckProhibitedDependenciesLifecyclePlugin.class);
project.getPlugins().withType(JavaBasePlugin.class, javaBasePlugin -> {
configureProhibitedDependencyChecks(project);
});
}
private void configureProhibitedDependencyChecks(Project project) {
SourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class);
sourceSets.all((sourceSet) -> createProhibitedDependenciesChecks(project,
sourceSet.getCompileClasspathConfigurationName(), sourceSet.getRuntimeClasspathConfigurationName()));
}
private void createProhibitedDependenciesChecks(Project project, String... configurationNames) {
ConfigurationContainer configurations = project.getConfigurations();
for (String configurationName : configurationNames) {
Configuration configuration = configurations.getByName(configurationName);
createProhibitedDependenciesCheck(configuration, project);
}
}
private void createProhibitedDependenciesCheck(Configuration classpath, Project project) {
String taskName = "check" + StringUtils.capitalize(classpath.getName() + "ForProhibitedDependencies");
TaskProvider<CheckClasspathForProhibitedDependencies> checkClasspathTask = project.getTasks().register(taskName,
CheckClasspathForProhibitedDependencies.class, checkClasspath -> {
checkClasspath.setGroup(LifecycleBasePlugin.CHECK_TASK_NAME);
checkClasspath.setDescription("Checks " + classpath.getName() + " for prohibited dependencies");
checkClasspath.setClasspath(classpath);
});
project.getTasks().named(CheckProhibitedDependenciesLifecyclePlugin.CHECK_PROHIBITED_DEPENDENCIES_TASK_NAME, checkProhibitedTask -> checkProhibitedTask.dependsOn(checkClasspathTask));
}
}
@@ -1,41 +0,0 @@
/*
* Copyright 2012-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.gradle.classpath;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.plugins.JavaBasePlugin;
import org.gradle.api.tasks.TaskProvider;
/**
* @author Rob Winch
*/
public class CheckProhibitedDependenciesLifecyclePlugin implements Plugin<Project> {
public static final String CHECK_PROHIBITED_DEPENDENCIES_TASK_NAME = "checkForProhibitedDependencies";
@Override
public void apply(Project project) {
TaskProvider<Task> checkProhibitedDependencies = project.getTasks().register(CheckProhibitedDependenciesLifecyclePlugin.CHECK_PROHIBITED_DEPENDENCIES_TASK_NAME, task -> {
task.setGroup(JavaBasePlugin.VERIFICATION_GROUP);
task.setDescription("Checks both the compile/runtime classpath of every SourceSet for prohibited dependencies");
});
project.getTasks().named(JavaBasePlugin.CHECK_TASK_NAME, checkTask -> {
checkTask.dependsOn(checkProhibitedDependencies);
});
}
}
@@ -16,9 +16,6 @@
package org.springframework.gradle.github.changelog;
import java.io.File;
import java.nio.file.Paths;
import org.gradle.api.Action;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
@@ -31,10 +28,12 @@ import org.gradle.api.artifacts.repositories.IvyArtifactRepository;
import org.gradle.api.artifacts.repositories.IvyPatternRepositoryLayout;
import org.gradle.api.tasks.JavaExec;
import java.io.File;
import java.nio.file.Paths;
public class GitHubChangelogPlugin implements Plugin<Project> {
public static final String CHANGELOG_GENERATOR_CONFIGURATION_NAME = "changelogGenerator";
public static final String RELEASE_NOTES_PATH = "changelog/release-notes.md";
@Override
public void apply(Project project) {
@@ -43,7 +42,7 @@ public class GitHubChangelogPlugin implements Plugin<Project> {
project.getTasks().register("generateChangelog", JavaExec.class, new Action<JavaExec>() {
@Override
public void execute(JavaExec generateChangelog) {
File outputFile = project.file(Paths.get(project.getBuildDir().getPath(), RELEASE_NOTES_PATH));
File outputFile = project.file(Paths.get(project.getBuildDir().getPath(), "changelog/release-notes.md"));
outputFile.getParentFile().mkdirs();
generateChangelog.setGroup("Release");
generateChangelog.setDescription("Generates the changelog");
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 the original author or authors.
* Copyright 2019-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,35 +16,22 @@
package org.springframework.gradle.github.milestones;
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.springframework.gradle.github.RepositoryRef;
import java.io.IOException;
import java.util.List;
public class GitHubMilestoneApi {
private String baseUrl = "https://api.github.com";
private OkHttpClient client;
private final Gson gson = new GsonBuilder()
.registerTypeAdapter(LocalDate.class, new LocalDateAdapter().nullSafe())
.registerTypeAdapter(LocalDateTime.class, new LocalDateTimeAdapter().nullSafe())
.create();
private Gson gson = new Gson();
public GitHubMilestoneApi() {
this.client = new OkHttpClient.Builder().build();
@@ -61,30 +48,26 @@ public class GitHubMilestoneApi {
}
public long findMilestoneNumberByTitle(RepositoryRef repositoryRef, String milestoneTitle) {
List<Milestone> milestones = this.getMilestones(repositoryRef);
for (Milestone milestone : milestones) {
if (milestoneTitle.equals(milestone.getTitle())) {
return milestone.getNumber();
}
}
if (milestones.size() <= 100) {
throw new RuntimeException("Could not find open milestone with title " + milestoneTitle + " for repository " + repositoryRef + " Got " + milestones);
}
throw new RuntimeException("It is possible there are too many open milestones (only 100 are supported). Could not find open milestone with title " + milestoneTitle + " for repository " + repositoryRef + " Got " + milestones);
}
public List<Milestone> getMilestones(RepositoryRef repositoryRef) {
String url = this.baseUrl + "/repos/" + repositoryRef.getOwner() + "/" + repositoryRef.getName() + "/milestones?per_page=100";
Request request = new Request.Builder().get().url(url)
.build();
try {
Response response = this.client.newCall(request).execute();
if (!response.isSuccessful()) {
throw new RuntimeException("Could not retrieve milestones for repository " + repositoryRef + ". Response " + response);
throw new RuntimeException("Could not find milestone with title " + milestoneTitle + " for repository " + repositoryRef + ". Response " + response);
}
return this.gson.fromJson(response.body().charStream(), new TypeToken<List<Milestone>>(){}.getType());
List<Milestone> milestones = this.gson.fromJson(response.body().charStream(), new TypeToken<List<Milestone>>(){}.getType());
for (Milestone milestone : milestones) {
if (milestoneTitle.equals(milestone.getTitle())) {
return milestone.getNumber();
}
}
if (milestones.size() <= 100) {
throw new RuntimeException("Could not find open milestone with title " + milestoneTitle + " for repository " + repositoryRef + " Got " + milestones);
}
throw new RuntimeException("It is possible there are too many open milestones open (only 100 are supported). Could not find open milestone with title " + milestoneTitle + " for repository " + repositoryRef + " Got " + milestones);
} catch (IOException e) {
throw new RuntimeException("Could not retrieve milestones for repository " + repositoryRef, e);
throw new RuntimeException("Could not find open milestone with title " + milestoneTitle + " for repository " + repositoryRef, e);
}
}
@@ -104,150 +87,10 @@ public class GitHubMilestoneApi {
}
}
/**
* Check if the given milestone is due today or past due.
*
* @param repositoryRef The repository owner/name
* @param milestoneTitle The title of the milestone whose due date should be checked
* @return true if the given milestone is due today or past due, false otherwise
*/
public boolean isMilestoneDueToday(RepositoryRef repositoryRef, String milestoneTitle) {
String url = this.baseUrl + "/repos/" + repositoryRef.getOwner() + "/" + repositoryRef.getName()
+ "/milestones?per_page=100";
Request request = new Request.Builder().get().url(url).build();
try {
Response response = this.client.newCall(request).execute();
if (!response.isSuccessful()) {
throw new RuntimeException("Could not find milestone with title " + milestoneTitle + " for repository "
+ repositoryRef + ". Response " + response);
}
List<Milestone> milestones = this.gson.fromJson(response.body().charStream(),
new TypeToken<List<Milestone>>() {
}.getType());
for (Milestone milestone : milestones) {
if (milestoneTitle.equals(milestone.getTitle())) {
LocalDate today = LocalDate.now();
return milestone.getDueOn() != null && today.compareTo(milestone.getDueOn().toLocalDate()) >= 0;
}
}
if (milestones.size() <= 100) {
throw new RuntimeException("Could not find open milestone with title " + milestoneTitle
+ " for repository " + repositoryRef + " Got " + milestones);
}
throw new RuntimeException(
"It is possible there are too many open milestones open (only 100 are supported). Could not find open milestone with title "
+ milestoneTitle + " for repository " + repositoryRef + " Got " + milestones);
}
catch (IOException e) {
throw new RuntimeException(
"Could not find open milestone with title " + milestoneTitle + " for repository " + repositoryRef,
e);
}
}
// public boolean isOpenIssuesForMilestoneName(String owner, String repository, String milestoneName) {
//
// }
/**
* Calculate the next release version based on the current version.
*
* The current version must conform to the pattern MAJOR.MINOR.PATCH-SNAPSHOT. If the
* current version is a snapshot of a patch release, then the patch release will be
* returned. For example, if the current version is 5.6.1-SNAPSHOT, then 5.6.1 will be
* returned. If the current version is a snapshot of a version that is not GA (i.e the
* PATCH segment is 0), then GitHub will be queried to find the next milestone or
* release candidate. If no pre-release versions are found, then the next version will
* be assumed to be the GA.
* @param repositoryRef The repository owner/name
* @param currentVersion The current project version
* @return the next matching milestone/release candidate or null if none exist
*/
public String getNextReleaseMilestone(RepositoryRef repositoryRef, String currentVersion) {
Pattern snapshotPattern = Pattern.compile("^([0-9]+)\\.([0-9]+)\\.([0-9]+)-SNAPSHOT$");
Matcher snapshotVersion = snapshotPattern.matcher(currentVersion);
if (snapshotVersion.find()) {
String patchSegment = snapshotVersion.group(3);
String currentVersionNoIdentifier = currentVersion.replace("-SNAPSHOT", "");
if (patchSegment.equals("0")) {
String nextPreRelease = getNextPreRelease(repositoryRef, currentVersionNoIdentifier);
return nextPreRelease != null ? nextPreRelease : currentVersionNoIdentifier;
}
else {
return currentVersionNoIdentifier;
}
}
else {
throw new IllegalStateException(
"Cannot calculate next release version because the current project version does not conform to the expected format");
}
}
/**
* Calculate the next pre-release version (milestone or release candidate) based on
* the current version.
*
* The current version must conform to the pattern MAJOR.MINOR.PATCH. If no matching
* milestone or release candidate is found in GitHub then it will return null.
* @param repositoryRef The repository owner/name
* @param currentVersionNoIdentifier The current project version without any
* identifier
* @return the next matching milestone/release candidate or null if none exist
*/
private String getNextPreRelease(RepositoryRef repositoryRef, String currentVersionNoIdentifier) {
String url = this.baseUrl + "/repos/" + repositoryRef.getOwner() + "/" + repositoryRef.getName()
+ "/milestones?per_page=100";
Request request = new Request.Builder().get().url(url).build();
try {
Response response = this.client.newCall(request).execute();
if (!response.isSuccessful()) {
throw new RuntimeException(
"Could not get milestones for repository " + repositoryRef + ". Response " + response);
}
List<Milestone> milestones = this.gson.fromJson(response.body().charStream(),
new TypeToken<List<Milestone>>() {
}.getType());
Optional<String> nextPreRelease = milestones.stream().map(Milestone::getTitle)
.filter(m -> m.startsWith(currentVersionNoIdentifier + "-"))
.min((m1, m2) -> {
Pattern preReleasePattern = Pattern.compile("^.*-([A-Z]+)([0-9]+)$");
Matcher matcher1 = preReleasePattern.matcher(m1);
Matcher matcher2 = preReleasePattern.matcher(m2);
matcher1.find();
matcher2.find();
if (!matcher1.group(1).equals(matcher2.group(1))) {
return m1.compareTo(m2);
}
else {
return Integer.valueOf(matcher1.group(2)).compareTo(Integer.valueOf(matcher2.group(2)));
}
});
return nextPreRelease.orElse(null);
}
catch (IOException e) {
throw new RuntimeException("Could not find open milestones with for repository " + repositoryRef, e);
}
}
/**
* Create a milestone.
*
* @param repository The repository owner/name
* @param milestone The milestone containing a title and due date
*/
public void createMilestone(RepositoryRef repository, Milestone milestone) {
String url = this.baseUrl + "/repos/" + repository.getOwner() + "/" + repository.getName() + "/milestones";
String json = this.gson.toJson(milestone);
RequestBody body = RequestBody.create(MediaType.parse("application/json"), json);
Request request = new Request.Builder().url(url).post(body).build();
try {
Response response = this.client.newCall(request).execute();
if (!response.isSuccessful()) {
throw new RuntimeException(String.format("Could not create milestone %s for repository %s/%s. Got response %s",
milestone.getTitle(), repository.getOwner(), repository.getName(), response));
}
} catch (IOException ex) {
throw new RuntimeException(String.format("Could not create release %s for repository %s/%s",
milestone.getTitle(), repository.getOwner(), repository.getName()), ex);
}
}
private static class AuthorizationInterceptor implements Interceptor {
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 the original author or authors.
* Copyright 2019-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,66 +17,30 @@ package org.springframework.gradle.github.milestones;
import org.gradle.api.Action;
import org.gradle.api.DefaultTask;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.TaskAction;
import org.gradle.work.DisableCachingByDefault;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import org.springframework.gradle.github.RepositoryRef;
@DisableCachingByDefault(because = "the due date needs to be checked every time in case it changes")
public abstract class GitHubMilestoneHasNoOpenIssuesTask extends DefaultTask {
public class GitHubMilestoneHasNoOpenIssuesTask extends DefaultTask {
@Input
private RepositoryRef repository = new RepositoryRef();
@Input @Optional
@Input
private String milestoneTitle;
@InputFile @Optional
public abstract RegularFileProperty getNextVersionFile();
@Input @Optional
private String gitHubAccessToken;
@OutputFile
public abstract RegularFileProperty getIsOpenIssuesFile();
private GitHubMilestoneApi milestones = new GitHubMilestoneApi();
@TaskAction
public void checkHasNoOpenIssues() throws IOException {
if (this.milestoneTitle == null) {
File nextVersionFile = getNextVersionFile().getAsFile().get();
Yaml yaml = new Yaml(new Constructor(NextVersionYml.class));
NextVersionYml nextVersionYml = yaml.load(new FileInputStream(nextVersionFile));
String nextVersion = nextVersionYml.getVersion();
if (nextVersion == null) {
throw new IllegalArgumentException(
"Could not find version property in provided file " + nextVersionFile.getName());
}
this.milestoneTitle = nextVersion;
}
public void checkHasNoOpenIssues() {
long milestoneNumber = this.milestones.findMilestoneNumberByTitle(this.repository, this.milestoneTitle);
boolean isOpenIssues = this.milestones.isOpenIssuesForMilestoneNumber(this.repository, milestoneNumber);
Path isOpenIssuesPath = getIsOpenIssuesFile().getAsFile().get().toPath();
Files.write(isOpenIssuesPath, String.valueOf(isOpenIssues).getBytes());
if (isOpenIssues) {
System.out.println("The repository " + this.repository + " has open issues for milestone with the title " + this.milestoneTitle + " and number " + milestoneNumber);
}
else {
System.out.println("The repository " + this.repository + " has no open issues for milestone with the title " + this.milestoneTitle + " and number " + milestoneNumber);
throw new IllegalStateException("The repository " + this.repository + " has open issues for milestone with the title " + this.milestoneTitle + " and number " + milestoneNumber);
}
System.out.println("The repository " + this.repository + " has no open issues for milestone with the title " + this.milestoneTitle + " and number " + milestoneNumber);
}
public RepositoryRef getRepository() {
@@ -1,93 +0,0 @@
/*
* Copyright 2019-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.gradle.github.milestones;
import org.gradle.api.Action;
import org.gradle.api.DefaultTask;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.TaskAction;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.nodes.Tag;
import org.yaml.snakeyaml.representer.Representer;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import org.springframework.gradle.github.RepositoryRef;
public abstract class GitHubMilestoneNextReleaseTask extends DefaultTask {
@Input
private RepositoryRef repository = new RepositoryRef();
@Input
@Optional
private String gitHubAccessToken;
private GitHubMilestoneApi milestones = new GitHubMilestoneApi();
@TaskAction
public void calculateNextReleaseMilestone() throws IOException {
String currentVersion = getProject().getVersion().toString();
String nextPreRelease = this.milestones.getNextReleaseMilestone(this.repository, currentVersion);
System.out.println("The next release milestone is: " + nextPreRelease);
NextVersionYml nextVersionYml = new NextVersionYml();
nextVersionYml.setVersion(nextPreRelease);
File outputFile = getNextReleaseFile().get().getAsFile();
FileWriter outputWriter = new FileWriter(outputFile);
Yaml yaml = getYaml();
yaml.dump(nextVersionYml, outputWriter);
}
@OutputFile
public abstract RegularFileProperty getNextReleaseFile();
public RepositoryRef getRepository() {
return repository;
}
public void repository(Action<RepositoryRef> repository) {
repository.execute(this.repository);
}
public void setRepository(RepositoryRef repository) {
this.repository = repository;
}
public String getGitHubAccessToken() {
return gitHubAccessToken;
}
public void setGitHubAccessToken(String gitHubAccessToken) {
this.gitHubAccessToken = gitHubAccessToken;
this.milestones = new GitHubMilestoneApi(gitHubAccessToken);
}
private Yaml getYaml() {
Representer representer = new Representer();
representer.addClassTag(NextVersionYml.class, Tag.MAP);
DumperOptions ymlOptions = new DumperOptions();
ymlOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
return new Yaml(representer, ymlOptions);
}
}
@@ -1,102 +0,0 @@
/*
* Copyright 2019-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.gradle.github.milestones;
import org.gradle.api.Action;
import org.gradle.api.DefaultTask;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.TaskAction;
import org.gradle.work.DisableCachingByDefault;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import org.springframework.gradle.github.RepositoryRef;
@DisableCachingByDefault(because = "the due date needs to be checked every time in case it changes")
public abstract class GitHubMilestoneNextVersionDueTodayTask extends DefaultTask {
@Input
private RepositoryRef repository = new RepositoryRef();
@Input
@Optional
private String gitHubAccessToken;
@InputFile
public abstract RegularFileProperty getNextVersionFile();
@OutputFile
public abstract RegularFileProperty getIsDueTodayFile();
private GitHubMilestoneApi milestones = new GitHubMilestoneApi();
@TaskAction
public void checkReleaseDueToday() throws IOException {
File nextVersionFile = getNextVersionFile().getAsFile().get();
Yaml yaml = new Yaml(new Constructor(NextVersionYml.class));
NextVersionYml nextVersionYml = yaml.load(new FileInputStream(nextVersionFile));
String nextVersion = nextVersionYml.getVersion();
if (nextVersion == null) {
throw new IllegalArgumentException(
"Could not find version property in provided file " + nextVersionFile.getName());
}
boolean milestoneDueToday = this.milestones.isMilestoneDueToday(this.repository, nextVersion);
Path isDueTodayPath = getIsDueTodayFile().getAsFile().get().toPath();
Files.writeString(isDueTodayPath, String.valueOf(milestoneDueToday));
if (milestoneDueToday) {
System.out.println("The milestone with the title " + nextVersion + " in the repository " + this.repository
+ " is due today");
}
else {
System.out.println("The milestone with the title " + nextVersion + " in the repository "
+ this.repository + " is not due yet");
}
}
public RepositoryRef getRepository() {
return repository;
}
public void repository(Action<RepositoryRef> repository) {
repository.execute(this.repository);
}
public void setRepository(RepositoryRef repository) {
this.repository = repository;
}
public String getGitHubAccessToken() {
return gitHubAccessToken;
}
public void setGitHubAccessToken(String gitHubAccessToken) {
this.gitHubAccessToken = gitHubAccessToken;
this.milestones = new GitHubMilestoneApi(gitHubAccessToken);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 the original author or authors.
* Copyright 2019-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,55 +16,23 @@
package org.springframework.gradle.github.milestones;
import org.gradle.api.Action;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.tasks.TaskProvider;
public class GitHubMilestonePlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
TaskProvider<GitHubMilestoneNextReleaseTask> nextReleaseMilestoneTask = project.getTasks().register("gitHubNextReleaseMilestone", GitHubMilestoneNextReleaseTask.class, (gitHubMilestoneNextReleaseTask) -> {
gitHubMilestoneNextReleaseTask.doNotTrackState("API call to GitHub needs to check for new milestones every time");
gitHubMilestoneNextReleaseTask.setGroup("Release");
gitHubMilestoneNextReleaseTask.setDescription("Calculates the next release version based on the current version and outputs it to a yaml file");
gitHubMilestoneNextReleaseTask.getNextReleaseFile()
.fileProvider(project.provider(() -> project.file("next-release.yml")));
if (project.hasProperty("gitHubAccessToken")) {
gitHubMilestoneNextReleaseTask
.setGitHubAccessToken((String) project.findProperty("gitHubAccessToken"));
project.getTasks().register("gitHubCheckMilestoneHasNoOpenIssues", GitHubMilestoneHasNoOpenIssuesTask.class, new Action<GitHubMilestoneHasNoOpenIssuesTask>() {
@Override
public void execute(GitHubMilestoneHasNoOpenIssuesTask githubCheckMilestoneHasNoOpenIssues) {
githubCheckMilestoneHasNoOpenIssues.setGroup("Release");
githubCheckMilestoneHasNoOpenIssues.setDescription("Checks if there are any open issues for the specified repository and milestone");
githubCheckMilestoneHasNoOpenIssues.setMilestoneTitle((String) project.findProperty("nextVersion"));
if (project.hasProperty("githubAccessToken")) {
githubCheckMilestoneHasNoOpenIssues.setGitHubAccessToken((String) project.findProperty("gitHubAccessToken"));
}
}
});
project.getTasks().register("gitHubCheckMilestoneHasNoOpenIssues", GitHubMilestoneHasNoOpenIssuesTask.class, (githubCheckMilestoneHasNoOpenIssues) -> {
githubCheckMilestoneHasNoOpenIssues.setGroup("Release");
githubCheckMilestoneHasNoOpenIssues.setDescription("Checks if there are any open issues for the specified repository and milestone");
githubCheckMilestoneHasNoOpenIssues.getIsOpenIssuesFile().value(project.getLayout().getBuildDirectory().file("github/milestones/is-open-issues"));
githubCheckMilestoneHasNoOpenIssues.setMilestoneTitle((String) project.findProperty("nextVersion"));
if (!project.hasProperty("nextVersion")) {
githubCheckMilestoneHasNoOpenIssues.getNextVersionFile().convention(
nextReleaseMilestoneTask.flatMap(GitHubMilestoneNextReleaseTask::getNextReleaseFile));
}
if (project.hasProperty("gitHubAccessToken")) {
githubCheckMilestoneHasNoOpenIssues.setGitHubAccessToken((String) project.findProperty("gitHubAccessToken"));
}
});
project.getTasks().register("gitHubCheckNextVersionDueToday", GitHubMilestoneNextVersionDueTodayTask.class, (gitHubMilestoneNextVersionDueTodayTask) -> {
gitHubMilestoneNextVersionDueTodayTask.setGroup("Release");
gitHubMilestoneNextVersionDueTodayTask.setDescription("Checks if the next release version is due today or past due, will fail if the next version is not due yet");
gitHubMilestoneNextVersionDueTodayTask.getIsDueTodayFile().value(project.getLayout().getBuildDirectory().file("github/milestones/is-due-today"));
gitHubMilestoneNextVersionDueTodayTask.getNextVersionFile().convention(
nextReleaseMilestoneTask.flatMap(GitHubMilestoneNextReleaseTask::getNextReleaseFile));
if (project.hasProperty("gitHubAccessToken")) {
gitHubMilestoneNextVersionDueTodayTask
.setGitHubAccessToken((String) project.findProperty("gitHubAccessToken"));
}
});
project.getTasks().register("scheduleNextRelease", ScheduleNextReleaseTask.class, (scheduleNextRelease) -> {
scheduleNextRelease.doNotTrackState("API call to GitHub needs to check for new milestones every time");
scheduleNextRelease.setGroup("Release");
scheduleNextRelease.setDescription("Schedule the next release (even months only) or release train (series of milestones starting in January or July) based on the current version");
scheduleNextRelease.setVersion((String) project.findProperty("nextVersion"));
scheduleNextRelease.setGitHubAccessToken((String) project.findProperty("gitHubAccessToken"));
});
}
}
@@ -1,23 +0,0 @@
package org.springframework.gradle.github.milestones;
import java.io.IOException;
import java.time.LocalDate;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
/**
* @author Steve Riesenberg
*/
class LocalDateAdapter extends TypeAdapter<LocalDate> {
@Override
public void write(JsonWriter jsonWriter, LocalDate localDate) throws IOException {
jsonWriter.value(localDate.toString());
}
@Override
public LocalDate read(JsonReader jsonReader) throws IOException {
return LocalDate.parse(jsonReader.nextString());
}
}
@@ -1,25 +0,0 @@
package org.springframework.gradle.github.milestones;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
/**
* @author Steve Riesenberg
*/
class LocalDateTimeAdapter extends TypeAdapter<LocalDateTime> {
@Override
public void write(JsonWriter jsonWriter, LocalDateTime localDateTime) throws IOException {
jsonWriter.value(localDateTime.atOffset(ZoneOffset.UTC).format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
}
@Override
public LocalDateTime read(JsonReader jsonReader) throws IOException {
return LocalDateTime.parse(jsonReader.nextString(), DateTimeFormatter.ISO_ZONED_DATE_TIME);
}
}
@@ -1,35 +1,9 @@
/*
* Copyright 2019-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.gradle.github.milestones;
import com.google.gson.annotations.SerializedName;
import java.time.LocalDateTime;
/**
* @author Steve Riesenberg
*/
public class Milestone {
private String title;
private Long number;
@SerializedName("due_on")
private LocalDateTime dueOn;
private long number;
public String getTitle() {
return title;
@@ -39,28 +13,19 @@ public class Milestone {
this.title = title;
}
public Long getNumber() {
public long getNumber() {
return number;
}
public void setNumber(Long number) {
public void setNumber(long number) {
this.number = number;
}
public LocalDateTime getDueOn() {
return dueOn;
}
public void setDueOn(LocalDateTime dueOn) {
this.dueOn = dueOn;
}
@Override
public String toString() {
return "Milestone{" +
"title='" + title + '\'' +
", number='" + number + '\'' +
", dueOn='" + dueOn + '\'' +
", number=" + number +
'}';
}
}
@@ -1,29 +0,0 @@
/*
* Copyright 2019-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.gradle.github.milestones;
public class NextVersionYml {
private String version;
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
}
@@ -1,16 +1,10 @@
package org.springframework.gradle.github;
import java.io.Serializable;
public class RepositoryRef implements Serializable {
private static final long serialVersionUID = 7151218536746822797L;
package org.springframework.gradle.github.milestones;
public class RepositoryRef {
private String owner;
private String name;
public RepositoryRef() {
RepositoryRef() {
}
public RepositoryRef(String owner, String name) {
@@ -68,3 +62,4 @@ public class RepositoryRef implements Serializable {
}
}
}
@@ -1,147 +0,0 @@
/*
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.gradle.github.milestones;
import java.time.LocalDate;
import java.time.LocalTime;
import org.gradle.api.Action;
import org.gradle.api.DefaultTask;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.TaskAction;
import org.springframework.gradle.github.RepositoryRef;
/**
* @author Steve Riesenberg
*/
public class ScheduleNextReleaseTask extends DefaultTask {
@Input
private RepositoryRef repository = new RepositoryRef();
@Input
private String gitHubAccessToken;
@Input
private String version;
@Input
private Integer weekOfMonth;
@Input
private Integer dayOfWeek;
@TaskAction
public void scheduleNextRelease() {
GitHubMilestoneApi gitHubMilestoneApi = new GitHubMilestoneApi(this.gitHubAccessToken);
String nextReleaseMilestone = gitHubMilestoneApi.getNextReleaseMilestone(this.repository, this.version);
// If the next release contains a dash (e.g. 5.6.0-RC1), it is already scheduled
if (nextReleaseMilestone.contains("-")) {
return;
}
// Check to see if a scheduled GA version already exists
boolean hasExistingMilestone = gitHubMilestoneApi.getMilestones(this.repository).stream()
.anyMatch(milestone -> nextReleaseMilestone.equals(milestone.getTitle()));
if (hasExistingMilestone) {
return;
}
// Next milestone is either a patch version or minor version
// Note: Major versions will be handled like minor and get a release
// train which can be manually updated to match the desired schedule.
if (nextReleaseMilestone.endsWith(".0")) {
// Create M1, M2, M3, RC1 and GA milestones for release train
getReleaseTrain(nextReleaseMilestone).getTrainDates().forEach((milestoneTitle, dueOn) -> {
Milestone milestone = new Milestone();
milestone.setTitle(milestoneTitle);
// Note: GitHub seems to store full date/time as UTC then displays
// as a date (no time) in your timezone, which means the date will
// not always be the same date as we intend.
// Using 12pm/noon UTC allows GitHub to schedule and display the
// correct date.
milestone.setDueOn(dueOn.atTime(LocalTime.NOON));
gitHubMilestoneApi.createMilestone(this.repository, milestone);
});
} else {
// Create GA milestone for patch release on the next even month
LocalDate startDate = LocalDate.now();
LocalDate dueOn = getReleaseTrain(nextReleaseMilestone).getNextReleaseDate(startDate);
Milestone milestone = new Milestone();
milestone.setTitle(nextReleaseMilestone);
milestone.setDueOn(dueOn.atTime(LocalTime.NOON));
gitHubMilestoneApi.createMilestone(this.repository, milestone);
}
}
private SpringReleaseTrain getReleaseTrain(String nextReleaseMilestone) {
SpringReleaseTrainSpec releaseTrainSpec =
SpringReleaseTrainSpec.builder()
.nextTrain()
.version(nextReleaseMilestone)
.weekOfMonth(this.weekOfMonth)
.dayOfWeek(this.dayOfWeek)
.build();
return new SpringReleaseTrain(releaseTrainSpec);
}
public RepositoryRef getRepository() {
return this.repository;
}
public void repository(Action<RepositoryRef> repository) {
repository.execute(this.repository);
}
public void setRepository(RepositoryRef repository) {
this.repository = repository;
}
public String getGitHubAccessToken() {
return this.gitHubAccessToken;
}
public void setGitHubAccessToken(String gitHubAccessToken) {
this.gitHubAccessToken = gitHubAccessToken;
}
public String getVersion() {
return this.version;
}
public void setVersion(String version) {
this.version = version;
}
public Integer getWeekOfMonth() {
return weekOfMonth;
}
public void setWeekOfMonth(Integer weekOfMonth) {
this.weekOfMonth = weekOfMonth;
}
public Integer getDayOfWeek() {
return dayOfWeek;
}
public void setDayOfWeek(Integer dayOfWeek) {
this.dayOfWeek = dayOfWeek;
}
}
@@ -1,136 +0,0 @@
/*
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.gradle.github.milestones;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.Month;
import java.time.Year;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAdjusters;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Spring release train generator based on rules contained in a specification.
* <p>
* The rules are:
* <ol>
* <li>Train 1 (January-May) or 2 (July-November)</li>
* <li>Version number (e.g. 0.1.2, 1.0.0, etc.)</li>
* <li>Week of month (1st, 2nd, 3rd, 4th)</li>
* <li>Day of week (Monday-Friday)</li>
* <li>Year (e.g. 2020, 2021, etc.)</li>
* </ol>
*
* The release train generated will contain M1, M2, M3, RC1 and GA versions
* mapped to their respective dates in the train.
*
* @author Steve Riesenberg
*/
public final class SpringReleaseTrain {
private final SpringReleaseTrainSpec releaseTrainSpec;
public SpringReleaseTrain(SpringReleaseTrainSpec releaseTrainSpec) {
this.releaseTrainSpec = releaseTrainSpec;
}
/**
* Calculate release train dates based on the release train specification.
*
* @return A mapping of release milestones to scheduled release dates
*/
public Map<String, LocalDate> getTrainDates() {
Map<String, LocalDate> releaseDates = new LinkedHashMap<>();
switch (this.releaseTrainSpec.getTrain()) {
case ONE:
addTrainDate(releaseDates, "M1", Month.JANUARY);
addTrainDate(releaseDates, "M2", Month.FEBRUARY);
addTrainDate(releaseDates, "M3", Month.MARCH);
addTrainDate(releaseDates, "RC1", Month.APRIL);
addTrainDate(releaseDates, null, Month.MAY);
break;
case TWO:
addTrainDate(releaseDates, "M1", Month.JULY);
addTrainDate(releaseDates, "M2", Month.AUGUST);
addTrainDate(releaseDates, "M3", Month.SEPTEMBER);
addTrainDate(releaseDates, "RC1", Month.OCTOBER);
addTrainDate(releaseDates, null, Month.NOVEMBER);
break;
}
return releaseDates;
}
/**
* Determine if a given date matches the due date of given version.
*
* @param version The version number (e.g. 5.6.0-M1, 5.6.0, etc.)
* @param expectedDate The expected date
* @return true if the given date matches the due date of the given version, false otherwise
*/
public boolean isTrainDate(String version, LocalDate expectedDate) {
return expectedDate.isEqual(getTrainDates().get(version));
}
/**
* Calculate the next release date following the given date.
* <p>
* The next release date is always on an even month so that a patch release
* is the month after the GA version of a release train. This method does
* not consider the year of the release train, only the given start date.
*
* @param startDate The start date
* @return The next release date following the given date
*/
public LocalDate getNextReleaseDate(LocalDate startDate) {
LocalDate trainDate;
LocalDate currentDate = startDate;
do {
trainDate = calculateReleaseDate(
Year.of(currentDate.getYear()),
currentDate.getMonth(),
this.releaseTrainSpec.getDayOfWeek().getDayOfWeek(),
this.releaseTrainSpec.getWeekOfMonth().getDayOffset()
);
currentDate = currentDate.plusMonths(1);
} while (!trainDate.isAfter(startDate) || trainDate.getMonthValue() % 2 != 0);
return trainDate;
}
private void addTrainDate(Map<String, LocalDate> releaseDates, String milestone, Month month) {
LocalDate releaseDate = calculateReleaseDate(
this.releaseTrainSpec.getYear(),
month,
this.releaseTrainSpec.getDayOfWeek().getDayOfWeek(),
this.releaseTrainSpec.getWeekOfMonth().getDayOffset()
);
String suffix = (milestone == null) ? "" : "-" + milestone;
releaseDates.put(this.releaseTrainSpec.getVersion() + suffix, releaseDate);
}
private static LocalDate calculateReleaseDate(Year year, Month month, DayOfWeek dayOfWeek, int dayOffset) {
TemporalAdjuster nextMonday = TemporalAdjusters.nextOrSame(DayOfWeek.MONDAY);
TemporalAdjuster nextDayOfWeek = TemporalAdjusters.nextOrSame(dayOfWeek);
LocalDate firstDayOfMonth = year.atMonth(month).atDay(1);
LocalDate firstMondayOfMonth = firstDayOfMonth.with(nextMonday);
return firstMondayOfMonth.with(nextDayOfWeek).plusDays(dayOffset);
}
}
@@ -1,205 +0,0 @@
/*
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.gradle.github.milestones;
import java.time.LocalDate;
import java.time.Month;
import java.time.Year;
import org.springframework.util.Assert;
/**
* A specification for a release train.
*
* @author Steve Riesenberg
* @see SpringReleaseTrain
*/
public final class SpringReleaseTrainSpec {
private final Train train;
private final String version;
private final WeekOfMonth weekOfMonth;
private final DayOfWeek dayOfWeek;
private final Year year;
public SpringReleaseTrainSpec(Train train, String version, WeekOfMonth weekOfMonth, DayOfWeek dayOfWeek, Year year) {
this.train = train;
this.version = version;
this.weekOfMonth = weekOfMonth;
this.dayOfWeek = dayOfWeek;
this.year = year;
}
public Train getTrain() {
return train;
}
public String getVersion() {
return version;
}
public WeekOfMonth getWeekOfMonth() {
return weekOfMonth;
}
public DayOfWeek getDayOfWeek() {
return dayOfWeek;
}
public Year getYear() {
return year;
}
public static Builder builder() {
return new Builder();
}
public enum WeekOfMonth {
FIRST(0), SECOND(7), THIRD(14), FOURTH(21);
private final int dayOffset;
WeekOfMonth(int dayOffset) {
this.dayOffset = dayOffset;
}
public int getDayOffset() {
return dayOffset;
}
}
public enum DayOfWeek {
MONDAY(java.time.DayOfWeek.MONDAY),
TUESDAY(java.time.DayOfWeek.TUESDAY),
WEDNESDAY(java.time.DayOfWeek.WEDNESDAY),
THURSDAY(java.time.DayOfWeek.THURSDAY),
FRIDAY(java.time.DayOfWeek.FRIDAY);
private final java.time.DayOfWeek dayOfWeek;
DayOfWeek(java.time.DayOfWeek dayOfWeek) {
this.dayOfWeek = dayOfWeek;
}
public java.time.DayOfWeek getDayOfWeek() {
return dayOfWeek;
}
}
public enum Train {
ONE, TWO
}
public static class Builder {
private Train train;
private String version;
private WeekOfMonth weekOfMonth;
private DayOfWeek dayOfWeek;
private Year year;
private Builder() {
}
public Builder train(int train) {
switch (train) {
case 1: this.train = Train.ONE; break;
case 2: this.train = Train.TWO; break;
default: throw new IllegalArgumentException("Invalid train: " + train);
}
return this;
}
public Builder train(Train train) {
this.train = train;
return this;
}
public Builder nextTrain() {
// Search for next train starting with this month
return nextTrain(LocalDate.now().withDayOfMonth(1));
}
public Builder nextTrain(LocalDate startDate) {
Train nextTrain = null;
// Search for next train from a given start date
LocalDate currentDate = startDate;
while (nextTrain == null) {
if (currentDate.getMonth() == Month.JANUARY) {
nextTrain = Train.ONE;
} else if (currentDate.getMonth() == Month.JULY) {
nextTrain = Train.TWO;
}
currentDate = currentDate.plusMonths(1);
}
return train(nextTrain).year(currentDate.getYear());
}
public Builder version(String version) {
this.version = version;
return this;
}
public Builder weekOfMonth(int weekOfMonth) {
switch (weekOfMonth) {
case 1: this.weekOfMonth = WeekOfMonth.FIRST; break;
case 2: this.weekOfMonth = WeekOfMonth.SECOND; break;
case 3: this.weekOfMonth = WeekOfMonth.THIRD; break;
case 4: this.weekOfMonth = WeekOfMonth.FOURTH; break;
default: throw new IllegalArgumentException("Invalid weekOfMonth: " + weekOfMonth);
}
return this;
}
public Builder weekOfMonth(WeekOfMonth weekOfMonth) {
this.weekOfMonth = weekOfMonth;
return this;
}
public Builder dayOfWeek(int dayOfWeek) {
switch (dayOfWeek) {
case 1: this.dayOfWeek = DayOfWeek.MONDAY; break;
case 2: this.dayOfWeek = DayOfWeek.TUESDAY; break;
case 3: this.dayOfWeek = DayOfWeek.WEDNESDAY; break;
case 4: this.dayOfWeek = DayOfWeek.THURSDAY; break;
case 5: this.dayOfWeek = DayOfWeek.FRIDAY; break;
default: throw new IllegalArgumentException("Invalid dayOfWeek: " + dayOfWeek);
}
return this;
}
public Builder dayOfWeek(DayOfWeek dayOfWeek) {
this.dayOfWeek = dayOfWeek;
return this;
}
public Builder year(int year) {
this.year = Year.of(year);
return this;
}
public SpringReleaseTrainSpec build() {
Assert.notNull(train, "train cannot be null");
Assert.notNull(version, "version cannot be null");
Assert.notNull(weekOfMonth, "weekOfMonth cannot be null");
Assert.notNull(dayOfWeek, "dayOfWeek cannot be null");
Assert.notNull(year, "year cannot be null");
return new SpringReleaseTrainSpec(train, version, weekOfMonth, dayOfWeek, year);
}
}
}
@@ -1,130 +0,0 @@
/*
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.gradle.github.release;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import org.gradle.api.Action;
import org.gradle.api.DefaultTask;
import org.gradle.api.Project;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.TaskAction;
import org.springframework.gradle.github.RepositoryRef;
import org.springframework.gradle.github.changelog.GitHubChangelogPlugin;
/**
* @author Steve Riesenberg
*/
public class CreateGitHubReleaseTask extends DefaultTask {
@Input
private RepositoryRef repository = new RepositoryRef();
@Input @Optional
private String gitHubAccessToken;
@Input
private String version;
@Input @Optional
private String branch = "main";
@Input
private boolean createRelease = false;
@TaskAction
public void createGitHubRelease() {
String body = readReleaseNotes();
Release release = Release.tag(this.version)
.commit(this.branch)
.name(this.version)
.body(body)
.preRelease(this.version.contains("-"))
.build();
System.out.printf("%sCreating GitHub release for %s/%s@%s\n",
this.createRelease ? "" : "[DRY RUN] ",
this.repository.getOwner(),
this.repository.getName(),
this.version
);
System.out.printf(" Release Notes:\n\n----\n%s\n----\n\n", body.trim());
if (this.createRelease) {
GitHubReleaseApi github = new GitHubReleaseApi(this.gitHubAccessToken);
github.publishRelease(this.repository, release);
}
}
private String readReleaseNotes() {
Project project = getProject();
File inputFile = project.file(Paths.get(project.getBuildDir().getPath(), GitHubChangelogPlugin.RELEASE_NOTES_PATH));
try {
return Files.readString(inputFile.toPath());
} catch (IOException ex) {
throw new RuntimeException("Unable to read release notes from " + inputFile, ex);
}
}
public RepositoryRef getRepository() {
return repository;
}
public void repository(Action<RepositoryRef> repository) {
repository.execute(this.repository);
}
public void setRepository(RepositoryRef repository) {
this.repository = repository;
}
public String getGitHubAccessToken() {
return gitHubAccessToken;
}
public void setGitHubAccessToken(String gitHubAccessToken) {
this.gitHubAccessToken = gitHubAccessToken;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getBranch() {
return branch;
}
public void setBranch(String branch) {
this.branch = branch;
}
public boolean isCreateRelease() {
return createRelease;
}
public void setCreateRelease(boolean createRelease) {
this.createRelease = createRelease;
}
}
@@ -1,84 +0,0 @@
/*
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.gradle.github.release;
import org.gradle.api.Action;
import org.gradle.api.DefaultTask;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.TaskAction;
import org.springframework.gradle.github.RepositoryRef;
/**
* @author Steve Riesenberg
*/
public class DispatchGitHubWorkflowTask extends DefaultTask {
@Input
private RepositoryRef repository = new RepositoryRef();
@Input
private String gitHubAccessToken;
@Input
private String branch;
@Input
private String workflowId;
@TaskAction
public void dispatchGitHubWorkflow() {
GitHubActionsApi gitHubActionsApi = new GitHubActionsApi(this.gitHubAccessToken);
WorkflowDispatch workflowDispatch = new WorkflowDispatch(this.branch, null);
gitHubActionsApi.dispatchWorkflow(this.repository, this.workflowId, workflowDispatch);
}
public RepositoryRef getRepository() {
return repository;
}
public void repository(Action<RepositoryRef> repository) {
repository.execute(this.repository);
}
public void setRepository(RepositoryRef repository) {
this.repository = repository;
}
public String getGitHubAccessToken() {
return gitHubAccessToken;
}
public void setGitHubAccessToken(String gitHubAccessToken) {
this.gitHubAccessToken = gitHubAccessToken;
}
public String getBranch() {
return branch;
}
public void setBranch(String branch) {
this.branch = branch;
}
public String getWorkflowId() {
return workflowId;
}
public void setWorkflowId(String workflowId) {
this.workflowId = workflowId;
}
}
@@ -1,98 +0,0 @@
/*
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.gradle.github.release;
import java.io.IOException;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.springframework.gradle.github.RepositoryRef;
/**
* Manage GitHub Actions.
*
* @author Steve Riesenberg
*/
public class GitHubActionsApi {
private String baseUrl = "https://api.github.com";
private final OkHttpClient client;
private final Gson gson = new GsonBuilder().create();
public GitHubActionsApi() {
this.client = new OkHttpClient.Builder().build();
}
public GitHubActionsApi(String gitHubToken) {
this.client = new OkHttpClient.Builder()
.addInterceptor(new AuthorizationInterceptor(gitHubToken))
.build();
}
public void setBaseUrl(String baseUrl) {
this.baseUrl = baseUrl;
}
/**
* Create a workflow dispatch event.
*
* @param repository The repository owner/name
* @param workflowId The ID of the workflow or the name of the workflow file name
* @param workflowDispatch The workflow dispatch containing a ref (branch) and optional inputs
*/
public void dispatchWorkflow(RepositoryRef repository, String workflowId, WorkflowDispatch workflowDispatch) {
String url = this.baseUrl + "/repos/" + repository.getOwner() + "/" + repository.getName() + "/actions/workflows/" + workflowId + "/dispatches";
String json = this.gson.toJson(workflowDispatch);
RequestBody body = RequestBody.create(MediaType.parse("application/json"), json);
Request request = new Request.Builder().url(url).post(body).build();
try {
Response response = this.client.newCall(request).execute();
if (!response.isSuccessful()) {
throw new RuntimeException(String.format("Could not create workflow dispatch %s for repository %s/%s. Got response %s",
workflowId, repository.getOwner(), repository.getName(), response));
}
} catch (IOException ex) {
throw new RuntimeException(String.format("Could not create workflow dispatch %s for repository %s/%s",
workflowId, repository.getOwner(), repository.getName()), ex);
}
}
private static class AuthorizationInterceptor implements Interceptor {
private final String token;
public AuthorizationInterceptor(String token) {
this.token = token;
}
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request().newBuilder()
.addHeader("Authorization", "Bearer " + this.token)
.build();
return chain.proceed(request);
}
}
}
@@ -1,91 +0,0 @@
/*
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.gradle.github.release;
import java.io.IOException;
import com.google.gson.Gson;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.springframework.gradle.github.RepositoryRef;
/**
* Manage GitHub releases.
*
* @author Steve Riesenberg
*/
public class GitHubReleaseApi {
private String baseUrl = "https://api.github.com";
private final OkHttpClient httpClient;
private Gson gson = new Gson();
public GitHubReleaseApi(String gitHubAccessToken) {
this.httpClient = new OkHttpClient.Builder()
.addInterceptor(new AuthorizationInterceptor(gitHubAccessToken))
.build();
}
public void setBaseUrl(String baseUrl) {
this.baseUrl = baseUrl;
}
/**
* Publish a release with no binary attachments.
*
* @param repository The repository owner/name
* @param release The contents of the release
*/
public void publishRelease(RepositoryRef repository, Release release) {
String url = this.baseUrl + "/repos/" + repository.getOwner() + "/" + repository.getName() + "/releases";
String json = this.gson.toJson(release);
RequestBody body = RequestBody.create(MediaType.parse("application/json"), json);
Request request = new Request.Builder().url(url).post(body).build();
try {
Response response = this.httpClient.newCall(request).execute();
if (!response.isSuccessful()) {
throw new RuntimeException(String.format("Could not create release %s for repository %s/%s. Got response %s",
release.getName(), repository.getOwner(), repository.getName(), response));
}
} catch (IOException ex) {
throw new RuntimeException(String.format("Could not create release %s for repository %s/%s",
release.getName(), repository.getOwner(), repository.getName()), ex);
}
}
private static class AuthorizationInterceptor implements Interceptor {
private final String token;
public AuthorizationInterceptor(String token) {
this.token = token;
}
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request().newBuilder()
.addHeader("Authorization", "Bearer " + this.token)
.build();
return chain.proceed(request);
}
}
}
@@ -1,54 +0,0 @@
/*
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.gradle.github.release;
import groovy.lang.MissingPropertyException;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
/**
* @author Steve Riesenberg
*/
public class GitHubReleasePlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
project.getTasks().register("createGitHubRelease", CreateGitHubReleaseTask.class, (createGitHubRelease) -> {
createGitHubRelease.setGroup("Release");
createGitHubRelease.setDescription("Create a github release");
createGitHubRelease.dependsOn("generateChangelog");
createGitHubRelease.setCreateRelease("true".equals(project.findProperty("createRelease")));
createGitHubRelease.setVersion((String) project.findProperty("nextVersion"));
if (project.hasProperty("branch")) {
createGitHubRelease.setBranch((String) project.findProperty("branch"));
}
createGitHubRelease.setGitHubAccessToken((String) project.findProperty("gitHubAccessToken"));
if (createGitHubRelease.isCreateRelease() && createGitHubRelease.getGitHubAccessToken() == null) {
throw new MissingPropertyException("Please provide an access token with -PgitHubAccessToken=...");
}
});
project.getTasks().register("dispatchGitHubWorkflow", DispatchGitHubWorkflowTask.class, (dispatchGitHubWorkflow) -> {
dispatchGitHubWorkflow.setGroup("Release");
dispatchGitHubWorkflow.setDescription("Create a workflow_dispatch event on a given branch");
dispatchGitHubWorkflow.setBranch((String) project.findProperty("branch"));
dispatchGitHubWorkflow.setWorkflowId((String) project.findProperty("workflowId"));
dispatchGitHubWorkflow.setGitHubAccessToken((String) project.findProperty("gitHubAccessToken"));
});
}
}
@@ -1,156 +0,0 @@
/*
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.gradle.github.release;
import com.google.gson.annotations.SerializedName;
/**
* @author Steve Riesenberg
*/
public class Release {
@SerializedName("tag_name")
private final String tag;
@SerializedName("target_commitish")
private final String commit;
@SerializedName("name")
private final String name;
@SerializedName("body")
private final String body;
@SerializedName("draft")
private final boolean draft;
@SerializedName("prerelease")
private final boolean preRelease;
@SerializedName("generate_release_notes")
private final boolean generateReleaseNotes;
private Release(String tag, String commit, String name, String body, boolean draft, boolean preRelease, boolean generateReleaseNotes) {
this.tag = tag;
this.commit = commit;
this.name = name;
this.body = body;
this.draft = draft;
this.preRelease = preRelease;
this.generateReleaseNotes = generateReleaseNotes;
}
public String getTag() {
return tag;
}
public String getCommit() {
return commit;
}
public String getName() {
return name;
}
public String getBody() {
return body;
}
public boolean isDraft() {
return draft;
}
public boolean isPreRelease() {
return preRelease;
}
public boolean isGenerateReleaseNotes() {
return generateReleaseNotes;
}
@Override
public String toString() {
return "Release{" +
"tag='" + tag + '\'' +
", commit='" + commit + '\'' +
", name='" + name + '\'' +
", body='" + body + '\'' +
", draft=" + draft +
", preRelease=" + preRelease +
", generateReleaseNotes=" + generateReleaseNotes +
'}';
}
public static Builder tag(String tag) {
return new Builder().tag(tag);
}
public static Builder commit(String commit) {
return new Builder().commit(commit);
}
public static final class Builder {
private String tag;
private String commit;
private String name;
private String body;
private boolean draft;
private boolean preRelease;
private boolean generateReleaseNotes;
private Builder() {
}
public Builder tag(String tag) {
this.tag = tag;
return this;
}
public Builder commit(String commit) {
this.commit = commit;
return this;
}
public Builder name(String name) {
this.name = name;
return this;
}
public Builder body(String body) {
this.body = body;
return this;
}
public Builder draft(boolean draft) {
this.draft = draft;
return this;
}
public Builder preRelease(boolean preRelease) {
this.preRelease = preRelease;
return this;
}
public Builder generateReleaseNotes(boolean generateReleaseNotes) {
this.generateReleaseNotes = generateReleaseNotes;
return this;
}
public Release build() {
return new Release(tag, commit, name, body, draft, preRelease, generateReleaseNotes);
}
}
}
@@ -1,51 +0,0 @@
/*
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.gradle.github.release;
import java.util.Map;
/**
* @author Steve Riesenberg
*/
public class WorkflowDispatch {
private String ref;
private Map<String, Object> inputs;
public WorkflowDispatch() {
}
public WorkflowDispatch(String ref, Map<String, Object> inputs) {
this.ref = ref;
this.inputs = inputs;
}
public String getRef() {
return ref;
}
public void setRef(String ref) {
this.ref = ref;
}
public Map<String, Object> getInputs() {
return inputs;
}
public void setInputs(Map<String, Object> inputs) {
this.inputs = inputs;
}
}
@@ -1,43 +0,0 @@
/*
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.gradle.propdeps
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.plugins.ide.eclipse.EclipsePlugin
/**
* Plugin to allow optional and provided dependency configurations to work with the
* standard gradle 'eclipse' plugin
*
* @author Phillip Webb
*/
class PropDepsEclipsePlugin implements Plugin<Project> {
public void apply(Project project) {
project.plugins.apply(PropDepsPlugin)
project.plugins.apply(EclipsePlugin)
project.eclipse {
classpath {
plusConfigurations += [project.configurations.provided, project.configurations.optional]
}
}
}
}
@@ -1,46 +0,0 @@
/*
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.gradle.propdeps
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.plugins.ide.idea.IdeaPlugin
/**
* Plugin to allow optional and provided dependency configurations to work with the
* standard gradle 'idea' plugin
*
* @author Phillip Webb
* @author Brian Clozel
* @link https://youtrack.jetbrains.com/issue/IDEA-107046
* @link https://youtrack.jetbrains.com/issue/IDEA-117668
*/
class PropDepsIdeaPlugin implements Plugin<Project> {
public void apply(Project project) {
project.plugins.apply(PropDepsPlugin)
project.plugins.apply(IdeaPlugin)
project.idea.module {
// IDEA internally deals with 4 scopes : COMPILE, TEST, PROVIDED, RUNTIME
// but only PROVIDED seems to be picked up
scopes.PROVIDED.plus += [project.configurations.provided]
scopes.PROVIDED.plus += [project.configurations.optional]
}
}
}
@@ -1,76 +0,0 @@
/*
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.gradle.propdeps
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.plugins.JavaLibraryPlugin
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.tasks.javadoc.Javadoc
/**
* Plugin to allow 'optional' and 'provided' dependency configurations
*
* As stated in the maven documentation, provided scope "is only available on the compilation and test classpath,
* and is not transitive".
*
* This plugin creates two new configurations, and each one:
* <ul>
* <li>is a parent of the compile configuration</li>
* <li>is not visible, not transitive</li>
* <li>all dependencies are excluded from the default configuration</li>
* </ul>
*
* @author Phillip Webb
* @author Brian Clozel
* @author Rob Winch
*
* @see <a href="https://www.gradle.org/docs/current/userguide/java_plugin.html#N121CF">Maven documentation</a>
* @see <a href="https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Scope">Gradle configurations</a>
* @see PropDepsEclipsePlugin
* @see PropDepsIdeaPlugin
*/
class PropDepsPlugin implements Plugin<Project> {
public void apply(Project project) {
project.plugins.apply(JavaPlugin)
Configuration provided = addConfiguration(project, "provided")
Configuration optional = addConfiguration(project, "optional")
Javadoc javadoc = project.tasks.getByName(JavaPlugin.JAVADOC_TASK_NAME)
javadoc.classpath = javadoc.classpath.plus(provided).plus(optional)
}
private Configuration addConfiguration(Project project, String name) {
Configuration configuration = project.configurations.create(name)
configuration.extendsFrom(project.configurations.implementation)
project.plugins.withType(JavaLibraryPlugin, {
configuration.extendsFrom(project.configurations.api)
})
project.sourceSets.all {
compileClasspath += configuration
runtimeClasspath += configuration
}
return configuration
}
}
@@ -1,49 +0,0 @@
/*
* Copyright 2019-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.convention.versions;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.Scanner;
class CommandLineUtils {
static void runCommand(File dir, String... args) {
try {
Process process = new ProcessBuilder()
.directory(dir)
.command(args)
.start();
writeLinesTo(process.getInputStream(), System.out);
writeLinesTo(process.getErrorStream(), System.out);
if (process.waitFor() != 0) {
new RuntimeException("Failed to run " + Arrays.toString(args));
}
} catch (IOException | InterruptedException e) {
throw new RuntimeException("Failed to run " + Arrays.toString(args), e);
}
}
private static void writeLinesTo(InputStream input, PrintStream out) {
Scanner scanner = new Scanner(input);
while(scanner.hasNextLine()) {
out.println(scanner.nextLine());
}
}
}
@@ -1,49 +0,0 @@
/*
* Copyright 2019-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.convention.versions;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.function.Function;
class FileUtils {
static void replaceFileText(File file, Function<String, String> replaceText) {
String buildFileText = readString(file);
String updatedBuildFileText = replaceText.apply(buildFileText);
writeString(file, updatedBuildFileText);
}
static String readString(File file) {
try {
byte[] bytes = Files.readAllBytes(file.toPath());
return new String(bytes);
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
private static void writeString(File file, String text) {
try {
Files.write(file.toPath(), text.getBytes());
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
}

Some files were not shown because too many files have changed in this diff Show More