Compare commits
81 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a8457b518f | |||
| 4fd5c7ffa3 | |||
| ce35bee1bd | |||
| 28ea347b5a | |||
| 8aa7b5897a | |||
| 29bc6745e8 | |||
| 08bc7a53d6 | |||
| e5212926a1 | |||
| 2ed93ec0cf | |||
| bb9d9d7f9d | |||
| 815891d6f0 | |||
| 5187bea5ea | |||
| c6c27d795b | |||
| f8c8d049c3 | |||
| bb92dd3cc5 | |||
| 60653ddf19 | |||
| 7c54f98944 | |||
| 5cd7c71923 | |||
| 7d0185f051 | |||
| b91d38752a | |||
| 9b12616913 | |||
| 08139cf9f4 | |||
| 801dcfdcb4 | |||
| 4939331501 | |||
| 8abd4e999f | |||
| 194eaf8491 | |||
| 60ed3602f6 | |||
| 214cfe807e | |||
| 1ab0705b47 | |||
| f04cd641b0 | |||
| 3bb82c4449 | |||
| 89366d0874 | |||
| 6884a16726 | |||
| 6b54afe9a3 | |||
| b9453da343 | |||
| 18427b6411 | |||
| 7e17a00197 | |||
| 53b8cff26f | |||
| cd8983d4e5 | |||
| 5598688fa6 | |||
| 22379e79e7 | |||
| 65426a40ec | |||
| 7ec3b55ab3 | |||
| ed3b0fbaad | |||
| 62e8799a8d | |||
| df0f6f83af | |||
| 925d531cbe | |||
| 074e38d565 | |||
| 3af619d565 | |||
| bb2d80fea3 | |||
| f49c286050 | |||
| dbe4d704f8 | |||
| a68411566e | |||
| 2bc643d6c8 | |||
| 1251cde04c | |||
| a3a9de1b9b | |||
| f838b7cb1d | |||
| 23e895f0b1 | |||
| 204f0b4599 | |||
| 43317c5a61 | |||
| dec858a5b7 | |||
| bbeca7cd65 | |||
| 3c18278123 | |||
| bb99d7d95a | |||
| d736a2b358 | |||
| cf95d3f91e | |||
| 17e28fa7aa | |||
| 739cdc1a4c | |||
| 02cd1dd3c4 | |||
| b7cc667d21 | |||
| 3fb1565cc0 | |||
| 00fafd878c | |||
| 96a6fef820 | |||
| 4318a51971 | |||
| 61ee4e5a76 | |||
| aa0f788f59 | |||
| 0c201565fc | |||
| 582629c087 | |||
| 399cf2e59d | |||
| ec8912aa47 | |||
| 7b15098570 |
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
#!/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"
|
||||
Executable
+21
@@ -0,0 +1,21 @@
|
||||
#!/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
|
||||
@@ -0,0 +1,16 @@
|
||||
name: Update Algolia Index
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 10 * * *' # Once per day at 10am UTC
|
||||
workflow_dispatch: # Manual trigger
|
||||
|
||||
jobs:
|
||||
update:
|
||||
name: Update Algolia Index
|
||||
runs-on: ubuntu-latest
|
||||
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"
|
||||
@@ -1,30 +1,19 @@
|
||||
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
|
||||
|
||||
@@ -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
|
||||
@@ -18,28 +16,19 @@ env:
|
||||
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 +40,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+github' >> ~/.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,11 +65,14 @@ 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+github' >> ~/.gradle/gradle.properties
|
||||
- name: Snapshot Tests
|
||||
run: |
|
||||
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
|
||||
@@ -90,23 +86,20 @@ 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+github' >> ~/.gradle/gradle.properties
|
||||
- name: Check samples project
|
||||
env:
|
||||
LOCAL_REPOSITORY_PATH: ${{ github.workspace }}/build/publications/repos
|
||||
SAMPLES_DIR: ../spring-security-samples
|
||||
VERSION: ${{ needs.prerequisites.outputs.project_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"
|
||||
./gradlew publishMavenJavaPublicationToLocalRepository
|
||||
./gradlew cloneSamples -PcloneOutputDirectory="$SAMPLES_DIR"
|
||||
./gradlew --project-dir "$SAMPLES_DIR" --init-script spring-security-ci.gradle -PlocalRepositoryPath="$LOCAL_REPOSITORY_PATH" -PspringSecurityVersion="$VERSION" :runAllTests
|
||||
./gradlew checkSamples --stacktrace
|
||||
check_tangles:
|
||||
name: Check for Package Tangles
|
||||
needs: [ prerequisites ]
|
||||
@@ -114,11 +107,14 @@ 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+github' >> ~/.gradle/gradle.properties
|
||||
- name: Check for package tangles
|
||||
run: |
|
||||
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
|
||||
@@ -131,11 +127,14 @@ jobs:
|
||||
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+github' >> ~/.gradle/gradle.properties
|
||||
- name: Deploy artifacts
|
||||
run: |
|
||||
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
|
||||
@@ -155,11 +154,14 @@ jobs:
|
||||
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+github' >> ~/.gradle/gradle.properties
|
||||
- name: Deploy Docs
|
||||
run: |
|
||||
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
|
||||
@@ -176,11 +178,14 @@ jobs:
|
||||
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+github' >> ~/.gradle/gradle.properties
|
||||
- name: Deploy Schema
|
||||
run: |
|
||||
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
|
||||
@@ -191,121 +196,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
|
||||
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, check_samples, check_tangles, 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 }}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
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
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
name: deploy
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'adopt'
|
||||
cache: gradle
|
||||
- name: Validate Gradle wrapper
|
||||
uses: gradle/wrapper-validation-action@e6e38bacfdf1a337459f332974bb2327a31aaf4b
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew :spring-security-docs:antora --stacktrace
|
||||
- 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 ~/.gradle/caches/modules-2/modules-2.lock
|
||||
rm -f ~/.gradle/caches/modules-2/gc.properties
|
||||
- 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 }}"
|
||||
@@ -5,15 +5,10 @@ on:
|
||||
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'"
|
||||
@@ -28,8 +23,6 @@ jobs:
|
||||
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
|
||||
|
||||
@@ -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,80 +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
|
||||
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'
|
||||
@@ -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
|
||||
+2
-9
@@ -43,12 +43,9 @@ If you're considering anything more than correcting a typo or fixing a minor bug
|
||||
|
||||
If you have not previously done so, please fill out and submit the https://cla.pivotal.io/sign/spring[Contributor License Agreement].
|
||||
|
||||
= Create your branch from oldest maintenance branch
|
||||
= Create your branch from main
|
||||
|
||||
Create your topic branch to be submitted as a pull request from the oldest impacted and supported maintenance branch.
|
||||
You can find the supported versions by looking at the https://github.com/spring-projects/spring-security/milestones[milestones page].
|
||||
Switch to a branch named `<major>.<minor>.x` from the smallest milestone in the format of `<major>.<minor>.<patch>(-<prerelease>)`.
|
||||
The spring team will ensure the code gets merged forward into additional branches.
|
||||
Create your topic branch to be submitted as a pull request from main. The Spring team will consider your pull request for backporting on a case-by-case basis; you don't need to worry about submitting anything for backporting.
|
||||
|
||||
= Use short branch names
|
||||
|
||||
@@ -136,10 +133,6 @@ Search the codebase to find related unit tests and add additional `@Test` method
|
||||
|
||||
Update the https://www.relaxng.org[RELAX NG] schema `spring-security-x.y.rnc` instead of `spring-security-x.y.xsd` if you contribute changes to supported XML configuration. The XML schema file can be generated the following Gradle task:
|
||||
|
||||
----
|
||||
./gradlew :spring-security-config:rncToXsd
|
||||
----
|
||||
|
||||
Changes to the XML schema will be overwritten by the Gradle build task.
|
||||
|
||||
= Squash commits
|
||||
|
||||
+1
-1
@@ -135,7 +135,7 @@ git push origin 5.4.0-RC1
|
||||
|
||||
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)
|
||||
|
||||
|
||||
@@ -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.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
|
||||
import org.springframework.security.acls.domain.PermissionFactory;
|
||||
import org.springframework.security.acls.domain.PrincipalSid;
|
||||
import org.springframework.security.acls.model.AccessControlEntry;
|
||||
@@ -51,6 +51,7 @@ 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;
|
||||
@@ -73,8 +74,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
|
||||
*/
|
||||
@@ -109,6 +110,8 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
|
||||
private final AclAuthorizationStrategy aclAuthorizationStrategy;
|
||||
|
||||
private ObjectIdentityGenerator objectIdentityGenerator;
|
||||
|
||||
private PermissionFactory permissionFactory = new DefaultPermissionFactory();
|
||||
|
||||
private final AclCache aclCache;
|
||||
@@ -162,6 +165,7 @@ 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);
|
||||
@@ -488,6 +492,11 @@ 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);
|
||||
}
|
||||
@@ -569,7 +578,8 @@ 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 = new ObjectIdentityImpl(rs.getString("class"), identifier);
|
||||
ObjectIdentity objectIdentity = BasicLookupStrategy.this.objectIdentityGenerator
|
||||
.createObjectIdentity(identifier, rs.getString("class"));
|
||||
|
||||
Acl parentAcl = null;
|
||||
long parentAclId = rs.getLong("parent_object");
|
||||
|
||||
@@ -31,11 +31,12 @@ 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.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
|
||||
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;
|
||||
|
||||
@@ -81,6 +82,8 @@ public class JdbcAclService implements AclService {
|
||||
|
||||
private AclClassIdUtils aclClassIdUtils;
|
||||
|
||||
private ObjectIdentityGenerator objectIdentityGenerator;
|
||||
|
||||
public JdbcAclService(DataSource dataSource, LookupStrategy lookupStrategy) {
|
||||
this(new JdbcTemplate(dataSource), lookupStrategy);
|
||||
}
|
||||
@@ -91,6 +94,7 @@ public class JdbcAclService implements AclService {
|
||||
this.jdbcOperations = jdbcOperations;
|
||||
this.lookupStrategy = lookupStrategy;
|
||||
this.aclClassIdUtils = new AclClassIdUtils();
|
||||
this.objectIdentityGenerator = new ObjectIdentityRetrievalStrategyImpl();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -105,7 +109,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 new ObjectIdentityImpl(javaType, identifier);
|
||||
return this.objectIdentityGenerator.createObjectIdentity(identifier, javaType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -165,6 +169,11 @@ 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;
|
||||
}
|
||||
|
||||
+9
@@ -318,4 +318,13 @@ 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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ 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;
|
||||
@@ -170,6 +171,26 @@ 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;
|
||||
|
||||
@@ -27,7 +27,3 @@ sourceSets.test.aspectj.srcDir "src/test/java"
|
||||
sourceSets.test.java.srcDirs = files()
|
||||
|
||||
compileAspectj.ajcOptions.outxmlfile = "META-INF/aop.xml"
|
||||
|
||||
aspectj {
|
||||
version = aspectjVersion
|
||||
}
|
||||
|
||||
+9
-54
@@ -1,10 +1,8 @@
|
||||
import io.spring.gradle.IncludeRepoTask
|
||||
|
||||
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.2.0"
|
||||
classpath "io.freefair.gradle:aspectj-plugin:6.3.0"
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
|
||||
classpath "com.netflix.nebula:nebula-project-plugin:8.2.0"
|
||||
}
|
||||
@@ -18,9 +16,9 @@ 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'
|
||||
@@ -38,7 +36,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/"
|
||||
}
|
||||
|
||||
@@ -49,29 +47,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"
|
||||
@@ -79,13 +54,6 @@ tasks.named("createGitHubRelease") {
|
||||
}
|
||||
}
|
||||
|
||||
tasks.named("dispatchGitHubWorkflow") {
|
||||
repository {
|
||||
owner = "spring-projects"
|
||||
name = "spring-security"
|
||||
}
|
||||
}
|
||||
|
||||
tasks.named("updateDependencies") {
|
||||
// we aren't Gradle 7 compatible yet
|
||||
checkForGradleUpdate = false
|
||||
@@ -103,10 +71,7 @@ updateDependenciesSettings {
|
||||
})
|
||||
dependencyExcludes {
|
||||
majorVersionBump()
|
||||
minorVersionBump()
|
||||
alphaBetaVersions()
|
||||
releaseCandidatesVersions()
|
||||
milestoneVersions()
|
||||
snapshotVersions()
|
||||
addRule { components ->
|
||||
components.withModule("commons-codec:commons-codec") { selection ->
|
||||
@@ -135,18 +100,6 @@ updateDependenciesSettings {
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -202,10 +155,12 @@ nohttp {
|
||||
|
||||
}
|
||||
|
||||
tasks.register('cloneSamples', IncludeRepoTask) {
|
||||
repository = 'spring-projects/spring-security-samples'
|
||||
ref = samplesBranch
|
||||
outputDirectory = project.hasProperty("cloneOutputDirectory") ? project.file("$cloneOutputDirectory") : project.file("build/samples")
|
||||
tasks.register('checkSamples') {
|
||||
includeCheckRemote {
|
||||
repository = 'spring-projects/spring-security-samples'
|
||||
ref = samplesBranch
|
||||
}
|
||||
dependsOn checkRemote
|
||||
}
|
||||
|
||||
s101 {
|
||||
|
||||
@@ -5,6 +5,7 @@ plugins {
|
||||
id 'com.apollographql.apollo' version '2.4.5'
|
||||
}
|
||||
|
||||
|
||||
sourceCompatibility = 1.8
|
||||
|
||||
repositories {
|
||||
@@ -28,7 +29,7 @@ gradlePlugin {
|
||||
plugins {
|
||||
checkAntoraVersion {
|
||||
id = "org.springframework.antora.check-version"
|
||||
implementationClass = "org.springframework.gradle.antora.AntoraVersionPlugin"
|
||||
implementationClass = "org.springframework.gradle.antora.CheckAntoraVersionPlugin"
|
||||
}
|
||||
trang {
|
||||
id = "trang"
|
||||
@@ -46,10 +47,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"
|
||||
@@ -87,7 +84,7 @@ dependencies {
|
||||
implementation localGroovy()
|
||||
|
||||
implementation 'io.github.gradle-nexus:publish-plugin:1.1.0'
|
||||
implementation 'io.projectreactor:reactor-core:3.4.24'
|
||||
implementation 'io.projectreactor:reactor-core:3.4.14'
|
||||
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'
|
||||
@@ -96,7 +93,7 @@ dependencies {
|
||||
implementation 'io.spring.nohttp:nohttp-gradle:0.0.10'
|
||||
implementation 'net.sourceforge.htmlunit:htmlunit:2.37.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.24.20'
|
||||
implementation 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.7.1'
|
||||
|
||||
testImplementation platform('org.junit:junit-bom:5.8.2')
|
||||
|
||||
@@ -54,7 +54,7 @@ abstract class IncludeRepoTask extends DefaultTask {
|
||||
* Directory where the project template should be copied.
|
||||
*/
|
||||
@OutputDirectory
|
||||
File outputDirectory = project.file("$project.buildDir/$name")
|
||||
final File outputDirectory = project.file("$project.buildDir/$name")
|
||||
|
||||
@TaskAction
|
||||
void checkoutAndCopy() {
|
||||
|
||||
@@ -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')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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.IncludeRepoTask
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.provider.Property
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
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']
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -59,14 +59,22 @@ public class IntegrationTestPlugin implements Plugin<Project> {
|
||||
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.integrationTestCompile
|
||||
runtimeClasspath = output + compileClasspath + project.configurations.integrationTestRuntime
|
||||
compileClasspath = project.sourceSets.main.output + project.sourceSets.test.output + project.configurations.integrationTestCompileClasspath
|
||||
runtimeClasspath = output + compileClasspath + project.configurations.integrationTestRuntimeClasspath
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +93,7 @@ public class IntegrationTestPlugin implements Plugin<Project> {
|
||||
project.idea {
|
||||
module {
|
||||
testSourceDirs += project.file('src/integration-test/java')
|
||||
scopes.TEST.plus += [ project.configurations.integrationTestCompile ]
|
||||
scopes.TEST.plus += [ project.configurations.integrationTestCompileClasspath ]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,7 +123,7 @@ public class IntegrationTestPlugin implements Plugin<Project> {
|
||||
|
||||
project.plugins.withType(EclipsePlugin) {
|
||||
project.eclipse.classpath {
|
||||
plusConfigurations += [ project.configurations.integrationTestCompile ]
|
||||
plusConfigurations += [ project.configurations.integrationTestCompileClasspath ]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,7 +32,6 @@ 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")
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
+22
-17
@@ -8,7 +8,7 @@ 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 class CheckAntoraVersionPlugin implements Plugin<Project> {
|
||||
public static final String ANTORA_CHECK_VERSION_TASK_NAME = "antoraCheckVersion";
|
||||
|
||||
@Override
|
||||
@@ -20,7 +20,6 @@ public class AntoraVersionPlugin implements Plugin<Project> {
|
||||
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")));
|
||||
}
|
||||
});
|
||||
@@ -35,29 +34,24 @@ public class AntoraVersionPlugin implements Plugin<Project> {
|
||||
});
|
||||
}
|
||||
});
|
||||
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);
|
||||
int preReleaseIndex = getSnapshotIndex(projectVersion);
|
||||
return isSnapshot(projectVersion) ? projectVersion.substring(0, preReleaseIndex) : 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);
|
||||
if (isSnapshot(projectVersion)) {
|
||||
int preReleaseIndex = getSnapshotIndex(projectVersion);
|
||||
return projectVersion.substring(preReleaseIndex);
|
||||
}
|
||||
if (isPreRelease(projectVersion)) {
|
||||
return Boolean.TRUE.toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String getProjectVersion(Project project) {
|
||||
@@ -68,4 +62,15 @@ public class AntoraVersionPlugin implements Plugin<Project> {
|
||||
return String.valueOf(projectVersion);
|
||||
}
|
||||
|
||||
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
-25
@@ -6,7 +6,6 @@ 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;
|
||||
@@ -23,7 +22,6 @@ public abstract class CheckAntoraVersionTask extends DefaultTask {
|
||||
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);
|
||||
@@ -34,17 +32,10 @@ public abstract class CheckAntoraVersionTask extends DefaultTask {
|
||||
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 + "'");
|
||||
throw new GradleException("The Gradle version of '" + getProject().getVersion() + "' should have version: '" + expectedAntoraVersion + "' and prerelease: '" + expectedAntoraPrerelease + "' defined in " + antoraYmlFile + " but got version: '" + actualAntoraVersion+"' and prerelease: '" + actualAntoraPrerelease + "'");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,20 +46,13 @@ public abstract class CheckAntoraVersionTask extends DefaultTask {
|
||||
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;
|
||||
}
|
||||
@@ -84,13 +68,5 @@ public abstract class CheckAntoraVersionTask extends DefaultTask {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-138
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
-99
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
-67
@@ -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));
|
||||
}
|
||||
}
|
||||
-41
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,6 @@
|
||||
package org.springframework.gradle.github;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class RepositoryRef implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 7151218536746822797L;
|
||||
|
||||
public class RepositoryRef {
|
||||
private String owner;
|
||||
|
||||
private String name;
|
||||
|
||||
+17
-172
@@ -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,21 +17,13 @@
|
||||
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;
|
||||
@@ -41,10 +33,7 @@ public class GitHubMilestoneApi {
|
||||
|
||||
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 +50,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 +89,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 {
|
||||
|
||||
|
||||
+6
-40
@@ -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,32 @@ 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() {
|
||||
|
||||
-93
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
-102
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+11
-43
@@ -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"));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
-23
@@ -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());
|
||||
}
|
||||
}
|
||||
-25
@@ -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 +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
-29
@@ -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;
|
||||
}
|
||||
}
|
||||
-147
@@ -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;
|
||||
}
|
||||
}
|
||||
-136
@@ -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);
|
||||
}
|
||||
}
|
||||
-205
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
-84
@@ -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;
|
||||
}
|
||||
}
|
||||
-98
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
-21
@@ -17,6 +17,7 @@
|
||||
package org.springframework.gradle.github.release;
|
||||
|
||||
import groovy.lang.MissingPropertyException;
|
||||
import org.gradle.api.Action;
|
||||
import org.gradle.api.Plugin;
|
||||
import org.gradle.api.Project;
|
||||
|
||||
@@ -26,29 +27,23 @@ import org.gradle.api.Project;
|
||||
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");
|
||||
project.getTasks().register("createGitHubRelease", CreateGitHubReleaseTask.class, new Action<CreateGitHubReleaseTask>() {
|
||||
@Override
|
||||
public void execute(CreateGitHubReleaseTask 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.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=...");
|
||||
}
|
||||
}
|
||||
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"));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
-51
@@ -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;
|
||||
}
|
||||
}
|
||||
-49
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
-49
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+57
-5
@@ -33,8 +33,13 @@ import org.gradle.api.artifacts.component.ModuleComponentIdentifier;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.nio.file.Files;
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -163,7 +168,7 @@ public class UpdateDependenciesPlugin implements Plugin<Project> {
|
||||
Integer issueNumber = gitHubApi.createIssue(createIssueResult.getRepositoryId(), title, createIssueResult.getLabelIds(), createIssueResult.getMilestoneId(), createIssueResult.getAssigneeId()).delayElement(Duration.ofSeconds(1)).block();
|
||||
commitMessage += "\n\nCloses gh-" + issueNumber;
|
||||
}
|
||||
CommandLineUtils.runCommand(rootDir, "git", "commit", "-am", commitMessage);
|
||||
runCommand(rootDir, "git", "commit", "-am", commitMessage);
|
||||
}
|
||||
|
||||
private Mono<GitHubApi.FindCreateIssueResult> createIssueResultMono(UpdateDependenciesExtension updateDependenciesExtension) {
|
||||
@@ -182,7 +187,7 @@ public class UpdateDependenciesPlugin implements Plugin<Project> {
|
||||
if (current.compareTo(running) > 0) {
|
||||
String title = "Update Gradle to " + current.getVersion();
|
||||
System.out.println(title);
|
||||
CommandLineUtils.runCommand(project.getRootDir(), "./gradlew", "wrapper", "--gradle-version", current.getVersion(), "--no-daemon");
|
||||
runCommand(project.getRootDir(), "./gradlew", "wrapper", "--gradle-version", current.getVersion(), "--no-daemon");
|
||||
afterGroup(updateDependenciesSettings, project.getRootDir(), title, createIssueResultMono(updateDependenciesSettings));
|
||||
}
|
||||
}
|
||||
@@ -199,6 +204,30 @@ public class UpdateDependenciesPlugin implements Plugin<Project> {
|
||||
};
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static void writeLinesTo(InputStream input, PrintStream out) {
|
||||
Scanner scanner = new Scanner(input);
|
||||
while(scanner.hasNextLine()) {
|
||||
out.println(scanner.nextLine());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static Action<ComponentSelectionWithCurrent> excludeWithRegex(String regex, String reason) {
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
return (selection) -> {
|
||||
@@ -213,17 +242,40 @@ public class UpdateDependenciesPlugin implements Plugin<Project> {
|
||||
String ga = dependency.getGroup() + ":" + dependency.getName() + ":";
|
||||
String originalDependency = ga + dependency.getVersion();
|
||||
String replacementDependency = ga + updatedVersion(dependency);
|
||||
FileUtils.replaceFileText(buildFile, buildFileText -> buildFileText.replace(originalDependency, replacementDependency));
|
||||
replaceFileText(buildFile, buildFileText -> buildFileText.replace(originalDependency, replacementDependency));
|
||||
}
|
||||
|
||||
static void replaceFileText(File file, Function<String, String> replaceText) {
|
||||
String buildFileText = readString(file);
|
||||
String updatedBuildFileText = replaceText.apply(buildFileText);
|
||||
writeString(file, updatedBuildFileText);
|
||||
}
|
||||
|
||||
private 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);
|
||||
}
|
||||
}
|
||||
|
||||
static void updateDependencyWithVersionVariable(File scanFile, File gradlePropertiesFile, DependencyOutdated dependency) {
|
||||
if (!gradlePropertiesFile.exists()) {
|
||||
return;
|
||||
}
|
||||
FileUtils.replaceFileText(gradlePropertiesFile, (gradlePropertiesText) -> {
|
||||
replaceFileText(gradlePropertiesFile, (gradlePropertiesText) -> {
|
||||
String ga = dependency.getGroup() + ":" + dependency.getName() + ":";
|
||||
Pattern pattern = Pattern.compile("\"" + ga + "\\$\\{?([^'\"]+?)\\}?\"");
|
||||
String buildFileText = FileUtils.readString(scanFile);
|
||||
String buildFileText = readString(scanFile);
|
||||
Matcher matcher = pattern.matcher(buildFileText);
|
||||
while (matcher.find()) {
|
||||
String versionVariable = matcher.group(1);
|
||||
|
||||
-44
@@ -1,44 +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 org.gradle.api.Action;
|
||||
import org.gradle.api.Plugin;
|
||||
import org.gradle.api.Project;
|
||||
|
||||
public class UpdateProjectVersionPlugin implements Plugin<Project> {
|
||||
@Override
|
||||
public void apply(Project project) {
|
||||
project.getTasks().register("updateProjectVersion", UpdateProjectVersionTask.class, new Action<UpdateProjectVersionTask>() {
|
||||
@Override
|
||||
public void execute(UpdateProjectVersionTask updateProjectVersionTask) {
|
||||
updateProjectVersionTask.setGroup("Release");
|
||||
updateProjectVersionTask.setDescription("Updates the project version to the next release in gradle.properties");
|
||||
updateProjectVersionTask.dependsOn("gitHubNextReleaseMilestone");
|
||||
updateProjectVersionTask.getNextVersionFile().fileProvider(project.provider(() -> project.file("next-release.yml")));
|
||||
}
|
||||
});
|
||||
project.getTasks().register("updateToSnapshotVersion", UpdateToSnapshotVersionTask.class, new Action<UpdateToSnapshotVersionTask>() {
|
||||
@Override
|
||||
public void execute(UpdateToSnapshotVersionTask updateToSnapshotVersionTask) {
|
||||
updateToSnapshotVersionTask.setGroup("Release");
|
||||
updateToSnapshotVersionTask.setDescription(
|
||||
"Updates the project version to the next snapshot in gradle.properties");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
-63
@@ -1,63 +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 org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.Project;
|
||||
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.TaskAction;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.constructor.Constructor;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
|
||||
import org.springframework.gradle.github.milestones.NextVersionYml;
|
||||
|
||||
public abstract class UpdateProjectVersionTask extends DefaultTask {
|
||||
|
||||
@InputFile
|
||||
public abstract RegularFileProperty getNextVersionFile();
|
||||
|
||||
@TaskAction
|
||||
public void checkReleaseDueToday() throws FileNotFoundException {
|
||||
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());
|
||||
}
|
||||
String currentVersion = getProject().getVersion().toString();
|
||||
File gradlePropertiesFile = getProject().getRootProject().file(Project.GRADLE_PROPERTIES);
|
||||
if (!gradlePropertiesFile.exists()) {
|
||||
return;
|
||||
}
|
||||
System.out.println("Updating the project version in " + Project.GRADLE_PROPERTIES + " from " + currentVersion
|
||||
+ " to " + nextVersion);
|
||||
FileUtils.replaceFileText(gradlePropertiesFile, (gradlePropertiesText) -> {
|
||||
gradlePropertiesText = gradlePropertiesText.replace("version=" + currentVersion, "version=" + nextVersion);
|
||||
return gradlePropertiesText;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
-68
@@ -1,68 +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 org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public abstract class UpdateToSnapshotVersionTask extends DefaultTask {
|
||||
|
||||
private static final String RELEASE_VERSION_PATTERN = "^([0-9]+)\\.([0-9]+)\\.([0-9]+)(-M\\d+|-RC\\d+)?$";
|
||||
|
||||
@TaskAction
|
||||
public void updateToSnapshotVersion() {
|
||||
String currentVersion = getProject().getVersion().toString();
|
||||
File gradlePropertiesFile = getProject().getRootProject().file(Project.GRADLE_PROPERTIES);
|
||||
if (!gradlePropertiesFile.exists()) {
|
||||
return;
|
||||
}
|
||||
String nextVersion = calculateNextSnapshotVersion(currentVersion);
|
||||
System.out.println("Updating the project version in " + Project.GRADLE_PROPERTIES + " from " + currentVersion
|
||||
+ " to " + nextVersion);
|
||||
FileUtils.replaceFileText(gradlePropertiesFile, (gradlePropertiesText) -> {
|
||||
gradlePropertiesText = gradlePropertiesText.replace("version=" + currentVersion, "version=" + nextVersion);
|
||||
return gradlePropertiesText;
|
||||
});
|
||||
}
|
||||
|
||||
private String calculateNextSnapshotVersion(String currentVersion) {
|
||||
Pattern releaseVersionPattern = Pattern.compile(RELEASE_VERSION_PATTERN);
|
||||
Matcher releaseVersion = releaseVersionPattern.matcher(currentVersion);
|
||||
|
||||
if (releaseVersion.find()) {
|
||||
String majorSegment = releaseVersion.group(1);
|
||||
String minorSegment = releaseVersion.group(2);
|
||||
String patchSegment = releaseVersion.group(3);
|
||||
String modifier = releaseVersion.group(4);
|
||||
if (modifier == null) {
|
||||
patchSegment = String.valueOf(Integer.parseInt(patchSegment) + 1);
|
||||
}
|
||||
System.out.println("modifier = " + modifier);
|
||||
return String.format("%s.%s.%s-SNAPSHOT", majorSegment, minorSegment, patchSegment);
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException(
|
||||
"Cannot calculate next snapshot version because the current project version does not conform to the expected format");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -164,14 +164,18 @@ public class S101Configurer {
|
||||
String source = "https://structure101.com/binaries/v6";
|
||||
try (final WebClient webClient = new WebClient()) {
|
||||
HtmlPage page = webClient.getPage(source);
|
||||
Matcher matcher = null;
|
||||
for (HtmlAnchor anchor : page.getAnchors()) {
|
||||
Matcher matcher = Pattern.compile("(structure101-build-java-all-)(.*).zip").matcher(anchor.getHrefAttribute());
|
||||
if (matcher.find()) {
|
||||
copyZipToFilesystem(source, installationDirectory, matcher.group(1) + matcher.group(2));
|
||||
return matcher.group(2);
|
||||
Matcher candidate = Pattern.compile("(structure101-build-java-all-)(.*).zip").matcher(anchor.getHrefAttribute());
|
||||
if (candidate.find()) {
|
||||
matcher = candidate;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
if (matcher == null) {
|
||||
return null;
|
||||
}
|
||||
copyZipToFilesystem(source, installationDirectory, matcher.group(1) + matcher.group(2));
|
||||
return matcher.group(2);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
implementation-class=io.spring.gradle.convention.IncludeCheckRemotePlugin
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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.IncludeRepoTask;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.tasks.GradleBuild;
|
||||
import org.gradle.testfixtures.ProjectBuilder;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class IncludeCheckRemotePluginTest {
|
||||
|
||||
Project rootProject;
|
||||
|
||||
@AfterEach
|
||||
public void cleanup() throws Exception {
|
||||
if (rootProject != null) {
|
||||
FileUtils.deleteDirectory(rootProject.getProjectDir());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void applyWhenExtensionPropertiesNoTasksThenCreateCheckRemoteTaskWithDefaultTask() {
|
||||
this.rootProject = ProjectBuilder.builder().build();
|
||||
this.rootProject.getPluginManager().apply(IncludeCheckRemotePlugin.class);
|
||||
this.rootProject.getExtensions().configure(IncludeCheckRemotePlugin.IncludeCheckRemoteExtension.class,
|
||||
(includeCheckRemoteExtension) -> {
|
||||
includeCheckRemoteExtension.setProperty("repository", "my-project/my-repository");
|
||||
includeCheckRemoteExtension.setProperty("ref", "main");
|
||||
});
|
||||
|
||||
GradleBuild checkRemote = (GradleBuild) this.rootProject.getTasks().named("checkRemote").get();
|
||||
assertThat(checkRemote.getTasks()).containsExactly("check");
|
||||
}
|
||||
|
||||
@Test
|
||||
void applyWhenExtensionPropertiesTasksThenCreateCheckRemoteWithProvidedTasks() {
|
||||
this.rootProject = ProjectBuilder.builder().build();
|
||||
this.rootProject.getPluginManager().apply(IncludeCheckRemotePlugin.class);
|
||||
this.rootProject.getExtensions().configure(IncludeCheckRemotePlugin.IncludeCheckRemoteExtension.class,
|
||||
(includeCheckRemoteExtension) -> {
|
||||
includeCheckRemoteExtension.setProperty("repository", "my-project/my-repository");
|
||||
includeCheckRemoteExtension.setProperty("ref", "main");
|
||||
includeCheckRemoteExtension.setProperty("tasks", Arrays.asList("clean", "build", "test"));
|
||||
});
|
||||
|
||||
GradleBuild checkRemote = (GradleBuild) this.rootProject.getTasks().named("checkRemote").get();
|
||||
assertThat(checkRemote.getTasks()).containsExactly("clean", "build", "test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void applyWhenExtensionPropertiesThenRegisterIncludeRepoTaskWithExtensionProperties() {
|
||||
this.rootProject = ProjectBuilder.builder().build();
|
||||
this.rootProject.getPluginManager().apply(IncludeCheckRemotePlugin.class);
|
||||
this.rootProject.getExtensions().configure(IncludeCheckRemotePlugin.IncludeCheckRemoteExtension.class,
|
||||
(includeCheckRemoteExtension) -> {
|
||||
includeCheckRemoteExtension.setProperty("repository", "my-project/my-repository");
|
||||
includeCheckRemoteExtension.setProperty("ref", "main");
|
||||
});
|
||||
|
||||
IncludeRepoTask includeRepo = (IncludeRepoTask) this.rootProject.getTasks().named("includeRepo").get();
|
||||
assertThat(includeRepo).isNotNull();
|
||||
assertThat(includeRepo.getRepository().get()).isEqualTo("my-project/my-repository");
|
||||
assertThat(includeRepo.getRef().get()).isEqualTo("main");
|
||||
}
|
||||
|
||||
@Test
|
||||
void applyWhenRegisterTasksThenCheckRemoteDirSameAsIncludeRepoOutputDir() {
|
||||
this.rootProject = ProjectBuilder.builder().build();
|
||||
this.rootProject.getPluginManager().apply(IncludeCheckRemotePlugin.class);
|
||||
this.rootProject.getExtensions().configure(IncludeCheckRemotePlugin.IncludeCheckRemoteExtension.class,
|
||||
(includeCheckRemoteExtension) -> {
|
||||
includeCheckRemoteExtension.setProperty("repository", "my-project/my-repository");
|
||||
includeCheckRemoteExtension.setProperty("ref", "main");
|
||||
});
|
||||
IncludeRepoTask includeRepo = (IncludeRepoTask) this.rootProject.getTasks().named("includeRepo").get();
|
||||
GradleBuild checkRemote = (GradleBuild) this.rootProject.getTasks().named("checkRemote").get();
|
||||
assertThat(checkRemote.getDir()).isEqualTo(includeRepo.getOutputDirectory());
|
||||
}
|
||||
|
||||
@Test
|
||||
void applyWhenNoExtensionPropertiesThenRegisterTasks() {
|
||||
this.rootProject = ProjectBuilder.builder().build();
|
||||
this.rootProject.getPluginManager().apply(IncludeCheckRemotePlugin.class);
|
||||
IncludeRepoTask includeRepo = (IncludeRepoTask) this.rootProject.getTasks().named("includeRepo").get();
|
||||
GradleBuild checkRemote = (GradleBuild) this.rootProject.getTasks().named("checkRemote").get();
|
||||
assertThat(includeRepo).isNotNull();
|
||||
assertThat(checkRemote).isNotNull();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -58,7 +58,7 @@ public class SaganApiTests {
|
||||
Release release = new Release();
|
||||
release.setVersion("5.6.0-SNAPSHOT");
|
||||
release.setApiDocUrl("https://docs.spring.io/spring-security/site/docs/{version}/api/");
|
||||
release.setReferenceDocUrl("https://docs.spring.io/spring-security/reference/{version}/index.html");
|
||||
release.setReferenceDocUrl("https://docs.spring.io/spring-security/site/docs/{version}/reference/html5/");
|
||||
this.sagan.createReleaseForProject(release, "spring-security");
|
||||
RecordedRequest request = this.server.takeRequest(1, TimeUnit.SECONDS);
|
||||
assertThat(request.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/projects/spring-security/releases");
|
||||
@@ -67,7 +67,7 @@ public class SaganApiTests {
|
||||
assertThat(request.getBody().readString(Charset.defaultCharset())).isEqualToIgnoringWhitespace("{\n" +
|
||||
" \"version\":\"5.6.0-SNAPSHOT\",\n" +
|
||||
" \"current\":false,\n" +
|
||||
" \"referenceDocUrl\":\"https://docs.spring.io/spring-security/reference/{version}/index.html\",\n" +
|
||||
" \"referenceDocUrl\":\"https://docs.spring.io/spring-security/site/docs/{version}/reference/html5/\",\n" +
|
||||
" \"apiDocUrl\":\"https://docs.spring.io/spring-security/site/docs/{version}/api/\"\n" +
|
||||
"}");
|
||||
}
|
||||
|
||||
+389
@@ -0,0 +1,389 @@
|
||||
package io.spring.gradle.github.milestones;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import okhttp3.mockwebserver.MockResponse;
|
||||
import okhttp3.mockwebserver.MockWebServer;
|
||||
import okhttp3.mockwebserver.RecordedRequest;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.gradle.github.RepositoryRef;
|
||||
import org.springframework.gradle.github.milestones.GitHubMilestoneApi;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
|
||||
public class GitHubMilestoneApiTests {
|
||||
private GitHubMilestoneApi github;
|
||||
|
||||
private RepositoryRef repositoryRef = RepositoryRef.owner("spring-projects").repository("spring-security").build();
|
||||
|
||||
private MockWebServer server;
|
||||
|
||||
private String baseUrl;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() throws Exception {
|
||||
this.server = new MockWebServer();
|
||||
this.server.start();
|
||||
this.github = new GitHubMilestoneApi("mock-oauth-token");
|
||||
this.baseUrl = this.server.url("/api").toString();
|
||||
this.github.setBaseUrl(this.baseUrl);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void cleanup() throws Exception {
|
||||
this.server.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findMilestoneNumberByTitleWhenFoundThenSuccess() throws Exception {
|
||||
String responseJson = "[\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" +
|
||||
" \"id\":6611880,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" +
|
||||
" \"number\":207,\n" +
|
||||
" \"title\":\"5.6.x\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jgrandja\",\n" +
|
||||
" \"id\":10884212,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jgrandja\",\n" +
|
||||
" \"html_url\":\"https://github.com/jgrandja\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":1,\n" +
|
||||
" \"closed_issues\":0,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2021-03-31T11:29:17Z\",\n" +
|
||||
" \"updated_at\":\"2021-03-31T11:30:47Z\",\n" +
|
||||
" \"due_on\":null,\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" +
|
||||
" \"id\":5884208,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" +
|
||||
" \"number\":191,\n" +
|
||||
" \"title\":\"5.5.0-RC1\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jzheaux\",\n" +
|
||||
" \"id\":3627351,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jzheaux\",\n" +
|
||||
" \"html_url\":\"https://github.com/jzheaux\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":21,\n" +
|
||||
" \"closed_issues\":23,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2020-09-16T13:28:03Z\",\n" +
|
||||
" \"updated_at\":\"2021-04-06T23:47:10Z\",\n" +
|
||||
" \"due_on\":\"2021-04-12T07:00:00Z\",\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
this.server.enqueue(new MockResponse().setBody(responseJson));
|
||||
|
||||
long milestoneNumberByTitle = this.github.findMilestoneNumberByTitle(this.repositoryRef, "5.5.0-RC1");
|
||||
|
||||
RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS);
|
||||
assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get");
|
||||
assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones?per_page=100");
|
||||
|
||||
assertThat(milestoneNumberByTitle).isEqualTo(191);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findMilestoneNumberByTitleWhenNotFoundThenException() throws Exception {
|
||||
String responseJson = "[\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" +
|
||||
" \"id\":6611880,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" +
|
||||
" \"number\":207,\n" +
|
||||
" \"title\":\"5.6.x\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jgrandja\",\n" +
|
||||
" \"id\":10884212,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jgrandja\",\n" +
|
||||
" \"html_url\":\"https://github.com/jgrandja\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":1,\n" +
|
||||
" \"closed_issues\":0,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2021-03-31T11:29:17Z\",\n" +
|
||||
" \"updated_at\":\"2021-03-31T11:30:47Z\",\n" +
|
||||
" \"due_on\":null,\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" +
|
||||
" \"id\":5884208,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" +
|
||||
" \"number\":191,\n" +
|
||||
" \"title\":\"5.5.0-RC1\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jzheaux\",\n" +
|
||||
" \"id\":3627351,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jzheaux\",\n" +
|
||||
" \"html_url\":\"https://github.com/jzheaux\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":21,\n" +
|
||||
" \"closed_issues\":23,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2020-09-16T13:28:03Z\",\n" +
|
||||
" \"updated_at\":\"2021-04-06T23:47:10Z\",\n" +
|
||||
" \"due_on\":\"2021-04-12T07:00:00Z\",\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
this.server.enqueue(new MockResponse().setBody(responseJson));
|
||||
|
||||
assertThatExceptionOfType(RuntimeException.class)
|
||||
.isThrownBy(() -> this.github.findMilestoneNumberByTitle(this.repositoryRef, "missing"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isOpenIssuesForMilestoneNumberWhenAllClosedThenFalse() throws Exception {
|
||||
String responseJson = "[]";
|
||||
long milestoneNumber = 202;
|
||||
this.server.enqueue(new MockResponse().setBody(responseJson));
|
||||
|
||||
assertThat(this.github.isOpenIssuesForMilestoneNumber(this.repositoryRef, milestoneNumber)).isFalse();
|
||||
|
||||
RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS);
|
||||
assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get");
|
||||
assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/issues?per_page=1&milestone=" + milestoneNumber);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isOpenIssuesForMilestoneNumberWhenOpenIssuesThenTrue() throws Exception {
|
||||
String responseJson = "[\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/issues/9562\",\n" +
|
||||
" \"repository_url\":\"https://api.github.com/repos/spring-projects/spring-security\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/issues/9562/labels{/name}\",\n" +
|
||||
" \"comments_url\":\"https://api.github.com/repos/spring-projects/spring-security/issues/9562/comments\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/repos/spring-projects/spring-security/issues/9562/events\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/pull/9562\",\n" +
|
||||
" \"id\":851886504,\n" +
|
||||
" \"node_id\":\"MDExOlB1bGxSZXF1ZXN0NjEwMjMzMDcw\",\n" +
|
||||
" \"number\":9562,\n" +
|
||||
" \"title\":\"Add package-list\",\n" +
|
||||
" \"user\":{\n" +
|
||||
" \"login\":\"jzheaux\",\n" +
|
||||
" \"id\":3627351,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jzheaux\",\n" +
|
||||
" \"html_url\":\"https://github.com/jzheaux\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"labels\":[\n" +
|
||||
" {\n" +
|
||||
" \"id\":322225043,\n" +
|
||||
" \"node_id\":\"MDU6TGFiZWwzMjIyMjUwNDM=\",\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/labels/in:%20build\",\n" +
|
||||
" \"name\":\"in: build\",\n" +
|
||||
" \"color\":\"e8f9de\",\n" +
|
||||
" \"default\":false,\n" +
|
||||
" \"description\":\"An issue in the build\"\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"id\":322225079,\n" +
|
||||
" \"node_id\":\"MDU6TGFiZWwzMjIyMjUwNzk=\",\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/labels/type:%20bug\",\n" +
|
||||
" \"name\":\"type: bug\",\n" +
|
||||
" \"color\":\"e3d9fc\",\n" +
|
||||
" \"default\":false,\n" +
|
||||
" \"description\":\"A general bug\"\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"locked\":false,\n" +
|
||||
" \"assignee\":{\n" +
|
||||
" \"login\":\"rwinch\",\n" +
|
||||
" \"id\":362503,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjM2MjUwMw==\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/362503?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/rwinch\",\n" +
|
||||
" \"html_url\":\"https://github.com/rwinch\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/rwinch/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/rwinch/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/rwinch/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/rwinch/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/rwinch/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/rwinch/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/rwinch/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/rwinch/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/rwinch/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"assignees\":[\n" +
|
||||
" {\n" +
|
||||
" \"login\":\"rwinch\",\n" +
|
||||
" \"id\":362503,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjM2MjUwMw==\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/362503?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/rwinch\",\n" +
|
||||
" \"html_url\":\"https://github.com/rwinch\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/rwinch/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/rwinch/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/rwinch/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/rwinch/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/rwinch/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/rwinch/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/rwinch/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/rwinch/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/rwinch/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"milestone\":{\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" +
|
||||
" \"id\":5884208,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" +
|
||||
" \"number\":191,\n" +
|
||||
" \"title\":\"5.5.0-RC1\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jzheaux\",\n" +
|
||||
" \"id\":3627351,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jzheaux\",\n" +
|
||||
" \"html_url\":\"https://github.com/jzheaux\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":21,\n" +
|
||||
" \"closed_issues\":23,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2020-09-16T13:28:03Z\",\n" +
|
||||
" \"updated_at\":\"2021-04-06T23:47:10Z\",\n" +
|
||||
" \"due_on\":\"2021-04-12T07:00:00Z\",\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" },\n" +
|
||||
" \"comments\":0,\n" +
|
||||
" \"created_at\":\"2021-04-06T23:47:10Z\",\n" +
|
||||
" \"updated_at\":\"2021-04-07T17:00:00Z\",\n" +
|
||||
" \"closed_at\":null,\n" +
|
||||
" \"author_association\":\"MEMBER\",\n" +
|
||||
" \"active_lock_reason\":null,\n" +
|
||||
" \"pull_request\":{\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/pulls/9562\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/pull/9562\",\n" +
|
||||
" \"diff_url\":\"https://github.com/spring-projects/spring-security/pull/9562.diff\",\n" +
|
||||
" \"patch_url\":\"https://github.com/spring-projects/spring-security/pull/9562.patch\"\n" +
|
||||
" },\n" +
|
||||
" \"body\":\"Closes gh-9528\\r\\n\\r\\n<!--\\r\\nFor Security Vulnerabilities, please use https://pivotal.io/security#reporting\\r\\n-->\\r\\n\\r\\n<!--\\r\\nBefore creating new features, we recommend creating an issue to discuss the feature. This ensures that everyone is on the same page before extensive work is done.\\r\\n\\r\\nThanks for contributing to Spring Security. Please provide a brief description of your pull-request and reference any related issue numbers (prefix references with gh-).\\r\\n-->\\r\\n\",\n" +
|
||||
" \"performed_via_github_app\":null\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
long milestoneNumber = 191;
|
||||
this.server.enqueue(new MockResponse().setBody(responseJson));
|
||||
|
||||
assertThat(this.github.isOpenIssuesForMilestoneNumber(this.repositoryRef, milestoneNumber)).isTrue();
|
||||
|
||||
RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS);
|
||||
assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get");
|
||||
assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/issues?per_page=1&milestone=" + milestoneNumber);
|
||||
}
|
||||
|
||||
}
|
||||
+33
-38
@@ -15,23 +15,22 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIOException;
|
||||
|
||||
class AntoraVersionPluginTests {
|
||||
class CheckAntoraVersionPluginTests {
|
||||
|
||||
@Test
|
||||
void defaultsPropertiesWhenSnapshot() {
|
||||
String expectedVersion = "1.0.0-SNAPSHOT";
|
||||
Project project = ProjectBuilder.builder().build();
|
||||
project.setVersion(expectedVersion);
|
||||
project.getPluginManager().apply(AntoraVersionPlugin.class);
|
||||
project.getPluginManager().apply(CheckAntoraVersionPlugin.class);
|
||||
|
||||
Task task = project.getTasks().findByName(AntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
Task task = project.getTasks().findByName(CheckAntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
|
||||
assertThat(task).isInstanceOf(CheckAntoraVersionTask.class);
|
||||
|
||||
CheckAntoraVersionTask checkAntoraVersionTask = (CheckAntoraVersionTask) task;
|
||||
assertThat(checkAntoraVersionTask.getAntoraVersion().get()).isEqualTo("1.0.0");
|
||||
assertThat(checkAntoraVersionTask.getAntoraPrerelease().get()).isEqualTo("-SNAPSHOT");
|
||||
assertThat(checkAntoraVersionTask.getAntoraDisplayVersion().isPresent()).isFalse();
|
||||
assertThat(checkAntoraVersionTask.getAntoraYmlFile().getAsFile().get()).isEqualTo(project.file("antora.yml"));
|
||||
}
|
||||
|
||||
@@ -40,16 +39,15 @@ class AntoraVersionPluginTests {
|
||||
String expectedVersion = "1.0.0-M1";
|
||||
Project project = ProjectBuilder.builder().build();
|
||||
project.setVersion(expectedVersion);
|
||||
project.getPluginManager().apply(AntoraVersionPlugin.class);
|
||||
project.getPluginManager().apply(CheckAntoraVersionPlugin.class);
|
||||
|
||||
Task task = project.getTasks().findByName(AntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
Task task = project.getTasks().findByName(CheckAntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
|
||||
assertThat(task).isInstanceOf(CheckAntoraVersionTask.class);
|
||||
|
||||
CheckAntoraVersionTask checkAntoraVersionTask = (CheckAntoraVersionTask) task;
|
||||
assertThat(checkAntoraVersionTask.getAntoraVersion().get()).isEqualTo("1.0.0-M1");
|
||||
assertThat(checkAntoraVersionTask.getAntoraPrerelease().get()).isEqualTo("true");
|
||||
assertThat(checkAntoraVersionTask.getAntoraDisplayVersion().get()).isEqualTo(checkAntoraVersionTask.getAntoraVersion().get());
|
||||
assertThat(checkAntoraVersionTask.getAntoraYmlFile().getAsFile().get()).isEqualTo(project.file("antora.yml"));
|
||||
}
|
||||
|
||||
@@ -58,16 +56,15 @@ class AntoraVersionPluginTests {
|
||||
String expectedVersion = "1.0.0-RC1";
|
||||
Project project = ProjectBuilder.builder().build();
|
||||
project.setVersion(expectedVersion);
|
||||
project.getPluginManager().apply(AntoraVersionPlugin.class);
|
||||
project.getPluginManager().apply(CheckAntoraVersionPlugin.class);
|
||||
|
||||
Task task = project.getTasks().findByName(AntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
Task task = project.getTasks().findByName(CheckAntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
|
||||
assertThat(task).isInstanceOf(CheckAntoraVersionTask.class);
|
||||
|
||||
CheckAntoraVersionTask checkAntoraVersionTask = (CheckAntoraVersionTask) task;
|
||||
assertThat(checkAntoraVersionTask.getAntoraVersion().get()).isEqualTo("1.0.0-RC1");
|
||||
assertThat(checkAntoraVersionTask.getAntoraPrerelease().get()).isEqualTo("true");
|
||||
assertThat(checkAntoraVersionTask.getAntoraDisplayVersion().get()).isEqualTo(checkAntoraVersionTask.getAntoraVersion().get());
|
||||
assertThat(checkAntoraVersionTask.getAntoraYmlFile().getAsFile().get()).isEqualTo(project.file("antora.yml"));
|
||||
}
|
||||
|
||||
@@ -76,32 +73,30 @@ class AntoraVersionPluginTests {
|
||||
String expectedVersion = "1.0.0";
|
||||
Project project = ProjectBuilder.builder().build();
|
||||
project.setVersion(expectedVersion);
|
||||
project.getPluginManager().apply(AntoraVersionPlugin.class);
|
||||
project.getPluginManager().apply(CheckAntoraVersionPlugin.class);
|
||||
|
||||
Task task = project.getTasks().findByName(AntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
Task task = project.getTasks().findByName(CheckAntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
|
||||
assertThat(task).isInstanceOf(CheckAntoraVersionTask.class);
|
||||
|
||||
CheckAntoraVersionTask checkAntoraVersionTask = (CheckAntoraVersionTask) task;
|
||||
assertThat(checkAntoraVersionTask.getAntoraVersion().get()).isEqualTo("1.0.0");
|
||||
assertThat(checkAntoraVersionTask.getAntoraPrerelease().isPresent()).isFalse();
|
||||
assertThat(checkAntoraVersionTask.getAntoraDisplayVersion().isPresent()).isFalse();
|
||||
assertThat(checkAntoraVersionTask.getAntoraYmlFile().getAsFile().get()).isEqualTo(project.file("antora.yml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void explicitProperties() {
|
||||
Project project = ProjectBuilder.builder().build();
|
||||
project.getPluginManager().apply(AntoraVersionPlugin.class);
|
||||
project.getPluginManager().apply(CheckAntoraVersionPlugin.class);
|
||||
|
||||
Task task = project.getTasks().findByName(AntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
Task task = project.getTasks().findByName(CheckAntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
|
||||
CheckAntoraVersionTask checkAntoraVersionTask = (CheckAntoraVersionTask) task;
|
||||
checkAntoraVersionTask.getAntoraVersion().set("1.0.0");
|
||||
checkAntoraVersionTask.getAntoraPrerelease().set("-SNAPSHOT");
|
||||
assertThat(checkAntoraVersionTask.getAntoraVersion().get()).isEqualTo("1.0.0");
|
||||
assertThat(checkAntoraVersionTask.getAntoraPrerelease().get()).isEqualTo("-SNAPSHOT");
|
||||
assertThat(checkAntoraVersionTask.getAntoraDisplayVersion().isPresent()).isFalse();
|
||||
assertThat(checkAntoraVersionTask.getAntoraYmlFile().getAsFile().get()).isEqualTo(project.file("antora.yml"));
|
||||
}
|
||||
|
||||
@@ -110,9 +105,9 @@ class AntoraVersionPluginTests {
|
||||
Project project = ProjectBuilder.builder().build();
|
||||
File rootDir = project.getRootDir();
|
||||
IOUtils.write("version: '1.0.0'", new FileOutputStream(new File(rootDir, "antora.yml")), StandardCharsets.UTF_8);
|
||||
project.getPluginManager().apply(AntoraVersionPlugin.class);
|
||||
project.getPluginManager().apply(CheckAntoraVersionPlugin.class);
|
||||
|
||||
Task task = project.getTasks().findByName(AntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
Task task = project.getTasks().findByName(CheckAntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
|
||||
assertThat(task).isInstanceOf(CheckAntoraVersionTask.class);
|
||||
|
||||
@@ -125,9 +120,9 @@ class AntoraVersionPluginTests {
|
||||
String expectedVersion = "1.0.0-SNAPSHOT";
|
||||
Project project = ProjectBuilder.builder().build();
|
||||
project.setVersion(expectedVersion);
|
||||
project.getPluginManager().apply(AntoraVersionPlugin.class);
|
||||
project.getPluginManager().apply(CheckAntoraVersionPlugin.class);
|
||||
|
||||
Task task = project.getTasks().findByName(AntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
Task task = project.getTasks().findByName(CheckAntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
|
||||
assertThat(task).isInstanceOf(CheckAntoraVersionTask.class);
|
||||
|
||||
@@ -142,9 +137,9 @@ class AntoraVersionPluginTests {
|
||||
File rootDir = project.getRootDir();
|
||||
IOUtils.write("version: '1.0.0'", new FileOutputStream(new File(rootDir, "antora.yml")), StandardCharsets.UTF_8);
|
||||
project.setVersion(expectedVersion);
|
||||
project.getPluginManager().apply(AntoraVersionPlugin.class);
|
||||
project.getPluginManager().apply(CheckAntoraVersionPlugin.class);
|
||||
|
||||
Task task = project.getTasks().findByName(AntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
Task task = project.getTasks().findByName(CheckAntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
|
||||
assertThat(task).isInstanceOf(CheckAntoraVersionTask.class);
|
||||
|
||||
@@ -160,9 +155,9 @@ class AntoraVersionPluginTests {
|
||||
File rootDir = project.getRootDir();
|
||||
IOUtils.write("version: '1.0.0'\nprerelease: '-SNAPSHOT'", new FileOutputStream(new File(rootDir, "antora.yml")), StandardCharsets.UTF_8);
|
||||
project.setVersion(expectedVersion);
|
||||
project.getPluginManager().apply(AntoraVersionPlugin.class);
|
||||
project.getPluginManager().apply(CheckAntoraVersionPlugin.class);
|
||||
|
||||
Task task = project.getTasks().findByName(AntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
Task task = project.getTasks().findByName(CheckAntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
|
||||
assertThat(task).isInstanceOf(CheckAntoraVersionTask.class);
|
||||
|
||||
@@ -175,11 +170,11 @@ class AntoraVersionPluginTests {
|
||||
String expectedVersion = "1.0.0-M1";
|
||||
Project project = ProjectBuilder.builder().build();
|
||||
File rootDir = project.getRootDir();
|
||||
IOUtils.write("version: '1.0.0-M1'\nprerelease: 'true'\ndisplay_version: '1.0.0-M1'", new FileOutputStream(new File(rootDir, "antora.yml")), StandardCharsets.UTF_8);
|
||||
IOUtils.write("version: '1.0.0-M1'\nprerelease: 'true'", new FileOutputStream(new File(rootDir, "antora.yml")), StandardCharsets.UTF_8);
|
||||
project.setVersion(expectedVersion);
|
||||
project.getPluginManager().apply(AntoraVersionPlugin.class);
|
||||
project.getPluginManager().apply(CheckAntoraVersionPlugin.class);
|
||||
|
||||
Task task = project.getTasks().findByName(AntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
Task task = project.getTasks().findByName(CheckAntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
|
||||
assertThat(task).isInstanceOf(CheckAntoraVersionTask.class);
|
||||
|
||||
@@ -192,11 +187,11 @@ class AntoraVersionPluginTests {
|
||||
String expectedVersion = "1.0.0-RC1";
|
||||
Project project = ProjectBuilder.builder().build();
|
||||
File rootDir = project.getRootDir();
|
||||
IOUtils.write("version: '1.0.0-RC1'\nprerelease: 'true'\ndisplay_version: '1.0.0-RC1'", new FileOutputStream(new File(rootDir, "antora.yml")), StandardCharsets.UTF_8);
|
||||
IOUtils.write("version: '1.0.0-RC1'\nprerelease: 'true'", new FileOutputStream(new File(rootDir, "antora.yml")), StandardCharsets.UTF_8);
|
||||
project.setVersion(expectedVersion);
|
||||
project.getPluginManager().apply(AntoraVersionPlugin.class);
|
||||
project.getPluginManager().apply(CheckAntoraVersionPlugin.class);
|
||||
|
||||
Task task = project.getTasks().findByName(AntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
Task task = project.getTasks().findByName(CheckAntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
|
||||
assertThat(task).isInstanceOf(CheckAntoraVersionTask.class);
|
||||
|
||||
@@ -211,9 +206,9 @@ class AntoraVersionPluginTests {
|
||||
File rootDir = project.getRootDir();
|
||||
IOUtils.write("version: '1.0.0'", new FileOutputStream(new File(rootDir, "antora.yml")), StandardCharsets.UTF_8);
|
||||
project.setVersion(expectedVersion);
|
||||
project.getPluginManager().apply(AntoraVersionPlugin.class);
|
||||
project.getPluginManager().apply(CheckAntoraVersionPlugin.class);
|
||||
|
||||
Task task = project.getTasks().findByName(AntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
Task task = project.getTasks().findByName(CheckAntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
|
||||
assertThat(task).isInstanceOf(CheckAntoraVersionTask.class);
|
||||
|
||||
@@ -226,9 +221,9 @@ class AntoraVersionPluginTests {
|
||||
Project project = ProjectBuilder.builder().build();
|
||||
File rootDir = project.getRootDir();
|
||||
IOUtils.write("version: '1.0.0'", new FileOutputStream(new File(rootDir, "antora.yml")), StandardCharsets.UTF_8);
|
||||
project.getPluginManager().apply(AntoraVersionPlugin.class);
|
||||
project.getPluginManager().apply(CheckAntoraVersionPlugin.class);
|
||||
|
||||
Task task = project.getTasks().findByName(AntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
Task task = project.getTasks().findByName(CheckAntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
|
||||
assertThat(task).isInstanceOf(CheckAntoraVersionTask.class);
|
||||
CheckAntoraVersionTask checkAntoraVersionTask = (CheckAntoraVersionTask) task;
|
||||
@@ -241,9 +236,9 @@ class AntoraVersionPluginTests {
|
||||
Project project = ProjectBuilder.builder().build();
|
||||
File rootDir = project.getRootDir();
|
||||
IOUtils.write("version: '1.0.0'\nprerelease: '-SNAPSHOT'", new FileOutputStream(new File(rootDir, "antora.yml")), StandardCharsets.UTF_8);
|
||||
project.getPluginManager().apply(AntoraVersionPlugin.class);
|
||||
project.getPluginManager().apply(CheckAntoraVersionPlugin.class);
|
||||
|
||||
Task task = project.getTasks().findByName(AntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
Task task = project.getTasks().findByName(CheckAntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
|
||||
assertThat(task).isInstanceOf(CheckAntoraVersionTask.class);
|
||||
CheckAntoraVersionTask checkAntoraVersionTask = (CheckAntoraVersionTask) task;
|
||||
@@ -257,9 +252,9 @@ class AntoraVersionPluginTests {
|
||||
Project project = ProjectBuilder.builder().build();
|
||||
File rootDir = project.getRootDir();
|
||||
IOUtils.write("name: 'ROOT'\nversion: '1.0.0'", new FileOutputStream(new File(rootDir, "antora.yml")), StandardCharsets.UTF_8);
|
||||
project.getPluginManager().apply(AntoraVersionPlugin.class);
|
||||
project.getPluginManager().apply(CheckAntoraVersionPlugin.class);
|
||||
|
||||
Task task = project.getTasks().findByName(AntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
Task task = project.getTasks().findByName(CheckAntoraVersionPlugin.ANTORA_CHECK_VERSION_TASK_NAME);
|
||||
|
||||
assertThat(task).isInstanceOf(CheckAntoraVersionTask.class);
|
||||
CheckAntoraVersionTask checkAntoraVersionTask = (CheckAntoraVersionTask) task;
|
||||
-837
@@ -1,10 +1,5 @@
|
||||
package org.springframework.gradle.github.milestones;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import okhttp3.mockwebserver.MockResponse;
|
||||
@@ -390,836 +385,4 @@ public class GitHubMilestoneApiTests {
|
||||
assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/issues?per_page=1&milestone=" + milestoneNumber);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isMilestoneDueTodayWhenNotFoundThenException() throws Exception {
|
||||
String responseJson = "[\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" +
|
||||
" \"id\":6611880,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" +
|
||||
" \"number\":207,\n" +
|
||||
" \"title\":\"5.6.x\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jgrandja\",\n" +
|
||||
" \"id\":10884212,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jgrandja\",\n" +
|
||||
" \"html_url\":\"https://github.com/jgrandja\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":1,\n" +
|
||||
" \"closed_issues\":0,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2021-03-31T11:29:17Z\",\n" +
|
||||
" \"updated_at\":\"2021-03-31T11:30:47Z\",\n" +
|
||||
" \"due_on\":null,\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" +
|
||||
" \"id\":5884208,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" +
|
||||
" \"number\":191,\n" +
|
||||
" \"title\":\"5.5.0-RC1\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jzheaux\",\n" +
|
||||
" \"id\":3627351,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jzheaux\",\n" +
|
||||
" \"html_url\":\"https://github.com/jzheaux\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":21,\n" +
|
||||
" \"closed_issues\":23,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2020-09-16T13:28:03Z\",\n" +
|
||||
" \"updated_at\":\"2021-04-06T23:47:10Z\",\n" +
|
||||
" \"due_on\":\"2021-04-12T07:00:00Z\",\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
this.server.enqueue(new MockResponse().setBody(responseJson));
|
||||
|
||||
assertThatExceptionOfType(RuntimeException.class)
|
||||
.isThrownBy(() -> this.github.isMilestoneDueToday(this.repositoryRef, "missing"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isMilestoneDueTodayWhenPastDueThenTrue() throws Exception {
|
||||
String responseJson = "[\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" +
|
||||
" \"id\":6611880,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" +
|
||||
" \"number\":207,\n" +
|
||||
" \"title\":\"5.6.x\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jgrandja\",\n" +
|
||||
" \"id\":10884212,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jgrandja\",\n" +
|
||||
" \"html_url\":\"https://github.com/jgrandja\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":1,\n" +
|
||||
" \"closed_issues\":0,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2021-03-31T11:29:17Z\",\n" +
|
||||
" \"updated_at\":\"2021-03-31T11:30:47Z\",\n" +
|
||||
" \"due_on\":null,\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" +
|
||||
" \"id\":5884208,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" +
|
||||
" \"number\":191,\n" +
|
||||
" \"title\":\"5.5.0-RC1\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jzheaux\",\n" +
|
||||
" \"id\":3627351,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jzheaux\",\n" +
|
||||
" \"html_url\":\"https://github.com/jzheaux\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":21,\n" +
|
||||
" \"closed_issues\":23,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2020-09-16T13:28:03Z\",\n" +
|
||||
" \"updated_at\":\"2021-04-06T23:47:10Z\",\n" +
|
||||
" \"due_on\":\"2021-04-12T07:00:00Z\",\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
this.server.enqueue(new MockResponse().setBody(responseJson));
|
||||
|
||||
boolean dueToday = this.github.isMilestoneDueToday(this.repositoryRef, "5.5.0-RC1");
|
||||
|
||||
RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS);
|
||||
assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get");
|
||||
assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones?per_page=100");
|
||||
|
||||
assertThat(dueToday).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isMilestoneDueTodayWhenDueTodayThenTrue() throws Exception {
|
||||
String responseJson = "[\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" +
|
||||
" \"id\":6611880,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" +
|
||||
" \"number\":207,\n" +
|
||||
" \"title\":\"5.6.x\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jgrandja\",\n" +
|
||||
" \"id\":10884212,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jgrandja\",\n" +
|
||||
" \"html_url\":\"https://github.com/jgrandja\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":1,\n" +
|
||||
" \"closed_issues\":0,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2021-03-31T11:29:17Z\",\n" +
|
||||
" \"updated_at\":\"2021-03-31T11:30:47Z\",\n" +
|
||||
" \"due_on\":null,\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" +
|
||||
" \"id\":5884208,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" +
|
||||
" \"number\":191,\n" +
|
||||
" \"title\":\"5.5.0-RC1\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jzheaux\",\n" +
|
||||
" \"id\":3627351,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jzheaux\",\n" +
|
||||
" \"html_url\":\"https://github.com/jzheaux\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":21,\n" +
|
||||
" \"closed_issues\":23,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2020-09-16T13:28:03Z\",\n" +
|
||||
" \"updated_at\":\"2021-04-06T23:47:10Z\",\n" +
|
||||
" \"due_on\":\"" + LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant().toString() + "\",\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
this.server.enqueue(new MockResponse().setBody(responseJson));
|
||||
|
||||
boolean dueToday = this.github.isMilestoneDueToday(this.repositoryRef, "5.5.0-RC1");
|
||||
|
||||
RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS);
|
||||
assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get");
|
||||
assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones?per_page=100");
|
||||
|
||||
assertThat(dueToday).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isMilestoneDueTodayWhenNoDueDateThenFalse() throws Exception {
|
||||
String responseJson = "[\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" +
|
||||
" \"id\":6611880,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" +
|
||||
" \"number\":207,\n" +
|
||||
" \"title\":\"5.6.x\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jgrandja\",\n" +
|
||||
" \"id\":10884212,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jgrandja\",\n" +
|
||||
" \"html_url\":\"https://github.com/jgrandja\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":1,\n" +
|
||||
" \"closed_issues\":0,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2021-03-31T11:29:17Z\",\n" +
|
||||
" \"updated_at\":\"2021-03-31T11:30:47Z\",\n" +
|
||||
" \"due_on\":null,\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" +
|
||||
" \"id\":5884208,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" +
|
||||
" \"number\":191,\n" +
|
||||
" \"title\":\"5.5.0-RC1\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jzheaux\",\n" +
|
||||
" \"id\":3627351,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jzheaux\",\n" +
|
||||
" \"html_url\":\"https://github.com/jzheaux\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":21,\n" +
|
||||
" \"closed_issues\":23,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2020-09-16T13:28:03Z\",\n" +
|
||||
" \"updated_at\":\"2021-04-06T23:47:10Z\",\n" +
|
||||
" \"due_on\":null,\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
this.server.enqueue(new MockResponse().setBody(responseJson));
|
||||
|
||||
boolean dueToday = this.github.isMilestoneDueToday(this.repositoryRef, "5.5.0-RC1");
|
||||
|
||||
RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS);
|
||||
assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get");
|
||||
assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones?per_page=100");
|
||||
|
||||
assertThat(dueToday).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isMilestoneDueTodayWhenDueDateInFutureThenFalse() throws Exception {
|
||||
String responseJson = "[\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" +
|
||||
" \"id\":6611880,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" +
|
||||
" \"number\":207,\n" +
|
||||
" \"title\":\"5.6.x\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jgrandja\",\n" +
|
||||
" \"id\":10884212,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jgrandja\",\n" +
|
||||
" \"html_url\":\"https://github.com/jgrandja\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":1,\n" +
|
||||
" \"closed_issues\":0,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2021-03-31T11:29:17Z\",\n" +
|
||||
" \"updated_at\":\"2021-03-31T11:30:47Z\",\n" +
|
||||
" \"due_on\":null,\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" +
|
||||
" \"id\":5884208,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" +
|
||||
" \"number\":191,\n" +
|
||||
" \"title\":\"5.5.0-RC1\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jzheaux\",\n" +
|
||||
" \"id\":3627351,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jzheaux\",\n" +
|
||||
" \"html_url\":\"https://github.com/jzheaux\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":21,\n" +
|
||||
" \"closed_issues\":23,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2020-09-16T13:28:03Z\",\n" +
|
||||
" \"updated_at\":\"2021-04-06T23:47:10Z\",\n" +
|
||||
" \"due_on\":\"3000-04-12T07:00:00Z\",\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
this.server.enqueue(new MockResponse().setBody(responseJson));
|
||||
|
||||
boolean dueToday = this.github.isMilestoneDueToday(this.repositoryRef, "5.5.0-RC1");
|
||||
|
||||
RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS);
|
||||
assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get");
|
||||
assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones?per_page=100");
|
||||
|
||||
assertThat(dueToday).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void calculateNextReleaseMilestoneWhenCurrentVersionIsNotSnapshotThenException() {
|
||||
assertThatExceptionOfType(RuntimeException.class)
|
||||
.isThrownBy(() -> this.github.getNextReleaseMilestone(this.repositoryRef, "5.5.0-RC1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void calculateNextReleaseMilestoneWhenPatchSegmentGreaterThan0ThenReturnsVersionWithoutSnapshot() {
|
||||
String nextVersion = this.github.getNextReleaseMilestone(this.repositoryRef, "5.5.1-SNAPSHOT");
|
||||
|
||||
assertThat(nextVersion).isEqualTo("5.5.1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void calculateNextReleaseMilestoneWhenMilestoneAndRcExistThenReturnsMilestone() throws Exception {
|
||||
String responseJson = "[\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" +
|
||||
" \"id\":6611880,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" +
|
||||
" \"number\":207,\n" +
|
||||
" \"title\":\"5.5.0-M1\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jgrandja\",\n" +
|
||||
" \"id\":10884212,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jgrandja\",\n" +
|
||||
" \"html_url\":\"https://github.com/jgrandja\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":1,\n" +
|
||||
" \"closed_issues\":0,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2021-03-31T11:29:17Z\",\n" +
|
||||
" \"updated_at\":\"2021-03-31T11:30:47Z\",\n" +
|
||||
" \"due_on\":null,\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" +
|
||||
" \"id\":5884208,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" +
|
||||
" \"number\":191,\n" +
|
||||
" \"title\":\"5.5.0-RC1\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jzheaux\",\n" +
|
||||
" \"id\":3627351,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jzheaux\",\n" +
|
||||
" \"html_url\":\"https://github.com/jzheaux\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":21,\n" +
|
||||
" \"closed_issues\":23,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2020-09-16T13:28:03Z\",\n" +
|
||||
" \"updated_at\":\"2021-04-06T23:47:10Z\",\n" +
|
||||
" \"due_on\":\"3000-04-12T07:00:00Z\",\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
this.server.enqueue(new MockResponse().setBody(responseJson));
|
||||
|
||||
String nextVersion = this.github.getNextReleaseMilestone(this.repositoryRef, "5.5.0-SNAPSHOT");
|
||||
|
||||
RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS);
|
||||
assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get");
|
||||
assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones?per_page=100");
|
||||
|
||||
assertThat(nextVersion).isEqualTo("5.5.0-M1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void calculateNextReleaseMilestoneWhenTwoMilestonesExistThenReturnsSmallerMilestone() throws Exception {
|
||||
String responseJson = "[\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" +
|
||||
" \"id\":6611880,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" +
|
||||
" \"number\":207,\n" +
|
||||
" \"title\":\"5.5.0-M9\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jgrandja\",\n" +
|
||||
" \"id\":10884212,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jgrandja\",\n" +
|
||||
" \"html_url\":\"https://github.com/jgrandja\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":1,\n" +
|
||||
" \"closed_issues\":0,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2021-03-31T11:29:17Z\",\n" +
|
||||
" \"updated_at\":\"2021-03-31T11:30:47Z\",\n" +
|
||||
" \"due_on\":null,\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" +
|
||||
" \"id\":5884208,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" +
|
||||
" \"number\":191,\n" +
|
||||
" \"title\":\"5.5.0-M10\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jzheaux\",\n" +
|
||||
" \"id\":3627351,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jzheaux\",\n" +
|
||||
" \"html_url\":\"https://github.com/jzheaux\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":21,\n" +
|
||||
" \"closed_issues\":23,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2020-09-16T13:28:03Z\",\n" +
|
||||
" \"updated_at\":\"2021-04-06T23:47:10Z\",\n" +
|
||||
" \"due_on\":\"3000-04-12T07:00:00Z\",\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
this.server.enqueue(new MockResponse().setBody(responseJson));
|
||||
|
||||
String nextVersion = this.github.getNextReleaseMilestone(this.repositoryRef, "5.5.0-SNAPSHOT");
|
||||
|
||||
RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS);
|
||||
assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get");
|
||||
assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones?per_page=100");
|
||||
|
||||
assertThat(nextVersion).isEqualTo("5.5.0-M9");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void calculateNextReleaseMilestoneWhenTwoRcsExistThenReturnsSmallerRc() throws Exception {
|
||||
String responseJson = "[\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" +
|
||||
" \"id\":6611880,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" +
|
||||
" \"number\":207,\n" +
|
||||
" \"title\":\"5.5.0-RC9\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jgrandja\",\n" +
|
||||
" \"id\":10884212,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jgrandja\",\n" +
|
||||
" \"html_url\":\"https://github.com/jgrandja\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":1,\n" +
|
||||
" \"closed_issues\":0,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2021-03-31T11:29:17Z\",\n" +
|
||||
" \"updated_at\":\"2021-03-31T11:30:47Z\",\n" +
|
||||
" \"due_on\":null,\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" +
|
||||
" \"id\":5884208,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" +
|
||||
" \"number\":191,\n" +
|
||||
" \"title\":\"5.5.0-RC10\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jzheaux\",\n" +
|
||||
" \"id\":3627351,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jzheaux\",\n" +
|
||||
" \"html_url\":\"https://github.com/jzheaux\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":21,\n" +
|
||||
" \"closed_issues\":23,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2020-09-16T13:28:03Z\",\n" +
|
||||
" \"updated_at\":\"2021-04-06T23:47:10Z\",\n" +
|
||||
" \"due_on\":\"3000-04-12T07:00:00Z\",\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
this.server.enqueue(new MockResponse().setBody(responseJson));
|
||||
|
||||
String nextVersion = this.github.getNextReleaseMilestone(this.repositoryRef, "5.5.0-SNAPSHOT");
|
||||
|
||||
RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS);
|
||||
assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get");
|
||||
assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones?per_page=100");
|
||||
|
||||
assertThat(nextVersion).isEqualTo("5.5.0-RC9");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void calculateNextReleaseMilestoneWhenNoPreReleaseThenReturnsVersionWithoutSnapshot() throws Exception {
|
||||
String responseJson = "[\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" +
|
||||
" \"id\":6611880,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" +
|
||||
" \"number\":207,\n" +
|
||||
" \"title\":\"5.6.x\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jgrandja\",\n" +
|
||||
" \"id\":10884212,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jgrandja\",\n" +
|
||||
" \"html_url\":\"https://github.com/jgrandja\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":1,\n" +
|
||||
" \"closed_issues\":0,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2021-03-31T11:29:17Z\",\n" +
|
||||
" \"updated_at\":\"2021-03-31T11:30:47Z\",\n" +
|
||||
" \"due_on\":null,\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" +
|
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" +
|
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" +
|
||||
" \"id\":5884208,\n" +
|
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" +
|
||||
" \"number\":191,\n" +
|
||||
" \"title\":\"5.4.3\",\n" +
|
||||
" \"description\":\"\",\n" +
|
||||
" \"creator\":{\n" +
|
||||
" \"login\":\"jzheaux\",\n" +
|
||||
" \"id\":3627351,\n" +
|
||||
" \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" +
|
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" +
|
||||
" \"gravatar_id\":\"\",\n" +
|
||||
" \"url\":\"https://api.github.com/users/jzheaux\",\n" +
|
||||
" \"html_url\":\"https://github.com/jzheaux\",\n" +
|
||||
" \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" +
|
||||
" \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" +
|
||||
" \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" +
|
||||
" \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" +
|
||||
" \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" +
|
||||
" \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" +
|
||||
" \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" +
|
||||
" \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" +
|
||||
" \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" +
|
||||
" \"type\":\"User\",\n" +
|
||||
" \"site_admin\":false\n" +
|
||||
" },\n" +
|
||||
" \"open_issues\":21,\n" +
|
||||
" \"closed_issues\":23,\n" +
|
||||
" \"state\":\"open\",\n" +
|
||||
" \"created_at\":\"2020-09-16T13:28:03Z\",\n" +
|
||||
" \"updated_at\":\"2021-04-06T23:47:10Z\",\n" +
|
||||
" \"due_on\":\"2021-04-12T07:00:00Z\",\n" +
|
||||
" \"closed_at\":null\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
this.server.enqueue(new MockResponse().setBody(responseJson));
|
||||
|
||||
String nextVersion = this.github.getNextReleaseMilestone(this.repositoryRef, "5.5.0-SNAPSHOT");
|
||||
|
||||
RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS);
|
||||
assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get");
|
||||
assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones?per_page=100");
|
||||
|
||||
assertThat(nextVersion).isEqualTo("5.5.0");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createMilestoneWhenValidParametersThenSuccess() throws Exception {
|
||||
this.server.enqueue(new MockResponse().setResponseCode(204));
|
||||
Milestone milestone = new Milestone();
|
||||
milestone.setTitle("1.0.0");
|
||||
milestone.setDueOn(LocalDate.of(2022, 5, 4).atTime(LocalTime.NOON));
|
||||
this.github.createMilestone(this.repositoryRef, milestone);
|
||||
|
||||
RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS);
|
||||
assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("post");
|
||||
assertThat(recordedRequest.getRequestUrl().toString())
|
||||
.isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones");
|
||||
assertThat(recordedRequest.getBody().readString(Charset.defaultCharset()))
|
||||
.isEqualTo("{\"title\":\"1.0.0\",\"due_on\":\"2022-05-04T12:00:00Z\"}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createMilestoneWhenErrorResponseThenException() throws Exception {
|
||||
this.server.enqueue(new MockResponse().setResponseCode(400));
|
||||
assertThatExceptionOfType(RuntimeException.class)
|
||||
.isThrownBy(() -> this.github.createMilestone(this.repositoryRef, new Milestone()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-245
@@ -1,245 +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.Year;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
|
||||
import org.springframework.gradle.github.milestones.SpringReleaseTrainSpec.Train;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
public class SpringReleaseTrainTests {
|
||||
@ParameterizedTest
|
||||
@CsvSource({
|
||||
"2019-12-31, ONE, 2020",
|
||||
"2020-01-01, ONE, 2020",
|
||||
"2020-01-31, ONE, 2020",
|
||||
"2020-02-01, TWO, 2020",
|
||||
"2020-07-31, TWO, 2020",
|
||||
"2020-08-01, ONE, 2021"
|
||||
})
|
||||
public void nextTrainWhenBoundaryConditionsThenSuccess(LocalDate startDate, Train expectedTrain, Year expectedYear) {
|
||||
SpringReleaseTrainSpec releaseTrainSpec =
|
||||
SpringReleaseTrainSpec.builder()
|
||||
.nextTrain(startDate)
|
||||
.version("1.0.0")
|
||||
.weekOfMonth(2)
|
||||
.dayOfWeek(2)
|
||||
.build();
|
||||
assertThat(releaseTrainSpec.getTrain()).isEqualTo(expectedTrain);
|
||||
assertThat(releaseTrainSpec.getYear()).isEqualTo(expectedYear);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTrainDatesWhenTrainOneIsSecondTuesdayOf2020ThenSuccess() {
|
||||
SpringReleaseTrainSpec releaseTrainSpec =
|
||||
SpringReleaseTrainSpec.builder()
|
||||
.train(1)
|
||||
.version("1.0.0")
|
||||
.weekOfMonth(2)
|
||||
.dayOfWeek(2)
|
||||
.year(2020)
|
||||
.build();
|
||||
|
||||
SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec);
|
||||
Map<String, LocalDate> trainDates = releaseTrain.getTrainDates();
|
||||
assertThat(trainDates).hasSize(5);
|
||||
assertThat(trainDates.get("1.0.0-M1")).isEqualTo(LocalDate.of(2020, 1, 14));
|
||||
assertThat(trainDates.get("1.0.0-M2")).isEqualTo(LocalDate.of(2020, 2, 11));
|
||||
assertThat(trainDates.get("1.0.0-M3")).isEqualTo(LocalDate.of(2020, 3, 10));
|
||||
assertThat(trainDates.get("1.0.0-RC1")).isEqualTo(LocalDate.of(2020, 4, 14));
|
||||
assertThat(trainDates.get("1.0.0")).isEqualTo(LocalDate.of(2020, 5, 12));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTrainDatesWhenTrainTwoIsSecondTuesdayOf2020ThenSuccess() {
|
||||
SpringReleaseTrainSpec releaseTrainSpec =
|
||||
SpringReleaseTrainSpec.builder()
|
||||
.train(2)
|
||||
.version("1.0.0")
|
||||
.weekOfMonth(2)
|
||||
.dayOfWeek(2)
|
||||
.year(2020)
|
||||
.build();
|
||||
|
||||
SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec);
|
||||
Map<String, LocalDate> trainDates = releaseTrain.getTrainDates();
|
||||
assertThat(trainDates).hasSize(5);
|
||||
assertThat(trainDates.get("1.0.0-M1")).isEqualTo(LocalDate.of(2020, 7, 14));
|
||||
assertThat(trainDates.get("1.0.0-M2")).isEqualTo(LocalDate.of(2020, 8, 11));
|
||||
assertThat(trainDates.get("1.0.0-M3")).isEqualTo(LocalDate.of(2020, 9, 15));
|
||||
assertThat(trainDates.get("1.0.0-RC1")).isEqualTo(LocalDate.of(2020, 10, 13));
|
||||
assertThat(trainDates.get("1.0.0")).isEqualTo(LocalDate.of(2020, 11, 10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTrainDatesWhenTrainOneIsSecondTuesdayOf2022ThenSuccess() {
|
||||
SpringReleaseTrainSpec releaseTrainSpec =
|
||||
SpringReleaseTrainSpec.builder()
|
||||
.train(1)
|
||||
.version("1.0.0")
|
||||
.weekOfMonth(2)
|
||||
.dayOfWeek(2)
|
||||
.year(2022)
|
||||
.build();
|
||||
|
||||
SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec);
|
||||
Map<String, LocalDate> trainDates = releaseTrain.getTrainDates();
|
||||
assertThat(trainDates).hasSize(5);
|
||||
assertThat(trainDates.get("1.0.0-M1")).isEqualTo(LocalDate.of(2022, 1, 11));
|
||||
assertThat(trainDates.get("1.0.0-M2")).isEqualTo(LocalDate.of(2022, 2, 15));
|
||||
assertThat(trainDates.get("1.0.0-M3")).isEqualTo(LocalDate.of(2022, 3, 15));
|
||||
assertThat(trainDates.get("1.0.0-RC1")).isEqualTo(LocalDate.of(2022, 4, 12));
|
||||
assertThat(trainDates.get("1.0.0")).isEqualTo(LocalDate.of(2022, 5, 10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTrainDatesWhenTrainTwoIsSecondTuesdayOf2022ThenSuccess() {
|
||||
SpringReleaseTrainSpec releaseTrainSpec =
|
||||
SpringReleaseTrainSpec.builder()
|
||||
.train(2)
|
||||
.version("1.0.0")
|
||||
.weekOfMonth(2)
|
||||
.dayOfWeek(2)
|
||||
.year(2022)
|
||||
.build();
|
||||
|
||||
SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec);
|
||||
Map<String, LocalDate> trainDates = releaseTrain.getTrainDates();
|
||||
assertThat(trainDates).hasSize(5);
|
||||
assertThat(trainDates.get("1.0.0-M1")).isEqualTo(LocalDate.of(2022, 7, 12));
|
||||
assertThat(trainDates.get("1.0.0-M2")).isEqualTo(LocalDate.of(2022, 8, 9));
|
||||
assertThat(trainDates.get("1.0.0-M3")).isEqualTo(LocalDate.of(2022, 9, 13));
|
||||
assertThat(trainDates.get("1.0.0-RC1")).isEqualTo(LocalDate.of(2022, 10, 11));
|
||||
assertThat(trainDates.get("1.0.0")).isEqualTo(LocalDate.of(2022, 11, 15));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTrainDatesWhenTrainOneIsThirdMondayOf2022ThenSuccess() {
|
||||
SpringReleaseTrainSpec releaseTrainSpec =
|
||||
SpringReleaseTrainSpec.builder()
|
||||
.train(1)
|
||||
.version("1.0.0")
|
||||
.weekOfMonth(3)
|
||||
.dayOfWeek(1)
|
||||
.year(2022)
|
||||
.build();
|
||||
|
||||
SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec);
|
||||
Map<String, LocalDate> trainDates = releaseTrain.getTrainDates();
|
||||
assertThat(trainDates).hasSize(5);
|
||||
assertThat(trainDates.get("1.0.0-M1")).isEqualTo(LocalDate.of(2022, 1, 17));
|
||||
assertThat(trainDates.get("1.0.0-M2")).isEqualTo(LocalDate.of(2022, 2, 21));
|
||||
assertThat(trainDates.get("1.0.0-M3")).isEqualTo(LocalDate.of(2022, 3, 21));
|
||||
assertThat(trainDates.get("1.0.0-RC1")).isEqualTo(LocalDate.of(2022, 4, 18));
|
||||
assertThat(trainDates.get("1.0.0")).isEqualTo(LocalDate.of(2022, 5, 16));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTrainDatesWhenTrainTwoIsThirdMondayOf2022ThenSuccess() {
|
||||
SpringReleaseTrainSpec releaseTrainSpec =
|
||||
SpringReleaseTrainSpec.builder()
|
||||
.train(2)
|
||||
.version("1.0.0")
|
||||
.weekOfMonth(3)
|
||||
.dayOfWeek(1)
|
||||
.year(2022)
|
||||
.build();
|
||||
|
||||
SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec);
|
||||
Map<String, LocalDate> trainDates = releaseTrain.getTrainDates();
|
||||
assertThat(trainDates).hasSize(5);
|
||||
assertThat(trainDates.get("1.0.0-M1")).isEqualTo(LocalDate.of(2022, 7, 18));
|
||||
assertThat(trainDates.get("1.0.0-M2")).isEqualTo(LocalDate.of(2022, 8, 15));
|
||||
assertThat(trainDates.get("1.0.0-M3")).isEqualTo(LocalDate.of(2022, 9, 19));
|
||||
assertThat(trainDates.get("1.0.0-RC1")).isEqualTo(LocalDate.of(2022, 10, 17));
|
||||
assertThat(trainDates.get("1.0.0")).isEqualTo(LocalDate.of(2022, 11, 21));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isTrainDateWhenTrainOneIsThirdMondayOf2022ThenSuccess() {
|
||||
SpringReleaseTrainSpec releaseTrainSpec =
|
||||
SpringReleaseTrainSpec.builder()
|
||||
.train(1)
|
||||
.version("1.0.0")
|
||||
.weekOfMonth(3)
|
||||
.dayOfWeek(1)
|
||||
.year(2022)
|
||||
.build();
|
||||
|
||||
SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec);
|
||||
for (int dayOfMonth = 1; dayOfMonth <= 31; dayOfMonth++) {
|
||||
assertThat(releaseTrain.isTrainDate("1.0.0-M1", LocalDate.of(2022, 1, dayOfMonth))).isEqualTo(dayOfMonth == 17);
|
||||
}
|
||||
for (int dayOfMonth = 1; dayOfMonth <= 28; dayOfMonth++) {
|
||||
assertThat(releaseTrain.isTrainDate("1.0.0-M2", LocalDate.of(2022, 2, dayOfMonth))).isEqualTo(dayOfMonth == 21);
|
||||
}
|
||||
for (int dayOfMonth = 1; dayOfMonth <= 31; dayOfMonth++) {
|
||||
assertThat(releaseTrain.isTrainDate("1.0.0-M3", LocalDate.of(2022, 3, dayOfMonth))).isEqualTo(dayOfMonth == 21);
|
||||
}
|
||||
for (int dayOfMonth = 1; dayOfMonth <= 30; dayOfMonth++) {
|
||||
assertThat(releaseTrain.isTrainDate("1.0.0-RC1", LocalDate.of(2022, 4, dayOfMonth))).isEqualTo(dayOfMonth == 18);
|
||||
}
|
||||
for (int dayOfMonth = 1; dayOfMonth <= 31; dayOfMonth++) {
|
||||
assertThat(releaseTrain.isTrainDate("1.0.0", LocalDate.of(2022, 5, dayOfMonth))).isEqualTo(dayOfMonth == 16);
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource({
|
||||
"2022-01-01, 2022-02-21",
|
||||
"2022-02-01, 2022-02-21",
|
||||
"2022-02-21, 2022-04-18",
|
||||
"2022-03-01, 2022-04-18",
|
||||
"2022-04-01, 2022-04-18",
|
||||
"2022-04-18, 2022-06-20",
|
||||
"2022-05-01, 2022-06-20",
|
||||
"2022-06-01, 2022-06-20",
|
||||
"2022-06-20, 2022-08-15",
|
||||
"2022-07-01, 2022-08-15",
|
||||
"2022-08-01, 2022-08-15",
|
||||
"2022-08-15, 2022-10-17",
|
||||
"2022-09-01, 2022-10-17",
|
||||
"2022-10-01, 2022-10-17",
|
||||
"2022-10-17, 2022-12-19",
|
||||
"2022-11-01, 2022-12-19",
|
||||
"2022-12-01, 2022-12-19",
|
||||
"2022-12-19, 2023-02-20"
|
||||
})
|
||||
public void getNextReleaseDateWhenBoundaryConditionsThenSuccess(LocalDate startDate, LocalDate expectedDate) {
|
||||
SpringReleaseTrainSpec releaseTrainSpec =
|
||||
SpringReleaseTrainSpec.builder()
|
||||
.train(1)
|
||||
.version("1.0.0")
|
||||
.weekOfMonth(3)
|
||||
.dayOfWeek(1)
|
||||
.year(2022)
|
||||
.build();
|
||||
|
||||
SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec);
|
||||
assertThat(releaseTrain.getNextReleaseDate(startDate)).isEqualTo(expectedDate);
|
||||
}
|
||||
}
|
||||
-89
@@ -1,89 +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.nio.charset.Charset;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import okhttp3.mockwebserver.MockResponse;
|
||||
import okhttp3.mockwebserver.MockWebServer;
|
||||
import okhttp3.mockwebserver.RecordedRequest;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.gradle.github.RepositoryRef;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
/**
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
public class GitHubActionsApiTests {
|
||||
private GitHubActionsApi gitHubActionsApi;
|
||||
|
||||
private MockWebServer server;
|
||||
|
||||
private String baseUrl;
|
||||
|
||||
private RepositoryRef repository;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() throws Exception {
|
||||
this.server = new MockWebServer();
|
||||
this.server.start();
|
||||
this.baseUrl = this.server.url("/api").toString();
|
||||
this.gitHubActionsApi = new GitHubActionsApi("mock-oauth-token");
|
||||
this.gitHubActionsApi.setBaseUrl(this.baseUrl);
|
||||
this.repository = new RepositoryRef("spring-projects", "spring-security");
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void cleanup() throws Exception {
|
||||
this.server.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dispatchWorkflowWhenValidParametersThenSuccess() throws Exception {
|
||||
this.server.enqueue(new MockResponse().setResponseCode(204));
|
||||
|
||||
Map<String, Object> inputs = new LinkedHashMap<>();
|
||||
inputs.put("input-1", "value");
|
||||
inputs.put("input-2", false);
|
||||
WorkflowDispatch workflowDispatch = new WorkflowDispatch("main", inputs);
|
||||
this.gitHubActionsApi.dispatchWorkflow(this.repository, "test-workflow.yml", workflowDispatch);
|
||||
|
||||
RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS);
|
||||
assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("post");
|
||||
assertThat(recordedRequest.getRequestUrl().toString())
|
||||
.isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/actions/workflows/test-workflow.yml/dispatches");
|
||||
assertThat(recordedRequest.getBody().readString(Charset.defaultCharset()))
|
||||
.isEqualTo("{\"ref\":\"main\",\"inputs\":{\"input-1\":\"value\",\"input-2\":false}}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dispatchWorkflowWhenErrorResponseThenException() throws Exception {
|
||||
this.server.enqueue(new MockResponse().setResponseCode(400));
|
||||
|
||||
WorkflowDispatch workflowDispatch = new WorkflowDispatch("main", null);
|
||||
assertThatExceptionOfType(RuntimeException.class)
|
||||
.isThrownBy(() -> this.gitHubActionsApi.dispatchWorkflow(this.repository, "test-workflow.yml", workflowDispatch));
|
||||
}
|
||||
}
|
||||
+11
-15
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* 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.
|
||||
@@ -16,15 +16,14 @@
|
||||
|
||||
package org.springframework.gradle.github.release;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import okhttp3.mockwebserver.MockResponse;
|
||||
import okhttp3.mockwebserver.MockWebServer;
|
||||
import okhttp3.mockwebserver.RecordedRequest;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.gradle.github.RepositoryRef;
|
||||
|
||||
@@ -35,22 +34,21 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
public class GitHubReleaseApiTests {
|
||||
private GitHubReleaseApi gitHubReleaseApi;
|
||||
private GitHubReleaseApi github;
|
||||
|
||||
private RepositoryRef repository = new RepositoryRef("spring-projects", "spring-security");
|
||||
|
||||
private MockWebServer server;
|
||||
|
||||
private String baseUrl;
|
||||
|
||||
private RepositoryRef repository;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() throws Exception {
|
||||
this.server = new MockWebServer();
|
||||
this.server.start();
|
||||
this.github = new GitHubReleaseApi("mock-oauth-token");
|
||||
this.baseUrl = this.server.url("/api").toString();
|
||||
this.gitHubReleaseApi = new GitHubReleaseApi("mock-oauth-token");
|
||||
this.gitHubReleaseApi.setBaseUrl(this.baseUrl);
|
||||
this.repository = new RepositoryRef("spring-projects", "spring-security");
|
||||
this.github.setBaseUrl(this.baseUrl);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
@@ -136,20 +134,18 @@ public class GitHubReleaseApiTests {
|
||||
" ]\n" +
|
||||
"}";
|
||||
this.server.enqueue(new MockResponse().setBody(responseJson));
|
||||
this.gitHubReleaseApi.publishRelease(this.repository, Release.tag("1.0.0").build());
|
||||
this.github.publishRelease(this.repository, Release.tag("1.0.0").build());
|
||||
|
||||
RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS);
|
||||
assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("post");
|
||||
assertThat(recordedRequest.getRequestUrl().toString())
|
||||
.isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/releases");
|
||||
assertThat(recordedRequest.getBody().readString(Charset.defaultCharset()))
|
||||
.isEqualTo("{\"tag_name\":\"1.0.0\",\"draft\":false,\"prerelease\":false,\"generate_release_notes\":false}");
|
||||
assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/releases");
|
||||
assertThat(recordedRequest.getBody().toString()).isEqualTo("{\"tag_name\":\"1.0.0\"}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publishReleaseWhenErrorResponseThenException() throws Exception {
|
||||
this.server.enqueue(new MockResponse().setResponseCode(400));
|
||||
assertThatExceptionOfType(RuntimeException.class)
|
||||
.isThrownBy(() -> this.gitHubReleaseApi.publishRelease(this.repository, Release.tag("1.0.0").build()));
|
||||
.isThrownBy(() -> this.github.publishRelease(this.repository, Release.tag("1.0.0").build()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,6 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
optional 'jakarta.servlet:jakarta.servlet-api:3.1.0'
|
||||
optional 'javax.servlet:javax.servlet-api:3.1.0'
|
||||
testCompile 'junit:junit:4.12'
|
||||
}
|
||||
@@ -4,10 +4,7 @@ dependencies {
|
||||
management platform(project(":spring-security-dependencies"))
|
||||
api project(':spring-security-core')
|
||||
api project(':spring-security-web')
|
||||
api('org.jasig.cas.client:cas-client-core') {
|
||||
exclude group: 'org.glassfish.jaxb', module: 'jaxb-core'
|
||||
exclude group: 'javax.xml.bind', module: 'jaxb-api'
|
||||
}
|
||||
api 'org.jasig.cas.client:cas-client-core'
|
||||
api 'org.springframework:spring-beans'
|
||||
api 'org.springframework:spring-context'
|
||||
api 'org.springframework:spring-core'
|
||||
@@ -16,7 +13,7 @@ dependencies {
|
||||
optional 'com.fasterxml.jackson.core:jackson-databind'
|
||||
optional 'net.sf.ehcache:ehcache'
|
||||
|
||||
provided 'jakarta.servlet:jakarta.servlet-api'
|
||||
provided 'javax.servlet:javax.servlet-api'
|
||||
|
||||
testImplementation "org.assertj:assertj-core"
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-api"
|
||||
|
||||
@@ -37,9 +37,9 @@ dependencies {
|
||||
optional'org.springframework:spring-websocket'
|
||||
optional 'org.jetbrains.kotlin:kotlin-reflect'
|
||||
optional 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
|
||||
optional 'jakarta.annotation:jakarta.annotation-api'
|
||||
optional 'javax.annotation:jsr250-api'
|
||||
|
||||
provided 'jakarta.servlet:jakarta.servlet-api'
|
||||
provided 'javax.servlet:javax.servlet-api'
|
||||
|
||||
testImplementation project(':spring-security-aspects')
|
||||
testImplementation project(':spring-security-cas')
|
||||
@@ -62,10 +62,8 @@ dependencies {
|
||||
testImplementation 'ch.qos.logback:logback-classic'
|
||||
testImplementation 'io.projectreactor.netty:reactor-netty'
|
||||
testImplementation 'io.rsocket:rsocket-transport-netty'
|
||||
testImplementation 'jakarta.annotation:jakarta.annotation-api:1.0'
|
||||
testImplementation "jakarta.inject:jakarta.inject-api"
|
||||
testImplementation "jakarta.transaction:jakarta.transaction-api"
|
||||
testImplementation 'jakarta.xml.bind:jakarta.xml.bind-api'
|
||||
testImplementation 'javax.annotation:jsr250-api:1.0'
|
||||
testImplementation 'javax.xml.bind:jaxb-api'
|
||||
testImplementation 'ldapsdk:ldapsdk:4.1'
|
||||
testImplementation('net.sourceforge.htmlunit:htmlunit') {
|
||||
exclude group: 'commons-logging', module: 'commons-logging'
|
||||
@@ -77,18 +75,12 @@ dependencies {
|
||||
testImplementation "org.apache.directory.server:apacheds-server-jndi"
|
||||
testImplementation 'org.apache.directory.shared:shared-ldap'
|
||||
testImplementation 'org.eclipse.persistence:javax.persistence'
|
||||
testImplementation('org.hibernate:hibernate-entitymanager') {
|
||||
exclude group: 'javax.activation', module: 'javax.activation-api'
|
||||
exclude group: 'javax.persistence', module: 'javax.persistence-api'
|
||||
exclude group: 'javax.xml.bind', module: 'jaxb-api'
|
||||
exclude group: 'org.jboss.spec.javax.transaction', module: 'jboss-transaction-api_1.2_spec'
|
||||
}
|
||||
testImplementation 'org.hibernate:hibernate-entitymanager'
|
||||
testImplementation 'org.hsqldb:hsqldb'
|
||||
testImplementation 'org.mockito:mockito-core'
|
||||
testImplementation "org.mockito:mockito-inline"
|
||||
testImplementation ('org.openid4java:openid4java-nodeps') {
|
||||
exclude group: 'com.google.code.guice', module: 'guice'
|
||||
exclude group: 'commons-logging', module: 'commons-logging'
|
||||
}
|
||||
testImplementation('org.seleniumhq.selenium:htmlunit-driver') {
|
||||
exclude group: 'commons-logging', module: 'commons-logging'
|
||||
@@ -97,6 +89,7 @@ dependencies {
|
||||
exclude group: 'commons-logging', module: 'commons-logging'
|
||||
exclude group: 'io.netty', module: 'netty'
|
||||
}
|
||||
testImplementation 'org.slf4j:jcl-over-slf4j'
|
||||
testImplementation 'org.springframework.ldap:spring-ldap-core'
|
||||
testImplementation 'org.springframework:spring-expression'
|
||||
testImplementation 'org.springframework:spring-jdbc'
|
||||
|
||||
+1
-1
@@ -65,7 +65,7 @@ public class NamespaceLdapAuthenticationProviderTestsConfigs {
|
||||
.ldif("classpath:users.xldif") // ldap-server@ldif
|
||||
.managerDn("uid=admin,ou=system") // ldap-server@manager-dn
|
||||
.managerPassword("secret") // ldap-server@manager-password
|
||||
.port(0) // ldap-server@port
|
||||
.port(33399) // ldap-server@port
|
||||
.root("dc=springframework,dc=org"); // ldap-server@root
|
||||
// .url("ldap://localhost:33389/dc-springframework,dc=org") this overrides root and port and is used for external
|
||||
// @formatter:on
|
||||
|
||||
+2
-2
@@ -94,7 +94,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||
if (!namespaceMatchesVersion(element)) {
|
||||
pc.getReaderContext().fatal("You cannot use a spring-security-2.0.xsd or spring-security-3.0.xsd or "
|
||||
+ "spring-security-3.1.xsd schema or spring-security-3.2.xsd schema or spring-security-4.0.xsd schema "
|
||||
+ "with Spring Security 5.6. Please update your schema declarations to the 5.6 schema.", element);
|
||||
+ "with Spring Security 5.7. Please update your schema declarations to the 5.7 schema.", element);
|
||||
}
|
||||
String name = pc.getDelegate().getLocalName(element);
|
||||
BeanDefinitionParser parser = this.parsers.get(name);
|
||||
@@ -215,7 +215,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||
|
||||
private boolean matchesVersionInternal(Element element) {
|
||||
String schemaLocation = element.getAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation");
|
||||
return schemaLocation.matches("(?m).*spring-security-5\\.6.*.xsd.*")
|
||||
return schemaLocation.matches("(?m).*spring-security-5\\.7.*.xsd.*")
|
||||
|| schemaLocation.matches("(?m).*spring-security.xsd.*")
|
||||
|| !schemaLocation.matches("(?m).*spring-security.*");
|
||||
}
|
||||
|
||||
+3
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2019 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.
|
||||
@@ -39,7 +39,6 @@ import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.core.log.LogMessage;
|
||||
import org.springframework.security.authentication.AuthenticationEventPublisher;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
|
||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.authentication.configurers.provisioning.InMemoryUserDetailsManagerConfigurer;
|
||||
@@ -80,7 +79,8 @@ public class AuthenticationConfiguration {
|
||||
public AuthenticationManagerBuilder authenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor,
|
||||
ApplicationContext context) {
|
||||
LazyPasswordEncoder defaultPasswordEncoder = new LazyPasswordEncoder(context);
|
||||
AuthenticationEventPublisher authenticationEventPublisher = getAuthenticationEventPublisher(context);
|
||||
AuthenticationEventPublisher authenticationEventPublisher = getBeanOrNull(context,
|
||||
AuthenticationEventPublisher.class);
|
||||
DefaultPasswordEncoderAuthenticationManagerBuilder result = new DefaultPasswordEncoderAuthenticationManagerBuilder(
|
||||
objectPostProcessor, defaultPasswordEncoder);
|
||||
if (authenticationEventPublisher != null) {
|
||||
@@ -142,13 +142,6 @@ public class AuthenticationConfiguration {
|
||||
this.objectPostProcessor = objectPostProcessor;
|
||||
}
|
||||
|
||||
private AuthenticationEventPublisher getAuthenticationEventPublisher(ApplicationContext context) {
|
||||
if (context.getBeanNamesForType(AuthenticationEventPublisher.class).length > 0) {
|
||||
return context.getBean(AuthenticationEventPublisher.class);
|
||||
}
|
||||
return this.objectPostProcessor.postProcess(new DefaultAuthenticationEventPublisher());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T lazyBean(Class<T> interfaceName) {
|
||||
LazyInitTargetSource lazyTargetSource = new LazyInitTargetSource();
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+15
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* 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.
|
||||
@@ -2889,8 +2889,15 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected DefaultSecurityFilterChain performBuild() {
|
||||
ExpressionUrlAuthorizationConfigurer<?> expressionConfigurer = getConfigurer(
|
||||
ExpressionUrlAuthorizationConfigurer.class);
|
||||
AuthorizeHttpRequestsConfigurer<?> httpConfigurer = getConfigurer(AuthorizeHttpRequestsConfigurer.class);
|
||||
boolean oneConfigurerPresent = expressionConfigurer == null ^ httpConfigurer == null;
|
||||
Assert.state((expressionConfigurer == null && httpConfigurer == null) || oneConfigurerPresent,
|
||||
"authorizeHttpRequests cannot be used in conjunction with authorizeRequests. Please select just one.");
|
||||
this.filters.sort(OrderComparator.INSTANCE);
|
||||
List<Filter> sortedFilters = new ArrayList<>(this.filters.size());
|
||||
for (Filter filter : this.filters) {
|
||||
@@ -3283,26 +3290,20 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
*/
|
||||
public final class MvcMatchersRequestMatcherConfigurer extends RequestMatcherConfigurer {
|
||||
|
||||
private final List<MvcRequestMatcher> mvcMatchers;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @param context the {@link ApplicationContext} to use
|
||||
* @param mvcMatchers the {@link MvcRequestMatcher} instances to set the servlet
|
||||
* path on if {@link #servletPath(String)} is set.
|
||||
* @param allMatchers the {@link RequestMatcher} instances to continue the
|
||||
* configuration
|
||||
* @param matchers the {@link MvcRequestMatcher} instances to set the servlet path
|
||||
* on if {@link #servletPath(String)} is set.
|
||||
*/
|
||||
private MvcMatchersRequestMatcherConfigurer(ApplicationContext context, List<MvcRequestMatcher> mvcMatchers,
|
||||
List<RequestMatcher> allMatchers) {
|
||||
private MvcMatchersRequestMatcherConfigurer(ApplicationContext context, List<MvcRequestMatcher> matchers) {
|
||||
super(context);
|
||||
this.mvcMatchers = new ArrayList<>(mvcMatchers);
|
||||
this.matchers = allMatchers;
|
||||
this.matchers = new ArrayList<>(matchers);
|
||||
}
|
||||
|
||||
public RequestMatcherConfigurer servletPath(String servletPath) {
|
||||
for (MvcRequestMatcher matcher : this.mvcMatchers) {
|
||||
matcher.setServletPath(servletPath);
|
||||
for (RequestMatcher matcher : this.matchers) {
|
||||
((MvcRequestMatcher) matcher).setServletPath(servletPath);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
@@ -3327,7 +3328,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
public MvcMatchersRequestMatcherConfigurer mvcMatchers(HttpMethod method, String... mvcPatterns) {
|
||||
List<MvcRequestMatcher> mvcMatchers = createMvcMatchers(method, mvcPatterns);
|
||||
setMatchers(mvcMatchers);
|
||||
return new MvcMatchersRequestMatcherConfigurer(getContext(), mvcMatchers, this.matchers);
|
||||
return new MvcMatchersRequestMatcherConfigurer(getContext(), mvcMatchers);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-7
@@ -264,7 +264,6 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
|
||||
* @deprecated Use {@link #privilegeEvaluator(WebInvocationPrivilegeEvaluator)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated
|
||||
public WebSecurity securityInterceptor(FilterSecurityInterceptor securityInterceptor) {
|
||||
this.filterSecurityInterceptor = securityInterceptor;
|
||||
return this;
|
||||
@@ -292,8 +291,6 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
|
||||
List<SecurityFilterChain> securityFilterChains = new ArrayList<>(chainSize);
|
||||
List<RequestMatcherEntry<List<WebInvocationPrivilegeEvaluator>>> requestMatcherPrivilegeEvaluatorsEntries = new ArrayList<>();
|
||||
for (RequestMatcher ignoredRequest : this.ignoredRequests) {
|
||||
WebSecurity.this.logger.warn("You are asking Spring Security to ignore " + ignoredRequest
|
||||
+ ". This is not recommended -- please use permitAll via HttpSecurity#authorizeHttpRequests instead.");
|
||||
SecurityFilterChain securityFilterChain = new DefaultSecurityFilterChain(ignoredRequest);
|
||||
securityFilterChains.add(securityFilterChain);
|
||||
requestMatcherPrivilegeEvaluatorsEntries
|
||||
@@ -345,10 +342,7 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
|
||||
if (filter instanceof AuthorizationFilter) {
|
||||
AuthorizationManager<HttpServletRequest> authorizationManager = ((AuthorizationFilter) filter)
|
||||
.getAuthorizationManager();
|
||||
AuthorizationManagerWebInvocationPrivilegeEvaluator evaluator = new AuthorizationManagerWebInvocationPrivilegeEvaluator(
|
||||
authorizationManager);
|
||||
evaluator.setServletContext(this.servletContext);
|
||||
privilegeEvaluators.add(evaluator);
|
||||
privilegeEvaluators.add(new AuthorizationManagerWebInvocationPrivilegeEvaluator(authorizationManager));
|
||||
}
|
||||
}
|
||||
return new RequestMatcherEntry<>(securityFilterChain::matches, privilegeEvaluators);
|
||||
|
||||
+1
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-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.
|
||||
@@ -24,9 +24,7 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.security.authentication.AuthenticationEventPublisher;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
|
||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||
@@ -84,7 +82,6 @@ class HttpSecurityConfiguration {
|
||||
AuthenticationManagerBuilder authenticationBuilder = new WebSecurityConfigurerAdapter.DefaultPasswordEncoderAuthenticationManagerBuilder(
|
||||
this.objectPostProcessor, passwordEncoder);
|
||||
authenticationBuilder.parentAuthenticationManager(authenticationManager());
|
||||
authenticationBuilder.authenticationEventPublisher(getAuthenticationEventPublisher());
|
||||
HttpSecurity http = new HttpSecurity(this.objectPostProcessor, authenticationBuilder, createSharedObjects());
|
||||
// @formatter:off
|
||||
http
|
||||
@@ -108,13 +105,6 @@ class HttpSecurityConfiguration {
|
||||
: this.authenticationConfiguration.getAuthenticationManager();
|
||||
}
|
||||
|
||||
private AuthenticationEventPublisher getAuthenticationEventPublisher() {
|
||||
if (this.context.getBeanNamesForType(AuthenticationEventPublisher.class).length > 0) {
|
||||
return this.context.getBean(AuthenticationEventPublisher.class);
|
||||
}
|
||||
return this.objectPostProcessor.postProcess(new DefaultAuthenticationEventPublisher());
|
||||
}
|
||||
|
||||
private Map<Class<?>, Object> createSharedObjects() {
|
||||
Map<Class<?>, Object> sharedObjects = new HashMap<>();
|
||||
sharedObjects.put(ApplicationContext.class, this.context);
|
||||
|
||||
+142
-31
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* 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.
|
||||
@@ -16,10 +16,14 @@
|
||||
|
||||
package org.springframework.security.config.annotation.web.configuration;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
@@ -67,17 +71,22 @@ class SecurityReactorContextConfiguration {
|
||||
|
||||
private static final String SECURITY_REACTOR_CONTEXT_OPERATOR_KEY = "org.springframework.security.SECURITY_REACTOR_CONTEXT_OPERATOR";
|
||||
|
||||
private static final Map<Object, Supplier<Object>> CONTEXT_ATTRIBUTE_VALUE_LOADERS = new HashMap<>();
|
||||
|
||||
static {
|
||||
CONTEXT_ATTRIBUTE_VALUE_LOADERS.put(HttpServletRequest.class,
|
||||
SecurityReactorContextSubscriberRegistrar::getRequest);
|
||||
CONTEXT_ATTRIBUTE_VALUE_LOADERS.put(HttpServletResponse.class,
|
||||
SecurityReactorContextSubscriberRegistrar::getResponse);
|
||||
CONTEXT_ATTRIBUTE_VALUE_LOADERS.put(Authentication.class,
|
||||
SecurityReactorContextSubscriberRegistrar::getAuthentication);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Function<? super Publisher<Object>, ? extends Publisher<Object>> lifter = Operators
|
||||
.liftPublisher((pub, sub) -> createSubscriberIfNecessary(sub));
|
||||
Hooks.onLastOperator(SECURITY_REACTOR_CONTEXT_OPERATOR_KEY, (pub) -> {
|
||||
if (!contextAttributesAvailable()) {
|
||||
// No need to decorate so return original Publisher
|
||||
return pub;
|
||||
}
|
||||
return lifter.apply(pub);
|
||||
});
|
||||
Hooks.onLastOperator(SECURITY_REACTOR_CONTEXT_OPERATOR_KEY, lifter::apply);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -93,36 +102,30 @@ class SecurityReactorContextConfiguration {
|
||||
return new SecurityReactorContextSubscriber<>(delegate, getContextAttributes());
|
||||
}
|
||||
|
||||
private static boolean contextAttributesAvailable() {
|
||||
return SecurityContextHolder.getContext().getAuthentication() != null
|
||||
|| RequestContextHolder.getRequestAttributes() instanceof ServletRequestAttributes;
|
||||
private static Map<Object, Object> getContextAttributes() {
|
||||
return new LoadingMap<>(CONTEXT_ATTRIBUTE_VALUE_LOADERS);
|
||||
}
|
||||
|
||||
private static Map<Object, Object> getContextAttributes() {
|
||||
HttpServletRequest servletRequest = null;
|
||||
HttpServletResponse servletResponse = null;
|
||||
private static HttpServletRequest getRequest() {
|
||||
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
|
||||
if (requestAttributes instanceof ServletRequestAttributes) {
|
||||
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
|
||||
servletRequest = servletRequestAttributes.getRequest();
|
||||
servletResponse = servletRequestAttributes.getResponse(); // possible null
|
||||
}
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (authentication == null && servletRequest == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<Object, Object> contextAttributes = new HashMap<>();
|
||||
if (servletRequest != null) {
|
||||
contextAttributes.put(HttpServletRequest.class, servletRequest);
|
||||
}
|
||||
if (servletResponse != null) {
|
||||
contextAttributes.put(HttpServletResponse.class, servletResponse);
|
||||
}
|
||||
if (authentication != null) {
|
||||
contextAttributes.put(Authentication.class, authentication);
|
||||
return servletRequestAttributes.getRequest();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return contextAttributes;
|
||||
private static HttpServletResponse getResponse() {
|
||||
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
|
||||
if (requestAttributes instanceof ServletRequestAttributes) {
|
||||
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
|
||||
return servletRequestAttributes.getResponse(); // possible null
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Authentication getAuthentication() {
|
||||
return SecurityContextHolder.getContext().getAuthentication();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -175,4 +178,112 @@ class SecurityReactorContextConfiguration {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A map that computes each value when {@link #get} is invoked
|
||||
*/
|
||||
static class LoadingMap<K, V> implements Map<K, V> {
|
||||
|
||||
private final Map<K, V> loaded = new ConcurrentHashMap<>();
|
||||
|
||||
private final Map<K, Supplier<V>> loaders;
|
||||
|
||||
LoadingMap(Map<K, Supplier<V>> loaders) {
|
||||
this.loaders = Collections.unmodifiableMap(new HashMap<>(loaders));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return this.loaders.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return this.loaders.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return this.loaders.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
return this.loaders.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(Object key) {
|
||||
if (!this.loaders.containsKey(key)) {
|
||||
throw new IllegalArgumentException(
|
||||
"This map only supports the following keys: " + this.loaders.keySet());
|
||||
}
|
||||
return this.loaded.computeIfAbsent((K) key, (k) -> this.loaders.get(k).get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
if (!this.loaders.containsKey(key)) {
|
||||
throw new IllegalArgumentException(
|
||||
"This map only supports the following keys: " + this.loaders.keySet());
|
||||
}
|
||||
return this.loaded.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(Object key) {
|
||||
if (!this.loaders.containsKey(key)) {
|
||||
throw new IllegalArgumentException(
|
||||
"This map only supports the following keys: " + this.loaders.keySet());
|
||||
}
|
||||
return this.loaded.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends K, ? extends V> m) {
|
||||
for (Map.Entry<? extends K, ? extends V> entry : m.entrySet()) {
|
||||
put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
this.loaded.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return this.loaded.containsValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
return this.loaded.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<K, V>> entrySet() {
|
||||
return this.loaded.entrySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LoadingMap<?, ?> that = (LoadingMap<?, ?>) o;
|
||||
|
||||
return this.loaded.equals(that.loaded);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.loaded.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* 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.
|
||||
@@ -24,7 +24,6 @@ import javax.servlet.Filter;
|
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -143,19 +142,20 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
|
||||
* instances used to create the web configuration.
|
||||
* @param objectPostProcessor the {@link ObjectPostProcessor} used to create a
|
||||
* {@link WebSecurity} instance
|
||||
* @param webSecurityConfigurers the
|
||||
* @param beanFactory the bean factory to use to retrieve the relevant
|
||||
* {@code <SecurityConfigurer<FilterChainProxy, WebSecurityBuilder>} instances used to
|
||||
* create the web configuration
|
||||
* @throws Exception
|
||||
*/
|
||||
@Autowired(required = false)
|
||||
public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor,
|
||||
@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
|
||||
throws Exception {
|
||||
ConfigurableListableBeanFactory beanFactory) throws Exception {
|
||||
this.webSecurity = objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
|
||||
if (this.debugEnabled != null) {
|
||||
this.webSecurity.debug(this.debugEnabled);
|
||||
}
|
||||
List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers = new AutowiredWebSecurityConfigurersIgnoreParents(
|
||||
beanFactory).getWebSecurityConfigurers();
|
||||
webSecurityConfigurers.sort(AnnotationAwareOrderComparator.INSTANCE);
|
||||
Integer previousOrder = null;
|
||||
Object previousConfig = null;
|
||||
@@ -189,12 +189,6 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
|
||||
return new RsaKeyConversionServicePostProcessor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public static AutowiredWebSecurityConfigurersIgnoreParents autowiredWebSecurityConfigurersIgnoreParents(
|
||||
ConfigurableListableBeanFactory beanFactory) {
|
||||
return new AutowiredWebSecurityConfigurersIgnoreParents(beanFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImportMetadata(AnnotationMetadata importMetadata) {
|
||||
Map<String, Object> enableWebSecurityAttrMap = importMetadata
|
||||
|
||||
+25
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* 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.
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -46,6 +47,9 @@ import org.springframework.util.Assert;
|
||||
public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
extends AbstractHttpConfigurer<AuthorizeHttpRequestsConfigurer<H>, H> {
|
||||
|
||||
static final AuthorizationManager<RequestAuthorizationContext> permitAllAuthorizationManager = (a,
|
||||
o) -> new AuthorizationDecision(true);
|
||||
|
||||
private final AuthorizationManagerRequestMatcherRegistry registry;
|
||||
|
||||
/**
|
||||
@@ -81,6 +85,12 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
|
||||
return this.registry;
|
||||
}
|
||||
|
||||
AuthorizationManagerRequestMatcherRegistry addFirst(RequestMatcher matcher,
|
||||
AuthorizationManager<RequestAuthorizationContext> manager) {
|
||||
this.registry.addFirst(matcher, manager);
|
||||
return this.registry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registry for mapping a {@link RequestMatcher} to an {@link AuthorizationManager}.
|
||||
*
|
||||
@@ -106,6 +116,19 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
|
||||
this.mappingCount++;
|
||||
}
|
||||
|
||||
private void addFirst(RequestMatcher matcher, AuthorizationManager<RequestAuthorizationContext> manager) {
|
||||
this.unmappedMatchers = null;
|
||||
this.managerBuilder.mappings((m) -> {
|
||||
LinkedHashMap<RequestMatcher, AuthorizationManager<RequestAuthorizationContext>> reorderedMap = new LinkedHashMap<>(
|
||||
m.size() + 1);
|
||||
reorderedMap.put(matcher, manager);
|
||||
reorderedMap.putAll(m);
|
||||
m.clear();
|
||||
m.putAll(reorderedMap);
|
||||
});
|
||||
this.mappingCount++;
|
||||
}
|
||||
|
||||
private AuthorizationManager<HttpServletRequest> createAuthorizationManager() {
|
||||
Assert.state(this.unmappedMatchers == null,
|
||||
() -> "An incomplete mapping was found for " + this.unmappedMatchers
|
||||
@@ -209,7 +232,7 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
|
||||
* customizations
|
||||
*/
|
||||
public AuthorizationManagerRequestMatcherRegistry permitAll() {
|
||||
return access((a, o) -> new AuthorizationDecision(true));
|
||||
return access(permitAllAuthorizationManager);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+19
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* 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.
|
||||
@@ -30,7 +30,9 @@ import org.springframework.security.config.annotation.SecurityBuilder;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.web.DefaultRedirectStrategy;
|
||||
import org.springframework.security.web.PortMapper;
|
||||
import org.springframework.security.web.RedirectStrategy;
|
||||
import org.springframework.security.web.access.channel.ChannelDecisionManagerImpl;
|
||||
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
|
||||
import org.springframework.security.web.access.channel.ChannelProcessor;
|
||||
@@ -75,6 +77,7 @@ import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
*
|
||||
* @param <H> the type of {@link HttpSecurityBuilder} that is being configured
|
||||
* @author Rob Winch
|
||||
* @author Onur Kagan Ozcan
|
||||
* @since 3.2
|
||||
*/
|
||||
public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
@@ -86,6 +89,8 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
|
||||
private List<ChannelProcessor> channelProcessors;
|
||||
|
||||
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
|
||||
|
||||
private final ChannelRequestMatcherRegistry REGISTRY;
|
||||
|
||||
/**
|
||||
@@ -123,9 +128,11 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
if (portMapper != null) {
|
||||
RetryWithHttpEntryPoint httpEntryPoint = new RetryWithHttpEntryPoint();
|
||||
httpEntryPoint.setPortMapper(portMapper);
|
||||
httpEntryPoint.setRedirectStrategy(this.redirectStrategy);
|
||||
insecureChannelProcessor.setEntryPoint(httpEntryPoint);
|
||||
RetryWithHttpsEntryPoint httpsEntryPoint = new RetryWithHttpsEntryPoint();
|
||||
httpsEntryPoint.setPortMapper(portMapper);
|
||||
httpsEntryPoint.setRedirectStrategy(this.redirectStrategy);
|
||||
secureChannelProcessor.setEntryPoint(httpsEntryPoint);
|
||||
}
|
||||
insecureChannelProcessor = postProcess(insecureChannelProcessor);
|
||||
@@ -185,6 +192,17 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link RedirectStrategy} instances to use in
|
||||
* {@link RetryWithHttpEntryPoint} and {@link RetryWithHttpsEntryPoint}
|
||||
* @param redirectStrategy
|
||||
* @return the {@link ChannelSecurityConfigurer} for further customizations
|
||||
*/
|
||||
public ChannelRequestMatcherRegistry redirectStrategy(RedirectStrategy redirectStrategy) {
|
||||
ChannelSecurityConfigurer.this.redirectStrategy = redirectStrategy;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link SecurityBuilder} when done using the
|
||||
* {@link SecurityConfigurer}. This is useful for method chaining.
|
||||
|
||||
+3
-3
@@ -237,8 +237,8 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
|
||||
/**
|
||||
* Gets the default {@link AccessDeniedHandler} from the
|
||||
* {@link ExceptionHandlingConfigurer#getAccessDeniedHandler()} or create a
|
||||
* {@link AccessDeniedHandlerImpl} if not available.
|
||||
* {@link ExceptionHandlingConfigurer#getAccessDeniedHandler(HttpSecurityBuilder)} or
|
||||
* create a {@link AccessDeniedHandlerImpl} if not available.
|
||||
* @param http the {@link HttpSecurityBuilder}
|
||||
* @return the {@link AccessDeniedHandler}
|
||||
*/
|
||||
@@ -247,7 +247,7 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
ExceptionHandlingConfigurer<H> exceptionConfig = http.getConfigurer(ExceptionHandlingConfigurer.class);
|
||||
AccessDeniedHandler handler = null;
|
||||
if (exceptionConfig != null) {
|
||||
handler = exceptionConfig.getAccessDeniedHandler();
|
||||
handler = exceptionConfig.getAccessDeniedHandler(http);
|
||||
}
|
||||
if (handler == null) {
|
||||
handler = new AccessDeniedHandlerImpl();
|
||||
|
||||
+1
-3
@@ -369,9 +369,7 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that URLs requires a specific IP Address or <a href=
|
||||
* "https://forum.spring.io/showthread.php?102783-How-to-use-hasIpAddress&p=343971#post343971"
|
||||
* >subnet</a>.
|
||||
* Specify that URLs requires a specific IP Address or subnet.
|
||||
* @param ipaddressExpression the ipaddress (i.e. 192.168.1.79) or local subnet
|
||||
* (i.e. 192.168.0/24)
|
||||
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
|
||||
|
||||
+228
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* 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.
|
||||
@@ -31,6 +31,9 @@ import org.springframework.security.web.header.HeaderWriter;
|
||||
import org.springframework.security.web.header.HeaderWriterFilter;
|
||||
import org.springframework.security.web.header.writers.CacheControlHeadersWriter;
|
||||
import org.springframework.security.web.header.writers.ContentSecurityPolicyHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.CrossOriginEmbedderPolicyHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.CrossOriginOpenerPolicyHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.CrossOriginResourcePolicyHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.FeaturePolicyHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.HpkpHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.HstsHeaderWriter;
|
||||
@@ -97,6 +100,12 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
|
||||
private final PermissionsPolicyConfig permissionsPolicy = new PermissionsPolicyConfig();
|
||||
|
||||
private final CrossOriginOpenerPolicyConfig crossOriginOpenerPolicy = new CrossOriginOpenerPolicyConfig();
|
||||
|
||||
private final CrossOriginEmbedderPolicyConfig crossOriginEmbedderPolicy = new CrossOriginEmbedderPolicyConfig();
|
||||
|
||||
private final CrossOriginResourcePolicyConfig crossOriginResourcePolicy = new CrossOriginResourcePolicyConfig();
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
@@ -392,6 +401,9 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
addIfNotNull(writers, this.referrerPolicy.writer);
|
||||
addIfNotNull(writers, this.featurePolicy.writer);
|
||||
addIfNotNull(writers, this.permissionsPolicy.writer);
|
||||
addIfNotNull(writers, this.crossOriginOpenerPolicy.writer);
|
||||
addIfNotNull(writers, this.crossOriginEmbedderPolicy.writer);
|
||||
addIfNotNull(writers, this.crossOriginResourcePolicy.writer);
|
||||
writers.addAll(this.headerWriters);
|
||||
return writers;
|
||||
}
|
||||
@@ -544,6 +556,129 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
return this.permissionsPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuration for <a href=
|
||||
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy">
|
||||
* Cross-Origin-Opener-Policy</a> header.
|
||||
* <p>
|
||||
* Configuration is provided to the {@link CrossOriginOpenerPolicyHeaderWriter} which
|
||||
* responsible for writing the header.
|
||||
* </p>
|
||||
* @return the {@link CrossOriginOpenerPolicyConfig} for additional confniguration
|
||||
* @since 5.7
|
||||
* @see CrossOriginOpenerPolicyHeaderWriter
|
||||
*/
|
||||
public CrossOriginOpenerPolicyConfig crossOriginOpenerPolicy() {
|
||||
this.crossOriginOpenerPolicy.writer = new CrossOriginOpenerPolicyHeaderWriter();
|
||||
return this.crossOriginOpenerPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuration for <a href=
|
||||
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy">
|
||||
* Cross-Origin-Opener-Policy</a> header.
|
||||
* <p>
|
||||
* Calling this method automatically enables (includes) the
|
||||
* {@code Cross-Origin-Opener-Policy} header in the response using the supplied
|
||||
* policy.
|
||||
* <p>
|
||||
* <p>
|
||||
* Configuration is provided to the {@link CrossOriginOpenerPolicyHeaderWriter} which
|
||||
* responsible for writing the header.
|
||||
* </p>
|
||||
* @return the {@link HeadersConfigurer} for additional customizations
|
||||
* @since 5.7
|
||||
* @see CrossOriginOpenerPolicyHeaderWriter
|
||||
*/
|
||||
public HeadersConfigurer<H> crossOriginOpenerPolicy(
|
||||
Customizer<CrossOriginOpenerPolicyConfig> crossOriginOpenerPolicyCustomizer) {
|
||||
this.crossOriginOpenerPolicy.writer = new CrossOriginOpenerPolicyHeaderWriter();
|
||||
crossOriginOpenerPolicyCustomizer.customize(this.crossOriginOpenerPolicy);
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuration for <a href=
|
||||
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy">
|
||||
* Cross-Origin-Embedder-Policy</a> header.
|
||||
* <p>
|
||||
* Configuration is provided to the {@link CrossOriginEmbedderPolicyHeaderWriter}
|
||||
* which is responsible for writing the header.
|
||||
* </p>
|
||||
* @return the {@link CrossOriginEmbedderPolicyConfig} for additional customizations
|
||||
* @since 5.7
|
||||
* @see CrossOriginEmbedderPolicyHeaderWriter
|
||||
*/
|
||||
public CrossOriginEmbedderPolicyConfig crossOriginEmbedderPolicy() {
|
||||
this.crossOriginEmbedderPolicy.writer = new CrossOriginEmbedderPolicyHeaderWriter();
|
||||
return this.crossOriginEmbedderPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuration for <a href=
|
||||
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy">
|
||||
* Cross-Origin-Embedder-Policy</a> header.
|
||||
* <p>
|
||||
* Calling this method automatically enables (includes) the
|
||||
* {@code Cross-Origin-Embedder-Policy} header in the response using the supplied
|
||||
* policy.
|
||||
* <p>
|
||||
* <p>
|
||||
* Configuration is provided to the {@link CrossOriginEmbedderPolicyHeaderWriter}
|
||||
* which is responsible for writing the header.
|
||||
* </p>
|
||||
* @return the {@link HeadersConfigurer} for additional customizations
|
||||
* @since 5.7
|
||||
* @see CrossOriginEmbedderPolicyHeaderWriter
|
||||
*/
|
||||
public HeadersConfigurer<H> crossOriginEmbedderPolicy(
|
||||
Customizer<CrossOriginEmbedderPolicyConfig> crossOriginEmbedderPolicyCustomizer) {
|
||||
this.crossOriginEmbedderPolicy.writer = new CrossOriginEmbedderPolicyHeaderWriter();
|
||||
crossOriginEmbedderPolicyCustomizer.customize(this.crossOriginEmbedderPolicy);
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuration for <a href=
|
||||
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy">
|
||||
* Cross-Origin-Resource-Policy</a> header.
|
||||
* <p>
|
||||
* Configuration is provided to the {@link CrossOriginResourcePolicyHeaderWriter}
|
||||
* which is responsible for writing the header:
|
||||
* </p>
|
||||
* @return the {@link HeadersConfigurer} for additional customizations
|
||||
* @since 5.7
|
||||
* @see CrossOriginResourcePolicyHeaderWriter
|
||||
*/
|
||||
public CrossOriginResourcePolicyConfig crossOriginResourcePolicy() {
|
||||
this.crossOriginResourcePolicy.writer = new CrossOriginResourcePolicyHeaderWriter();
|
||||
return this.crossOriginResourcePolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuration for <a href=
|
||||
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy">
|
||||
* Cross-Origin-Resource-Policy</a> header.
|
||||
* <p>
|
||||
* Calling this method automatically enables (includes) the
|
||||
* {@code Cross-Origin-Resource-Policy} header in the response using the supplied
|
||||
* policy.
|
||||
* <p>
|
||||
* <p>
|
||||
* Configuration is provided to the {@link CrossOriginResourcePolicyHeaderWriter}
|
||||
* which is responsible for writing the header:
|
||||
* </p>
|
||||
* @return the {@link HeadersConfigurer} for additional customizations
|
||||
* @since 5.7
|
||||
* @see CrossOriginResourcePolicyHeaderWriter
|
||||
*/
|
||||
public HeadersConfigurer<H> crossOriginResourcePolicy(
|
||||
Customizer<CrossOriginResourcePolicyConfig> crossOriginResourcePolicyCustomizer) {
|
||||
this.crossOriginResourcePolicy.writer = new CrossOriginResourcePolicyHeaderWriter();
|
||||
crossOriginResourcePolicyCustomizer.customize(this.crossOriginResourcePolicy);
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
public final class ContentTypeOptionsConfig {
|
||||
|
||||
private XContentTypeOptionsHeaderWriter writer;
|
||||
@@ -1142,4 +1277,96 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
|
||||
}
|
||||
|
||||
public final class CrossOriginOpenerPolicyConfig {
|
||||
|
||||
private CrossOriginOpenerPolicyHeaderWriter writer;
|
||||
|
||||
public CrossOriginOpenerPolicyConfig() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the policy to be used in the {@code Cross-Origin-Opener-Policy} header
|
||||
* @param openerPolicy a {@code Cross-Origin-Opener-Policy}
|
||||
* @return the {@link CrossOriginOpenerPolicyConfig} for additional configuration
|
||||
* @throws IllegalArgumentException if openerPolicy is null
|
||||
*/
|
||||
public CrossOriginOpenerPolicyConfig policy(
|
||||
CrossOriginOpenerPolicyHeaderWriter.CrossOriginOpenerPolicy openerPolicy) {
|
||||
this.writer.setPolicy(openerPolicy);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows completing configuration of Cross Origin Opener Policy and continuing
|
||||
* configuration of headers.
|
||||
* @return the {@link HeadersConfigurer} for additional configuration
|
||||
*/
|
||||
public HeadersConfigurer<H> and() {
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public final class CrossOriginEmbedderPolicyConfig {
|
||||
|
||||
private CrossOriginEmbedderPolicyHeaderWriter writer;
|
||||
|
||||
public CrossOriginEmbedderPolicyConfig() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the policy to be used in the {@code Cross-Origin-Embedder-Policy} header
|
||||
* @param embedderPolicy a {@code Cross-Origin-Embedder-Policy}
|
||||
* @return the {@link CrossOriginEmbedderPolicyConfig} for additional
|
||||
* configuration
|
||||
* @throws IllegalArgumentException if embedderPolicy is null
|
||||
*/
|
||||
public CrossOriginEmbedderPolicyConfig policy(
|
||||
CrossOriginEmbedderPolicyHeaderWriter.CrossOriginEmbedderPolicy embedderPolicy) {
|
||||
this.writer.setPolicy(embedderPolicy);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows completing configuration of Cross-Origin-Embedder-Policy and continuing
|
||||
* configuration of headers.
|
||||
* @return the {@link HeadersConfigurer} for additional configuration
|
||||
*/
|
||||
public HeadersConfigurer<H> and() {
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public final class CrossOriginResourcePolicyConfig {
|
||||
|
||||
private CrossOriginResourcePolicyHeaderWriter writer;
|
||||
|
||||
public CrossOriginResourcePolicyConfig() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the policy to be used in the {@code Cross-Origin-Resource-Policy} header
|
||||
* @param resourcePolicy a {@code Cross-Origin-Resource-Policy}
|
||||
* @return the {@link CrossOriginResourcePolicyConfig} for additional
|
||||
* configuration
|
||||
* @throws IllegalArgumentException if resourcePolicy is null
|
||||
*/
|
||||
public CrossOriginResourcePolicyConfig policy(
|
||||
CrossOriginResourcePolicyHeaderWriter.CrossOriginResourcePolicy resourcePolicy) {
|
||||
this.writer.setPolicy(resourcePolicy);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows completing configuration of Cross-Origin-Resource-Policy and continuing
|
||||
* configuration of headers.
|
||||
* @return the {@link HeadersConfigurer} for additional configuration
|
||||
*/
|
||||
public HeadersConfigurer<H> and() {
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+15
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* 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.
|
||||
@@ -48,11 +48,22 @@ final class PermitAllSupport {
|
||||
RequestMatcher... requestMatchers) {
|
||||
ExpressionUrlAuthorizationConfigurer<?> configurer = http
|
||||
.getConfigurer(ExpressionUrlAuthorizationConfigurer.class);
|
||||
Assert.state(configurer != null, "permitAll only works with HttpSecurity.authorizeRequests()");
|
||||
AuthorizeHttpRequestsConfigurer<?> httpConfigurer = http.getConfigurer(AuthorizeHttpRequestsConfigurer.class);
|
||||
|
||||
boolean oneConfigurerPresent = configurer == null ^ httpConfigurer == null;
|
||||
Assert.state(oneConfigurerPresent,
|
||||
"permitAll only works with either HttpSecurity.authorizeRequests() or HttpSecurity.authorizeHttpRequests(). "
|
||||
+ "Please define one or the other but not both.");
|
||||
|
||||
for (RequestMatcher matcher : requestMatchers) {
|
||||
if (matcher != null) {
|
||||
configurer.getRegistry().addMapping(0, new UrlMapping(matcher,
|
||||
SecurityConfig.createList(ExpressionUrlAuthorizationConfigurer.permitAll)));
|
||||
if (configurer != null) {
|
||||
configurer.getRegistry().addMapping(0, new UrlMapping(matcher,
|
||||
SecurityConfig.createList(ExpressionUrlAuthorizationConfigurer.permitAll)));
|
||||
}
|
||||
else {
|
||||
httpConfigurer.addFirst(matcher, AuthorizeHttpRequestsConfigurer.permitAllAuthorizationManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
@@ -201,6 +201,12 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* {@link HttpServletResponse#encodeRedirectURL(String)} or
|
||||
* {@link HttpServletResponse#encodeURL(String)}, otherwise disallows HTTP sessions to
|
||||
* be included in the URL. This prevents leaking information to external domains.
|
||||
* <p>
|
||||
* This is achieved by guarding {@link HttpServletResponse#encodeURL} and
|
||||
* {@link HttpServletResponse#encodeRedirectURL} invocations. Any code that also
|
||||
* overrides either of these two methods, like
|
||||
* {@link org.springframework.web.servlet.resource.ResourceUrlEncodingFilter}, needs
|
||||
* to come after the security filter chain or risk being skipped.
|
||||
* @param enableSessionUrlRewriting true if should allow the JSESSIONID to be
|
||||
* rewritten into the URLs, else false (default)
|
||||
* @return the {@link SessionManagementConfigurer} for further customization
|
||||
|
||||
+15
-1
@@ -18,6 +18,9 @@ package org.springframework.security.config.annotation.web.configurers.oauth2.se
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -25,6 +28,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.AuthenticationManagerResolver;
|
||||
@@ -51,6 +55,9 @@ import org.springframework.security.oauth2.server.resource.web.DefaultBearerToke
|
||||
import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
|
||||
import org.springframework.security.web.access.DelegatingAccessDeniedHandler;
|
||||
import org.springframework.security.web.csrf.CsrfException;
|
||||
import org.springframework.security.web.util.matcher.AndRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
|
||||
@@ -153,12 +160,19 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
||||
|
||||
private OpaqueTokenConfigurer opaqueTokenConfigurer;
|
||||
|
||||
private AccessDeniedHandler accessDeniedHandler = new BearerTokenAccessDeniedHandler();
|
||||
private AccessDeniedHandler accessDeniedHandler = new DelegatingAccessDeniedHandler(
|
||||
new LinkedHashMap<>(createAccessDeniedHandlers()), new BearerTokenAccessDeniedHandler());
|
||||
|
||||
private AuthenticationEntryPoint authenticationEntryPoint = new BearerTokenAuthenticationEntryPoint();
|
||||
|
||||
private BearerTokenRequestMatcher requestMatcher = new BearerTokenRequestMatcher();
|
||||
|
||||
private static Map<Class<? extends AccessDeniedException>, AccessDeniedHandler> createAccessDeniedHandlers() {
|
||||
Map<Class<? extends AccessDeniedException>, AccessDeniedHandler> handlers = new HashMap<>();
|
||||
handlers.put(CsrfException.class, new AccessDeniedHandlerImpl());
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public OAuth2ResourceServerConfigurer(ApplicationContext context) {
|
||||
Assert.notNull(context, "context cannot be null");
|
||||
this.context = context;
|
||||
|
||||
+82
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* 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.
|
||||
@@ -36,6 +36,9 @@ import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.web.header.HeaderWriterFilter;
|
||||
import org.springframework.security.web.header.writers.CacheControlHeadersWriter;
|
||||
import org.springframework.security.web.header.writers.ContentSecurityPolicyHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.CrossOriginEmbedderPolicyHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.CrossOriginOpenerPolicyHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.CrossOriginResourcePolicyHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.FeaturePolicyHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.HpkpHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.HstsHeaderWriter;
|
||||
@@ -122,6 +125,12 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
private static final String PERMISSIONS_POLICY_ELEMENT = "permissions-policy";
|
||||
|
||||
private static final String CROSS_ORIGIN_OPENER_POLICY_ELEMENT = "cross-origin-opener-policy";
|
||||
|
||||
private static final String CROSS_ORIGIN_EMBEDDER_POLICY_ELEMENT = "cross-origin-embedder-policy";
|
||||
|
||||
private static final String CROSS_ORIGIN_RESOURCE_POLICY_ELEMENT = "cross-origin-resource-policy";
|
||||
|
||||
private static final String ALLOW_FROM = "ALLOW-FROM";
|
||||
|
||||
private ManagedList<BeanMetadataElement> headerWriters;
|
||||
@@ -144,6 +153,9 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
|
||||
parseReferrerPolicyElement(element, parserContext);
|
||||
parseFeaturePolicyElement(element, parserContext);
|
||||
parsePermissionsPolicyElement(element, parserContext);
|
||||
parseCrossOriginOpenerPolicy(disabled, element);
|
||||
parseCrossOriginEmbedderPolicy(disabled, element);
|
||||
parseCrossOriginResourcePolicy(disabled, element);
|
||||
parseHeaderElements(element);
|
||||
boolean noWriters = this.headerWriters.isEmpty();
|
||||
if (disabled && !noWriters) {
|
||||
@@ -376,6 +388,75 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
|
||||
this.headerWriters.add(headersWriter.getBeanDefinition());
|
||||
}
|
||||
|
||||
private void parseCrossOriginOpenerPolicy(boolean elementDisabled, Element element) {
|
||||
if (elementDisabled || element == null) {
|
||||
return;
|
||||
}
|
||||
CrossOriginOpenerPolicyHeaderWriter writer = new CrossOriginOpenerPolicyHeaderWriter();
|
||||
Element crossOriginOpenerPolicyElement = DomUtils.getChildElementByTagName(element,
|
||||
CROSS_ORIGIN_OPENER_POLICY_ELEMENT);
|
||||
if (crossOriginOpenerPolicyElement != null) {
|
||||
addCrossOriginOpenerPolicy(crossOriginOpenerPolicyElement, writer);
|
||||
}
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(CrossOriginOpenerPolicyHeaderWriter.class, () -> writer);
|
||||
this.headerWriters.add(builder.getBeanDefinition());
|
||||
}
|
||||
|
||||
private void parseCrossOriginEmbedderPolicy(boolean elementDisabled, Element element) {
|
||||
if (elementDisabled || element == null) {
|
||||
return;
|
||||
}
|
||||
CrossOriginEmbedderPolicyHeaderWriter writer = new CrossOriginEmbedderPolicyHeaderWriter();
|
||||
Element crossOriginEmbedderPolicyElement = DomUtils.getChildElementByTagName(element,
|
||||
CROSS_ORIGIN_EMBEDDER_POLICY_ELEMENT);
|
||||
if (crossOriginEmbedderPolicyElement != null) {
|
||||
addCrossOriginEmbedderPolicy(crossOriginEmbedderPolicyElement, writer);
|
||||
}
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(CrossOriginEmbedderPolicyHeaderWriter.class, () -> writer);
|
||||
this.headerWriters.add(builder.getBeanDefinition());
|
||||
}
|
||||
|
||||
private void parseCrossOriginResourcePolicy(boolean elementDisabled, Element element) {
|
||||
if (elementDisabled || element == null) {
|
||||
return;
|
||||
}
|
||||
CrossOriginResourcePolicyHeaderWriter writer = new CrossOriginResourcePolicyHeaderWriter();
|
||||
Element crossOriginResourcePolicyElement = DomUtils.getChildElementByTagName(element,
|
||||
CROSS_ORIGIN_RESOURCE_POLICY_ELEMENT);
|
||||
if (crossOriginResourcePolicyElement != null) {
|
||||
addCrossOriginResourcePolicy(crossOriginResourcePolicyElement, writer);
|
||||
}
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(CrossOriginResourcePolicyHeaderWriter.class, () -> writer);
|
||||
this.headerWriters.add(builder.getBeanDefinition());
|
||||
}
|
||||
|
||||
private void addCrossOriginResourcePolicy(Element crossOriginResourcePolicyElement,
|
||||
CrossOriginResourcePolicyHeaderWriter writer) {
|
||||
String policy = crossOriginResourcePolicyElement.getAttribute(ATT_POLICY);
|
||||
if (StringUtils.hasText(policy)) {
|
||||
writer.setPolicy(CrossOriginResourcePolicyHeaderWriter.CrossOriginResourcePolicy.from(policy));
|
||||
}
|
||||
}
|
||||
|
||||
private void addCrossOriginEmbedderPolicy(Element crossOriginEmbedderPolicyElement,
|
||||
CrossOriginEmbedderPolicyHeaderWriter writer) {
|
||||
String policy = crossOriginEmbedderPolicyElement.getAttribute(ATT_POLICY);
|
||||
if (StringUtils.hasText(policy)) {
|
||||
writer.setPolicy(CrossOriginEmbedderPolicyHeaderWriter.CrossOriginEmbedderPolicy.from(policy));
|
||||
}
|
||||
}
|
||||
|
||||
private void addCrossOriginOpenerPolicy(Element crossOriginOpenerPolicyElement,
|
||||
CrossOriginOpenerPolicyHeaderWriter writer) {
|
||||
String policy = crossOriginOpenerPolicyElement.getAttribute(ATT_POLICY);
|
||||
if (StringUtils.hasText(policy)) {
|
||||
writer.setPolicy(CrossOriginOpenerPolicyHeaderWriter.CrossOriginOpenerPolicy.from(policy));
|
||||
}
|
||||
}
|
||||
|
||||
private void attrNotAllowed(ParserContext context, String attrName, String otherAttrName, Element element) {
|
||||
context.getReaderContext().error("Only one of '" + attrName + "' or '" + otherAttrName + "' can be set.",
|
||||
element);
|
||||
|
||||
+198
-1
@@ -133,6 +133,7 @@ import org.springframework.security.web.server.authorization.AuthorizationContex
|
||||
import org.springframework.security.web.server.authorization.AuthorizationWebFilter;
|
||||
import org.springframework.security.web.server.authorization.DelegatingReactiveAuthorizationManager;
|
||||
import org.springframework.security.web.server.authorization.ExceptionTranslationWebFilter;
|
||||
import org.springframework.security.web.server.authorization.IpAddressReactiveAuthorizationManager;
|
||||
import org.springframework.security.web.server.authorization.ServerAccessDeniedHandler;
|
||||
import org.springframework.security.web.server.authorization.ServerWebExchangeDelegatingServerAccessDeniedHandler;
|
||||
import org.springframework.security.web.server.context.NoOpServerSecurityContextRepository;
|
||||
@@ -148,6 +149,12 @@ import org.springframework.security.web.server.header.CacheControlServerHttpHead
|
||||
import org.springframework.security.web.server.header.CompositeServerHttpHeadersWriter;
|
||||
import org.springframework.security.web.server.header.ContentSecurityPolicyServerHttpHeadersWriter;
|
||||
import org.springframework.security.web.server.header.ContentTypeOptionsServerHttpHeadersWriter;
|
||||
import org.springframework.security.web.server.header.CrossOriginEmbedderPolicyServerHttpHeadersWriter;
|
||||
import org.springframework.security.web.server.header.CrossOriginEmbedderPolicyServerHttpHeadersWriter.CrossOriginEmbedderPolicy;
|
||||
import org.springframework.security.web.server.header.CrossOriginOpenerPolicyServerHttpHeadersWriter;
|
||||
import org.springframework.security.web.server.header.CrossOriginOpenerPolicyServerHttpHeadersWriter.CrossOriginOpenerPolicy;
|
||||
import org.springframework.security.web.server.header.CrossOriginResourcePolicyServerHttpHeadersWriter;
|
||||
import org.springframework.security.web.server.header.CrossOriginResourcePolicyServerHttpHeadersWriter.CrossOriginResourcePolicy;
|
||||
import org.springframework.security.web.server.header.FeaturePolicyServerHttpHeadersWriter;
|
||||
import org.springframework.security.web.server.header.HttpHeaderWriterWebFilter;
|
||||
import org.springframework.security.web.server.header.PermissionsPolicyServerHttpHeadersWriter;
|
||||
@@ -1682,6 +1689,18 @@ public class ServerHttpSecurity {
|
||||
return access(AuthenticatedReactiveAuthorizationManager.authenticated());
|
||||
}
|
||||
|
||||
/**
|
||||
* Require a specific IP address or range using an IP/Netmask (e.g.
|
||||
* 192.168.1.0/24).
|
||||
* @param ipAddress the address or range of addresses from which the request
|
||||
* must come.
|
||||
* @return the {@link AuthorizeExchangeSpec} to configure
|
||||
* @since 5.7
|
||||
*/
|
||||
public AuthorizeExchangeSpec hasIpAddress(String ipAddress) {
|
||||
return access(IpAddressReactiveAuthorizationManager.hasIpAddress(ipAddress));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows plugging in a custom authorization strategy
|
||||
* @param manager the authorization manager to use
|
||||
@@ -2367,10 +2386,17 @@ public class ServerHttpSecurity {
|
||||
|
||||
private ReferrerPolicyServerHttpHeadersWriter referrerPolicy = new ReferrerPolicyServerHttpHeadersWriter();
|
||||
|
||||
private CrossOriginOpenerPolicyServerHttpHeadersWriter crossOriginOpenerPolicy = new CrossOriginOpenerPolicyServerHttpHeadersWriter();
|
||||
|
||||
private CrossOriginEmbedderPolicyServerHttpHeadersWriter crossOriginEmbedderPolicy = new CrossOriginEmbedderPolicyServerHttpHeadersWriter();
|
||||
|
||||
private CrossOriginResourcePolicyServerHttpHeadersWriter crossOriginResourcePolicy = new CrossOriginResourcePolicyServerHttpHeadersWriter();
|
||||
|
||||
private HeaderSpec() {
|
||||
this.writers = new ArrayList<>(Arrays.asList(this.cacheControl, this.contentTypeOptions, this.hsts,
|
||||
this.frameOptions, this.xss, this.featurePolicy, this.permissionsPolicy, this.contentSecurityPolicy,
|
||||
this.referrerPolicy));
|
||||
this.referrerPolicy, this.crossOriginOpenerPolicy, this.crossOriginEmbedderPolicy,
|
||||
this.crossOriginResourcePolicy));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2582,6 +2608,84 @@ public class ServerHttpSecurity {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the <a href=
|
||||
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy">
|
||||
* Cross-Origin-Opener-Policy</a> header.
|
||||
* @return the {@link CrossOriginOpenerPolicySpec} to configure
|
||||
* @since 5.7
|
||||
* @see CrossOriginOpenerPolicyServerHttpHeadersWriter
|
||||
*/
|
||||
public CrossOriginOpenerPolicySpec crossOriginOpenerPolicy() {
|
||||
return new CrossOriginOpenerPolicySpec();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the <a href=
|
||||
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy">
|
||||
* Cross-Origin-Opener-Policy</a> header.
|
||||
* @return the {@link HeaderSpec} to customize
|
||||
* @since 5.7
|
||||
* @see CrossOriginOpenerPolicyServerHttpHeadersWriter
|
||||
*/
|
||||
public HeaderSpec crossOriginOpenerPolicy(
|
||||
Customizer<CrossOriginOpenerPolicySpec> crossOriginOpenerPolicyCustomizer) {
|
||||
crossOriginOpenerPolicyCustomizer.customize(new CrossOriginOpenerPolicySpec());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the <a href=
|
||||
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy">
|
||||
* Cross-Origin-Embedder-Policy</a> header.
|
||||
* @return the {@link CrossOriginEmbedderPolicySpec} to configure
|
||||
* @since 5.7
|
||||
* @see CrossOriginEmbedderPolicyServerHttpHeadersWriter
|
||||
*/
|
||||
public CrossOriginEmbedderPolicySpec crossOriginEmbedderPolicy() {
|
||||
return new CrossOriginEmbedderPolicySpec();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the <a href=
|
||||
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy">
|
||||
* Cross-Origin-Embedder-Policy</a> header.
|
||||
* @return the {@link HeaderSpec} to customize
|
||||
* @since 5.7
|
||||
* @see CrossOriginEmbedderPolicyServerHttpHeadersWriter
|
||||
*/
|
||||
public HeaderSpec crossOriginEmbedderPolicy(
|
||||
Customizer<CrossOriginEmbedderPolicySpec> crossOriginEmbedderPolicyCustomizer) {
|
||||
crossOriginEmbedderPolicyCustomizer.customize(new CrossOriginEmbedderPolicySpec());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the <a href=
|
||||
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy">
|
||||
* Cross-Origin-Resource-Policy</a> header.
|
||||
* @return the {@link CrossOriginResourcePolicySpec} to configure
|
||||
* @since 5.7
|
||||
* @see CrossOriginResourcePolicyServerHttpHeadersWriter
|
||||
*/
|
||||
public CrossOriginResourcePolicySpec crossOriginResourcePolicy() {
|
||||
return new CrossOriginResourcePolicySpec();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the <a href=
|
||||
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy">
|
||||
* Cross-Origin-Resource-Policy</a> header.
|
||||
* @return the {@link HeaderSpec} to customize
|
||||
* @since 5.7
|
||||
* @see CrossOriginResourcePolicyServerHttpHeadersWriter
|
||||
*/
|
||||
public HeaderSpec crossOriginResourcePolicy(
|
||||
Customizer<CrossOriginResourcePolicySpec> crossOriginResourcePolicyCustomizer) {
|
||||
crossOriginResourcePolicyCustomizer.customize(new CrossOriginResourcePolicySpec());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures cache control headers
|
||||
*
|
||||
@@ -2897,6 +3001,99 @@ public class ServerHttpSecurity {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the Cross-Origin-Opener-Policy header
|
||||
*
|
||||
* @since 5.7
|
||||
*/
|
||||
public final class CrossOriginOpenerPolicySpec {
|
||||
|
||||
private CrossOriginOpenerPolicySpec() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value to be used in the `Cross-Origin-Opener-Policy` header
|
||||
* @param openerPolicy a opener policy
|
||||
* @return the {@link CrossOriginOpenerPolicySpec} to continue configuring
|
||||
*/
|
||||
public CrossOriginOpenerPolicySpec policy(CrossOriginOpenerPolicy openerPolicy) {
|
||||
HeaderSpec.this.crossOriginOpenerPolicy.setPolicy(openerPolicy);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows method chaining to continue configuring the
|
||||
* {@link ServerHttpSecurity}.
|
||||
* @return the {@link HeaderSpec} to continue configuring
|
||||
*/
|
||||
public HeaderSpec and() {
|
||||
return HeaderSpec.this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the Cross-Origin-Embedder-Policy header
|
||||
*
|
||||
* @since 5.7
|
||||
*/
|
||||
public final class CrossOriginEmbedderPolicySpec {
|
||||
|
||||
private CrossOriginEmbedderPolicySpec() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value to be used in the `Cross-Origin-Embedder-Policy` header
|
||||
* @param embedderPolicy a opener policy
|
||||
* @return the {@link CrossOriginEmbedderPolicySpec} to continue configuring
|
||||
*/
|
||||
public CrossOriginEmbedderPolicySpec policy(CrossOriginEmbedderPolicy embedderPolicy) {
|
||||
HeaderSpec.this.crossOriginEmbedderPolicy.setPolicy(embedderPolicy);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows method chaining to continue configuring the
|
||||
* {@link ServerHttpSecurity}.
|
||||
* @return the {@link HeaderSpec} to continue configuring
|
||||
*/
|
||||
public HeaderSpec and() {
|
||||
return HeaderSpec.this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the Cross-Origin-Resource-Policy header
|
||||
*
|
||||
* @since 5.7
|
||||
*/
|
||||
public final class CrossOriginResourcePolicySpec {
|
||||
|
||||
private CrossOriginResourcePolicySpec() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value to be used in the `Cross-Origin-Resource-Policy` header
|
||||
* @param resourcePolicy a opener policy
|
||||
* @return the {@link CrossOriginResourcePolicySpec} to continue configuring
|
||||
*/
|
||||
public CrossOriginResourcePolicySpec policy(CrossOriginResourcePolicy resourcePolicy) {
|
||||
HeaderSpec.this.crossOriginResourcePolicy.setPolicy(resourcePolicy);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows method chaining to continue configuring the
|
||||
* {@link ServerHttpSecurity}.
|
||||
* @return the {@link HeaderSpec} to continue configuring
|
||||
*/
|
||||
public HeaderSpec and() {
|
||||
return HeaderSpec.this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+9
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* 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.
|
||||
@@ -22,6 +22,7 @@ import org.springframework.security.authorization.AuthorizationDecision
|
||||
import org.springframework.security.authorization.ReactiveAuthorizationManager
|
||||
import org.springframework.security.core.Authentication
|
||||
import org.springframework.security.web.server.authorization.AuthorizationContext
|
||||
import org.springframework.security.web.server.authorization.IpAddressReactiveAuthorizationManager
|
||||
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher
|
||||
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher
|
||||
@@ -108,6 +109,13 @@ class AuthorizeExchangeDsl {
|
||||
fun hasAnyAuthority(vararg authorities: String): ReactiveAuthorizationManager<AuthorizationContext> =
|
||||
AuthorityReactiveAuthorizationManager.hasAnyAuthority<AuthorizationContext>(*authorities)
|
||||
|
||||
/**
|
||||
* Require a specific IP or range of IP addresses.
|
||||
* @since 5.7
|
||||
*/
|
||||
fun hasIpAddress(ipAddress: String): ReactiveAuthorizationManager<AuthorizationContext> =
|
||||
IpAddressReactiveAuthorizationManager.hasIpAddress(ipAddress)
|
||||
|
||||
/**
|
||||
* Require an authenticated user.
|
||||
*/
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.security.config.web.server
|
||||
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.web.server.header.CrossOriginEmbedderPolicyServerHttpHeadersWriter
|
||||
|
||||
/**
|
||||
* A Kotlin DSL to configure the [HttpSecurity] Cross-Origin-Embedder-Policy header using
|
||||
* idiomatic Kotlin code.
|
||||
*
|
||||
* @author Marcus Da Coregio
|
||||
* @since 5.7
|
||||
* @property policy the policy to be used in the response header.
|
||||
*/
|
||||
@ServerSecurityMarker
|
||||
class ServerCrossOriginEmbedderPolicyDsl {
|
||||
|
||||
var policy: CrossOriginEmbedderPolicyServerHttpHeadersWriter.CrossOriginEmbedderPolicy? = null
|
||||
|
||||
internal fun get(): (ServerHttpSecurity.HeaderSpec.CrossOriginEmbedderPolicySpec) -> Unit {
|
||||
return { crossOriginEmbedderPolicy ->
|
||||
policy?.also {
|
||||
crossOriginEmbedderPolicy.policy(policy)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.security.config.web.server
|
||||
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.web.server.header.CrossOriginOpenerPolicyServerHttpHeadersWriter
|
||||
|
||||
/**
|
||||
* A Kotlin DSL to configure the [HttpSecurity] Cross-Origin-Opener-Policy header using
|
||||
* idiomatic Kotlin code.
|
||||
*
|
||||
* @author Marcus Da Coregio
|
||||
* @since 5.7
|
||||
* @property policy the policy to be used in the response header.
|
||||
*/
|
||||
@ServerSecurityMarker
|
||||
class ServerCrossOriginOpenerPolicyDsl {
|
||||
|
||||
var policy: CrossOriginOpenerPolicyServerHttpHeadersWriter.CrossOriginOpenerPolicy? = null
|
||||
|
||||
internal fun get(): (ServerHttpSecurity.HeaderSpec.CrossOriginOpenerPolicySpec) -> Unit {
|
||||
return { crossOriginOpenerPolicy ->
|
||||
policy?.also {
|
||||
crossOriginOpenerPolicy.policy(policy)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.security.config.web.server
|
||||
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.web.server.header.CrossOriginResourcePolicyServerHttpHeadersWriter
|
||||
|
||||
/**
|
||||
* A Kotlin DSL to configure the [HttpSecurity] Cross-Origin-Resource-Policy header using
|
||||
* idiomatic Kotlin code.
|
||||
*
|
||||
* @author Marcus Da Coregio
|
||||
* @since 5.7
|
||||
* @property policy the policy to be used in the response header.
|
||||
*/
|
||||
@ServerSecurityMarker
|
||||
class ServerCrossOriginResourcePolicyDsl {
|
||||
|
||||
var policy: CrossOriginResourcePolicyServerHttpHeadersWriter.CrossOriginResourcePolicy? = null
|
||||
|
||||
internal fun get(): (ServerHttpSecurity.HeaderSpec.CrossOriginResourcePolicySpec) -> Unit {
|
||||
return { crossOriginResourcePolicy ->
|
||||
policy?.also {
|
||||
crossOriginResourcePolicy.policy(policy)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+51
-1
@@ -16,7 +16,12 @@
|
||||
|
||||
package org.springframework.security.config.web.server
|
||||
|
||||
import org.springframework.security.web.server.header.*
|
||||
import org.springframework.security.web.server.header.CacheControlServerHttpHeadersWriter
|
||||
import org.springframework.security.web.server.header.ContentTypeOptionsServerHttpHeadersWriter
|
||||
import org.springframework.security.web.server.header.ReferrerPolicyServerHttpHeadersWriter
|
||||
import org.springframework.security.web.server.header.StrictTransportSecurityServerHttpHeadersWriter
|
||||
import org.springframework.security.web.server.header.XFrameOptionsServerHttpHeadersWriter
|
||||
import org.springframework.security.web.server.header.XXssProtectionServerHttpHeadersWriter
|
||||
|
||||
/**
|
||||
* A Kotlin DSL to configure [ServerHttpSecurity] headers using idiomatic Kotlin code.
|
||||
@@ -35,6 +40,9 @@ class ServerHeadersDsl {
|
||||
private var referrerPolicy: ((ServerHttpSecurity.HeaderSpec.ReferrerPolicySpec) -> Unit)? = null
|
||||
private var featurePolicyDirectives: String? = null
|
||||
private var permissionsPolicy: ((ServerHttpSecurity.HeaderSpec.PermissionsPolicySpec) -> Unit)? = null
|
||||
private var crossOriginOpenerPolicy: ((ServerHttpSecurity.HeaderSpec.CrossOriginOpenerPolicySpec) -> Unit)? = null
|
||||
private var crossOriginEmbedderPolicy: ((ServerHttpSecurity.HeaderSpec.CrossOriginEmbedderPolicySpec) -> Unit)? = null
|
||||
private var crossOriginResourcePolicy: ((ServerHttpSecurity.HeaderSpec.CrossOriginResourcePolicySpec) -> Unit)? = null
|
||||
|
||||
private var disabled = false
|
||||
|
||||
@@ -157,6 +165,39 @@ class ServerHeadersDsl {
|
||||
this.permissionsPolicy = ServerPermissionsPolicyDsl().apply(permissionsPolicyConfig).get()
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuration for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy">
|
||||
* Cross-Origin-Opener-Policy</a> header.
|
||||
*
|
||||
* @since 5.7
|
||||
* @param crossOriginOpenerPolicyConfig the customization to apply to the header
|
||||
*/
|
||||
fun crossOriginOpenerPolicy(crossOriginOpenerPolicyConfig: ServerCrossOriginOpenerPolicyDsl.() -> Unit) {
|
||||
this.crossOriginOpenerPolicy = ServerCrossOriginOpenerPolicyDsl().apply(crossOriginOpenerPolicyConfig).get()
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuration for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy">
|
||||
* Cross-Origin-Embedder-Policy</a> header.
|
||||
*
|
||||
* @since 5.7
|
||||
* @param crossOriginEmbedderPolicyConfig the customization to apply to the header
|
||||
*/
|
||||
fun crossOriginEmbedderPolicy(crossOriginEmbedderPolicyConfig: ServerCrossOriginEmbedderPolicyDsl.() -> Unit) {
|
||||
this.crossOriginEmbedderPolicy = ServerCrossOriginEmbedderPolicyDsl().apply(crossOriginEmbedderPolicyConfig).get()
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuration for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy">
|
||||
* Cross-Origin-Resource-Policy</a> header.
|
||||
*
|
||||
* @since 5.7
|
||||
* @param crossOriginResourcePolicyConfig the customization to apply to the header
|
||||
*/
|
||||
fun crossOriginResourcePolicy(crossOriginResourcePolicyConfig: ServerCrossOriginResourcePolicyDsl.() -> Unit) {
|
||||
this.crossOriginResourcePolicy = ServerCrossOriginResourcePolicyDsl().apply(crossOriginResourcePolicyConfig).get()
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables HTTP response headers.
|
||||
*/
|
||||
@@ -194,6 +235,15 @@ class ServerHeadersDsl {
|
||||
referrerPolicy?.also {
|
||||
headers.referrerPolicy(referrerPolicy)
|
||||
}
|
||||
crossOriginOpenerPolicy?.also {
|
||||
headers.crossOriginOpenerPolicy(crossOriginOpenerPolicy)
|
||||
}
|
||||
crossOriginEmbedderPolicy?.also {
|
||||
headers.crossOriginEmbedderPolicy(crossOriginEmbedderPolicy)
|
||||
}
|
||||
crossOriginResourcePolicy?.also {
|
||||
headers.crossOriginResourcePolicy(crossOriginResourcePolicy)
|
||||
}
|
||||
if (disabled) {
|
||||
headers.disable()
|
||||
}
|
||||
|
||||
@@ -42,6 +42,9 @@ class HeadersDsl {
|
||||
private var referrerPolicy: ((HeadersConfigurer<HttpSecurity>.ReferrerPolicyConfig) -> Unit)? = null
|
||||
private var featurePolicyDirectives: String? = null
|
||||
private var permissionsPolicy: ((HeadersConfigurer<HttpSecurity>.PermissionsPolicyConfig) -> Unit)? = null
|
||||
private var crossOriginOpenerPolicy: ((HeadersConfigurer<HttpSecurity>.CrossOriginOpenerPolicyConfig) -> Unit)? = null
|
||||
private var crossOriginEmbedderPolicy: ((HeadersConfigurer<HttpSecurity>.CrossOriginEmbedderPolicyConfig) -> Unit)? = null
|
||||
private var crossOriginResourcePolicy: ((HeadersConfigurer<HttpSecurity>.CrossOriginResourcePolicyConfig) -> Unit)? = null
|
||||
private var disabled = false
|
||||
private var headerWriters = mutableListOf<HeaderWriter>()
|
||||
|
||||
@@ -181,6 +184,54 @@ class HeadersDsl {
|
||||
this.permissionsPolicy = PermissionsPolicyDsl().apply(permissionsPolicyConfig).get()
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuration for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy">
|
||||
* Cross-Origin-Opener-Policy</a> header.
|
||||
*
|
||||
* <p>
|
||||
* Calling this method automatically enables (includes) the Cross-Origin-Opener-Policy
|
||||
* header in the response using the supplied policy.
|
||||
* <p>
|
||||
*
|
||||
* @since 5.7
|
||||
* @param crossOriginOpenerPolicyConfig the customization to apply to the header
|
||||
*/
|
||||
fun crossOriginOpenerPolicy(crossOriginOpenerPolicyConfig: CrossOriginOpenerPolicyDsl.() -> Unit) {
|
||||
this.crossOriginOpenerPolicy = CrossOriginOpenerPolicyDsl().apply(crossOriginOpenerPolicyConfig).get()
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuration for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy">
|
||||
* Cross-Origin-Embedder-Policy</a> header.
|
||||
*
|
||||
* <p>
|
||||
* Calling this method automatically enables (includes) the Cross-Origin-Embedder-Policy
|
||||
* header in the response using the supplied policy.
|
||||
* <p>
|
||||
*
|
||||
* @since 5.7
|
||||
* @param crossOriginEmbedderPolicyConfig the customization to apply to the header
|
||||
*/
|
||||
fun crossOriginEmbedderPolicy(crossOriginEmbedderPolicyConfig: CrossOriginEmbedderPolicyDsl.() -> Unit) {
|
||||
this.crossOriginEmbedderPolicy = CrossOriginEmbedderPolicyDsl().apply(crossOriginEmbedderPolicyConfig).get()
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy">
|
||||
* Cross-Origin-Resource-Policy</a> header.
|
||||
*
|
||||
* <p>
|
||||
* Calling this method automatically enables (includes) the Cross-Origin-Resource-Policy
|
||||
* header in the response using the supplied policy.
|
||||
* <p>
|
||||
*
|
||||
* @since 5.7
|
||||
* @param crossOriginResourcePolicyConfig the customization to apply to the header
|
||||
*/
|
||||
fun crossOriginResourcePolicy(crossOriginResourcePolicyConfig: CrossOriginResourcePolicyDsl.() -> Unit) {
|
||||
this.crossOriginResourcePolicy = CrossOriginResourcePolicyDsl().apply(crossOriginResourcePolicyConfig).get()
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a [HeaderWriter] instance.
|
||||
*
|
||||
@@ -238,6 +289,15 @@ class HeadersDsl {
|
||||
permissionsPolicy?.also {
|
||||
headers.permissionsPolicy(permissionsPolicy)
|
||||
}
|
||||
crossOriginOpenerPolicy?.also {
|
||||
headers.crossOriginOpenerPolicy(crossOriginOpenerPolicy)
|
||||
}
|
||||
crossOriginEmbedderPolicy?.also {
|
||||
headers.crossOriginEmbedderPolicy(crossOriginEmbedderPolicy)
|
||||
}
|
||||
crossOriginResourcePolicy?.also {
|
||||
headers.crossOriginResourcePolicy(crossOriginResourcePolicy)
|
||||
}
|
||||
headerWriters.forEach { headerWriter ->
|
||||
headers.addHeaderWriter(headerWriter)
|
||||
}
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.security.config.web.servlet.headers
|
||||
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer
|
||||
import org.springframework.security.web.header.writers.CrossOriginEmbedderPolicyHeaderWriter
|
||||
|
||||
/**
|
||||
* A Kotlin DSL to configure the [HttpSecurity] Cross-Origin-Embedder-Policy header using
|
||||
* idiomatic Kotlin code.
|
||||
*
|
||||
* @author Marcus Da Coregio
|
||||
* @since 5.7
|
||||
* @property policy the policy to be used in the response header.
|
||||
*/
|
||||
@HeadersSecurityMarker
|
||||
class CrossOriginEmbedderPolicyDsl {
|
||||
|
||||
var policy: CrossOriginEmbedderPolicyHeaderWriter.CrossOriginEmbedderPolicy? = null
|
||||
|
||||
internal fun get(): (HeadersConfigurer<HttpSecurity>.CrossOriginEmbedderPolicyConfig) -> Unit {
|
||||
return { crossOriginEmbedderPolicy ->
|
||||
policy?.also {
|
||||
crossOriginEmbedderPolicy.policy(policy)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.security.config.web.servlet.headers
|
||||
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer
|
||||
import org.springframework.security.web.header.writers.CrossOriginOpenerPolicyHeaderWriter
|
||||
|
||||
/**
|
||||
* A Kotlin DSL to configure the [HttpSecurity] Cross-Origin-Opener-Policy header using
|
||||
* idiomatic Kotlin code.
|
||||
*
|
||||
* @author Marcus Da Coregio
|
||||
* @since 5.7
|
||||
* @property policy the policy to be used in the response header.
|
||||
*/
|
||||
@HeadersSecurityMarker
|
||||
class CrossOriginOpenerPolicyDsl {
|
||||
|
||||
var policy: CrossOriginOpenerPolicyHeaderWriter.CrossOriginOpenerPolicy? = null
|
||||
|
||||
internal fun get(): (HeadersConfigurer<HttpSecurity>.CrossOriginOpenerPolicyConfig) -> Unit {
|
||||
return { crossOriginOpenerPolicy ->
|
||||
policy?.also {
|
||||
crossOriginOpenerPolicy.policy(policy)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.security.config.web.servlet.headers
|
||||
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer
|
||||
import org.springframework.security.web.header.writers.CrossOriginResourcePolicyHeaderWriter
|
||||
|
||||
/**
|
||||
* A Kotlin DSL to configure the [HttpSecurity] Cross-Origin-Resource-Policy header using
|
||||
* idiomatic Kotlin code.
|
||||
*
|
||||
* @author Marcus Da Coregio
|
||||
* @since 5.7
|
||||
* @property policy the policy to be used in the response header.
|
||||
*/
|
||||
@HeadersSecurityMarker
|
||||
class CrossOriginResourcePolicyDsl {
|
||||
|
||||
var policy: CrossOriginResourcePolicyHeaderWriter.CrossOriginResourcePolicy? = null
|
||||
|
||||
internal fun get(): (HeadersConfigurer<HttpSecurity>.CrossOriginResourcePolicyConfig) -> Unit {
|
||||
return { crossOriginResourcePolicy ->
|
||||
policy?.also {
|
||||
crossOriginResourcePolicy.policy(policy)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-5.6.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-5.7.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-5.7.xsd=org/springframework/security/config/spring-security-5.7.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-5.6.xsd=org/springframework/security/config/spring-security-5.6.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-5.5.xsd=org/springframework/security/config/spring-security-5.5.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-5.4.xsd=org/springframework/security/config/spring-security-5.4.xsd
|
||||
@@ -17,7 +18,8 @@ http\://www.springframework.org/schema/security/spring-security-2.0.xsd=org/spri
|
||||
http\://www.springframework.org/schema/security/spring-security-2.0.1.xsd=org/springframework/security/config/spring-security-2.0.1.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-2.0.2.xsd=org/springframework/security/config/spring-security-2.0.2.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-2.0.4.xsd=org/springframework/security/config/spring-security-2.0.4.xsd
|
||||
https\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-5.6.xsd
|
||||
https\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-5.7.xsd
|
||||
https\://www.springframework.org/schema/security/spring-security-5.7.xsd=org/springframework/security/config/spring-security-5.7.xsd
|
||||
https\://www.springframework.org/schema/security/spring-security-5.6.xsd=org/springframework/security/config/spring-security-5.6.xsd
|
||||
https\://www.springframework.org/schema/security/spring-security-5.5.xsd=org/springframework/security/config/spring-security-5.5.xsd
|
||||
https\://www.springframework.org/schema/security/spring-security-5.4.xsd=org/springframework/security/config/spring-security-5.4.xsd
|
||||
|
||||
+1151
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user