198 changed files with 49 additions and 4872 deletions
@ -0,0 +1,11 @@
@@ -0,0 +1,11 @@
|
||||
spring: |
||||
main: |
||||
banner-mode: off |
||||
sonatype: |
||||
exclude: |
||||
- "build-info\.json" |
||||
- "org/springframework/boot/spring-boot-docs/.*" |
||||
sdkman: |
||||
artifact: "org.springframework.boot:spring-boot-cli:*:zip:bin" |
||||
broadcast-url: "https://github.com/spring-projects/spring-boot/releases/v%s" |
||||
candidate: "springboot" |
||||
@ -1,7 +0,0 @@
@@ -1,7 +0,0 @@
|
||||
#!/bin/bash |
||||
set -ex |
||||
|
||||
pushd /release-scripts |
||||
./mvnw clean install |
||||
popd |
||||
cp /release-scripts/target/spring-boot-release-scripts.jar . |
||||
@ -1,31 +0,0 @@
@@ -1,31 +0,0 @@
|
||||
HELP.md |
||||
target/ |
||||
!.mvn/wrapper/maven-wrapper.jar |
||||
!**/src/main/** |
||||
!**/src/test/** |
||||
|
||||
### STS ### |
||||
.apt_generated |
||||
.classpath |
||||
.factorypath |
||||
.project |
||||
.settings |
||||
.springBeans |
||||
.sts4-cache |
||||
|
||||
### IntelliJ IDEA ### |
||||
.idea |
||||
*.iws |
||||
*.iml |
||||
*.ipr |
||||
|
||||
### NetBeans ### |
||||
/nbproject/private/ |
||||
/nbbuild/ |
||||
/dist/ |
||||
/nbdist/ |
||||
/.nb-gradle/ |
||||
build/ |
||||
|
||||
### VS Code ### |
||||
.vscode/ |
||||
@ -1,118 +0,0 @@
@@ -1,118 +0,0 @@
|
||||
/* |
||||
Licensed to the Apache Software Foundation (ASF) under one |
||||
or more contributor license agreements. See the NOTICE file |
||||
distributed with this work for additional information |
||||
regarding copyright ownership. The ASF licenses this file |
||||
to you 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. |
||||
*/ |
||||
|
||||
import java.io.File; |
||||
import java.io.FileInputStream; |
||||
import java.io.FileOutputStream; |
||||
import java.io.IOException; |
||||
import java.net.URL; |
||||
import java.nio.channels.Channels; |
||||
import java.nio.channels.ReadableByteChannel; |
||||
import java.util.Properties; |
||||
|
||||
public class MavenWrapperDownloader { |
||||
|
||||
/** |
||||
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. |
||||
*/ |
||||
private static final String DEFAULT_DOWNLOAD_URL = |
||||
"https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; |
||||
|
||||
/** |
||||
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to |
||||
* use instead of the default one. |
||||
*/ |
||||
private static final String MAVEN_WRAPPER_PROPERTIES_PATH = |
||||
".mvn/wrapper/maven-wrapper.properties"; |
||||
|
||||
/** |
||||
* Path where the maven-wrapper.jar will be saved to. |
||||
*/ |
||||
private static final String MAVEN_WRAPPER_JAR_PATH = |
||||
".mvn/wrapper/maven-wrapper.jar"; |
||||
|
||||
/** |
||||
* Name of the property which should be used to override the default download url for the wrapper. |
||||
*/ |
||||
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; |
||||
|
||||
public static void main(String args[]) { |
||||
System.out.println("- Downloader started"); |
||||
File baseDirectory = new File(args[0]); |
||||
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); |
||||
|
||||
// If the maven-wrapper.properties exists, read it and check if it contains a custom
|
||||
// wrapperUrl parameter.
|
||||
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); |
||||
String url = DEFAULT_DOWNLOAD_URL; |
||||
if (mavenWrapperPropertyFile.exists()) { |
||||
FileInputStream mavenWrapperPropertyFileInputStream = null; |
||||
try { |
||||
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); |
||||
Properties mavenWrapperProperties = new Properties(); |
||||
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); |
||||
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); |
||||
} |
||||
catch (IOException e) { |
||||
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); |
||||
} |
||||
finally { |
||||
try { |
||||
if (mavenWrapperPropertyFileInputStream != null) { |
||||
mavenWrapperPropertyFileInputStream.close(); |
||||
} |
||||
} |
||||
catch (IOException e) { |
||||
// Ignore ...
|
||||
} |
||||
} |
||||
} |
||||
System.out.println("- Downloading from: : " + url); |
||||
|
||||
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); |
||||
if (!outputFile.getParentFile().exists()) { |
||||
if (!outputFile.getParentFile().mkdirs()) { |
||||
System.out.println( |
||||
"- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); |
||||
} |
||||
} |
||||
System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); |
||||
try { |
||||
downloadFileFromURL(url, outputFile); |
||||
System.out.println("Done"); |
||||
System.exit(0); |
||||
} |
||||
catch (Throwable e) { |
||||
System.out.println("- Error downloading"); |
||||
e.printStackTrace(); |
||||
System.exit(1); |
||||
} |
||||
} |
||||
|
||||
private static void downloadFileFromURL(String urlString, File destination) throws Exception { |
||||
URL website = new URL(urlString); |
||||
ReadableByteChannel rbc; |
||||
rbc = Channels.newChannel(website.openStream()); |
||||
FileOutputStream fos = new FileOutputStream(destination); |
||||
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); |
||||
fos.close(); |
||||
rbc.close(); |
||||
} |
||||
|
||||
} |
||||
Binary file not shown.
@ -1,17 +0,0 @@
@@ -1,17 +0,0 @@
|
||||
# |
||||
# Copyright 2012-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. |
||||
# 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. |
||||
# |
||||
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip |
||||
@ -1,286 +0,0 @@
@@ -1,286 +0,0 @@
|
||||
#!/bin/sh |
||||
# ---------------------------------------------------------------------------- |
||||
# Licensed to the Apache Software Foundation (ASF) under one |
||||
# or more contributor license agreements. See the NOTICE file |
||||
# distributed with this work for additional information |
||||
# regarding copyright ownership. The ASF licenses this file |
||||
# to you 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. |
||||
# ---------------------------------------------------------------------------- |
||||
|
||||
# ---------------------------------------------------------------------------- |
||||
# Maven2 Start Up Batch script |
||||
# |
||||
# Required ENV vars: |
||||
# ------------------ |
||||
# JAVA_HOME - location of a JDK home dir |
||||
# |
||||
# Optional ENV vars |
||||
# ----------------- |
||||
# M2_HOME - location of maven2's installed home dir |
||||
# MAVEN_OPTS - parameters passed to the Java VM when running Maven |
||||
# e.g. to debug Maven itself, use |
||||
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 |
||||
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files |
||||
# ---------------------------------------------------------------------------- |
||||
|
||||
if [ -z "$MAVEN_SKIP_RC" ] ; then |
||||
|
||||
if [ -f /etc/mavenrc ] ; then |
||||
. /etc/mavenrc |
||||
fi |
||||
|
||||
if [ -f "$HOME/.mavenrc" ] ; then |
||||
. "$HOME/.mavenrc" |
||||
fi |
||||
|
||||
fi |
||||
|
||||
# OS specific support. $var _must_ be set to either true or false. |
||||
cygwin=false; |
||||
darwin=false; |
||||
mingw=false |
||||
case "`uname`" in |
||||
CYGWIN*) cygwin=true ;; |
||||
MINGW*) mingw=true;; |
||||
Darwin*) darwin=true |
||||
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home |
||||
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html |
||||
if [ -z "$JAVA_HOME" ]; then |
||||
if [ -x "/usr/libexec/java_home" ]; then |
||||
export JAVA_HOME="`/usr/libexec/java_home`" |
||||
else |
||||
export JAVA_HOME="/Library/Java/Home" |
||||
fi |
||||
fi |
||||
;; |
||||
esac |
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then |
||||
if [ -r /etc/gentoo-release ] ; then |
||||
JAVA_HOME=`java-config --jre-home` |
||||
fi |
||||
fi |
||||
|
||||
if [ -z "$M2_HOME" ] ; then |
||||
## resolve links - $0 may be a link to maven's home |
||||
PRG="$0" |
||||
|
||||
# need this for relative symlinks |
||||
while [ -h "$PRG" ] ; do |
||||
ls=`ls -ld "$PRG"` |
||||
link=`expr "$ls" : '.*-> \(.*\)$'` |
||||
if expr "$link" : '/.*' > /dev/null; then |
||||
PRG="$link" |
||||
else |
||||
PRG="`dirname "$PRG"`/$link" |
||||
fi |
||||
done |
||||
|
||||
saveddir=`pwd` |
||||
|
||||
M2_HOME=`dirname "$PRG"`/.. |
||||
|
||||
# make it fully qualified |
||||
M2_HOME=`cd "$M2_HOME" && pwd` |
||||
|
||||
cd "$saveddir" |
||||
# echo Using m2 at $M2_HOME |
||||
fi |
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched |
||||
if $cygwin ; then |
||||
[ -n "$M2_HOME" ] && |
||||
M2_HOME=`cygpath --unix "$M2_HOME"` |
||||
[ -n "$JAVA_HOME" ] && |
||||
JAVA_HOME=`cygpath --unix "$JAVA_HOME"` |
||||
[ -n "$CLASSPATH" ] && |
||||
CLASSPATH=`cygpath --path --unix "$CLASSPATH"` |
||||
fi |
||||
|
||||
# For Mingw, ensure paths are in UNIX format before anything is touched |
||||
if $mingw ; then |
||||
[ -n "$M2_HOME" ] && |
||||
M2_HOME="`(cd "$M2_HOME"; pwd)`" |
||||
[ -n "$JAVA_HOME" ] && |
||||
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" |
||||
# TODO classpath? |
||||
fi |
||||
|
||||
if [ -z "$JAVA_HOME" ]; then |
||||
javaExecutable="`which javac`" |
||||
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then |
||||
# readlink(1) is not available as standard on Solaris 10. |
||||
readLink=`which readlink` |
||||
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then |
||||
if $darwin ; then |
||||
javaHome="`dirname \"$javaExecutable\"`" |
||||
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" |
||||
else |
||||
javaExecutable="`readlink -f \"$javaExecutable\"`" |
||||
fi |
||||
javaHome="`dirname \"$javaExecutable\"`" |
||||
javaHome=`expr "$javaHome" : '\(.*\)/bin'` |
||||
JAVA_HOME="$javaHome" |
||||
export JAVA_HOME |
||||
fi |
||||
fi |
||||
fi |
||||
|
||||
if [ -z "$JAVACMD" ] ; then |
||||
if [ -n "$JAVA_HOME" ] ; then |
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then |
||||
# IBM's JDK on AIX uses strange locations for the executables |
||||
JAVACMD="$JAVA_HOME/jre/sh/java" |
||||
else |
||||
JAVACMD="$JAVA_HOME/bin/java" |
||||
fi |
||||
else |
||||
JAVACMD="`which java`" |
||||
fi |
||||
fi |
||||
|
||||
if [ ! -x "$JAVACMD" ] ; then |
||||
echo "Error: JAVA_HOME is not defined correctly." >&2 |
||||
echo " We cannot execute $JAVACMD" >&2 |
||||
exit 1 |
||||
fi |
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then |
||||
echo "Warning: JAVA_HOME environment variable is not set." |
||||
fi |
||||
|
||||
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher |
||||
|
||||
# traverses directory structure from process work directory to filesystem root |
||||
# first directory with .mvn subdirectory is considered project base directory |
||||
find_maven_basedir() { |
||||
|
||||
if [ -z "$1" ] |
||||
then |
||||
echo "Path not specified to find_maven_basedir" |
||||
return 1 |
||||
fi |
||||
|
||||
basedir="$1" |
||||
wdir="$1" |
||||
while [ "$wdir" != '/' ] ; do |
||||
if [ -d "$wdir"/.mvn ] ; then |
||||
basedir=$wdir |
||||
break |
||||
fi |
||||
# workaround for JBEAP-8937 (on Solaris 10/Sparc) |
||||
if [ -d "${wdir}" ]; then |
||||
wdir=`cd "$wdir/.."; pwd` |
||||
fi |
||||
# end of workaround |
||||
done |
||||
echo "${basedir}" |
||||
} |
||||
|
||||
# concatenates all lines of a file |
||||
concat_lines() { |
||||
if [ -f "$1" ]; then |
||||
echo "$(tr -s '\n' ' ' < "$1")" |
||||
fi |
||||
} |
||||
|
||||
BASE_DIR=`find_maven_basedir "$(pwd)"` |
||||
if [ -z "$BASE_DIR" ]; then |
||||
exit 1; |
||||
fi |
||||
|
||||
########################################################################################## |
||||
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central |
||||
# This allows using the maven wrapper in projects that prohibit checking in binary data. |
||||
########################################################################################## |
||||
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then |
||||
if [ "$MVNW_VERBOSE" = true ]; then |
||||
echo "Found .mvn/wrapper/maven-wrapper.jar" |
||||
fi |
||||
else |
||||
if [ "$MVNW_VERBOSE" = true ]; then |
||||
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." |
||||
fi |
||||
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" |
||||
while IFS="=" read key value; do |
||||
case "$key" in (wrapperUrl) jarUrl="$value"; break ;; |
||||
esac |
||||
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" |
||||
if [ "$MVNW_VERBOSE" = true ]; then |
||||
echo "Downloading from: $jarUrl" |
||||
fi |
||||
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" |
||||
|
||||
if command -v wget > /dev/null; then |
||||
if [ "$MVNW_VERBOSE" = true ]; then |
||||
echo "Found wget ... using wget" |
||||
fi |
||||
wget "$jarUrl" -O "$wrapperJarPath" |
||||
elif command -v curl > /dev/null; then |
||||
if [ "$MVNW_VERBOSE" = true ]; then |
||||
echo "Found curl ... using curl" |
||||
fi |
||||
curl -o "$wrapperJarPath" "$jarUrl" |
||||
else |
||||
if [ "$MVNW_VERBOSE" = true ]; then |
||||
echo "Falling back to using Java to download" |
||||
fi |
||||
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" |
||||
if [ -e "$javaClass" ]; then |
||||
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then |
||||
if [ "$MVNW_VERBOSE" = true ]; then |
||||
echo " - Compiling MavenWrapperDownloader.java ..." |
||||
fi |
||||
# Compiling the Java class |
||||
("$JAVA_HOME/bin/javac" "$javaClass") |
||||
fi |
||||
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then |
||||
# Running the downloader |
||||
if [ "$MVNW_VERBOSE" = true ]; then |
||||
echo " - Running MavenWrapperDownloader.java ..." |
||||
fi |
||||
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") |
||||
fi |
||||
fi |
||||
fi |
||||
fi |
||||
########################################################################################## |
||||
# End of extension |
||||
########################################################################################## |
||||
|
||||
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} |
||||
if [ "$MVNW_VERBOSE" = true ]; then |
||||
echo $MAVEN_PROJECTBASEDIR |
||||
fi |
||||
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" |
||||
|
||||
# For Cygwin, switch paths to Windows format before running java |
||||
if $cygwin; then |
||||
[ -n "$M2_HOME" ] && |
||||
M2_HOME=`cygpath --path --windows "$M2_HOME"` |
||||
[ -n "$JAVA_HOME" ] && |
||||
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` |
||||
[ -n "$CLASSPATH" ] && |
||||
CLASSPATH=`cygpath --path --windows "$CLASSPATH"` |
||||
[ -n "$MAVEN_PROJECTBASEDIR" ] && |
||||
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` |
||||
fi |
||||
|
||||
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain |
||||
|
||||
exec "$JAVACMD" \ |
||||
$MAVEN_OPTS \ |
||||
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ |
||||
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ |
||||
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" |
||||
@ -1,161 +0,0 @@
@@ -1,161 +0,0 @@
|
||||
@REM ---------------------------------------------------------------------------- |
||||
@REM Licensed to the Apache Software Foundation (ASF) under one |
||||
@REM or more contributor license agreements. See the NOTICE file |
||||
@REM distributed with this work for additional information |
||||
@REM regarding copyright ownership. The ASF licenses this file |
||||
@REM to you under the Apache License, Version 2.0 (the |
||||
@REM "License"); you may not use this file except in compliance |
||||
@REM with the License. You may obtain a copy of the License at |
||||
@REM |
||||
@REM https://www.apache.org/licenses/LICENSE-2.0 |
||||
@REM |
||||
@REM Unless required by applicable law or agreed to in writing, |
||||
@REM software distributed under the License is distributed on an |
||||
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
||||
@REM KIND, either express or implied. See the License for the |
||||
@REM specific language governing permissions and limitations |
||||
@REM under the License. |
||||
@REM ---------------------------------------------------------------------------- |
||||
|
||||
@REM ---------------------------------------------------------------------------- |
||||
@REM Maven2 Start Up Batch script |
||||
@REM |
||||
@REM Required ENV vars: |
||||
@REM JAVA_HOME - location of a JDK home dir |
||||
@REM |
||||
@REM Optional ENV vars |
||||
@REM M2_HOME - location of maven2's installed home dir |
||||
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands |
||||
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending |
||||
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven |
||||
@REM e.g. to debug Maven itself, use |
||||
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 |
||||
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files |
||||
@REM ---------------------------------------------------------------------------- |
||||
|
||||
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' |
||||
@echo off |
||||
@REM set title of command window |
||||
title %0 |
||||
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' |
||||
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% |
||||
|
||||
@REM set %HOME% to equivalent of $HOME |
||||
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") |
||||
|
||||
@REM Execute a user defined script before this one |
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre |
||||
@REM check for pre script, once with legacy .bat ending and once with .cmd ending |
||||
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" |
||||
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" |
||||
:skipRcPre |
||||
|
||||
@setlocal |
||||
|
||||
set ERROR_CODE=0 |
||||
|
||||
@REM To isolate internal variables from possible post scripts, we use another setlocal |
||||
@setlocal |
||||
|
||||
@REM ==== START VALIDATION ==== |
||||
if not "%JAVA_HOME%" == "" goto OkJHome |
||||
|
||||
echo. |
||||
echo Error: JAVA_HOME not found in your environment. >&2 |
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2 |
||||
echo location of your Java installation. >&2 |
||||
echo. |
||||
goto error |
||||
|
||||
:OkJHome |
||||
if exist "%JAVA_HOME%\bin\java.exe" goto init |
||||
|
||||
echo. |
||||
echo Error: JAVA_HOME is set to an invalid directory. >&2 |
||||
echo JAVA_HOME = "%JAVA_HOME%" >&2 |
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2 |
||||
echo location of your Java installation. >&2 |
||||
echo. |
||||
goto error |
||||
|
||||
@REM ==== END VALIDATION ==== |
||||
|
||||
:init |
||||
|
||||
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". |
||||
@REM Fallback to current working directory if not found. |
||||
|
||||
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% |
||||
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir |
||||
|
||||
set EXEC_DIR=%CD% |
||||
set WDIR=%EXEC_DIR% |
||||
:findBaseDir |
||||
IF EXIST "%WDIR%"\.mvn goto baseDirFound |
||||
cd .. |
||||
IF "%WDIR%"=="%CD%" goto baseDirNotFound |
||||
set WDIR=%CD% |
||||
goto findBaseDir |
||||
|
||||
:baseDirFound |
||||
set MAVEN_PROJECTBASEDIR=%WDIR% |
||||
cd "%EXEC_DIR%" |
||||
goto endDetectBaseDir |
||||
|
||||
:baseDirNotFound |
||||
set MAVEN_PROJECTBASEDIR=%EXEC_DIR% |
||||
cd "%EXEC_DIR%" |
||||
|
||||
:endDetectBaseDir |
||||
|
||||
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig |
||||
|
||||
@setlocal EnableExtensions EnableDelayedExpansion |
||||
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a |
||||
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% |
||||
|
||||
:endReadAdditionalConfig |
||||
|
||||
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" |
||||
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" |
||||
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain |
||||
|
||||
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" |
||||
FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( |
||||
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B |
||||
) |
||||
|
||||
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central |
||||
@REM This allows using the maven wrapper in projects that prohibit checking in binary data. |
||||
if exist %WRAPPER_JAR% ( |
||||
echo Found %WRAPPER_JAR% |
||||
) else ( |
||||
echo Couldn't find %WRAPPER_JAR%, downloading it ... |
||||
echo Downloading from: %DOWNLOAD_URL% |
||||
powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" |
||||
echo Finished downloading %WRAPPER_JAR% |
||||
) |
||||
@REM End of extension |
||||
|
||||
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* |
||||
if ERRORLEVEL 1 goto error |
||||
goto end |
||||
|
||||
:error |
||||
set ERROR_CODE=1 |
||||
|
||||
:end |
||||
@endlocal & set ERROR_CODE=%ERROR_CODE% |
||||
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost |
||||
@REM check for post script, once with legacy .bat ending and once with .cmd ending |
||||
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" |
||||
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" |
||||
:skipRcPost |
||||
|
||||
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' |
||||
if "%MAVEN_BATCH_PAUSE%" == "on" pause |
||||
|
||||
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% |
||||
|
||||
exit /B %ERROR_CODE% |
||||
@ -1,92 +0,0 @@
@@ -1,92 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
<parent> |
||||
<groupId>org.springframework.boot</groupId> |
||||
<artifactId>spring-boot-starter-parent</artifactId> |
||||
<version>2.2.4.RELEASE</version> |
||||
<relativePath /> <!-- lookup parent from repository --> |
||||
</parent> |
||||
<groupId>io.spring.concourse.releasescripts</groupId> |
||||
<artifactId>release-scripts</artifactId> |
||||
<version>0.0.1-SNAPSHOT</version> |
||||
<name>releasescripts</name> |
||||
<description>Utility that can be used when releasing Java projects</description> |
||||
<properties> |
||||
<java.version>1.8</java.version> |
||||
<spring-javaformat.version>0.0.26</spring-javaformat.version> |
||||
</properties> |
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>org.bouncycastle</groupId> |
||||
<artifactId>bcpg-jdk18on</artifactId> |
||||
<version>1.71</version> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.springframework.boot</groupId> |
||||
<artifactId>spring-boot-starter</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.springframework</groupId> |
||||
<artifactId>spring-web</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>com.fasterxml.jackson.core</groupId> |
||||
<artifactId>jackson-databind</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>com.fasterxml.jackson.datatype</groupId> |
||||
<artifactId>jackson-datatype-jdk8</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>com.fasterxml.jackson.datatype</groupId> |
||||
<artifactId>jackson-datatype-jsr310</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>com.fasterxml.jackson.module</groupId> |
||||
<artifactId>jackson-module-parameter-names</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.awaitility</groupId> |
||||
<artifactId>awaitility</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.springframework.boot</groupId> |
||||
<artifactId>spring-boot-starter-test</artifactId> |
||||
<scope>test</scope> |
||||
<exclusions> |
||||
<exclusion> |
||||
<groupId>org.junit.vintage</groupId> |
||||
<artifactId>junit-vintage-engine</artifactId> |
||||
</exclusion> |
||||
</exclusions> |
||||
</dependency> |
||||
</dependencies> |
||||
<build> |
||||
<finalName>spring-boot-release-scripts</finalName> |
||||
<plugins> |
||||
<plugin> |
||||
<groupId>org.springframework.boot</groupId> |
||||
<artifactId>spring-boot-maven-plugin</artifactId> |
||||
</plugin> |
||||
<plugin> |
||||
<groupId>io.spring.javaformat</groupId> |
||||
<artifactId>spring-javaformat-maven-plugin</artifactId> |
||||
<version>${spring-javaformat.version}</version> |
||||
<executions> |
||||
<execution> |
||||
<phase>validate</phase> |
||||
<configuration> |
||||
<skip>${disable.checks}</skip> |
||||
</configuration> |
||||
<goals> |
||||
<goal>validate</goal> |
||||
</goals> |
||||
</execution> |
||||
</executions> |
||||
</plugin> |
||||
</plugins> |
||||
</build> |
||||
</project> |
||||
@ -1,31 +0,0 @@
@@ -1,31 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2020 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package io.spring.concourse.releasescripts; |
||||
|
||||
import org.springframework.boot.SpringApplication; |
||||
import org.springframework.boot.autoconfigure.SpringBootApplication; |
||||
import org.springframework.boot.context.properties.ConfigurationPropertiesScan; |
||||
|
||||
@SpringBootApplication |
||||
@ConfigurationPropertiesScan |
||||
public class Application { |
||||
|
||||
public static void main(String[] args) { |
||||
SpringApplication.run(Application.class, args); |
||||
} |
||||
|
||||
} |
||||
@ -1,82 +0,0 @@
@@ -1,82 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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. |
||||
* 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.concourse.releasescripts; |
||||
|
||||
import io.spring.concourse.releasescripts.artifactory.payload.BuildInfoResponse; |
||||
|
||||
import org.springframework.boot.context.properties.PropertyMapper; |
||||
import org.springframework.util.StringUtils; |
||||
|
||||
/** |
||||
* Properties corresponding to the release. |
||||
* |
||||
* @author Madhura Bhave |
||||
*/ |
||||
public class ReleaseInfo { |
||||
|
||||
private String buildName; |
||||
|
||||
private String buildNumber; |
||||
|
||||
private String groupId; |
||||
|
||||
private String version; |
||||
|
||||
public static ReleaseInfo from(BuildInfoResponse.BuildInfo buildInfo) { |
||||
ReleaseInfo info = new ReleaseInfo(); |
||||
PropertyMapper propertyMapper = PropertyMapper.get(); |
||||
propertyMapper.from(buildInfo.getName()).to(info::setBuildName); |
||||
propertyMapper.from(buildInfo.getNumber()).to(info::setBuildNumber); |
||||
String[] moduleInfo = StringUtils.delimitedListToStringArray(buildInfo.getModules()[0].getId(), ":"); |
||||
propertyMapper.from(moduleInfo[0]).to(info::setGroupId); |
||||
propertyMapper.from(moduleInfo[2]).to(info::setVersion); |
||||
return info; |
||||
} |
||||
|
||||
public String getBuildName() { |
||||
return this.buildName; |
||||
} |
||||
|
||||
public void setBuildName(String buildName) { |
||||
this.buildName = buildName; |
||||
} |
||||
|
||||
public String getBuildNumber() { |
||||
return this.buildNumber; |
||||
} |
||||
|
||||
public void setBuildNumber(String buildNumber) { |
||||
this.buildNumber = buildNumber; |
||||
} |
||||
|
||||
public String getGroupId() { |
||||
return this.groupId; |
||||
} |
||||
|
||||
public void setGroupId(String groupId) { |
||||
this.groupId = groupId; |
||||
} |
||||
|
||||
public String getVersion() { |
||||
return this.version; |
||||
} |
||||
|
||||
public void setVersion(String version) { |
||||
this.version = version; |
||||
} |
||||
|
||||
} |
||||
@ -1,69 +0,0 @@
@@ -1,69 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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. |
||||
* 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.concourse.releasescripts; |
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
|
||||
/** |
||||
* {@link ConfigurationProperties @ConfigurationProperties} corresponding to the release. |
||||
* |
||||
* @author Madhura Bhave |
||||
*/ |
||||
@ConfigurationProperties(prefix = "release") |
||||
public class ReleaseProperties { |
||||
|
||||
private String buildName; |
||||
|
||||
private String buildNumber; |
||||
|
||||
private String groupId; |
||||
|
||||
private String version; |
||||
|
||||
public String getBuildName() { |
||||
return this.buildName; |
||||
} |
||||
|
||||
public void setBuildName(String buildName) { |
||||
this.buildName = buildName; |
||||
} |
||||
|
||||
public String getBuildNumber() { |
||||
return this.buildNumber; |
||||
} |
||||
|
||||
public void setBuildNumber(String buildNumber) { |
||||
this.buildNumber = buildNumber; |
||||
} |
||||
|
||||
public String getGroupId() { |
||||
return this.groupId; |
||||
} |
||||
|
||||
public void setGroupId(String groupId) { |
||||
this.groupId = groupId; |
||||
} |
||||
|
||||
public String getVersion() { |
||||
return this.version; |
||||
} |
||||
|
||||
public void setVersion(String version) { |
||||
this.version = version; |
||||
} |
||||
|
||||
} |
||||
@ -1,54 +0,0 @@
@@ -1,54 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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. |
||||
* 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.concourse.releasescripts; |
||||
|
||||
/** |
||||
* Release type. |
||||
* |
||||
* @author Madhura Bhave |
||||
*/ |
||||
public enum ReleaseType { |
||||
|
||||
MILESTONE("M", "libs-milestone-local"), |
||||
|
||||
RELEASE_CANDIDATE("RC", "libs-milestone-local"), |
||||
|
||||
RELEASE("RELEASE", "libs-release-local"); |
||||
|
||||
private final String identifier; |
||||
|
||||
private final String repo; |
||||
|
||||
ReleaseType(String identifier, String repo) { |
||||
this.identifier = identifier; |
||||
this.repo = repo; |
||||
} |
||||
|
||||
public static ReleaseType from(String releaseType) { |
||||
for (ReleaseType type : ReleaseType.values()) { |
||||
if (type.identifier.equals(releaseType)) { |
||||
return type; |
||||
} |
||||
} |
||||
throw new IllegalArgumentException("Invalid release type"); |
||||
} |
||||
|
||||
public String getRepo() { |
||||
return this.repo; |
||||
} |
||||
|
||||
} |
||||
@ -1,49 +0,0 @@
@@ -1,49 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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. |
||||
* 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.concourse.releasescripts.artifactory; |
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
|
||||
/** |
||||
* {@link ConfigurationProperties @ConfigurationProperties} for an Artifactory server. |
||||
* |
||||
* @author Madhura Bhave |
||||
*/ |
||||
@ConfigurationProperties(prefix = "artifactory") |
||||
public class ArtifactoryProperties { |
||||
|
||||
private String username; |
||||
|
||||
private String password; |
||||
|
||||
public String getUsername() { |
||||
return this.username; |
||||
} |
||||
|
||||
public void setUsername(String username) { |
||||
this.username = username; |
||||
} |
||||
|
||||
public String getPassword() { |
||||
return this.password; |
||||
} |
||||
|
||||
public void setPassword(String password) { |
||||
this.password = password; |
||||
} |
||||
|
||||
} |
||||
@ -1,119 +0,0 @@
@@ -1,119 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.concourse.releasescripts.artifactory; |
||||
|
||||
import java.net.URI; |
||||
|
||||
import io.spring.concourse.releasescripts.ReleaseInfo; |
||||
import io.spring.concourse.releasescripts.artifactory.payload.BuildInfoResponse; |
||||
import io.spring.concourse.releasescripts.artifactory.payload.BuildInfoResponse.Status; |
||||
import io.spring.concourse.releasescripts.artifactory.payload.PromotionRequest; |
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder; |
||||
import org.springframework.http.MediaType; |
||||
import org.springframework.http.RequestEntity; |
||||
import org.springframework.http.ResponseEntity; |
||||
import org.springframework.stereotype.Component; |
||||
import org.springframework.util.StringUtils; |
||||
import org.springframework.web.client.HttpClientErrorException; |
||||
import org.springframework.web.client.RestTemplate; |
||||
|
||||
/** |
||||
* Central class for interacting with Artifactory's REST API. |
||||
* |
||||
* @author Madhura Bhave |
||||
*/ |
||||
@Component |
||||
public class ArtifactoryService { |
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ArtifactoryService.class); |
||||
|
||||
private static final String ARTIFACTORY_URL = "https://repo.spring.io"; |
||||
|
||||
private static final String PROMOTION_URL = ARTIFACTORY_URL + "/api/build/promote/"; |
||||
|
||||
private static final String BUILD_INFO_URL = ARTIFACTORY_URL + "/api/build/"; |
||||
|
||||
private static final String STAGING_REPO = "libs-staging-local"; |
||||
|
||||
private final RestTemplate restTemplate; |
||||
|
||||
public ArtifactoryService(RestTemplateBuilder builder, ArtifactoryProperties artifactoryProperties) { |
||||
String username = artifactoryProperties.getUsername(); |
||||
String password = artifactoryProperties.getPassword(); |
||||
if (StringUtils.hasLength(username)) { |
||||
builder = builder.basicAuthentication(username, password); |
||||
} |
||||
this.restTemplate = builder.build(); |
||||
} |
||||
|
||||
/** |
||||
* Move artifacts to a target repository in Artifactory. |
||||
* @param targetRepo the targetRepo |
||||
* @param releaseInfo the release information |
||||
*/ |
||||
public void promote(String targetRepo, ReleaseInfo releaseInfo) { |
||||
PromotionRequest request = getPromotionRequest(targetRepo); |
||||
String buildName = releaseInfo.getBuildName(); |
||||
String buildNumber = releaseInfo.getBuildNumber(); |
||||
logger.info("Promoting " + buildName + "/" + buildNumber + " to " + request.getTargetRepo()); |
||||
RequestEntity<PromotionRequest> requestEntity = RequestEntity |
||||
.post(URI.create(PROMOTION_URL + buildName + "/" + buildNumber)).contentType(MediaType.APPLICATION_JSON) |
||||
.body(request); |
||||
try { |
||||
this.restTemplate.exchange(requestEntity, String.class); |
||||
logger.debug("Promotion complete"); |
||||
} |
||||
catch (HttpClientErrorException ex) { |
||||
boolean isAlreadyPromoted = isAlreadyPromoted(buildName, buildNumber, request.getTargetRepo()); |
||||
if (isAlreadyPromoted) { |
||||
logger.info("Already promoted."); |
||||
} |
||||
else { |
||||
logger.info("Promotion failed."); |
||||
throw ex; |
||||
} |
||||
} |
||||
} |
||||
|
||||
private boolean isAlreadyPromoted(String buildName, String buildNumber, String targetRepo) { |
||||
try { |
||||
logger.debug("Checking if already promoted"); |
||||
ResponseEntity<BuildInfoResponse> entity = this.restTemplate |
||||
.getForEntity(BUILD_INFO_URL + buildName + "/" + buildNumber, BuildInfoResponse.class); |
||||
Status[] statuses = entity.getBody().getBuildInfo().getStatuses(); |
||||
BuildInfoResponse.Status status = (statuses != null) ? statuses[0] : null; |
||||
if (status == null) { |
||||
logger.debug("Returned no status object"); |
||||
return false; |
||||
} |
||||
logger.debug("Returned repository " + status.getRepository() + " expecting " + targetRepo); |
||||
return status.getRepository().equals(targetRepo); |
||||
} |
||||
catch (HttpClientErrorException ex) { |
||||
logger.debug("Client error, assuming not promoted"); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
private PromotionRequest getPromotionRequest(String targetRepo) { |
||||
return new PromotionRequest("staged", STAGING_REPO, targetRepo); |
||||
} |
||||
|
||||
} |
||||
@ -1,38 +0,0 @@
@@ -1,38 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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. |
||||
* 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.concourse.releasescripts.artifactory; |
||||
|
||||
/** |
||||
* Runtime exception if artifact distribution to Bintray fails. |
||||
* |
||||
* @author Madhura Bhave |
||||
*/ |
||||
public class DistributionTimeoutException extends RuntimeException { |
||||
|
||||
private String message; |
||||
|
||||
DistributionTimeoutException(String message) { |
||||
super(message); |
||||
this.message = message; |
||||
} |
||||
|
||||
@Override |
||||
public String getMessage() { |
||||
return this.message; |
||||
} |
||||
|
||||
} |
||||
@ -1,166 +0,0 @@
@@ -1,166 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2020 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package io.spring.concourse.releasescripts.artifactory.payload; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.Set; |
||||
import java.util.function.Predicate; |
||||
import java.util.stream.Collectors; |
||||
import java.util.stream.Stream; |
||||
|
||||
/** |
||||
* Represents the response from Artifactory's buildInfo endpoint. |
||||
* |
||||
* @author Madhura Bhave |
||||
*/ |
||||
public class BuildInfoResponse { |
||||
|
||||
private BuildInfo buildInfo; |
||||
|
||||
public BuildInfo getBuildInfo() { |
||||
return this.buildInfo; |
||||
} |
||||
|
||||
public void setBuildInfo(BuildInfo buildInfo) { |
||||
this.buildInfo = buildInfo; |
||||
} |
||||
|
||||
public static class BuildInfo { |
||||
|
||||
private String name; |
||||
|
||||
private String number; |
||||
|
||||
private String version; |
||||
|
||||
private Status[] statuses; |
||||
|
||||
private Module[] modules; |
||||
|
||||
public Status[] getStatuses() { |
||||
return this.statuses; |
||||
} |
||||
|
||||
public void setStatuses(Status[] statuses) { |
||||
this.statuses = statuses; |
||||
} |
||||
|
||||
public String getName() { |
||||
return this.name; |
||||
} |
||||
|
||||
public void setName(String name) { |
||||
this.name = name; |
||||
} |
||||
|
||||
public String getNumber() { |
||||
return this.number; |
||||
} |
||||
|
||||
public void setNumber(String number) { |
||||
this.number = number; |
||||
} |
||||
|
||||
public Module[] getModules() { |
||||
return this.modules; |
||||
} |
||||
|
||||
public void setModules(Module[] modules) { |
||||
this.modules = modules; |
||||
} |
||||
|
||||
public String getVersion() { |
||||
return this.version; |
||||
} |
||||
|
||||
public void setVersion(String version) { |
||||
this.version = version; |
||||
|
||||
} |
||||
|
||||
public Set<String> getArtifactDigests(Predicate<Artifact> predicate) { |
||||
return Arrays.stream(this.modules).flatMap((module) -> { |
||||
Artifact[] artifacts = module.getArtifacts(); |
||||
return (artifacts != null) ? Arrays.stream(artifacts) : Stream.empty(); |
||||
}).filter(predicate).map(Artifact::getSha256).collect(Collectors.toSet()); |
||||
} |
||||
|
||||
} |
||||
|
||||
public static class Status { |
||||
|
||||
private String repository; |
||||
|
||||
public String getRepository() { |
||||
return this.repository; |
||||
} |
||||
|
||||
public void setRepository(String repository) { |
||||
this.repository = repository; |
||||
} |
||||
|
||||
} |
||||
|
||||
public static class Module { |
||||
|
||||
private String id; |
||||
|
||||
private Artifact[] artifacts; |
||||
|
||||
public String getId() { |
||||
return this.id; |
||||
} |
||||
|
||||
public void setId(String id) { |
||||
this.id = id; |
||||
} |
||||
|
||||
public Artifact[] getArtifacts() { |
||||
return this.artifacts; |
||||
} |
||||
|
||||
public void setArtifacts(Artifact[] artifacts) { |
||||
this.artifacts = artifacts; |
||||
} |
||||
|
||||
} |
||||
|
||||
public static class Artifact { |
||||
|
||||
private String name; |
||||
|
||||
private String sha256; |
||||
|
||||
public String getName() { |
||||
return this.name; |
||||
} |
||||
|
||||
public void setName(String name) { |
||||
this.name = name; |
||||
} |
||||
|
||||
public String getSha256() { |
||||
return this.sha256; |
||||
} |
||||
|
||||
public void setSha256(String sha256) { |
||||
this.sha256 = sha256; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,48 +0,0 @@
@@ -1,48 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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. |
||||
* 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.concourse.releasescripts.artifactory.payload; |
||||
|
||||
/** |
||||
* Represents a request to distribute artifacts from Artifactory to Bintray. |
||||
* |
||||
* @author Madhura Bhave |
||||
*/ |
||||
public class DistributionRequest { |
||||
|
||||
private final String[] sourceRepos; |
||||
|
||||
private final String targetRepo = "spring-distributions"; |
||||
|
||||
private final String async = "true"; |
||||
|
||||
public DistributionRequest(String[] sourceRepos) { |
||||
this.sourceRepos = sourceRepos; |
||||
} |
||||
|
||||
public String[] getSourceRepos() { |
||||
return sourceRepos; |
||||
} |
||||
|
||||
public String getTargetRepo() { |
||||
return targetRepo; |
||||
} |
||||
|
||||
public String getAsync() { |
||||
return async; |
||||
} |
||||
|
||||
} |
||||
@ -1,50 +0,0 @@
@@ -1,50 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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. |
||||
* 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.concourse.releasescripts.artifactory.payload; |
||||
|
||||
/** |
||||
* Represents a request to promote artifacts from a sourceRepo to a targetRepo. |
||||
* |
||||
* @author Madhura Bhave |
||||
*/ |
||||
public class PromotionRequest { |
||||
|
||||
private final String status; |
||||
|
||||
private final String sourceRepo; |
||||
|
||||
private final String targetRepo; |
||||
|
||||
public PromotionRequest(String status, String sourceRepo, String targetRepo) { |
||||
this.status = status; |
||||
this.sourceRepo = sourceRepo; |
||||
this.targetRepo = targetRepo; |
||||
} |
||||
|
||||
public String getTargetRepo() { |
||||
return this.targetRepo; |
||||
} |
||||
|
||||
public String getSourceRepo() { |
||||
return this.sourceRepo; |
||||
} |
||||
|
||||
public String getStatus() { |
||||
return this.status; |
||||
} |
||||
|
||||
} |
||||
@ -1,41 +0,0 @@
@@ -1,41 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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. |
||||
* 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.concourse.releasescripts.command; |
||||
|
||||
import org.springframework.boot.ApplicationArguments; |
||||
import org.springframework.util.ClassUtils; |
||||
|
||||
/** |
||||
* @author Madhura Bhave |
||||
*/ |
||||
public interface Command { |
||||
|
||||
default String getName() { |
||||
String name = ClassUtils.getShortName(getClass()); |
||||
int lastDot = name.lastIndexOf("."); |
||||
if (lastDot != -1) { |
||||
name = name.substring(lastDot + 1, name.length()); |
||||
} |
||||
if (name.endsWith("Command")) { |
||||
name = name.substring(0, name.length() - "Command".length()); |
||||
} |
||||
return name.toLowerCase(); |
||||
} |
||||
|
||||
void run(ApplicationArguments args) throws Exception; |
||||
|
||||
} |
||||
@ -1,58 +0,0 @@
@@ -1,58 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2020 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package io.spring.concourse.releasescripts.command; |
||||
|
||||
import java.util.Collections; |
||||
import java.util.List; |
||||
|
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
import org.springframework.boot.ApplicationArguments; |
||||
import org.springframework.boot.ApplicationRunner; |
||||
import org.springframework.stereotype.Component; |
||||
import org.springframework.util.Assert; |
||||
|
||||
/** |
||||
* {@link ApplicationRunner} to delegate incoming requests to commands. |
||||
* |
||||
* @author Madhura Bhave |
||||
*/ |
||||
@Component |
||||
public class CommandProcessor implements ApplicationRunner { |
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CommandProcessor.class); |
||||
|
||||
private final List<Command> commands; |
||||
|
||||
public CommandProcessor(List<Command> commands) { |
||||
this.commands = Collections.unmodifiableList(commands); |
||||
} |
||||
|
||||
@Override |
||||
public void run(ApplicationArguments args) throws Exception { |
||||
logger.debug("Running command processor"); |
||||
List<String> nonOptionArgs = args.getNonOptionArgs(); |
||||
Assert.state(!nonOptionArgs.isEmpty(), "No command argument specified"); |
||||
String request = nonOptionArgs.get(0); |
||||
Command command = this.commands.stream().filter((candidate) -> candidate.getName().equals(request)).findFirst() |
||||
.orElseThrow(() -> new IllegalStateException("Unknown command '" + request + "'")); |
||||
logger.debug("Found command " + command.getClass().getName()); |
||||
command.run(args); |
||||
} |
||||
|
||||
} |
||||
@ -1,69 +0,0 @@
@@ -1,69 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2020 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package io.spring.concourse.releasescripts.command; |
||||
|
||||
import java.io.File; |
||||
import java.nio.file.Files; |
||||
import java.util.List; |
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper; |
||||
import io.spring.concourse.releasescripts.ReleaseInfo; |
||||
import io.spring.concourse.releasescripts.ReleaseType; |
||||
import io.spring.concourse.releasescripts.artifactory.ArtifactoryService; |
||||
import io.spring.concourse.releasescripts.artifactory.payload.BuildInfoResponse; |
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
import org.springframework.boot.ApplicationArguments; |
||||
import org.springframework.stereotype.Component; |
||||
import org.springframework.util.Assert; |
||||
|
||||
/** |
||||
* Command used to move the build artifacts to a target repository in Artifactory. |
||||
* |
||||
* @author Madhura Bhave |
||||
*/ |
||||
@Component |
||||
public class PromoteCommand implements Command { |
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PromoteCommand.class); |
||||
|
||||
private final ArtifactoryService service; |
||||
|
||||
private final ObjectMapper objectMapper; |
||||
|
||||
public PromoteCommand(ArtifactoryService service, ObjectMapper objectMapper) { |
||||
this.service = service; |
||||
this.objectMapper = objectMapper; |
||||
} |
||||
|
||||
@Override |
||||
public void run(ApplicationArguments args) throws Exception { |
||||
logger.debug("Running 'promote' command"); |
||||
List<String> nonOptionArgs = args.getNonOptionArgs(); |
||||
Assert.state(!nonOptionArgs.isEmpty(), "No command argument specified"); |
||||
Assert.state(nonOptionArgs.size() == 3, "Release type or build info location not specified"); |
||||
String releaseType = nonOptionArgs.get(1); |
||||
ReleaseType type = ReleaseType.from(releaseType); |
||||
String buildInfoLocation = nonOptionArgs.get(2); |
||||
byte[] content = Files.readAllBytes(new File(buildInfoLocation).toPath()); |
||||
BuildInfoResponse buildInfoResponse = this.objectMapper.readValue(new String(content), BuildInfoResponse.class); |
||||
ReleaseInfo releaseInfo = ReleaseInfo.from(buildInfoResponse.getBuildInfo()); |
||||
this.service.promote(type.getRepo(), releaseInfo); |
||||
} |
||||
|
||||
} |
||||
@ -1,80 +0,0 @@
@@ -1,80 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.concourse.releasescripts.command; |
||||
|
||||
import java.io.File; |
||||
import java.nio.file.Files; |
||||
import java.util.List; |
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper; |
||||
import io.spring.concourse.releasescripts.ReleaseInfo; |
||||
import io.spring.concourse.releasescripts.ReleaseType; |
||||
import io.spring.concourse.releasescripts.artifactory.payload.BuildInfoResponse; |
||||
import io.spring.concourse.releasescripts.artifactory.payload.BuildInfoResponse.BuildInfo; |
||||
import io.spring.concourse.releasescripts.sonatype.SonatypeService; |
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
import org.springframework.boot.ApplicationArguments; |
||||
import org.springframework.stereotype.Component; |
||||
import org.springframework.util.Assert; |
||||
|
||||
/** |
||||
* Command used to publish a release to Maven Central. |
||||
* |
||||
* @author Andy Wilkinson |
||||
*/ |
||||
@Component |
||||
public class PublishToCentralCommand implements Command { |
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PublishToCentralCommand.class); |
||||
|
||||
private final SonatypeService sonatype; |
||||
|
||||
private final ObjectMapper objectMapper; |
||||
|
||||
public PublishToCentralCommand(SonatypeService sonatype, ObjectMapper objectMapper) { |
||||
this.sonatype = sonatype; |
||||
this.objectMapper = objectMapper; |
||||
} |
||||
|
||||
@Override |
||||
public String getName() { |
||||
return "publishToCentral"; |
||||
} |
||||
|
||||
@Override |
||||
public void run(ApplicationArguments args) throws Exception { |
||||
List<String> nonOptionArgs = args.getNonOptionArgs(); |
||||
Assert.state(nonOptionArgs.size() == 4, |
||||
"Release type, build info location, or artifacts location not specified"); |
||||
String releaseType = nonOptionArgs.get(1); |
||||
ReleaseType type = ReleaseType.from(releaseType); |
||||
if (!ReleaseType.RELEASE.equals(type)) { |
||||
return; |
||||
} |
||||
String buildInfoLocation = nonOptionArgs.get(2); |
||||
logger.debug("Loading build-info from " + buildInfoLocation); |
||||
byte[] content = Files.readAllBytes(new File(buildInfoLocation).toPath()); |
||||
BuildInfoResponse buildInfoResponse = this.objectMapper.readValue(content, BuildInfoResponse.class); |
||||
BuildInfo buildInfo = buildInfoResponse.getBuildInfo(); |
||||
ReleaseInfo releaseInfo = ReleaseInfo.from(buildInfo); |
||||
String artifactsLocation = nonOptionArgs.get(3); |
||||
this.sonatype.publish(releaseInfo, new File(artifactsLocation).toPath()); |
||||
} |
||||
|
||||
} |
||||
@ -1,72 +0,0 @@
@@ -1,72 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2020 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package io.spring.concourse.releasescripts.command; |
||||
|
||||
import java.util.List; |
||||
|
||||
import io.spring.concourse.releasescripts.ReleaseType; |
||||
import io.spring.concourse.releasescripts.sdkman.SdkmanService; |
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
import org.springframework.boot.ApplicationArguments; |
||||
import org.springframework.stereotype.Component; |
||||
import org.springframework.util.Assert; |
||||
|
||||
/** |
||||
* Command used to publish to SDKMAN. |
||||
* |
||||
* @author Madhura Bhave |
||||
*/ |
||||
@Component |
||||
public class PublishToSdkmanCommand implements Command { |
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PublishToSdkmanCommand.class); |
||||
|
||||
private static final String PUBLISH_TO_SDKMAN_COMMAND = "publishToSdkman"; |
||||
|
||||
private final SdkmanService service; |
||||
|
||||
public PublishToSdkmanCommand(SdkmanService service) { |
||||
this.service = service; |
||||
} |
||||
|
||||
@Override |
||||
public String getName() { |
||||
return PUBLISH_TO_SDKMAN_COMMAND; |
||||
} |
||||
|
||||
@Override |
||||
public void run(ApplicationArguments args) throws Exception { |
||||
logger.debug("Running 'push to SDKMAN' command"); |
||||
List<String> nonOptionArgs = args.getNonOptionArgs(); |
||||
Assert.state(!nonOptionArgs.isEmpty(), "No command argument specified"); |
||||
Assert.state(nonOptionArgs.size() >= 3, "Release type or version not specified"); |
||||
String releaseType = nonOptionArgs.get(1); |
||||
ReleaseType type = ReleaseType.from(releaseType); |
||||
if (!ReleaseType.RELEASE.equals(type)) { |
||||
return; |
||||
} |
||||
String version = nonOptionArgs.get(2); |
||||
boolean makeDefault = false; |
||||
if (nonOptionArgs.size() == 4) { |
||||
makeDefault = Boolean.parseBoolean(nonOptionArgs.get(3)); |
||||
} |
||||
this.service.publish(version, makeDefault); |
||||
} |
||||
|
||||
} |
||||
@ -1,49 +0,0 @@
@@ -1,49 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2020 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package io.spring.concourse.releasescripts.sdkman; |
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
|
||||
/** |
||||
* {@link ConfigurationProperties @ConfigurationProperties} for SDKMAN. |
||||
* |
||||
* @author Madhura Bhave |
||||
*/ |
||||
@ConfigurationProperties(prefix = "sdkman") |
||||
public class SdkmanProperties { |
||||
|
||||
private String consumerKey; |
||||
|
||||
private String consumerToken; |
||||
|
||||
public String getConsumerKey() { |
||||
return this.consumerKey; |
||||
} |
||||
|
||||
public void setConsumerKey(String consumerKey) { |
||||
this.consumerKey = consumerKey; |
||||
} |
||||
|
||||
public String getConsumerToken() { |
||||
return this.consumerToken; |
||||
} |
||||
|
||||
public void setConsumerToken(String consumerToken) { |
||||
this.consumerToken = consumerToken; |
||||
} |
||||
|
||||
} |
||||
@ -1,158 +0,0 @@
@@ -1,158 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2023 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.concourse.releasescripts.sdkman; |
||||
|
||||
import java.net.URI; |
||||
|
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder; |
||||
import org.springframework.http.MediaType; |
||||
import org.springframework.http.RequestEntity; |
||||
import org.springframework.stereotype.Component; |
||||
import org.springframework.web.client.RestTemplate; |
||||
|
||||
/** |
||||
* Central class for interacting with SDKMAN's API. |
||||
* |
||||
* @author Madhura Bhave |
||||
* @author Moritz Halbritter |
||||
*/ |
||||
@Component |
||||
public class SdkmanService { |
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SdkmanService.class); |
||||
|
||||
private static final String SDKMAN_URL = "https://vendors.sdkman.io/"; |
||||
|
||||
private static final String DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot-cli/" |
||||
+ "%s/spring-boot-cli-%s-bin.zip"; |
||||
|
||||
private static final String CHANGELOG_URL = "https://github.com/spring-projects/spring-boot/releases/tag/v%s"; |
||||
|
||||
private static final String SPRING_BOOT = "springboot"; |
||||
|
||||
private final RestTemplate restTemplate; |
||||
|
||||
private final SdkmanProperties properties; |
||||
|
||||
private final String CONSUMER_KEY_HEADER = "Consumer-Key"; |
||||
|
||||
private final String CONSUMER_TOKEN_HEADER = "Consumer-Token"; |
||||
|
||||
public SdkmanService(RestTemplateBuilder builder, SdkmanProperties properties) { |
||||
this.restTemplate = builder.build(); |
||||
this.properties = properties; |
||||
} |
||||
|
||||
public void publish(String version, boolean makeDefault) { |
||||
release(version); |
||||
if (makeDefault) { |
||||
makeDefault(version); |
||||
} |
||||
broadcast(version); |
||||
} |
||||
|
||||
private void broadcast(String version) { |
||||
BroadcastRequest broadcastRequest = new BroadcastRequest(version, String.format(CHANGELOG_URL, version)); |
||||
RequestEntity<BroadcastRequest> broadcastEntity = RequestEntity.post(URI.create(SDKMAN_URL + "announce/struct")) |
||||
.header(CONSUMER_KEY_HEADER, this.properties.getConsumerKey()) |
||||
.header(CONSUMER_TOKEN_HEADER, this.properties.getConsumerToken()) |
||||
.contentType(MediaType.APPLICATION_JSON).body(broadcastRequest); |
||||
this.restTemplate.exchange(broadcastEntity, String.class); |
||||
logger.debug("Broadcast complete"); |
||||
} |
||||
|
||||
private void makeDefault(String version) { |
||||
logger.debug("Making this version the default"); |
||||
Request request = new Request(version); |
||||
RequestEntity<Request> requestEntity = RequestEntity.put(URI.create(SDKMAN_URL + "default")) |
||||
.header(CONSUMER_KEY_HEADER, this.properties.getConsumerKey()) |
||||
.header(CONSUMER_TOKEN_HEADER, this.properties.getConsumerToken()) |
||||
.contentType(MediaType.APPLICATION_JSON).body(request); |
||||
this.restTemplate.exchange(requestEntity, String.class); |
||||
logger.debug("Make default complete"); |
||||
} |
||||
|
||||
private void release(String version) { |
||||
ReleaseRequest releaseRequest = new ReleaseRequest(version, String.format(DOWNLOAD_URL, version, version)); |
||||
RequestEntity<ReleaseRequest> releaseEntity = RequestEntity.post(URI.create(SDKMAN_URL + "release")) |
||||
.header(CONSUMER_KEY_HEADER, this.properties.getConsumerKey()) |
||||
.header(CONSUMER_TOKEN_HEADER, this.properties.getConsumerToken()) |
||||
.contentType(MediaType.APPLICATION_JSON).body(releaseRequest); |
||||
this.restTemplate.exchange(releaseEntity, String.class); |
||||
logger.debug("Release complete"); |
||||
} |
||||
|
||||
static class Request { |
||||
|
||||
private final String candidate = SPRING_BOOT; |
||||
|
||||
private final String version; |
||||
|
||||
Request(String version) { |
||||
this.version = version; |
||||
} |
||||
|
||||
public String getCandidate() { |
||||
return this.candidate; |
||||
} |
||||
|
||||
public String getVersion() { |
||||
return this.version; |
||||
} |
||||
|
||||
} |
||||
|
||||
static class ReleaseRequest extends Request { |
||||
|
||||
private final String url; |
||||
|
||||
ReleaseRequest(String version, String url) { |
||||
super(version); |
||||
this.url = url; |
||||
} |
||||
|
||||
public String getUrl() { |
||||
return this.url; |
||||
} |
||||
|
||||
} |
||||
|
||||
static class BroadcastRequest extends Request { |
||||
|
||||
private final String hashtag = SPRING_BOOT; |
||||
|
||||
private final String url; |
||||
|
||||
BroadcastRequest(String version, String url) { |
||||
super(version); |
||||
this.url = url; |
||||
} |
||||
|
||||
public String getHashtag() { |
||||
return this.hashtag; |
||||
} |
||||
|
||||
public String getUrl() { |
||||
return url; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,64 +0,0 @@
@@ -1,64 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.concourse.releasescripts.sonatype; |
||||
|
||||
import java.io.IOException; |
||||
import java.nio.file.Files; |
||||
import java.nio.file.Path; |
||||
import java.util.Collection; |
||||
import java.util.List; |
||||
import java.util.function.Predicate; |
||||
import java.util.regex.Pattern; |
||||
import java.util.stream.Collectors; |
||||
import java.util.stream.Stream; |
||||
|
||||
import org.springframework.core.io.PathResource; |
||||
|
||||
/** |
||||
* Collects artifacts to be deployed. |
||||
* |
||||
* @author Andy Wilkinson |
||||
*/ |
||||
class ArtifactCollector { |
||||
|
||||
private final Predicate<Path> excludeFilter; |
||||
|
||||
ArtifactCollector(List<String> exclude) { |
||||
this.excludeFilter = excludeFilter(exclude); |
||||
} |
||||
|
||||
private Predicate<Path> excludeFilter(List<String> exclude) { |
||||
Predicate<String> patternFilter = exclude.stream().map(Pattern::compile).map(Pattern::asPredicate) |
||||
.reduce((path) -> false, Predicate::or).negate(); |
||||
return (path) -> patternFilter.test(path.toString()); |
||||
} |
||||
|
||||
Collection<DeployableArtifact> collectArtifacts(Path root) { |
||||
try (Stream<Path> artifacts = Files.walk(root)) { |
||||
return artifacts.filter(Files::isRegularFile).filter(this.excludeFilter) |
||||
.map((artifact) -> deployableArtifact(artifact, root)).collect(Collectors.toList()); |
||||
} |
||||
catch (IOException ex) { |
||||
throw new RuntimeException("Could not read artifacts from '" + root + "'"); |
||||
} |
||||
} |
||||
|
||||
private DeployableArtifact deployableArtifact(Path artifact, Path root) { |
||||
return new DeployableArtifact(new PathResource(artifact), root.relativize(artifact).toString()); |
||||
} |
||||
|
||||
} |
||||
@ -1,45 +0,0 @@
@@ -1,45 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.concourse.releasescripts.sonatype; |
||||
|
||||
import org.springframework.core.io.Resource; |
||||
|
||||
/** |
||||
* An artifact that can be deployed. |
||||
* |
||||
* @author Andy Wilkinson |
||||
*/ |
||||
class DeployableArtifact { |
||||
|
||||
private final Resource resource; |
||||
|
||||
private final String path; |
||||
|
||||
DeployableArtifact(Resource resource, String path) { |
||||
this.resource = resource; |
||||
this.path = path; |
||||
} |
||||
|
||||
Resource getResource() { |
||||
return this.resource; |
||||
} |
||||
|
||||
String getPath() { |
||||
return this.path; |
||||
} |
||||
|
||||
} |
||||
@ -1,123 +0,0 @@
@@ -1,123 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.concourse.releasescripts.sonatype; |
||||
|
||||
import java.time.Duration; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty; |
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
|
||||
/** |
||||
* {@link ConfigurationProperties @ConfigurationProperties} for Sonatype. |
||||
* |
||||
* @author Madhura Bhave |
||||
*/ |
||||
@ConfigurationProperties(prefix = "sonatype") |
||||
public class SonatypeProperties { |
||||
|
||||
@JsonProperty("username") |
||||
private String userToken; |
||||
|
||||
@JsonProperty("password") |
||||
private String passwordToken; |
||||
|
||||
/** |
||||
* URL of the Nexus instance used to publish releases. |
||||
*/ |
||||
private String url; |
||||
|
||||
/** |
||||
* ID of the staging profile used to publish releases. |
||||
*/ |
||||
private String stagingProfileId; |
||||
|
||||
/** |
||||
* Time between requests made to determine if the closing of a staging repository has |
||||
* completed. |
||||
*/ |
||||
private Duration pollingInterval = Duration.ofSeconds(15); |
||||
|
||||
/** |
||||
* Number of threads used to upload artifacts to the staging repository. |
||||
*/ |
||||
private int uploadThreads = 8; |
||||
|
||||
/** |
||||
* Regular expression patterns of artifacts to exclude |
||||
*/ |
||||
private List<String> exclude = new ArrayList<>(); |
||||
|
||||
public String getUserToken() { |
||||
return this.userToken; |
||||
} |
||||
|
||||
public void setUserToken(String userToken) { |
||||
this.userToken = userToken; |
||||
} |
||||
|
||||
public String getPasswordToken() { |
||||
return this.passwordToken; |
||||
} |
||||
|
||||
public void setPasswordToken(String passwordToken) { |
||||
this.passwordToken = passwordToken; |
||||
} |
||||
|
||||
public String getUrl() { |
||||
return this.url; |
||||
} |
||||
|
||||
public void setUrl(String url) { |
||||
this.url = url; |
||||
} |
||||
|
||||
public String getStagingProfileId() { |
||||
return this.stagingProfileId; |
||||
} |
||||
|
||||
public void setStagingProfileId(String stagingProfileId) { |
||||
this.stagingProfileId = stagingProfileId; |
||||
} |
||||
|
||||
public Duration getPollingInterval() { |
||||
return this.pollingInterval; |
||||
} |
||||
|
||||
public void setPollingInterval(Duration pollingInterval) { |
||||
this.pollingInterval = pollingInterval; |
||||
} |
||||
|
||||
public int getUploadThreads() { |
||||
return this.uploadThreads; |
||||
} |
||||
|
||||
public void setUploadThreads(int uploadThreads) { |
||||
this.uploadThreads = uploadThreads; |
||||
} |
||||
|
||||
public List<String> getExclude() { |
||||
return this.exclude; |
||||
} |
||||
|
||||
public void setExclude(List<String> exclude) { |
||||
this.exclude = exclude; |
||||
} |
||||
|
||||
} |
||||
@ -1,306 +0,0 @@
@@ -1,306 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.concourse.releasescripts.sonatype; |
||||
|
||||
import java.nio.file.Path; |
||||
import java.time.Duration; |
||||
import java.util.Arrays; |
||||
import java.util.Collection; |
||||
import java.util.Collections; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.concurrent.CompletableFuture; |
||||
import java.util.concurrent.ExecutionException; |
||||
import java.util.concurrent.ExecutorService; |
||||
import java.util.concurrent.Executors; |
||||
import java.util.concurrent.TimeUnit; |
||||
import java.util.concurrent.TimeoutException; |
||||
import java.util.stream.Collectors; |
||||
import java.util.stream.Stream; |
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator; |
||||
import com.fasterxml.jackson.annotation.JsonCreator.Mode; |
||||
import com.fasterxml.jackson.annotation.JsonProperty; |
||||
import io.spring.concourse.releasescripts.ReleaseInfo; |
||||
import org.apache.logging.log4j.util.Strings; |
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder; |
||||
import org.springframework.http.HttpStatus; |
||||
import org.springframework.http.ResponseEntity; |
||||
import org.springframework.stereotype.Component; |
||||
import org.springframework.util.StringUtils; |
||||
import org.springframework.web.client.HttpClientErrorException; |
||||
import org.springframework.web.client.RestTemplate; |
||||
|
||||
/** |
||||
* Central class for interacting with Sonatype. |
||||
* |
||||
* @author Madhura Bhave |
||||
* @author Andy Wilkinson |
||||
*/ |
||||
@Component |
||||
public class SonatypeService { |
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SonatypeService.class); |
||||
|
||||
private static final String NEXUS_REPOSITORY_PATH = "/service/local/repositories/releases/content/org/springframework/boot/spring-boot/"; |
||||
|
||||
private static final String NEXUS_STAGING_PATH = "/service/local/staging/"; |
||||
|
||||
private final ArtifactCollector artifactCollector; |
||||
|
||||
private final RestTemplate restTemplate; |
||||
|
||||
private final String stagingProfileId; |
||||
|
||||
private final Duration pollingInterval; |
||||
|
||||
private final int threads; |
||||
|
||||
public SonatypeService(RestTemplateBuilder builder, SonatypeProperties sonatypeProperties) { |
||||
String username = sonatypeProperties.getUserToken(); |
||||
String password = sonatypeProperties.getPasswordToken(); |
||||
if (StringUtils.hasLength(username)) { |
||||
builder = builder.basicAuthentication(username, password); |
||||
} |
||||
this.restTemplate = builder.rootUri(sonatypeProperties.getUrl()).build(); |
||||
this.stagingProfileId = sonatypeProperties.getStagingProfileId(); |
||||
this.pollingInterval = sonatypeProperties.getPollingInterval(); |
||||
this.threads = sonatypeProperties.getUploadThreads(); |
||||
|
||||
this.artifactCollector = new ArtifactCollector(sonatypeProperties.getExclude()); |
||||
} |
||||
|
||||
/** |
||||
* Publishes the release by creating a staging repository and deploying to it the |
||||
* artifacts at the given {@code artifactsRoot}. The repository is then closed and, |
||||
* upon successfully closure, it is released. |
||||
* @param releaseInfo the release information |
||||
* @param artifactsRoot the root directory of the artifacts to stage |
||||
*/ |
||||
public void publish(ReleaseInfo releaseInfo, Path artifactsRoot) { |
||||
if (artifactsPublished(releaseInfo)) { |
||||
return; |
||||
} |
||||
logger.info("Creating staging repository"); |
||||
String buildId = releaseInfo.getBuildNumber(); |
||||
String repositoryId = createStagingRepository(buildId); |
||||
Collection<DeployableArtifact> artifacts = this.artifactCollector.collectArtifacts(artifactsRoot); |
||||
logger.info("Staging repository {} created. Deploying {} artifacts", repositoryId, artifacts.size()); |
||||
deploy(artifacts, repositoryId); |
||||
logger.info("Deploy complete. Closing staging repository"); |
||||
close(repositoryId); |
||||
logger.info("Staging repository closed"); |
||||
release(repositoryId, buildId); |
||||
logger.info("Staging repository released"); |
||||
} |
||||
|
||||
private boolean artifactsPublished(ReleaseInfo releaseInfo) { |
||||
try { |
||||
ResponseEntity<?> entity = this.restTemplate |
||||
.getForEntity(String.format(NEXUS_REPOSITORY_PATH + "%s/spring-boot-%s.jar.sha1", |
||||
releaseInfo.getVersion(), releaseInfo.getVersion()), byte[].class); |
||||
if (HttpStatus.OK.equals(entity.getStatusCode())) { |
||||
logger.info("Already published to Sonatype."); |
||||
return true; |
||||
} |
||||
} |
||||
catch (HttpClientErrorException ex) { |
||||
|
||||
} |
||||
return false; |
||||
} |
||||
|
||||
private String createStagingRepository(String buildId) { |
||||
Map<String, Object> body = new HashMap<>(); |
||||
body.put("data", Collections.singletonMap("description", buildId)); |
||||
PromoteResponse response = this.restTemplate.postForObject( |
||||
String.format(NEXUS_STAGING_PATH + "profiles/%s/start", this.stagingProfileId), body, |
||||
PromoteResponse.class); |
||||
String repositoryId = response.data.stagedRepositoryId; |
||||
return repositoryId; |
||||
} |
||||
|
||||
private void deploy(Collection<DeployableArtifact> artifacts, String repositoryId) { |
||||
ExecutorService executor = Executors.newFixedThreadPool(this.threads); |
||||
try { |
||||
CompletableFuture.allOf(artifacts.stream() |
||||
.map((artifact) -> CompletableFuture.runAsync(() -> deploy(artifact, repositoryId), executor)) |
||||
.toArray(CompletableFuture[]::new)).get(60, TimeUnit.MINUTES); |
||||
} |
||||
catch (InterruptedException ex) { |
||||
Thread.currentThread().interrupt(); |
||||
throw new RuntimeException("Interrupted during artifact deploy"); |
||||
} |
||||
catch (ExecutionException ex) { |
||||
throw new RuntimeException("Deploy failed", ex); |
||||
} |
||||
catch (TimeoutException ex) { |
||||
throw new RuntimeException("Deploy timed out", ex); |
||||
} |
||||
finally { |
||||
executor.shutdown(); |
||||
} |
||||
} |
||||
|
||||
private void deploy(DeployableArtifact deployableArtifact, String repositoryId) { |
||||
try { |
||||
this.restTemplate.put( |
||||
NEXUS_STAGING_PATH + "deployByRepositoryId/" + repositoryId + "/" + deployableArtifact.getPath(), |
||||
deployableArtifact.getResource()); |
||||
logger.info("Deloyed {}", deployableArtifact.getPath()); |
||||
} |
||||
catch (HttpClientErrorException ex) { |
||||
logger.error("Failed to deploy {}. Error response: {}", deployableArtifact.getPath(), |
||||
ex.getResponseBodyAsString()); |
||||
throw ex; |
||||
} |
||||
} |
||||
|
||||
private void close(String stagedRepositoryId) { |
||||
Map<String, Object> body = new HashMap<>(); |
||||
body.put("data", Collections.singletonMap("stagedRepositoryId", stagedRepositoryId)); |
||||
this.restTemplate.postForEntity(String.format(NEXUS_STAGING_PATH + "profiles/%s/finish", this.stagingProfileId), |
||||
body, Void.class); |
||||
logger.info("Close requested. Awaiting result"); |
||||
while (true) { |
||||
StagingRepository repository = this.restTemplate |
||||
.getForObject(NEXUS_STAGING_PATH + "repository/" + stagedRepositoryId, StagingRepository.class); |
||||
if (!repository.transitioning) { |
||||
if ("open".equals(repository.type)) { |
||||
logFailures(stagedRepositoryId); |
||||
throw new RuntimeException("Close failed"); |
||||
} |
||||
return; |
||||
} |
||||
try { |
||||
Thread.sleep(this.pollingInterval.toMillis()); |
||||
} |
||||
catch (InterruptedException ex) { |
||||
Thread.currentThread().interrupt(); |
||||
throw new RuntimeException("Interrupted while waiting for staging repository to close", ex); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private void logFailures(String stagedRepositoryId) { |
||||
try { |
||||
StagingRepositoryActivity[] activities = this.restTemplate.getForObject( |
||||
NEXUS_STAGING_PATH + "repository/" + stagedRepositoryId + "/activity", |
||||
StagingRepositoryActivity[].class); |
||||
List<String> failureMessages = Stream.of(activities).flatMap((activity) -> activity.events.stream()) |
||||
.filter((event) -> event.severity > 0).flatMap((event) -> event.properties.stream()) |
||||
.filter((property) -> "failureMessage".equals(property.name)) |
||||
.map((property) -> " " + property.value).collect(Collectors.toList()); |
||||
if (failureMessages.isEmpty()) { |
||||
logger.error("Close failed for unknown reasons"); |
||||
} |
||||
logger.error("Close failed:\n{}", Strings.join(failureMessages, '\n')); |
||||
} |
||||
catch (Exception ex) { |
||||
logger.error("Failed to determine causes of close failure", ex); |
||||
} |
||||
} |
||||
|
||||
private void release(String stagedRepositoryId, String buildId) { |
||||
Map<String, Object> data = new HashMap<>(); |
||||
data.put("stagedRepositoryIds", Arrays.asList(stagedRepositoryId)); |
||||
data.put("description", "Releasing " + buildId); |
||||
data.put("autoDropAfterRelease", true); |
||||
Map<String, Object> body = Collections.singletonMap("data", data); |
||||
this.restTemplate.postForEntity(NEXUS_STAGING_PATH + "bulk/promote", body, Void.class); |
||||
} |
||||
|
||||
private static final class PromoteResponse { |
||||
|
||||
private final Data data; |
||||
|
||||
@JsonCreator(mode = Mode.PROPERTIES) |
||||
private PromoteResponse(@JsonProperty("data") Data data) { |
||||
this.data = data; |
||||
} |
||||
|
||||
private static final class Data { |
||||
|
||||
private final String stagedRepositoryId; |
||||
|
||||
@JsonCreator(mode = Mode.PROPERTIES) |
||||
Data(@JsonProperty("stagedRepositoryId") String stagedRepositoryId) { |
||||
this.stagedRepositoryId = stagedRepositoryId; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
private static final class StagingRepository { |
||||
|
||||
private final String type; |
||||
|
||||
private final boolean transitioning; |
||||
|
||||
private StagingRepository(String type, boolean transitioning) { |
||||
this.type = type; |
||||
this.transitioning = transitioning; |
||||
} |
||||
|
||||
} |
||||
|
||||
private static final class StagingRepositoryActivity { |
||||
|
||||
private final List<Event> events; |
||||
|
||||
@JsonCreator |
||||
private StagingRepositoryActivity(@JsonProperty("events") List<Event> events) { |
||||
this.events = events; |
||||
} |
||||
|
||||
private static class Event { |
||||
|
||||
private final List<Property> properties; |
||||
|
||||
private final int severity; |
||||
|
||||
@JsonCreator |
||||
public Event(@JsonProperty("name") String name, @JsonProperty("properties") List<Property> properties, |
||||
@JsonProperty("severity") int severity) { |
||||
this.properties = properties; |
||||
this.severity = severity; |
||||
} |
||||
|
||||
private static class Property { |
||||
|
||||
private final String name; |
||||
|
||||
private final String value; |
||||
|
||||
@JsonCreator |
||||
private Property(@JsonProperty("name") String name, @JsonProperty("value") String value) { |
||||
this.name = name; |
||||
this.value = value; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,4 +0,0 @@
@@ -1,4 +0,0 @@
|
||||
spring.main.banner-mode=off |
||||
sonatype.exclude[0]=build-info\\.json |
||||
sonatype.exclude[1]=org/springframework/boot/spring-boot-docs/.* |
||||
logging.level.io.spring.concourse=DEBUG |
||||
@ -1,137 +0,0 @@
@@ -1,137 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.concourse.releasescripts.artifactory; |
||||
|
||||
import io.spring.concourse.releasescripts.ReleaseInfo; |
||||
import org.junit.jupiter.api.AfterEach; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties; |
||||
import org.springframework.boot.test.autoconfigure.web.client.RestClientTest; |
||||
import org.springframework.core.io.ClassPathResource; |
||||
import org.springframework.http.HttpMethod; |
||||
import org.springframework.http.HttpStatus; |
||||
import org.springframework.http.MediaType; |
||||
import org.springframework.test.web.client.MockRestServiceServer; |
||||
import org.springframework.test.web.client.response.DefaultResponseCreator; |
||||
import org.springframework.util.Base64Utils; |
||||
import org.springframework.web.client.HttpClientErrorException; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; |
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.content; |
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.header; |
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; |
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; |
||||
import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus; |
||||
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; |
||||
|
||||
/** |
||||
* Tests for {@link ArtifactoryService}. |
||||
* |
||||
* @author Madhura Bhave |
||||
*/ |
||||
@RestClientTest(ArtifactoryService.class) |
||||
@EnableConfigurationProperties(ArtifactoryProperties.class) |
||||
class ArtifactoryServiceTests { |
||||
|
||||
@Autowired |
||||
private ArtifactoryService service; |
||||
|
||||
@Autowired |
||||
private ArtifactoryProperties properties; |
||||
|
||||
@Autowired |
||||
private MockRestServiceServer server; |
||||
|
||||
@AfterEach |
||||
void tearDown() { |
||||
this.server.reset(); |
||||
} |
||||
|
||||
@Test |
||||
void promoteWhenSuccessful() { |
||||
this.server.expect(requestTo("https://repo.spring.io/api/build/promote/example-build/example-build-1")) |
||||
.andExpect(method(HttpMethod.POST)) |
||||
.andExpect(content().json( |
||||
"{\"status\": \"staged\", \"sourceRepo\": \"libs-staging-local\", \"targetRepo\": \"libs-milestone-local\"}")) |
||||
.andExpect(header("Authorization", "Basic " + Base64Utils.encodeToString(String |
||||
.format("%s:%s", this.properties.getUsername(), this.properties.getPassword()).getBytes()))) |
||||
.andExpect(header("Content-Type", MediaType.APPLICATION_JSON.toString())).andRespond(withSuccess()); |
||||
this.service.promote("libs-milestone-local", getReleaseInfo()); |
||||
this.server.verify(); |
||||
} |
||||
|
||||
@Test |
||||
void promoteWhenArtifactsAlreadyPromoted() { |
||||
this.server.expect(requestTo("https://repo.spring.io/api/build/promote/example-build/example-build-1")) |
||||
.andRespond(withStatus(HttpStatus.CONFLICT)); |
||||
this.server.expect(requestTo("https://repo.spring.io/api/build/example-build/example-build-1")) |
||||
.andRespond(withJsonFrom("build-info-response.json")); |
||||
this.service.promote("libs-release-local", getReleaseInfo()); |
||||
this.server.verify(); |
||||
} |
||||
|
||||
@Test |
||||
void promoteWhenCheckForArtifactsAlreadyPromotedFails() { |
||||
this.server.expect(requestTo("https://repo.spring.io/api/build/promote/example-build/example-build-1")) |
||||
.andRespond(withStatus(HttpStatus.CONFLICT)); |
||||
this.server.expect(requestTo("https://repo.spring.io/api/build/example-build/example-build-1")) |
||||
.andRespond(withStatus(HttpStatus.FORBIDDEN)); |
||||
assertThatExceptionOfType(HttpClientErrorException.class) |
||||
.isThrownBy(() -> this.service.promote("libs-release-local", getReleaseInfo())); |
||||
this.server.verify(); |
||||
} |
||||
|
||||
@Test |
||||
void promoteWhenCheckForArtifactsAlreadyPromotedReturnsNoStatus() { |
||||
this.server.expect(requestTo("https://repo.spring.io/api/build/promote/example-build/example-build-1")) |
||||
.andRespond(withStatus(HttpStatus.CONFLICT)); |
||||
this.server.expect(requestTo("https://repo.spring.io/api/build/example-build/example-build-1")) |
||||
.andRespond(withJsonFrom("no-status-build-info-response.json")); |
||||
assertThatExceptionOfType(HttpClientErrorException.class) |
||||
.isThrownBy(() -> this.service.promote("libs-milestone-local", getReleaseInfo())); |
||||
this.server.verify(); |
||||
} |
||||
|
||||
@Test |
||||
void promoteWhenPromotionFails() { |
||||
this.server.expect(requestTo("https://repo.spring.io/api/build/promote/example-build/example-build-1")) |
||||
.andRespond(withStatus(HttpStatus.CONFLICT)); |
||||
this.server.expect(requestTo("https://repo.spring.io/api/build/example-build/example-build-1")) |
||||
.andRespond(withJsonFrom("staged-build-info-response.json")); |
||||
assertThatExceptionOfType(HttpClientErrorException.class) |
||||
.isThrownBy(() -> this.service.promote("libs-release-local", getReleaseInfo())); |
||||
this.server.verify(); |
||||
} |
||||
|
||||
private ReleaseInfo getReleaseInfo() { |
||||
ReleaseInfo releaseInfo = new ReleaseInfo(); |
||||
releaseInfo.setBuildName("example-build"); |
||||
releaseInfo.setBuildNumber("example-build-1"); |
||||
return releaseInfo; |
||||
} |
||||
|
||||
private DefaultResponseCreator withJsonFrom(String path) { |
||||
return withSuccess(getClassPathResource(path), MediaType.APPLICATION_JSON); |
||||
} |
||||
|
||||
private ClassPathResource getClassPathResource(String path) { |
||||
return new ClassPathResource(path, getClass()); |
||||
} |
||||
|
||||
} |
||||
@ -1,88 +0,0 @@
@@ -1,88 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2023 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.concourse.releasescripts.sdkman; |
||||
|
||||
import org.junit.jupiter.api.AfterEach; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties; |
||||
import org.springframework.boot.test.autoconfigure.web.client.RestClientTest; |
||||
import org.springframework.http.HttpMethod; |
||||
import org.springframework.http.MediaType; |
||||
import org.springframework.test.web.client.MockRestServiceServer; |
||||
|
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.content; |
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.header; |
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; |
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; |
||||
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; |
||||
|
||||
/** |
||||
* Tests for {@link SdkmanService}. |
||||
* |
||||
* @author Madhura Bhave |
||||
*/ |
||||
@EnableConfigurationProperties(SdkmanProperties.class) |
||||
@RestClientTest(SdkmanService.class) |
||||
class SdkmanServiceTests { |
||||
|
||||
@Autowired |
||||
private SdkmanService service; |
||||
|
||||
@Autowired |
||||
private MockRestServiceServer server; |
||||
|
||||
@AfterEach |
||||
void tearDown() { |
||||
this.server.reset(); |
||||
} |
||||
|
||||
@Test |
||||
void publishWhenMakeDefaultTrue() { |
||||
setupExpectation("https://vendors.sdkman.io/release", |
||||
"{\"candidate\": \"springboot\", \"version\": \"1.2.3\", \"url\": \"https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot-cli/1.2.3/spring-boot-cli-1.2.3-bin.zip\"}"); |
||||
setupExpectation("https://vendors.sdkman.io/default", "{\"candidate\": \"springboot\", \"version\": \"1.2.3\"}", |
||||
HttpMethod.PUT); |
||||
setupExpectation("https://vendors.sdkman.io/announce/struct", |
||||
"{\"candidate\": \"springboot\", \"version\": \"1.2.3\", \"hashtag\": \"springboot\", \"url\": \"https://github.com/spring-projects/spring-boot/releases/tag/v1.2.3\"}"); |
||||
this.service.publish("1.2.3", true); |
||||
this.server.verify(); |
||||
} |
||||
|
||||
@Test |
||||
void publishWhenMakeDefaultFalse() { |
||||
setupExpectation("https://vendors.sdkman.io/release", |
||||
"{\"candidate\": \"springboot\", \"version\": \"1.2.3\", \"url\": \"https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot-cli/1.2.3/spring-boot-cli-1.2.3-bin.zip\"}"); |
||||
setupExpectation("https://vendors.sdkman.io/announce/struct", |
||||
"{\"candidate\": \"springboot\", \"version\": \"1.2.3\", \"hashtag\": \"springboot\", \"url\": \"https://github.com/spring-projects/spring-boot/releases/tag/v1.2.3\"}"); |
||||
this.service.publish("1.2.3", false); |
||||
this.server.verify(); |
||||
} |
||||
|
||||
private void setupExpectation(String url, String body) { |
||||
setupExpectation(url, body, HttpMethod.POST); |
||||
} |
||||
|
||||
private void setupExpectation(String url, String body, HttpMethod method) { |
||||
this.server.expect(requestTo(url)).andExpect(method(method)).andExpect(content().json(body)) |
||||
.andExpect(header("Consumer-Key", "sdkman-consumer-key")) |
||||
.andExpect(header("Consumer-Token", "sdkman-consumer-token")) |
||||
.andExpect(header("Content-Type", MediaType.APPLICATION_JSON.toString())).andRespond(withSuccess()); |
||||
} |
||||
|
||||
} |
||||
@ -1,236 +0,0 @@
@@ -1,236 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-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.concourse.releasescripts.sonatype; |
||||
|
||||
import java.io.File; |
||||
import java.io.IOException; |
||||
import java.nio.file.Files; |
||||
import java.nio.file.Path; |
||||
import java.util.Arrays; |
||||
import java.util.HashSet; |
||||
import java.util.Iterator; |
||||
import java.util.Set; |
||||
import java.util.stream.Collectors; |
||||
import java.util.stream.Stream; |
||||
|
||||
import io.spring.concourse.releasescripts.ReleaseInfo; |
||||
import org.junit.jupiter.api.AfterEach; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties; |
||||
import org.springframework.boot.test.autoconfigure.web.client.RestClientTest; |
||||
import org.springframework.core.io.FileSystemResource; |
||||
import org.springframework.http.HttpMethod; |
||||
import org.springframework.http.HttpStatus; |
||||
import org.springframework.http.MediaType; |
||||
import org.springframework.http.client.ClientHttpRequest; |
||||
import org.springframework.test.web.client.ExpectedCount; |
||||
import org.springframework.test.web.client.MockRestServiceServer; |
||||
import org.springframework.test.web.client.RequestMatcher; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; |
||||
import static org.hamcrest.Matchers.equalTo; |
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.header; |
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.jsonPath; |
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; |
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; |
||||
import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus; |
||||
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; |
||||
|
||||
/** |
||||
* Tests for {@link SonatypeService}. |
||||
* |
||||
* @author Madhura Bhave |
||||
*/ |
||||
@RestClientTest(components = SonatypeService.class, properties = "sonatype.url=https://nexus.example.org") |
||||
@EnableConfigurationProperties(SonatypeProperties.class) |
||||
class SonatypeServiceTests { |
||||
|
||||
@Autowired |
||||
private SonatypeService service; |
||||
|
||||
@Autowired |
||||
private MockRestServiceServer server; |
||||
|
||||
@AfterEach |
||||
void tearDown() { |
||||
this.server.reset(); |
||||
} |
||||
|
||||
@Test |
||||
void publishWhenAlreadyPublishedShouldNotPublish() { |
||||
this.server.expect(requestTo(String.format( |
||||
"/service/local/repositories/releases/content/org/springframework/boot/spring-boot/%s/spring-boot-%s.jar.sha1", |
||||
"1.1.0.RELEASE", "1.1.0.RELEASE"))).andExpect(method(HttpMethod.GET)) |
||||
.andRespond(withSuccess().body("ce8d8b6838ecceb68962b9150b18682f4237ccf71".getBytes())); |
||||
Path artifactsRoot = new File("src/test/resources/io/spring/concourse/releasescripts/sonatype/artifactory-repo") |
||||
.toPath(); |
||||
this.service.publish(getReleaseInfo(), artifactsRoot); |
||||
this.server.verify(); |
||||
} |
||||
|
||||
@Test |
||||
void publishWithSuccessfulClose() throws IOException { |
||||
this.server.expect(requestTo(String.format( |
||||
"/service/local/repositories/releases/content/org/springframework/boot/spring-boot/%s/spring-boot-%s.jar.sha1", |
||||
"1.1.0.RELEASE", "1.1.0.RELEASE"))).andExpect(method(HttpMethod.GET)) |
||||
.andRespond(withStatus(HttpStatus.NOT_FOUND)); |
||||
this.server.expect(requestTo("/service/local/staging/profiles/1a2b3c4d/start")) |
||||
.andExpect(method(HttpMethod.POST)).andExpect(header("Content-Type", "application/json")) |
||||
.andExpect(header("Accept", "application/json, application/*+json")) |
||||
.andExpect(jsonPath("$.data.description").value("example-build-1")) |
||||
.andRespond(withStatus(HttpStatus.CREATED).contentType(MediaType.APPLICATION_JSON).body( |
||||
"{\"data\":{\"stagedRepositoryId\":\"example-6789\", \"description\":\"example-build\"}}")); |
||||
Path artifactsRoot = new File("src/test/resources/io/spring/concourse/releasescripts/sonatype/artifactory-repo") |
||||
.toPath(); |
||||
try (Stream<Path> artifacts = Files.walk(artifactsRoot)) { |
||||
Set<RequestMatcher> uploads = artifacts.filter(Files::isRegularFile) |
||||
.map((artifact) -> artifactsRoot.relativize(artifact)) |
||||
.filter((artifact) -> !artifact.startsWith("build-info.json")) |
||||
.map((artifact) -> requestTo( |
||||
"/service/local/staging/deployByRepositoryId/example-6789/" + artifact.toString())) |
||||
.collect(Collectors.toCollection(HashSet::new)); |
||||
AnyOfRequestMatcher uploadRequestsMatcher = anyOf(uploads); |
||||
assertThat(uploadRequestsMatcher.candidates).hasSize(150); |
||||
this.server.expect(ExpectedCount.times(150), uploadRequestsMatcher).andExpect(method(HttpMethod.PUT)) |
||||
.andRespond(withSuccess()); |
||||
this.server.expect(requestTo("/service/local/staging/profiles/1a2b3c4d/finish")) |
||||
.andExpect(method(HttpMethod.POST)).andExpect(header("Content-Type", "application/json")) |
||||
.andExpect(header("Accept", "application/json, application/*+json")) |
||||
.andRespond(withStatus(HttpStatus.CREATED)); |
||||
this.server.expect(ExpectedCount.times(2), requestTo("/service/local/staging/repository/example-6789")) |
||||
.andExpect(method(HttpMethod.GET)) |
||||
.andExpect(header("Accept", "application/json, application/*+json")) |
||||
.andRespond(withSuccess().contentType(MediaType.APPLICATION_JSON) |
||||
.body("{\"type\":\"open\", \"transitioning\":true}")); |
||||
this.server.expect(requestTo("/service/local/staging/repository/example-6789")) |
||||
.andExpect(method(HttpMethod.GET)) |
||||
.andExpect(header("Accept", "application/json, application/*+json")) |
||||
.andRespond(withSuccess().contentType(MediaType.APPLICATION_JSON) |
||||
.body("{\"type\":\"closed\", \"transitioning\":false}")); |
||||
this.server.expect(requestTo("/service/local/staging/bulk/promote")).andExpect(method(HttpMethod.POST)) |
||||
.andExpect(header("Content-Type", "application/json")) |
||||
.andExpect(header("Accept", "application/json, application/*+json")) |
||||
.andExpect(jsonPath("$.data.description").value("Releasing example-build-1")) |
||||
.andExpect(jsonPath("$.data.autoDropAfterRelease").value(true)) |
||||
.andExpect(jsonPath("$.data.stagedRepositoryIds").value(equalTo(Arrays.asList("example-6789")))) |
||||
.andRespond(withSuccess()); |
||||
this.service.publish(getReleaseInfo(), artifactsRoot); |
||||
this.server.verify(); |
||||
assertThat(uploadRequestsMatcher.candidates).hasSize(0); |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
void publishWithCloseFailureDueToRuleViolations() throws IOException { |
||||
this.server.expect(requestTo(String.format( |
||||
"/service/local/repositories/releases/content/org/springframework/boot/spring-boot/%s/spring-boot-%s.jar.sha1", |
||||
"1.1.0.RELEASE", "1.1.0.RELEASE"))).andExpect(method(HttpMethod.GET)) |
||||
.andRespond(withStatus(HttpStatus.NOT_FOUND)); |
||||
this.server.expect(requestTo("/service/local/staging/profiles/1a2b3c4d/start")) |
||||
.andExpect(method(HttpMethod.POST)).andExpect(header("Content-Type", "application/json")) |
||||
.andExpect(header("Accept", "application/json, application/*+json")) |
||||
.andExpect(jsonPath("$.data.description").value("example-build-1")) |
||||
.andRespond(withStatus(HttpStatus.CREATED).contentType(MediaType.APPLICATION_JSON).body( |
||||
"{\"data\":{\"stagedRepositoryId\":\"example-6789\", \"description\":\"example-build\"}}")); |
||||
Path artifactsRoot = new File("src/test/resources/io/spring/concourse/releasescripts/sonatype/artifactory-repo") |
||||
.toPath(); |
||||
try (Stream<Path> artifacts = Files.walk(artifactsRoot)) { |
||||
Set<RequestMatcher> uploads = artifacts.filter(Files::isRegularFile) |
||||
.map((artifact) -> artifactsRoot.relativize(artifact)) |
||||
.filter((artifact) -> !"build-info.json".equals(artifact.toString())) |
||||
.map((artifact) -> requestTo( |
||||
"/service/local/staging/deployByRepositoryId/example-6789/" + artifact.toString())) |
||||
.collect(Collectors.toCollection(HashSet::new)); |
||||
AnyOfRequestMatcher uploadRequestsMatcher = anyOf(uploads); |
||||
assertThat(uploadRequestsMatcher.candidates).hasSize(150); |
||||
this.server.expect(ExpectedCount.times(150), uploadRequestsMatcher).andExpect(method(HttpMethod.PUT)) |
||||
.andRespond(withSuccess()); |
||||
this.server.expect(requestTo("/service/local/staging/profiles/1a2b3c4d/finish")) |
||||
.andExpect(method(HttpMethod.POST)).andExpect(header("Content-Type", "application/json")) |
||||
.andExpect(header("Accept", "application/json, application/*+json")) |
||||
.andRespond(withStatus(HttpStatus.CREATED)); |
||||
this.server.expect(ExpectedCount.times(2), requestTo("/service/local/staging/repository/example-6789")) |
||||
.andExpect(method(HttpMethod.GET)) |
||||
.andExpect(header("Accept", "application/json, application/*+json")) |
||||
.andRespond(withSuccess().contentType(MediaType.APPLICATION_JSON) |
||||
.body("{\"type\":\"open\", \"transitioning\":true}")); |
||||
this.server.expect(requestTo("/service/local/staging/repository/example-6789")) |
||||
.andExpect(method(HttpMethod.GET)) |
||||
.andExpect(header("Accept", "application/json, application/*+json")) |
||||
.andRespond(withSuccess().contentType(MediaType.APPLICATION_JSON) |
||||
.body("{\"type\":\"open\", \"transitioning\":false}")); |
||||
this.server.expect(requestTo("/service/local/staging/repository/example-6789/activity")) |
||||
.andExpect(method(HttpMethod.GET)) |
||||
.andExpect(header("Accept", "application/json, application/*+json")) |
||||
.andRespond(withSuccess().contentType(MediaType.APPLICATION_JSON).body(new FileSystemResource( |
||||
new File("src/test/resources/io/spring/concourse/releasescripts/sonatype/activity.json")))); |
||||
assertThatExceptionOfType(RuntimeException.class) |
||||
.isThrownBy(() -> this.service.publish(getReleaseInfo(), artifactsRoot)) |
||||
.withMessage("Close failed"); |
||||
this.server.verify(); |
||||
assertThat(uploadRequestsMatcher.candidates).hasSize(0); |
||||
} |
||||
} |
||||
|
||||
private ReleaseInfo getReleaseInfo() { |
||||
ReleaseInfo releaseInfo = new ReleaseInfo(); |
||||
releaseInfo.setBuildName("example-build"); |
||||
releaseInfo.setBuildNumber("example-build-1"); |
||||
releaseInfo.setVersion("1.1.0.RELEASE"); |
||||
releaseInfo.setGroupId("example"); |
||||
return releaseInfo; |
||||
} |
||||
|
||||
private AnyOfRequestMatcher anyOf(Set<RequestMatcher> candidates) { |
||||
return new AnyOfRequestMatcher(candidates); |
||||
} |
||||
|
||||
private static class AnyOfRequestMatcher implements RequestMatcher { |
||||
|
||||
private final Object monitor = new Object(); |
||||
|
||||
private final Set<RequestMatcher> candidates; |
||||
|
||||
private AnyOfRequestMatcher(Set<RequestMatcher> candidates) { |
||||
this.candidates = candidates; |
||||
} |
||||
|
||||
@Override |
||||
public void match(ClientHttpRequest request) throws IOException, AssertionError { |
||||
synchronized (this.monitor) { |
||||
Iterator<RequestMatcher> iterator = this.candidates.iterator(); |
||||
while (iterator.hasNext()) { |
||||
try { |
||||
iterator.next().match(request); |
||||
iterator.remove(); |
||||
return; |
||||
} |
||||
catch (AssertionError ex) { |
||||
// Continue
|
||||
} |
||||
} |
||||
throw new AssertionError( |
||||
"No matching request matcher was found for request to '" + request.getURI() + "'"); |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,16 +0,0 @@
@@ -1,16 +0,0 @@
|
||||
artifactory: |
||||
username: user |
||||
password: password |
||||
bintray: |
||||
username: bintray-user |
||||
api-key: bintray-api-key |
||||
repo: test |
||||
subject: jars |
||||
sonatype: |
||||
user-token: sonatype-user |
||||
password-token: sonatype-password |
||||
polling-interval: 1s |
||||
staging-profile-id: 1a2b3c4d |
||||
sdkman: |
||||
consumer-key: sdkman-consumer-key |
||||
consumer-token: sdkman-consumer-token |
||||
@ -1,35 +0,0 @@
@@ -1,35 +0,0 @@
|
||||
{ |
||||
"buildInfo": { |
||||
"version": "1.0.1", |
||||
"name": "example", |
||||
"number": "example-build-1", |
||||
"started": "2019-09-10T12:18:05.430+0000", |
||||
"durationMillis": 0, |
||||
"artifactoryPrincipal": "user", |
||||
"url": "https://my-ci.com", |
||||
"modules": [ |
||||
{ |
||||
"id": "org.example.demo:demo:2.2.0", |
||||
"artifacts": [ |
||||
{ |
||||
"type": "jar", |
||||
"sha1": "ayyyya9151a22cb3145538e523dbbaaaaaaaa", |
||||
"sha256": "aaaaaaaaa85f5c5093721f3ed0edda8ff8290yyyyyyyyyy", |
||||
"md5": "aaaaaacddea1724b0b69d8yyyyyyy", |
||||
"name": "demo-2.2.0.jar" |
||||
} |
||||
] |
||||
} |
||||
], |
||||
"statuses": [ |
||||
{ |
||||
"status": "staged", |
||||
"repository": "libs-release-local", |
||||
"timestamp": "2019-09-10T12:42:24.716+0000", |
||||
"user": "user", |
||||
"timestampDate": 1568119344716 |
||||
} |
||||
] |
||||
}, |
||||
"uri": "https://my-artifactory-repo.com/api/build/example/example-build-1" |
||||
} |
||||
@ -1,59 +0,0 @@
@@ -1,59 +0,0 @@
|
||||
{ |
||||
"buildInfo": { |
||||
"version": "1.0.1", |
||||
"name": "example", |
||||
"number": "example-build-1", |
||||
"started": "2019-09-10T12:18:05.430+0000", |
||||
"durationMillis": 0, |
||||
"artifactoryPrincipal": "user", |
||||
"url": "https://my-ci.com", |
||||
"modules": [ |
||||
{ |
||||
"id": "org.example.demo:demo:2.2.0", |
||||
"artifacts": [ |
||||
{ |
||||
"type": "jar", |
||||
"sha1": "ayyyya9151a22cb3145538e523dbbaaaaaaaa", |
||||
"sha256": "aaaaaaaaa85f5c5093721f3ed0edda8ff8290yyyyyyyyyy", |
||||
"md5": "aaaaaacddea1724b0b69d8yyyyyyy", |
||||
"name": "demo-2.2.0.jar" |
||||
} |
||||
] |
||||
}, |
||||
{ |
||||
"id": "org.example.demo:demo:2.2.0:zip", |
||||
"artifacts": [ |
||||
{ |
||||
"type": "zip", |
||||
"sha1": "ayyyya9151a22cb3145538e523dbbaaaaaaab", |
||||
"sha256": "aaaaaaaaa85f5c5093721f3ed0edda8ff8290yyyyyyyyyz", |
||||
"md5": "aaaaaacddea1724b0b69d8yyyyyyz", |
||||
"name": "demo-2.2.0.zip" |
||||
} |
||||
] |
||||
}, |
||||
{ |
||||
"id": "org.example.demo:demo:2.2.0:doc", |
||||
"artifacts": [ |
||||
{ |
||||
"type": "jar", |
||||
"sha1": "ayyyya9151a22cb3145538e523dbbaaaaaaba", |
||||
"sha256": "aaaaaaaaa85f5c5093721f3ed0edda8ff8290yyyyyyyyzy", |
||||
"md5": "aaaaaacddea1724b0b69d8yyyyyzy", |
||||
"name": "demo-2.2.0.doc" |
||||
} |
||||
] |
||||
} |
||||
], |
||||
"statuses": [ |
||||
{ |
||||
"status": "staged", |
||||
"repository": "libs-release-local", |
||||
"timestamp": "2019-09-10T12:42:24.716+0000", |
||||
"user": "user", |
||||
"timestampDate": 1568119344716 |
||||
} |
||||
] |
||||
}, |
||||
"uri": "https://my-artifactory-repo.com/api/build/example/example-build-1" |
||||
} |
||||
@ -1,26 +0,0 @@
@@ -1,26 +0,0 @@
|
||||
{ |
||||
"buildInfo": { |
||||
"version": "1.0.1", |
||||
"name": "example", |
||||
"number": "example-build-1", |
||||
"started": "2019-09-10T12:18:05.430+0000", |
||||
"durationMillis": 0, |
||||
"artifactoryPrincipal": "user", |
||||
"url": "https://my-ci.com", |
||||
"modules": [ |
||||
{ |
||||
"id": "org.example.demo:demo:2.2.0", |
||||
"artifacts": [ |
||||
{ |
||||
"type": "jar", |
||||
"sha1": "ayyyya9151a22cb3145538e523dbbaaaaaaaa", |
||||
"sha256": "aaaaaaaaa85f5c5093721f3ed0edda8ff8290yyyyyyyyyy", |
||||
"md5": "aaaaaacddea1724b0b69d8yyyyyyy", |
||||
"name": "demo-2.2.0.jar" |
||||
} |
||||
] |
||||
} |
||||
] |
||||
}, |
||||
"uri": "https://my-artifactory-repo.com/api/build/example/example-build-1" |
||||
} |
||||
@ -1,35 +0,0 @@
@@ -1,35 +0,0 @@
|
||||
{ |
||||
"buildInfo": { |
||||
"version": "1.0.1", |
||||
"name": "example", |
||||
"number": "example-build-1", |
||||
"started": "2019-09-10T12:18:05.430+0000", |
||||
"durationMillis": 0, |
||||
"artifactoryPrincipal": "user", |
||||
"url": "https://my-ci.com", |
||||
"modules": [ |
||||
{ |
||||
"id": "org.example.demo:demo:2.2.0", |
||||
"artifacts": [ |
||||
{ |
||||
"type": "jar", |
||||
"sha1": "ayyyya9151a22cb3145538e523dbbaaaaaaaa", |
||||
"sha256": "aaaaaaaaa85f5c5093721f3ed0edda8ff8290yyyyyyyyyy", |
||||
"md5": "aaaaaacddea1724b0b69d8yyyyyyy", |
||||
"name": "demo-2.2.0.jar" |
||||
} |
||||
] |
||||
} |
||||
], |
||||
"statuses": [ |
||||
{ |
||||
"status": "staged", |
||||
"repository": "libs-staging-local", |
||||
"timestamp": "2019-09-10T12:42:24.716+0000", |
||||
"user": "user", |
||||
"timestampDate": 1568119344716 |
||||
} |
||||
] |
||||
}, |
||||
"uri": "https://my-artifactory-repo.com/api/build/example/example-build-1" |
||||
} |
||||
@ -1,362 +0,0 @@
@@ -1,362 +0,0 @@
|
||||
[ |
||||
{ |
||||
"events": [ |
||||
{ |
||||
"name": "repositoryCreated", |
||||
"properties": [ |
||||
{ |
||||
"name": "id", |
||||
"value": "orgspringframework-7161" |
||||
}, |
||||
{ |
||||
"name": "user", |
||||
"value": "user" |
||||
}, |
||||
{ |
||||
"name": "ip", |
||||
"value": "127.0.0.1" |
||||
} |
||||
], |
||||
"severity": 0, |
||||
"timestamp": "2021-02-08T14:31:13.523Z" |
||||
} |
||||
], |
||||
"name": "open", |
||||
"started": "2021-02-08T14:31:00.662Z", |
||||
"stopped": "2021-02-08T14:31:14.855Z" |
||||
}, |
||||
{ |
||||
"events": [ |
||||
{ |
||||
"name": "rulesEvaluate", |
||||
"properties": [ |
||||
{ |
||||
"name": "id", |
||||
"value": "5e9e8e6f8d20a3" |
||||
}, |
||||
{ |
||||
"name": "rule", |
||||
"value": "no-traversal-paths-in-archive-file" |
||||
}, |
||||
{ |
||||
"name": "rule", |
||||
"value": "profile-target-matching-staging" |
||||
}, |
||||
{ |
||||
"name": "rule", |
||||
"value": "sbom-report" |
||||
}, |
||||
{ |
||||
"name": "rule", |
||||
"value": "checksum-staging" |
||||
}, |
||||
{ |
||||
"name": "rule", |
||||
"value": "javadoc-staging" |
||||
}, |
||||
{ |
||||
"name": "rule", |
||||
"value": "pom-staging" |
||||
}, |
||||
{ |
||||
"name": "rule", |
||||
"value": "signature-staging" |
||||
}, |
||||
{ |
||||
"name": "rule", |
||||
"value": "sources-staging" |
||||
} |
||||
], |
||||
"severity": 0, |
||||
"timestamp": "2021-02-08T14:31:37.327Z" |
||||
}, |
||||
{ |
||||
"name": "ruleEvaluate", |
||||
"properties": [ |
||||
{ |
||||
"name": "typeId", |
||||
"value": "no-traversal-paths-in-archive-file" |
||||
} |
||||
], |
||||
"severity": 0, |
||||
"timestamp": "2021-02-08T14:31:41.254Z" |
||||
}, |
||||
{ |
||||
"name": "rulePassed", |
||||
"properties": [ |
||||
{ |
||||
"name": "typeId", |
||||
"value": "no-traversal-paths-in-archive-file" |
||||
} |
||||
], |
||||
"severity": 0, |
||||
"timestamp": "2021-02-08T14:31:47.498Z" |
||||
}, |
||||
{ |
||||
"name": "ruleEvaluate", |
||||
"properties": [ |
||||
{ |
||||
"name": "typeId", |
||||
"value": "javadoc-staging" |
||||
} |
||||
], |
||||
"severity": 0, |
||||
"timestamp": "2021-02-08T14:31:53.438Z" |
||||
}, |
||||
{ |
||||
"name": "rulePassed", |
||||
"properties": [ |
||||
{ |
||||
"name": "typeId", |
||||
"value": "javadoc-staging" |
||||
} |
||||
], |
||||
"severity": 0, |
||||
"timestamp": "2021-02-08T14:31:54.623Z" |
||||
}, |
||||
{ |
||||
"name": "ruleEvaluate", |
||||
"properties": [ |
||||
{ |
||||
"name": "typeId", |
||||
"value": "pom-staging" |
||||
} |
||||
], |
||||
"severity": 0, |
||||
"timestamp": "2021-02-08T14:31:58.091Z" |
||||
}, |
||||
{ |
||||
"name": "ruleFailed", |
||||
"properties": [ |
||||
{ |
||||
"name": "typeId", |
||||
"value": "pom-staging" |
||||
}, |
||||
{ |
||||
"name": "failureMessage", |
||||
"value": "Invalid POM: /org/springframework/example/module-one/1.0.0/module-one-1.0.0.pom: Project name missing, Project description missing, Project URL missing, License information missing, SCM URL missing, Developer information missing" |
||||
}, |
||||
{ |
||||
"name": "failureMessage", |
||||
"value": "Invalid POM: /org/springframework/example/module-two/1.0.0/module-two-1.0.0.pom: Project name missing, Project description missing, Project URL missing, License information missing, SCM URL missing, Developer information missing" |
||||
}, |
||||
{ |
||||
"name": "failureMessage", |
||||
"value": "Invalid POM: /org/springframework/example/module-three/1.0.0/module-three-1.0.0.pom: Project name missing, Project description missing, Project URL missing, License information missing, SCM URL missing, Developer information missing" |
||||
} |
||||
], |
||||
"severity": 1, |
||||
"timestamp": "2021-02-08T14:31:59.403Z" |
||||
}, |
||||
{ |
||||
"name": "ruleEvaluate", |
||||
"properties": [ |
||||
{ |
||||
"name": "typeId", |
||||
"value": "profile-target-matching-staging" |
||||
} |
||||
], |
||||
"severity": 0, |
||||
"timestamp": "2021-02-08T14:32:05.322Z" |
||||
}, |
||||
{ |
||||
"name": "rulePassed", |
||||
"properties": [ |
||||
{ |
||||
"name": "typeId", |
||||
"value": "profile-target-matching-staging" |
||||
} |
||||
], |
||||
"severity": 0, |
||||
"timestamp": "2021-02-08T14:32:06.492Z" |
||||
}, |
||||
{ |
||||
"name": "ruleEvaluate", |
||||
"properties": [ |
||||
{ |
||||
"name": "typeId", |
||||
"value": "checksum-staging" |
||||
} |
||||
], |
||||
"severity": 0, |
||||
"timestamp": "2021-02-08T14:32:12.415Z" |
||||
}, |
||||
{ |
||||
"name": "rulePassed", |
||||
"properties": [ |
||||
{ |
||||
"name": "typeId", |
||||
"value": "checksum-staging" |
||||
} |
||||
], |
||||
"severity": 0, |
||||
"timestamp": "2021-02-08T14:32:13.568Z" |
||||
}, |
||||
{ |
||||
"name": "ruleEvaluate", |
||||
"properties": [ |
||||
{ |
||||
"name": "typeId", |
||||
"value": "signature-staging" |
||||
} |
||||
], |
||||
"severity": 0, |
||||
"timestamp": "2021-02-08T14:32:18.288Z" |
||||
}, |
||||
{ |
||||
"name": "ruleFailed", |
||||
"properties": [ |
||||
{ |
||||
"name": "typeId", |
||||
"value": "signature-staging" |
||||
}, |
||||
{ |
||||
"name": "failureMessage", |
||||
"value": "Missing Signature: '/org/springframework/example/module-one/1.0.0/module-one-1.0.0-javadoc.jar.asc' does not exist for 'module-one-1.0.0-javadoc.jar'." |
||||
}, |
||||
{ |
||||
"name": "failureMessage", |
||||
"value": "Missing Signature: '/org/springframework/example/module-one/1.0.0/module-one-1.0.0.jar.asc' does not exist for 'module-one-1.0.0.jar'." |
||||
}, |
||||
{ |
||||
"name": "failureMessage", |
||||
"value": "Missing Signature: '/org/springframework/example/module-one/1.0.0/module-one-1.0.0-sources.jar.asc' does not exist for 'module-one-1.0.0-sources.jar'." |
||||
}, |
||||
{ |
||||
"name": "failureMessage", |
||||
"value": "Missing Signature: '/org/springframework/example/module-one/1.0.0/module-one-1.0.0.module.asc' does not exist for 'module-one-1.0.0.module'." |
||||
}, |
||||
{ |
||||
"name": "failureMessage", |
||||
"value": "Missing Signature: '/org/springframework/example/module-one/1.0.0/module-one-1.0.0.pom.asc' does not exist for 'module-one-1.0.0.pom'." |
||||
}, |
||||
{ |
||||
"name": "failureMessage", |
||||
"value": "Missing Signature: '/org/springframework/example/module-two/1.0.0/module-two-1.0.0.module.asc' does not exist for 'module-two-1.0.0.module'." |
||||
}, |
||||
{ |
||||
"name": "failureMessage", |
||||
"value": "Missing Signature: '/org/springframework/example/module-two/1.0.0/module-two-1.0.0.pom.asc' does not exist for 'module-two-1.0.0.pom'." |
||||
}, |
||||
{ |
||||
"name": "failureMessage", |
||||
"value": "Missing Signature: '/org/springframework/example/module-two/1.0.0/module-two-1.0.0-sources.jar.asc' does not exist for 'module-two-1.0.0-sources.jar'." |
||||
}, |
||||
{ |
||||
"name": "failureMessage", |
||||
"value": "Missing Signature: '/org/springframework/example/module-two/1.0.0/module-two-1.0.0.jar.asc' does not exist for 'module-two-1.0.0.jar'." |
||||
}, |
||||
{ |
||||
"name": "failureMessage", |
||||
"value": "Missing Signature: '/org/springframework/example/module-two/1.0.0/module-two-1.0.0-javadoc.jar.asc' does not exist for 'module-two-1.0.0-javadoc.jar'." |
||||
}, |
||||
{ |
||||
"name": "failureMessage", |
||||
"value": "Missing Signature: '/org/springframework/example/module-three/1.0.0/module-three-1.0.0.module.asc' does not exist for 'module-three-1.0.0.module'." |
||||
}, |
||||
{ |
||||
"name": "failureMessage", |
||||
"value": "Missing Signature: '/org/springframework/example/module-three/1.0.0/module-three-1.0.0-javadoc.jar.asc' does not exist for 'module-three-1.0.0-javadoc.jar'." |
||||
}, |
||||
{ |
||||
"name": "failureMessage", |
||||
"value": "Missing Signature: '/org/springframework/example/module-three/1.0.0/module-three-1.0.0-sources.jar.asc' does not exist for 'module-three-1.0.0-sources.jar'." |
||||
}, |
||||
{ |
||||
"name": "failureMessage", |
||||
"value": "Missing Signature: '/org/springframework/example/module-three/1.0.0/module-three-1.0.0.jar.asc' does not exist for 'module-three-1.0.0.jar'." |
||||
}, |
||||
{ |
||||
"name": "failureMessage", |
||||
"value": "Missing Signature: '/org/springframework/example/module-three/1.0.0/module-three-1.0.0.pom.asc' does not exist for 'module-three-1.0.0.pom'." |
||||
} |
||||
], |
||||
"severity": 1, |
||||
"timestamp": "2021-02-08T14:32:19.443Z" |
||||
}, |
||||
{ |
||||
"name": "ruleEvaluate", |
||||
"properties": [ |
||||
{ |
||||
"name": "typeId", |
||||
"value": "sources-staging" |
||||
} |
||||
], |
||||
"severity": 0, |
||||
"timestamp": "2021-02-08T14:32:24.175Z" |
||||
}, |
||||
{ |
||||
"name": "rulePassed", |
||||
"properties": [ |
||||
{ |
||||
"name": "typeId", |
||||
"value": "sources-staging" |
||||
} |
||||
], |
||||
"severity": 0, |
||||
"timestamp": "2021-02-08T14:32:28.940Z" |
||||
}, |
||||
{ |
||||
"name": "ruleEvaluate", |
||||
"properties": [ |
||||
{ |
||||
"name": "typeId", |
||||
"value": "sbom-report" |
||||
} |
||||
], |
||||
"severity": 0, |
||||
"timestamp": "2021-02-08T14:32:34.906Z" |
||||
}, |
||||
{ |
||||
"name": "rulePassed", |
||||
"properties": [ |
||||
{ |
||||
"name": "typeId", |
||||
"value": "sbom-report" |
||||
}, |
||||
{ |
||||
"name": "successMessage", |
||||
"value": "Successfully requested SBOM report" |
||||
} |
||||
], |
||||
"severity": 0, |
||||
"timestamp": "2021-02-08T14:32:36.520Z" |
||||
}, |
||||
{ |
||||
"name": "rulesFailed", |
||||
"properties": [ |
||||
{ |
||||
"name": "id", |
||||
"value": "5e9e8e6f8d20a3" |
||||
}, |
||||
{ |
||||
"name": "failureCount", |
||||
"value": "2" |
||||
} |
||||
], |
||||
"severity": 1, |
||||
"timestamp": "2021-02-08T14:32:42.068Z" |
||||
}, |
||||
{ |
||||
"name": "repositoryCloseFailed", |
||||
"properties": [ |
||||
{ |
||||
"name": "id", |
||||
"value": "orgspringframework-7161" |
||||
}, |
||||
{ |
||||
"name": "cause", |
||||
"value": "com.sonatype.nexus.staging.StagingRulesFailedException: One or more rules have failed" |
||||
} |
||||
], |
||||
"severity": 1, |
||||
"timestamp": "2021-02-08T14:32:43.218Z" |
||||
} |
||||
], |
||||
"name": "close", |
||||
"started": "2021-02-08T14:31:34.943Z", |
||||
"startedByIpAddress": "127.0.0.1", |
||||
"startedByUserId": "user", |
||||
"stopped": "2021-02-08T14:32:47.138Z" |
||||
} |
||||
] |
||||
@ -1,35 +0,0 @@
@@ -1,35 +0,0 @@
|
||||
{ |
||||
"buildInfo": { |
||||
"version": "1.0.1", |
||||
"name": "example", |
||||
"number": "example-build-1", |
||||
"started": "2019-09-10T12:18:05.430+0000", |
||||
"durationMillis": 0, |
||||
"artifactoryPrincipal": "user", |
||||
"url": "https://my-ci.com", |
||||
"modules": [ |
||||
{ |
||||
"id": "org.example.demo:demo:2.2.0", |
||||
"artifacts": [ |
||||
{ |
||||
"type": "jar", |
||||
"sha1": "ayyyya9151a22cb3145538e523dbbaaaaaaaa", |
||||
"sha256": "aaaaaaaaa85f5c5093721f3ed0edda8ff8290yyyyyyyyyy", |
||||
"md5": "aaaaaacddea1724b0b69d8yyyyyyy", |
||||
"name": "demo-2.2.0.jar" |
||||
} |
||||
] |
||||
} |
||||
], |
||||
"statuses": [ |
||||
{ |
||||
"status": "staged", |
||||
"repository": "libs-release-local", |
||||
"timestamp": "2019-09-10T12:42:24.716+0000", |
||||
"user": "user", |
||||
"timestampDate": 1568119344716 |
||||
} |
||||
] |
||||
}, |
||||
"uri": "https://my-artifactory-repo.com/api/build/example/example-build-1" |
||||
} |
||||
Binary file not shown.
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE----- |
||||
|
||||
iQEzBAABCAAdFiEE4qywN5M83qq3v3fUmix6mORXxT0FAmAiY1oACgkQmix6mORX |
||||
xT3qtgf8CeDvxzi7lPghlrZtmYTTjaic4FZsGRWTPky3H24i4wSRDhG0L5sj4uPK |
||||
eLLlITr5a9j26UCas9HRSthiC8+EgIMAhSN0X482SQhUZHAW67ErIvaHlwL+ixMD |
||||
0T5pmsW8PKN3lV1TFMhNYSEC2GRG/4GF+3yQA8LR+BgeEu/E5nmysIH8vuQMkOD6 |
||||
3pKA8VKNBml591j6UTqxoHtPX+rThaziz3Hy3+ekf5iWslllTTGPd2SWqTvnj2Ae |
||||
GvRzsbli+FEM0Aj/v8jUQnQzOz891QSvWR+fMfCqZimiJMc+GBzJ9umbcyQsB5tY |
||||
e26mAoYd9KEpGXMKN4biHbJZNp1GGw== |
||||
=x/MY |
||||
-----END PGP SIGNATURE----- |
||||
@ -1 +0,0 @@
@@ -1 +0,0 @@
|
||||
e84da489be91de821c95d41b8f0e0a0a |
||||
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE----- |
||||
|
||||
iQEzBAABCAAdFiEE4qywN5M83qq3v3fUmix6mORXxT0FAmAiY1oACgkQmix6mORX |
||||
xT1PSwf+InTdlh+BVVy3RFszEL5vN7waSPYMImXhgd5EZ1d4Lxd6EeOwtNgWNKpG |
||||
E+Ps/Kw0jZDvoD49WJlcUjzDHBNHcE7C/L3GAWHV6WwklhtQaJ4EegsynWdSXz6k |
||||
fqJY6r58aGKGjpKPutRWAjvfcdC170+ZRsc2oi9xrAgHCpvXzTjq4+O9Ah0t5jwW |
||||
jcZ/Xubcw4vjsw774OucHbtwGsvRN5SDJ3IONOH8WCwhUP5vEEKvA6MYX0KGoTdS |
||||
3wTCyZTzU3qtTWxcbTCpiJIWbYwRR7TzLB/uydWHlAMzuz6coIiBpYsGiO6wkmfg |
||||
W+QvcE7wyW2jtb22pCImLyObyZ21VA== |
||||
=VjDv |
||||
-----END PGP SIGNATURE----- |
||||
@ -1 +0,0 @@
@@ -1 +0,0 @@
|
||||
8992b17455ce660da9c5fe47226b7ded9e872637 |
||||
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE----- |
||||
|
||||
iQEzBAABCAAdFiEE4qywN5M83qq3v3fUmix6mORXxT0FAmAiY1oACgkQmix6mORX |
||||
xT2HQgf+MTUEnwzXK4zi76VI7C5cchGan26lIA2Ebq4vtYGKDqNSISOAAdWs9+nT |
||||
U6ZA6OIFo5qdeD6F/45s91IoDbxbhMDMFEsSijKASqiuZN5TZM1U2h2kWFAl/sEl |
||||
EI1RTygn+xDw/ah4V3/duuMFC+jRgvJ/LgemIF4KBvECWaTQKNu0fu5d4dPXMpp+ |
||||
jrxMEZPQZsivpOvklzV8O7wAkf/ZQhJdcB2m8uOfSPlJ91a4EEtXF9/GzzkXUi1P |
||||
bzt4NsmOag3227B3mO1Bc6yZdDBNu8wQ9apiJVCpqsxB9Dz0PCL4dHNa1u9g6Xo6 |
||||
ElRgneV4HZp+LB125VoNabKuNH00bw== |
||||
=2yDl |
||||
-----END PGP SIGNATURE----- |
||||
@ -1 +0,0 @@
@@ -1 +0,0 @@
|
||||
10ce8a82f7e53c67f2af8d4dc4b8cdb4d0630d0e1d21818da4d5b3ca2de08385 |
||||
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE----- |
||||
|
||||
iQEzBAABCAAdFiEE4qywN5M83qq3v3fUmix6mORXxT0FAmAiY1oACgkQmix6mORX |
||||
xT0ScQf7Bip+quFq1CzDCTDxUhdTTOIpQcCfMKo1Jegpa2Hlm63XuK+6zVI9u6S+ |
||||
dBXPdYeneMOqMPQUAaw3M06ZqohaDOt8Ti1EiQFGXCdOvbonTA52Lrd4EEZxwNnK |
||||
BdPuIh/8qCfozm5KbZe1bFyGVRAdNyf27KvzHgfBTirLtI+3MiOdL4bvNZbWRPfh |
||||
J84Ko+Ena8jPFgyz6nJv2Q2U/V3dCooLJAXs2vEG6owwk5J9zvSysWpHaJbXas5v |
||||
KXO9TOBBjf3+vxb1WVQa8ZYUU3+FIFes0RFVgOWghJXIooOcWrwOV2Q8z9qWXwoK |
||||
mMZ2oLS+z/7clXibK45KeRUeCX5DvQ== |
||||
=5oO1 |
||||
-----END PGP SIGNATURE----- |
||||
@ -1 +0,0 @@
@@ -1 +0,0 @@
|
||||
2730ac0859e1c2f450d54647c29ece43d095eb834e2130d4949dd1151317d013c072fa8f96f5f4b49836eff7c19a2eeeb5ca7483e5dac24c368bbcd522c27a00 |
||||
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE----- |
||||
|
||||
iQEzBAABCAAdFiEE4qywN5M83qq3v3fUmix6mORXxT0FAmAiY1oACgkQmix6mORX |
||||
xT3d+AgAwQvlwnKQLLuiZADGL+I922/YG317N2Re1EjC6WlMRZUKXH54fckRTyPm |
||||
4ZLyxVHy8LlUD2Q10g69opb7HRd/tV0miBJhn5OU1wIM3hqTgxNp9EFckK4md45k |
||||
osnhQJNDsFToxJL8zPP+KRs/aWPZs+FrRcH6k26lwLl2gTfyBDsaU11HFRVEN9yi |
||||
X41obVyKiVNlc9efSSvlLtRBSVt0VhAFhck+3t61H6D9H09QxaDGAqmduDua3Tg3 |
||||
t5eqURuDfv3TfSztYgK3JBmG/6gVMsZodCgyC+8rhDDs6vSoDG30apx5Leg2rPbj |
||||
xuk2wi/WNzc94IgY9tVS3tAfT2k6yQ== |
||||
=6+Cv |
||||
-----END PGP SIGNATURE----- |
||||
Binary file not shown.
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE----- |
||||
|
||||
iQEzBAABCAAdFiEE4qywN5M83qq3v3fUmix6mORXxT0FAmAiY1oACgkQmix6mORX |
||||
xT3qtgf8CeDvxzi7lPghlrZtmYTTjaic4FZsGRWTPky3H24i4wSRDhG0L5sj4uPK |
||||
eLLlITr5a9j26UCas9HRSthiC8+EgIMAhSN0X482SQhUZHAW67ErIvaHlwL+ixMD |
||||
0T5pmsW8PKN3lV1TFMhNYSEC2GRG/4GF+3yQA8LR+BgeEu/E5nmysIH8vuQMkOD6 |
||||
3pKA8VKNBml591j6UTqxoHtPX+rThaziz3Hy3+ekf5iWslllTTGPd2SWqTvnj2Ae |
||||
GvRzsbli+FEM0Aj/v8jUQnQzOz891QSvWR+fMfCqZimiJMc+GBzJ9umbcyQsB5tY |
||||
e26mAoYd9KEpGXMKN4biHbJZNp1GGw== |
||||
=x/MY |
||||
-----END PGP SIGNATURE----- |
||||
@ -1 +0,0 @@
@@ -1 +0,0 @@
|
||||
e84da489be91de821c95d41b8f0e0a0a |
||||
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE----- |
||||
|
||||
iQEzBAABCAAdFiEE4qywN5M83qq3v3fUmix6mORXxT0FAmAiY1oACgkQmix6mORX |
||||
xT1PSwf+InTdlh+BVVy3RFszEL5vN7waSPYMImXhgd5EZ1d4Lxd6EeOwtNgWNKpG |
||||
E+Ps/Kw0jZDvoD49WJlcUjzDHBNHcE7C/L3GAWHV6WwklhtQaJ4EegsynWdSXz6k |
||||
fqJY6r58aGKGjpKPutRWAjvfcdC170+ZRsc2oi9xrAgHCpvXzTjq4+O9Ah0t5jwW |
||||
jcZ/Xubcw4vjsw774OucHbtwGsvRN5SDJ3IONOH8WCwhUP5vEEKvA6MYX0KGoTdS |
||||
3wTCyZTzU3qtTWxcbTCpiJIWbYwRR7TzLB/uydWHlAMzuz6coIiBpYsGiO6wkmfg |
||||
W+QvcE7wyW2jtb22pCImLyObyZ21VA== |
||||
=VjDv |
||||
-----END PGP SIGNATURE----- |
||||
@ -1 +0,0 @@
@@ -1 +0,0 @@
|
||||
8992b17455ce660da9c5fe47226b7ded9e872637 |
||||
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE----- |
||||
|
||||
iQEzBAABCAAdFiEE4qywN5M83qq3v3fUmix6mORXxT0FAmAiY1oACgkQmix6mORX |
||||
xT2HQgf+MTUEnwzXK4zi76VI7C5cchGan26lIA2Ebq4vtYGKDqNSISOAAdWs9+nT |
||||
U6ZA6OIFo5qdeD6F/45s91IoDbxbhMDMFEsSijKASqiuZN5TZM1U2h2kWFAl/sEl |
||||
EI1RTygn+xDw/ah4V3/duuMFC+jRgvJ/LgemIF4KBvECWaTQKNu0fu5d4dPXMpp+ |
||||
jrxMEZPQZsivpOvklzV8O7wAkf/ZQhJdcB2m8uOfSPlJ91a4EEtXF9/GzzkXUi1P |
||||
bzt4NsmOag3227B3mO1Bc6yZdDBNu8wQ9apiJVCpqsxB9Dz0PCL4dHNa1u9g6Xo6 |
||||
ElRgneV4HZp+LB125VoNabKuNH00bw== |
||||
=2yDl |
||||
-----END PGP SIGNATURE----- |
||||
@ -1 +0,0 @@
@@ -1 +0,0 @@
|
||||
10ce8a82f7e53c67f2af8d4dc4b8cdb4d0630d0e1d21818da4d5b3ca2de08385 |
||||
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE----- |
||||
|
||||
iQEzBAABCAAdFiEE4qywN5M83qq3v3fUmix6mORXxT0FAmAiY1oACgkQmix6mORX |
||||
xT0ScQf7Bip+quFq1CzDCTDxUhdTTOIpQcCfMKo1Jegpa2Hlm63XuK+6zVI9u6S+ |
||||
dBXPdYeneMOqMPQUAaw3M06ZqohaDOt8Ti1EiQFGXCdOvbonTA52Lrd4EEZxwNnK |
||||
BdPuIh/8qCfozm5KbZe1bFyGVRAdNyf27KvzHgfBTirLtI+3MiOdL4bvNZbWRPfh |
||||
J84Ko+Ena8jPFgyz6nJv2Q2U/V3dCooLJAXs2vEG6owwk5J9zvSysWpHaJbXas5v |
||||
KXO9TOBBjf3+vxb1WVQa8ZYUU3+FIFes0RFVgOWghJXIooOcWrwOV2Q8z9qWXwoK |
||||
mMZ2oLS+z/7clXibK45KeRUeCX5DvQ== |
||||
=5oO1 |
||||
-----END PGP SIGNATURE----- |
||||
@ -1 +0,0 @@
@@ -1 +0,0 @@
|
||||
2730ac0859e1c2f450d54647c29ece43d095eb834e2130d4949dd1151317d013c072fa8f96f5f4b49836eff7c19a2eeeb5ca7483e5dac24c368bbcd522c27a00 |
||||
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE----- |
||||
|
||||
iQEzBAABCAAdFiEE4qywN5M83qq3v3fUmix6mORXxT0FAmAiY1oACgkQmix6mORX |
||||
xT3d+AgAwQvlwnKQLLuiZADGL+I922/YG317N2Re1EjC6WlMRZUKXH54fckRTyPm |
||||
4ZLyxVHy8LlUD2Q10g69opb7HRd/tV0miBJhn5OU1wIM3hqTgxNp9EFckK4md45k |
||||
osnhQJNDsFToxJL8zPP+KRs/aWPZs+FrRcH6k26lwLl2gTfyBDsaU11HFRVEN9yi |
||||
X41obVyKiVNlc9efSSvlLtRBSVt0VhAFhck+3t61H6D9H09QxaDGAqmduDua3Tg3 |
||||
t5eqURuDfv3TfSztYgK3JBmG/6gVMsZodCgyC+8rhDDs6vSoDG30apx5Leg2rPbj |
||||
xuk2wi/WNzc94IgY9tVS3tAfT2k6yQ== |
||||
=6+Cv |
||||
-----END PGP SIGNATURE----- |
||||
Binary file not shown.
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE----- |
||||
|
||||
iQEzBAABCAAdFiEE4qywN5M83qq3v3fUmix6mORXxT0FAmAiY1oACgkQmix6mORX |
||||
xT3qtgf8CeDvxzi7lPghlrZtmYTTjaic4FZsGRWTPky3H24i4wSRDhG0L5sj4uPK |
||||
eLLlITr5a9j26UCas9HRSthiC8+EgIMAhSN0X482SQhUZHAW67ErIvaHlwL+ixMD |
||||
0T5pmsW8PKN3lV1TFMhNYSEC2GRG/4GF+3yQA8LR+BgeEu/E5nmysIH8vuQMkOD6 |
||||
3pKA8VKNBml591j6UTqxoHtPX+rThaziz3Hy3+ekf5iWslllTTGPd2SWqTvnj2Ae |
||||
GvRzsbli+FEM0Aj/v8jUQnQzOz891QSvWR+fMfCqZimiJMc+GBzJ9umbcyQsB5tY |
||||
e26mAoYd9KEpGXMKN4biHbJZNp1GGw== |
||||
=x/MY |
||||
-----END PGP SIGNATURE----- |
||||
@ -1 +0,0 @@
@@ -1 +0,0 @@
|
||||
e84da489be91de821c95d41b8f0e0a0a |
||||
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE----- |
||||
|
||||
iQEzBAABCAAdFiEE4qywN5M83qq3v3fUmix6mORXxT0FAmAiY1oACgkQmix6mORX |
||||
xT1PSwf+InTdlh+BVVy3RFszEL5vN7waSPYMImXhgd5EZ1d4Lxd6EeOwtNgWNKpG |
||||
E+Ps/Kw0jZDvoD49WJlcUjzDHBNHcE7C/L3GAWHV6WwklhtQaJ4EegsynWdSXz6k |
||||
fqJY6r58aGKGjpKPutRWAjvfcdC170+ZRsc2oi9xrAgHCpvXzTjq4+O9Ah0t5jwW |
||||
jcZ/Xubcw4vjsw774OucHbtwGsvRN5SDJ3IONOH8WCwhUP5vEEKvA6MYX0KGoTdS |
||||
3wTCyZTzU3qtTWxcbTCpiJIWbYwRR7TzLB/uydWHlAMzuz6coIiBpYsGiO6wkmfg |
||||
W+QvcE7wyW2jtb22pCImLyObyZ21VA== |
||||
=VjDv |
||||
-----END PGP SIGNATURE----- |
||||
@ -1 +0,0 @@
@@ -1 +0,0 @@
|
||||
8992b17455ce660da9c5fe47226b7ded9e872637 |
||||
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE----- |
||||
|
||||
iQEzBAABCAAdFiEE4qywN5M83qq3v3fUmix6mORXxT0FAmAiY1oACgkQmix6mORX |
||||
xT2HQgf+MTUEnwzXK4zi76VI7C5cchGan26lIA2Ebq4vtYGKDqNSISOAAdWs9+nT |
||||
U6ZA6OIFo5qdeD6F/45s91IoDbxbhMDMFEsSijKASqiuZN5TZM1U2h2kWFAl/sEl |
||||
EI1RTygn+xDw/ah4V3/duuMFC+jRgvJ/LgemIF4KBvECWaTQKNu0fu5d4dPXMpp+ |
||||
jrxMEZPQZsivpOvklzV8O7wAkf/ZQhJdcB2m8uOfSPlJ91a4EEtXF9/GzzkXUi1P |
||||
bzt4NsmOag3227B3mO1Bc6yZdDBNu8wQ9apiJVCpqsxB9Dz0PCL4dHNa1u9g6Xo6 |
||||
ElRgneV4HZp+LB125VoNabKuNH00bw== |
||||
=2yDl |
||||
-----END PGP SIGNATURE----- |
||||
@ -1 +0,0 @@
@@ -1 +0,0 @@
|
||||
10ce8a82f7e53c67f2af8d4dc4b8cdb4d0630d0e1d21818da4d5b3ca2de08385 |
||||
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE----- |
||||
|
||||
iQEzBAABCAAdFiEE4qywN5M83qq3v3fUmix6mORXxT0FAmAiY1oACgkQmix6mORX |
||||
xT0ScQf7Bip+quFq1CzDCTDxUhdTTOIpQcCfMKo1Jegpa2Hlm63XuK+6zVI9u6S+ |
||||
dBXPdYeneMOqMPQUAaw3M06ZqohaDOt8Ti1EiQFGXCdOvbonTA52Lrd4EEZxwNnK |
||||
BdPuIh/8qCfozm5KbZe1bFyGVRAdNyf27KvzHgfBTirLtI+3MiOdL4bvNZbWRPfh |
||||
J84Ko+Ena8jPFgyz6nJv2Q2U/V3dCooLJAXs2vEG6owwk5J9zvSysWpHaJbXas5v |
||||
KXO9TOBBjf3+vxb1WVQa8ZYUU3+FIFes0RFVgOWghJXIooOcWrwOV2Q8z9qWXwoK |
||||
mMZ2oLS+z/7clXibK45KeRUeCX5DvQ== |
||||
=5oO1 |
||||
-----END PGP SIGNATURE----- |
||||
@ -1 +0,0 @@
@@ -1 +0,0 @@
|
||||
2730ac0859e1c2f450d54647c29ece43d095eb834e2130d4949dd1151317d013c072fa8f96f5f4b49836eff7c19a2eeeb5ca7483e5dac24c368bbcd522c27a00 |
||||
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE----- |
||||
|
||||
iQEzBAABCAAdFiEE4qywN5M83qq3v3fUmix6mORXxT0FAmAiY1oACgkQmix6mORX |
||||
xT3d+AgAwQvlwnKQLLuiZADGL+I922/YG317N2Re1EjC6WlMRZUKXH54fckRTyPm |
||||
4ZLyxVHy8LlUD2Q10g69opb7HRd/tV0miBJhn5OU1wIM3hqTgxNp9EFckK4md45k |
||||
osnhQJNDsFToxJL8zPP+KRs/aWPZs+FrRcH6k26lwLl2gTfyBDsaU11HFRVEN9yi |
||||
X41obVyKiVNlc9efSSvlLtRBSVt0VhAFhck+3t61H6D9H09QxaDGAqmduDua3Tg3 |
||||
t5eqURuDfv3TfSztYgK3JBmG/6gVMsZodCgyC+8rhDDs6vSoDG30apx5Leg2rPbj |
||||
xuk2wi/WNzc94IgY9tVS3tAfT2k6yQ== |
||||
=6+Cv |
||||
-----END PGP SIGNATURE----- |
||||
@ -1,101 +0,0 @@
@@ -1,101 +0,0 @@
|
||||
{ |
||||
"formatVersion": "1.1", |
||||
"component": { |
||||
"group": "org.springframework.example", |
||||
"module": "module-one", |
||||
"version": "1.0.0", |
||||
"attributes": { |
||||
"org.gradle.status": "release" |
||||
} |
||||
}, |
||||
"createdBy": { |
||||
"gradle": { |
||||
"version": "6.5.1", |
||||
"buildId": "mvqepqsdqjcahjl7cii6b6ucoe" |
||||
} |
||||
}, |
||||
"variants": [ |
||||
{ |
||||
"name": "apiElements", |
||||
"attributes": { |
||||
"org.gradle.category": "library", |
||||
"org.gradle.dependency.bundling": "external", |
||||
"org.gradle.jvm.version": 8, |
||||
"org.gradle.libraryelements": "jar", |
||||
"org.gradle.usage": "java-api" |
||||
}, |
||||
"files": [ |
||||
{ |
||||
"name": "module-one-1.0.0.jar", |
||||
"url": "module-one-1.0.0.jar", |
||||
"size": 261, |
||||
"sha512": "2730ac0859e1c2f450d54647c29ece43d095eb834e2130d4949dd1151317d013c072fa8f96f5f4b49836eff7c19a2eeeb5ca7483e5dac24c368bbcd522c27a00", |
||||
"sha256": "10ce8a82f7e53c67f2af8d4dc4b8cdb4d0630d0e1d21818da4d5b3ca2de08385", |
||||
"sha1": "8992b17455ce660da9c5fe47226b7ded9e872637", |
||||
"md5": "e84da489be91de821c95d41b8f0e0a0a" |
||||
} |
||||
] |
||||
}, |
||||
{ |
||||
"name": "runtimeElements", |
||||
"attributes": { |
||||
"org.gradle.category": "library", |
||||
"org.gradle.dependency.bundling": "external", |
||||
"org.gradle.jvm.version": 8, |
||||
"org.gradle.libraryelements": "jar", |
||||
"org.gradle.usage": "java-runtime" |
||||
}, |
||||
"files": [ |
||||
{ |
||||
"name": "module-one-1.0.0.jar", |
||||
"url": "module-one-1.0.0.jar", |
||||
"size": 261, |
||||
"sha512": "2730ac0859e1c2f450d54647c29ece43d095eb834e2130d4949dd1151317d013c072fa8f96f5f4b49836eff7c19a2eeeb5ca7483e5dac24c368bbcd522c27a00", |
||||
"sha256": "10ce8a82f7e53c67f2af8d4dc4b8cdb4d0630d0e1d21818da4d5b3ca2de08385", |
||||
"sha1": "8992b17455ce660da9c5fe47226b7ded9e872637", |
||||
"md5": "e84da489be91de821c95d41b8f0e0a0a" |
||||
} |
||||
] |
||||
}, |
||||
{ |
||||
"name": "javadocElements", |
||||
"attributes": { |
||||
"org.gradle.category": "documentation", |
||||
"org.gradle.dependency.bundling": "external", |
||||
"org.gradle.docstype": "javadoc", |
||||
"org.gradle.usage": "java-runtime" |
||||
}, |
||||
"files": [ |
||||
{ |
||||
"name": "module-one-1.0.0-javadoc.jar", |
||||
"url": "module-one-1.0.0-javadoc.jar", |
||||
"size": 261, |
||||
"sha512": "2730ac0859e1c2f450d54647c29ece43d095eb834e2130d4949dd1151317d013c072fa8f96f5f4b49836eff7c19a2eeeb5ca7483e5dac24c368bbcd522c27a00", |
||||
"sha256": "10ce8a82f7e53c67f2af8d4dc4b8cdb4d0630d0e1d21818da4d5b3ca2de08385", |
||||
"sha1": "8992b17455ce660da9c5fe47226b7ded9e872637", |
||||
"md5": "e84da489be91de821c95d41b8f0e0a0a" |
||||
} |
||||
] |
||||
}, |
||||
{ |
||||
"name": "sourcesElements", |
||||
"attributes": { |
||||
"org.gradle.category": "documentation", |
||||
"org.gradle.dependency.bundling": "external", |
||||
"org.gradle.docstype": "sources", |
||||
"org.gradle.usage": "java-runtime" |
||||
}, |
||||
"files": [ |
||||
{ |
||||
"name": "module-one-1.0.0-sources.jar", |
||||
"url": "module-one-1.0.0-sources.jar", |
||||
"size": 261, |
||||
"sha512": "2730ac0859e1c2f450d54647c29ece43d095eb834e2130d4949dd1151317d013c072fa8f96f5f4b49836eff7c19a2eeeb5ca7483e5dac24c368bbcd522c27a00", |
||||
"sha256": "10ce8a82f7e53c67f2af8d4dc4b8cdb4d0630d0e1d21818da4d5b3ca2de08385", |
||||
"sha1": "8992b17455ce660da9c5fe47226b7ded9e872637", |
||||
"md5": "e84da489be91de821c95d41b8f0e0a0a" |
||||
} |
||||
] |
||||
} |
||||
] |
||||
} |
||||
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE----- |
||||
|
||||
iQEzBAABCAAdFiEE4qywN5M83qq3v3fUmix6mORXxT0FAmAiY1oACgkQmix6mORX |
||||
xT1HBQf/fCBHR+fpZjkcgonkAVWcGvRx5kRHlsCISs64XMw90++DTawoKxr9/TvY |
||||
fltQlq/xaf+2O2Xzh9HIymtZBeKp7a4fWQ2AHf/ygkGyIKvy8h+mu3MGDdmHZeA4 |
||||
fn9FGjaE0a/wYJmCEHJ1qJ4GaNq47gzRTu76jzZNafnNRlq1rlyVu2txnlks6xDr |
||||
oE8EnRT86Y67Ku8YArjkhZSHhf/tzSSwdTAgBinh6eba5tW5ueRXfsheqgtpJMov |
||||
hiDIVxuAlJoHy2cQ8L9+8geg0OSXLwQ9BXrBsDCLvrDauU735/Hv/NGrWE95kemw |
||||
Ay9jCXhXFWKkzCw2ps3QHTTpTK4aVw== |
||||
=1QME |
||||
-----END PGP SIGNATURE----- |
||||
@ -1 +0,0 @@
@@ -1 +0,0 @@
|
||||
b5b2aedb082633674ef9308a2ac21934 |
||||
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE----- |
||||
|
||||
iQEzBAABCAAdFiEE4qywN5M83qq3v3fUmix6mORXxT0FAmAiY1oACgkQmix6mORX |
||||
xT1SLQgApB6OWW9cgtaofOu3HwgsVxaxLYPsDf057m2O5pI6uV5Ikyt97B1txjTB |
||||
9EXcy4gsfu7rxwgRHIEPCQkQKhhZioscT1SPFN0yopCwsJEvxrJE018ojyaIem/L |
||||
KVcbtiBVMj3GZCbS0DHpwZNx2u7yblyBqUGhCMKLkYqVL7nUHJKtECECs5jbJnb9 |
||||
xXGFe0xlZ/IbkHv5QXyStgUYCah7ayWQDvjN7UJrpJL1lmTD0rjWLilkeKsVu3/k |
||||
11cZb5YdOmrL9a+8ql1jXPkma3HPjoIPRC5LB2BnloduwEPsiiLGG7Cs8UFEJNjQ |
||||
m5w+l4dDd03y5ioaW8fI/meAKpBm4g== |
||||
=gwLM |
||||
-----END PGP SIGNATURE----- |
||||
@ -1 +0,0 @@
@@ -1 +0,0 @@
|
||||
b7cb6c2ce7fbb98b8eb502c3ef8fcab0dd4880fc |
||||
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE----- |
||||
|
||||
iQEzBAABCAAdFiEE4qywN5M83qq3v3fUmix6mORXxT0FAmAiY1oACgkQmix6mORX |
||||
xT2y5AgAlI4H5hwDIgVmXtRq/ri7kxEJnC9L9FOv8aE9YasHAruaU1YR5m17Jncl |
||||
4guJHc+gSd3BiSx1rsI6PNxLACabw4Vy56eCRpmiFWeIkoCETBUk8AN25Q/1tzgw |
||||
hHmIRgOkF9PzSBWDTUNsyx/7E9P2QSiJOkMAGGuMKGDpYTR9zmaluzwfY+BI/VoW |
||||
BbZpdzt02OGQosWmA7DlwkXUwip6iBjga79suUFIsyH0hmRW2q/nCeJ04ttzXUog |
||||
NTNkpEwMYpZAzQXE7ks7WJJlAPkVYPWy/j5YCV7xTFb9I/56ux+/wRUaGU5fumSR |
||||
lr3PNoYNToC/4GLX6Kc2OH0e1LXNTQ== |
||||
=s02D |
||||
-----END PGP SIGNATURE----- |
||||
@ -1 +0,0 @@
@@ -1 +0,0 @@
|
||||
4ef7e1ba5fda72b0168c9aab4746ec6ee57fb73020c49fe2f49251187aaab074 |
||||
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE----- |
||||
|
||||
iQEzBAABCAAdFiEE4qywN5M83qq3v3fUmix6mORXxT0FAmAiY1oACgkQmix6mORX |
||||
xT1/vwgAhUTLKjxmry4W3cVdfX/D/vxDTLAp5OxwJy36CZmJwsVuN9TLjPo4tRqq |
||||
woiopR2oSTaJqld2pe98WlIeDJJRe4ta1Uwvg7k4Sf6YaZXm01Wufk4a835sFUwY |
||||
BTWmnFYX0+dp5mLyXZmZjrAr5Q2bowRuqZd2DAYiNY/E5MH2T7OAJE2hCOHUpCaB |
||||
JVeP7HcbaGYR3NX/mLq0t8+xjTPXQk/OHijuusuLQxfLZvZiaikDoOHUD6l0dlRw |
||||
xcLTghG5+jd1q7noKAbUVgoEOshstfomCHZpPMj11c7KIuG1+3wRMdm+F67lkcJ5 |
||||
eDW2fmF+6LYr+WlEi33rDIyTk3GhlQ== |
||||
=mHUe |
||||
-----END PGP SIGNATURE----- |
||||
@ -1 +0,0 @@
@@ -1 +0,0 @@
|
||||
29b1bc06a150e4764826e35e2d2541933b0583ce823f5b00c02effad9f37f02f0d2eef1c81214d69eaf74220e1f77332c5e6a91eb413a3022b5a8a1d7914c4c3 |
||||
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE----- |
||||
|
||||
iQEzBAABCAAdFiEE4qywN5M83qq3v3fUmix6mORXxT0FAmAiY1oACgkQmix6mORX |
||||
xT0QLAf/ffTpTfH4IebklGJIKZC8ZjRt4CgwpR431qNeWkY25cHmWFj48x2u9dmS |
||||
ZpxN572d3PPjcMigT/9wM05omiU+4DHxGgHq/Xj6GXN1DNaENcu7uoye96thjKPv |
||||
jz98tPIRMC9hYr3m/K1CJ3+ZG0++7JorCZRpodH/MhklRWXOvNszs81VWtgvMnpd |
||||
h9r0PuoaYBl6bIl19o7E3JJU6dKgwfre4b+a1RSYI+A8bmJOKMgHytAKi+804r0P |
||||
4R2WuQT4q+dSmkMtgp65vJ9giv/xuFrd1bT4n+qcDkwE8pTcWvsB4w1RkDOKs4fK |
||||
/ta5xBQ1hiKAd6nJffke1b0MBrZOrA== |
||||
=ZMpE |
||||
-----END PGP SIGNATURE----- |
||||
@ -1,49 +0,0 @@
@@ -1,49 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
||||
<!-- This module was also published with a richer model, Gradle metadata, --> |
||||
<!-- which should be used instead. Do not delete the following line which --> |
||||
<!-- is to indicate to Gradle or any Gradle module metadata file consumer --> |
||||
<!-- that they should prefer consuming it instead. --> |
||||
<!-- do_not_remove: published-with-gradle-metadata --> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
<groupId>org.springframework.example</groupId> |
||||
<artifactId>module-one</artifactId> |
||||
<version>1.0.0</version> |
||||
<name>module-one</name> |
||||
<description>Example module</description> |
||||
<url>https://spring.io/projects/spring-boot</url> |
||||
<organization> |
||||
<name>Spring</name> |
||||
<url>https://spring.io</url> |
||||
</organization> |
||||
<licenses> |
||||
<license> |
||||
<name>Apache License, Version 2.0</name> |
||||
<url>https://www.apache.org/licenses/LICENSE-2.0</url> |
||||
</license> |
||||
</licenses> |
||||
<developers> |
||||
<developer> |
||||
<name>Spring</name> |
||||
<email>ask@spring.io</email> |
||||
<organization>Spring</organization> |
||||
<organizationUrl>https://www.spring.io</organizationUrl> |
||||
</developer> |
||||
</developers> |
||||
<scm> |
||||
<connection> |
||||
scm:git:git://github.com/spring-projects/spring-boot.git |
||||
</connection> |
||||
<developerConnection> |
||||
scm:git:ssh://git@github.com/spring-projects/spring-boot.git |
||||
</developerConnection> |
||||
<url>https://github.com/spring-projects/spring-boot</url> |
||||
</scm> |
||||
<issueManagement> |
||||
<system>GitHub</system> |
||||
<url> |
||||
https://github.com/spring-projects/spring-boot/issues |
||||
</url> |
||||
</issueManagement> |
||||
</project> |
||||
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE----- |
||||
|
||||
iQEzBAABCAAdFiEE4qywN5M83qq3v3fUmix6mORXxT0FAmAiY1oACgkQmix6mORX |
||||
xT04rwgAwJHic8GGHFZ+UAJYLW/OxJOVyd0ebx4yT5zAyTjyvxnrlKmKZ6GP/NhZ |
||||
htJQnZez85lUKA0TsMvl/6H2iEhKOns6HgqY3PLFkKNRKOq601phtD9HCkxDibWB |
||||
UDT01I0q2xNOljD03lhfytefnSnZ96AaySol2v5DBIZsOKWGir0/8KJCpEQJHjCF |
||||
TwNk8lNF3moGlO4zUfoBbkSZ+J0J8Bq5QI3nIAWFYxHcrZ2YGsAZd48kux8x2V3C |
||||
c6QsYEonmztqxop76a7K8Gv+MDmo/u/vqM8z5C63/WpOoDtRG+F5vtPkhCrR6M5f |
||||
ygubQUy5TL+dWdHE8zgA2O9hZuoHEg== |
||||
=bkxG |
||||
-----END PGP SIGNATURE----- |
||||
@ -1 +0,0 @@
@@ -1 +0,0 @@
|
||||
48776112e8bc3ca36b6392b0e9d6d619 |
||||
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE----- |
||||
|
||||
iQEzBAABCAAdFiEE4qywN5M83qq3v3fUmix6mORXxT0FAmAiY1oACgkQmix6mORX |
||||
xT0XEAf+O9a/29MIWBtj1oLxIT1LLdzTU68qt5+qW+58SNQmMxu0MaESW4GZOc3p |
||||
mTV0EJyxUkCLJyoqOY4/GhqBAm33mMZSY8BQtvUZPYxpbJwBo+pE8YfnH3n1v20P |
||||
4pS4oJKekXAhTqShpx5oFjCK4J3chaz+Xc8Ldm1DXakCRc1bc/YYZ+87sy2z+PXk |
||||
PmN3KPcc/XjH4GPjmVUR8vR1TGUjUMQGvbAdrgkjFyaCGNvyreuHLsAFWrFFbIOn |
||||
/mB++enkXhmjWbiyvmvWQvtU0QFA4sRGYww0Lup1GRQ+00IqHF1QRMskqujAwmok |
||||
+TuB3Zc9WuAERPre+Qr1DEevClNwAQ== |
||||
=3beu |
||||
-----END PGP SIGNATURE----- |
||||
@ -1 +0,0 @@
@@ -1 +0,0 @@
|
||||
a5cc75e17f8eccfc4ac30bfbb09f42d5f34ecbb1 |
||||
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE----- |
||||
|
||||
iQEzBAABCAAdFiEE4qywN5M83qq3v3fUmix6mORXxT0FAmAiY1oACgkQmix6mORX |
||||
xT2aVAf+MQhSBr1jzcQE5mo1bMOXa4owaRr+dRir5Q4Gr7Fz4NuGoQEIzoL7XP5r |
||||
0zIjebzworxCaw+JNyaIxniHNBeK3sPHTLeW8bCrdJLkhE9RtGdEHLyPYXwPuFin |
||||
xVw3VQHWiA0uPM+JaekgdPDtK5wGFQ/AK3pc6vR108oT0kV4zQEqgRnvLqV9Q5zZ |
||||
UPHBi5kypu1BmCW4upYL1dmjASWPn9Q8cNpHcX/NJPNJ9zW0yxAAtq4wLfh7PQml |
||||
3EaHEYllsf8v1vMv00+zZNhc6O4BBP1qrRiaYHDAJhJjn6ctV9GFhJ2Ttxh/NmSy |
||||
H679tlC2PeRjGMi8bOHBshcikn5KUw== |
||||
=4aJI |
||||
-----END PGP SIGNATURE----- |
||||
@ -1 +0,0 @@
@@ -1 +0,0 @@
|
||||
3b31f2abf79368001e2fab02997446ac62db714b9db9cb78c4c542aa962485dc |
||||
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE----- |
||||
|
||||
iQEzBAABCAAdFiEE4qywN5M83qq3v3fUmix6mORXxT0FAmAiY1oACgkQmix6mORX |
||||
xT0nDQgAlfchq7/W/wubx3IR3tQs0tKiix3nZIc97zuH6sR8+r+CJe78wbmSE9Oo |
||||
/z96wfzeZYNIKh2v+dBLHF7OfcPGBE7tiX07jfCa6KzjjY3hFBhW+muMP/aBRb+4 |
||||
itSs6F3lkZOPW2+hpSdFQ6U8Rm81cAlZv7Zk2XswwTQkJo8GcNL1w/5wAVpNK0yG |
||||
VinZr8YRMFs6OYQxLqGSypDLAmv9rOaJ7aCdaKnQwYES65kC7tbe0SRZGQoDe8n4 |
||||
XLzpvC8rM9MXZDEN4qI+ZAANOJNVsXUmDZLDSe4ak48u/cTOokY8I6bR2k/XOhbu |
||||
L+D4W7oKAE9HmzlTMusosyjNOBQAmQ== |
||||
=Wjji |
||||
-----END PGP SIGNATURE----- |
||||
@ -1 +0,0 @@
@@ -1 +0,0 @@
|
||||
05bd8fd394a15b9dcc1bfaece0a63b0fdc2c3625a7e0aa5230fd3b5b75a8f8934a0af550b44437aa1486909058e84703e63fdec6f637d639d565b55bdaf1fa6c |
||||
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE----- |
||||
|
||||
iQEzBAABCAAdFiEE4qywN5M83qq3v3fUmix6mORXxT0FAmAiY1oACgkQmix6mORX |
||||
xT19rwf/a6sZxSDNTxN72VvsrKsHq+wMes5UUcQ+L7e5QLjaCTx2ayW2FdHMBaNi |
||||
IDBBE9kxnxa/S6G6nSRARUjXowsEYZGUNLLvUjNZ4Z3g2R9XyGPaz3Ky9yWpRm36 |
||||
E0lFqf8aaCLpzwV2z7cfeVNYsd2gnHakphK/UiZzXFz+GYzqby/0m5Kk8Zs7rK6V |
||||
/ji0bYWUi8t1jli8MfTHQtM8EUHG0nXRfEKilyoYkO3UsTEh/UN1VRpJ5DgcRC8L |
||||
Zbd2zPnV15MPUzZvz3kkycUulQdhOqTDjUod9P/WoASwjDuKCG2/kquwOvnoHXJ9 |
||||
9Ju+ca0s9y0jbotIygYxJXZVev3EiA== |
||||
=oWIp |
||||
-----END PGP SIGNATURE----- |
||||
Binary file not shown.
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE----- |
||||
|
||||
iQEzBAABCAAdFiEE4qywN5M83qq3v3fUmix6mORXxT0FAmAiY1oACgkQmix6mORX |
||||
xT3qtgf8CeDvxzi7lPghlrZtmYTTjaic4FZsGRWTPky3H24i4wSRDhG0L5sj4uPK |
||||
eLLlITr5a9j26UCas9HRSthiC8+EgIMAhSN0X482SQhUZHAW67ErIvaHlwL+ixMD |
||||
0T5pmsW8PKN3lV1TFMhNYSEC2GRG/4GF+3yQA8LR+BgeEu/E5nmysIH8vuQMkOD6 |
||||
3pKA8VKNBml591j6UTqxoHtPX+rThaziz3Hy3+ekf5iWslllTTGPd2SWqTvnj2Ae |
||||
GvRzsbli+FEM0Aj/v8jUQnQzOz891QSvWR+fMfCqZimiJMc+GBzJ9umbcyQsB5tY |
||||
e26mAoYd9KEpGXMKN4biHbJZNp1GGw== |
||||
=x/MY |
||||
-----END PGP SIGNATURE----- |
||||
@ -1 +0,0 @@
@@ -1 +0,0 @@
|
||||
e84da489be91de821c95d41b8f0e0a0a |
||||
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE----- |
||||
|
||||
iQEzBAABCAAdFiEE4qywN5M83qq3v3fUmix6mORXxT0FAmAiY1oACgkQmix6mORX |
||||
xT1PSwf+InTdlh+BVVy3RFszEL5vN7waSPYMImXhgd5EZ1d4Lxd6EeOwtNgWNKpG |
||||
E+Ps/Kw0jZDvoD49WJlcUjzDHBNHcE7C/L3GAWHV6WwklhtQaJ4EegsynWdSXz6k |
||||
fqJY6r58aGKGjpKPutRWAjvfcdC170+ZRsc2oi9xrAgHCpvXzTjq4+O9Ah0t5jwW |
||||
jcZ/Xubcw4vjsw774OucHbtwGsvRN5SDJ3IONOH8WCwhUP5vEEKvA6MYX0KGoTdS |
||||
3wTCyZTzU3qtTWxcbTCpiJIWbYwRR7TzLB/uydWHlAMzuz6coIiBpYsGiO6wkmfg |
||||
W+QvcE7wyW2jtb22pCImLyObyZ21VA== |
||||
=VjDv |
||||
-----END PGP SIGNATURE----- |
||||
@ -1 +0,0 @@
@@ -1 +0,0 @@
|
||||
8992b17455ce660da9c5fe47226b7ded9e872637 |
||||
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE----- |
||||
|
||||
iQEzBAABCAAdFiEE4qywN5M83qq3v3fUmix6mORXxT0FAmAiY1oACgkQmix6mORX |
||||
xT2HQgf+MTUEnwzXK4zi76VI7C5cchGan26lIA2Ebq4vtYGKDqNSISOAAdWs9+nT |
||||
U6ZA6OIFo5qdeD6F/45s91IoDbxbhMDMFEsSijKASqiuZN5TZM1U2h2kWFAl/sEl |
||||
EI1RTygn+xDw/ah4V3/duuMFC+jRgvJ/LgemIF4KBvECWaTQKNu0fu5d4dPXMpp+ |
||||
jrxMEZPQZsivpOvklzV8O7wAkf/ZQhJdcB2m8uOfSPlJ91a4EEtXF9/GzzkXUi1P |
||||
bzt4NsmOag3227B3mO1Bc6yZdDBNu8wQ9apiJVCpqsxB9Dz0PCL4dHNa1u9g6Xo6 |
||||
ElRgneV4HZp+LB125VoNabKuNH00bw== |
||||
=2yDl |
||||
-----END PGP SIGNATURE----- |
||||
@ -1 +0,0 @@
@@ -1 +0,0 @@
|
||||
10ce8a82f7e53c67f2af8d4dc4b8cdb4d0630d0e1d21818da4d5b3ca2de08385 |
||||
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE----- |
||||
|
||||
iQEzBAABCAAdFiEE4qywN5M83qq3v3fUmix6mORXxT0FAmAiY1oACgkQmix6mORX |
||||
xT0ScQf7Bip+quFq1CzDCTDxUhdTTOIpQcCfMKo1Jegpa2Hlm63XuK+6zVI9u6S+ |
||||
dBXPdYeneMOqMPQUAaw3M06ZqohaDOt8Ti1EiQFGXCdOvbonTA52Lrd4EEZxwNnK |
||||
BdPuIh/8qCfozm5KbZe1bFyGVRAdNyf27KvzHgfBTirLtI+3MiOdL4bvNZbWRPfh |
||||
J84Ko+Ena8jPFgyz6nJv2Q2U/V3dCooLJAXs2vEG6owwk5J9zvSysWpHaJbXas5v |
||||
KXO9TOBBjf3+vxb1WVQa8ZYUU3+FIFes0RFVgOWghJXIooOcWrwOV2Q8z9qWXwoK |
||||
mMZ2oLS+z/7clXibK45KeRUeCX5DvQ== |
||||
=5oO1 |
||||
-----END PGP SIGNATURE----- |
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue