initial commit

This commit is contained in:
Fabian Krüger
2023-12-14 01:26:14 +01:00
commit 96abad9b8c
291 changed files with 18428 additions and 0 deletions

22
.gitignore vendored Normal file
View File

@@ -0,0 +1,22 @@
*.tmp
*.swp
**/*.log
*.iml
**/target/
build
!**/src/main/**/build/
!**/src/test/**/build/
bin/
internal/
out/
.settings/
.idea/
.gradle/
.DS_Store
.classpath
.project
.factorypath
pom.xml.versionsBackup
**/src/generated/java/META-INF
**.java-version
**/.rewrite-cache

117
.mvn/wrapper/MavenWrapperDownloader.java vendored Normal file
View File

@@ -0,0 +1,117 @@
/*
* Copyright 2007-present 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
*
* http://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.net.*;
import java.io.*;
import java.nio.channels.*;
import java.util.Properties;
public class MavenWrapperDownloader {
private static final String WRAPPER_VERSION = "0.5.6";
/**
* 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/"
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".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 directory '" + 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 {
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
String username = System.getenv("MVNW_USERNAME");
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
}
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();
}
}

BIN
.mvn/wrapper/maven-wrapper.jar vendored Normal file

Binary file not shown.

18
.mvn/wrapper/maven-wrapper.properties vendored Normal file
View File

@@ -0,0 +1,18 @@
#
# Copyright 2021 - 2022 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar

44
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,44 @@
# Contributor Code of Conduct
As contributors and maintainers of this project, and in the interest of fostering an open
and welcoming community, we pledge to respect all people who contribute through reporting
issues, posting feature requests, updating documentation, submitting pull requests or
patches, and other activities.
We are committed to making participation in this project a harassment-free experience for
everyone, regardless of level of experience, gender, gender identity and expression,
sexual orientation, disability, personal appearance, body size, race, ethnicity, age,
religion, or nationality.
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery
* Personal attacks
* Trolling or insulting/derogatory comments
* Public or private harassment
* Publishing other's private information, such as physical or electronic addresses,
without explicit permission
* Other unethical or unprofessional conduct
Project maintainers have the right and responsibility to remove, edit, or reject comments,
commits, code, wiki edits, issues, and other contributions that are not aligned to this
Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors
that they deem inappropriate, threatening, offensive, or harmful.
By adopting this Code of Conduct, project maintainers commit themselves to fairly and
consistently applying these principles to every aspect of managing this project. Project
maintainers who do not follow or enforce the Code of Conduct may be permanently removed
from the project team.
This Code of Conduct applies both within project spaces and in public spaces when an
individual is representing the project or its community.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by
contacting a project maintainer at spring-code-of-conduct@pivotal.io . All complaints will
be reviewed and investigated and will result in a response that is deemed necessary and
appropriate to the circumstances. Maintainers are obligated to maintain confidentiality
with regard to the reporter of an incident.
This Code of Conduct is adapted from the
[Contributor Covenant](https://contributor-covenant.org), version 1.3.0, available at
[contributor-covenant.org/version/1/3/0/](https://contributor-covenant.org/version/1/3/0/)

45
CONTRIBUTING.adoc Normal file
View File

@@ -0,0 +1,45 @@
= Contributing to Spring Boot Migrator
Spring Boot Migrator is released under the Apache 2.0 license.
If you would like to contribute something, or want to hack on the code this document should help you get started.
== Code of Conduct
This project adheres to the Contributor Covenant link:CODE_OF_CONDUCT.md[code of conduct].
By participating, you are expected to uphold this code. Please report unacceptable behavior to spring-code-of-conduct@pivotal.io.
== Using GitHub Issues
We use GitHub issues to track bugs and enhancements.
If you are reporting a bug, please help to speed up problem diagnosis by providing as much information as possible.
Ideally, that would include a small sample project that reproduces the problem.
== Reporting Security Vulnerabilities
If you think you have found a security vulnerability in Spring Boot please *DO NOT* disclose it publicly until we've had a chance to fix it.
Please don't report security vulnerabilities using GitHub issues, instead head over to https://spring.io/security-policy and learn how to disclose them responsibly.
== Sign the Contributor License Agreement
Before we accept a non-trivial patch or pull request we will need you to https://cla.pivotal.io/sign/spring[sign the Contributor License Agreement].
Signing the contributor's agreement does not grant anyone commit rights to the main repository, but it does mean that we can accept your contributions, and you will get an author credit if we do.
Active contributors might be asked to join the core team, and given the ability to merge pull requests.
== Code Conventions and Housekeeping
None of these is essential for a pull request, but they will all help. They can also be
added after the original pull request but before a merge.
* Make sure all new `.java` files have a Javadoc class comment with at least an `@author` tag identifying you, and preferably at least a paragraph on what the class is for.
* Add the ASF license header comment to all new `.java` files (copy from existing files in the project). +
The license headers can be generated using the license plugin: `mvn license:format`
* Add yourself as an `@author` to the `.java` files that you modify substantially (more than cosmetic changes).
* Add some Javadocs.
* A few unit tests would help a lot as well -- someone has to do it.
* If no-one else is using your branch, please rebase it against the current main branch (or other target branch in the project).
* When writing a commit message please follow https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html[these conventions].

202
LICENSE.txt Normal file
View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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
http://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.

38
README.adoc Normal file
View File

@@ -0,0 +1,38 @@
= Spring Rewrite Commons
:partials_dir: spring-rewrite-commons-docs/src/main/antora/modules/ROOT/pages/partials
:project-version: 0.1.0-SNAPSHOTS
:projectVersion: {project-version}
:docs: https://docs.spring.io/spring-rewrite-commons/docs/current-SNAPSHOT/reference/html/
[quote]
____
Spring Rewrite Commons provides a set of components to parse a Java project to https://github.com/openrewrite[OpenRewrite,window=_blank] LST and apply recipes outside a build tool plugin.
____
== Get started
=== Add Dependency
**Maven**
include::{partials_dir}/maven-dependency-snippet.adoc[]
**Gradle**
include::{partials_dir}/gradle-dependency-snippet.adoc[]
=== Implement a Recipe Launcher
include::{partials_dir}/example-application-code.adoc[]
== Reference documentation
Find the reference documentation link:{docs}[here].
== Contributing
https://help.github.com/articles/creating-a-pull-request[Pull requests] are welcome. Note, that we expect everyone to follow the https://github.com/spring-projects/.github/blob/main/CODE_OF_CONDUCT.md[code of conduct].
== License
Spring Rewrite Commons is Open Source software released under the
https://www.apache.org/licenses/LICENSE-2.0.html[Apache 2.0 license].

6
SECURITY.md Normal file
View File

@@ -0,0 +1,6 @@
# Security Policy
## Reporting a Vulnerability
If you think you have found a security vulnerability, please **DO NOT** disclose it publicly until weve had a chance to fix it.
Please dont report security vulnerabilities using GitHub issues, instead head over to https://spring.io/security-policy and learn how to disclose them responsibly.

307
mvnw vendored Executable file
View File

@@ -0,0 +1,307 @@
#!/bin/sh
#
# Copyright 2021 - 2022 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# ----------------------------------------------------------------------------
# Maven 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)`"
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
if [ -n "$MVNW_REPOURL" ]; then
jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
else
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
fi
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 $cygwin; then
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
fi
if command -v wget > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget "$jarUrl" -O "$wrapperJarPath"
else
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
fi
elif command -v curl > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl -o "$wrapperJarPath" "$jarUrl" -f
else
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaClass=`cygpath --path --windows "$javaClass"`
fi
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
# Provide a "standardized" way to retrieve the CLI args that will
# work with both Windows and non-Windows executions.
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
export MAVEN_CMD_LINE_ARGS
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 "$@"

182
mvnw.cmd vendored Normal file
View File

@@ -0,0 +1,182 @@
@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 http://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 Maven 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 keystroke 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 by 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.5.6/maven-wrapper-0.5.6.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% (
if "%MVNW_VERBOSE%" == "true" (
echo Found %WRAPPER_JAR%
)
) else (
if not "%MVNW_REPOURL%" == "" (
SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
)
powershell -Command "&{"^
"$webclient = new-object System.Net.WebClient;"^
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
"}"^
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
"}"
if "%MVNW_VERBOSE%" == "true" (
echo Finished downloading %WRAPPER_JAR%
)
)
@REM End of extension
@REM Provide a "standardized" way to retrieve the CLI args that will
@REM work with both Windows and non-Windows executions.
set MAVEN_CMD_LINE_ARGS=%*
%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%

326
pom.xml Normal file
View File

@@ -0,0 +1,326 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.rewrite</groupId>
<artifactId>spring-rewrite-commons</artifactId>
<version>0.1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Spring Rewrite Commons</name>
<description>Run OpenRewrite recipes without a build tool plugin</description>
<url>https://github.com/spring-projects/spring-rewrite-commons</url>
<modules>
<module>spring-rewrite-commons-launcher</module>
<module>spring-rewrite-commons-docs</module>
<module>spring-rewrite-commons-examples</module>
</modules>
<organization>
<name>VMware Inc.</name>
<url>https://spring.io</url>
</organization>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- prod dependencies -->
<spring-boot.version>3.1.3</spring-boot.version>
<rewrite.version>8.5.1</rewrite.version>
<rewrite-maven-plugin.version>5.3.2</rewrite-maven-plugin.version>
<jaxb-api.version>2.3.1</jaxb-api.version>
<!-- testing dependencies -->
<maven.version>3.9.1</maven.version>
<maven-resolver.version>1.9.13</maven-resolver.version>
<maven-wagon-http.version>3.5.3</maven-wagon-http.version>
<plexus-cypher.version>1.8</plexus-cypher.version>
<maven-invoker.version>3.2.0</maven-invoker.version>
<junit-pioneer.version>2.1.0</junit-pioneer.version>
<!-- documentation dependencies -->
<io.spring.maven.antora-version>0.0.4</io.spring.maven.antora-version>
<asciidoctorj-pdf.version>1.6.2</asciidoctorj-pdf.version> <!-- FIXME build failure with version 2.3.9 -->
<asciidoctorj-epub.version>1.5.1</asciidoctorj-epub.version>
<spring-asciidoctor-backends.version>0.0.6</spring-asciidoctor-backends.version>
<!-- plugins -->
<maven-compiler-plugin.version>3.11.0</maven-compiler-plugin.version>
<maven-surefire-plugin.version>3.0.0-M7</maven-surefire-plugin.version>
<maven-javadoc-plugin.version>3.4.1</maven-javadoc-plugin.version>
<maven-jar-plugin.version>3.3.0</maven-jar-plugin.version>
<maven-assembly-plugin.version>3.6.0</maven-assembly-plugin.version>
<maven-deploy-plugin.version>3.1.1</maven-deploy-plugin.version>
<versions-maven-plugin.version>2.16.2</versions-maven-plugin.version>
<spring-javaformat-maven-plugin.version>0.0.39</spring-javaformat-maven-plugin.version>
<license-maven-plugin.version>4.3</license-maven-plugin.version>
<artifactory-maven-plugin.version>3.6.1</artifactory-maven-plugin.version>
<asciidoctor-maven-plugin.version>2.2.3</asciidoctor-maven-plugin.version>
<project.inceptionYear>2021</project.inceptionYear>
</properties>
<developers>
<developer>
<id>fkrueger</id>
<name>Fabian Krüger</name>
<email>fkrueger at vmware.com</email>
<organization>VMware</organization>
<organizationUrl>http://www.spring.io</organizationUrl>
<roles>
<role>lead</role>
</roles>
</developer>
</developers>
<scm>
<url>https://github.com/spring-projects/rewrite-commons</url>
<connection>scm:git:https://github.com/spring-projects/spring-rewrite-commons</connection>
<developerConnection>scm:git:https://github.com/spring-projects/spring-rewrite-commons.git</developerConnection>
<tag>spring-rewrite-commons-0.1.0</tag>
</scm>
<issueManagement>
<system>Github Issues</system>
<url>https://github.com/spring-projects/spring-rewrite-commons/issues</url>
</issueManagement>
<ciManagement>
<system>Github Actions</system>
<url>https://github.com/spring-projects/spring-rewrite-commons/actions</url>
</ciManagement>
<distributionManagement>
<snapshotRepository>
<id>spring-snapshots</id>
<url>https://repo.spring.io/libs-snapshot-local</url>
<layout>default</layout>
<releases>
<enabled>false</enabled>
</releases>
</snapshotRepository>
</distributionManagement>
<licenses>
<license>
<name>Apache-2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>${maven-javadoc-plugin.version}</version>
<configuration>
<doclint>accessibility,html,reference,syntax</doclint>
<show>package</show>
<quiet>true</quiet>
<level>public</level>
<fixTags>author</fixTags>
<fixClassComment>true</fixClassComment>
<fixFieldComment>false</fixFieldComment>
<fixMethodComment>false</fixMethodComment>
<excludePackageNames>*.acme.*:*.example.*</excludePackageNames>
</configuration>
</plugin>
<plugin>
<groupId>io.spring.javaformat</groupId>
<artifactId>spring-javaformat-maven-plugin</artifactId>
<version>${spring-javaformat-maven-plugin.version}</version>
<executions>
<execution>
<phase>validate</phase>
<inherited>true</inherited>
<goals>
<goal>validate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>io.spring.javaformat</groupId>
<artifactId>spring-javaformat-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.4.0</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>versions-maven-plugin</artifactId>
<version>${versions-maven-plugin.version}</version>
</plugin>
<plugin>
<groupId>com.mycila</groupId>
<artifactId>license-maven-plugin</artifactId>
<version>${license-maven-plugin.version}</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
<configuration>
<properties>
<owner>the original author or authors.</owner>
<email />
<year>2023</year>
<inceptionYear>2021</inceptionYear>
</properties>
<licenseSets>
<licenseSet>
<inlineHeader>
<!-- @formatter:off -->
Copyright ${inceptionYear} - ${year} 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.
<!-- @formatter:on -->
</inlineHeader>
<excludes>
<exclude>**/internal/**</exclude>
<exclude>**/demo/**</exclude>
<exclude>**/.sdkmanrc</exclude>
<exclude>**/*.adoc</exclude>
<exclude>**/*.puml</exclude>
<exclude>**/.rewrite*/**</exclude>
<exclude>**/src/main/resources/banner.txt</exclude>
<exclude>**/testcode/**</exclude>
<exclude>**/test-code/**</exclude>
<exclude>**/pom.xml</exclude>
<exclude>**/*.properties</exclude>
<exclude>**/*.yaml</exclude>
<exclude>**/*.yml</exclude>
<exclude>**/*.map</exclude>
<exclude>**/*.html</exclude>
<exclude>**/*.xhtml</exclude>
<exclude>**/*.jsp</exclude>
<exclude>**/*.js</exclude>
<exclude>**/*.css</exclude>
<exclude>**/*.txt</exclude>
<exclude>**/*.xjb</exclude>
<exclude>**/*.ftl</exclude>
<exclude>**/*.xsd</exclude>
<exclude>**/*.xml</exclude>
<exclude>**/*.sh</exclude>
<exclude>**/generated/**</exclude>
<exclude>**/Dockerfile</exclude>
<exclude>**/META-INF/**</exclude>
</excludes>
</licenseSet>
</licenseSets>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>functional-tests</id>
<modules>
<module>spring-rewrite-commons-functional-tests</module>
</modules>
</profile>
<profile>
<id>artifactory</id>
<properties>
<maven.test.skip>true</maven.test.skip>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.jfrog.buildinfo</groupId>
<artifactId>artifactory-maven-plugin</artifactId>
<version>${artifactory-maven-plugin.version}</version>
<inherited>false</inherited>
<executions>
<execution>
<id>deploy-to-artifactory</id>
<goals>
<goal>publish</goal>
</goals>
<configuration>
<publisher>
<contextUrl>https://repo.spring.io</contextUrl>
<!--suppress UnresolvedMavenProperty -->
<username>${env.ARTIFACTORY_USERNAME}</username>
<!--suppress UnresolvedMavenProperty -->
<password>${env.ARTIFACTORY_PASSWORD}</password>
<repoKey>libs-milestone-local</repoKey>
<snapshotRepoKey>libs-snapshot-local</snapshotRepoKey>
</publisher>
<buildInfo>
<buildName>CI build for sbm-support-rewrite ${project.version}</buildName>
</buildInfo>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestone</id>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshot</id>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
</profile>
</profiles>
</project>

View File

@@ -0,0 +1,4 @@
node
node_modules
package-lock.json
package.json

View File

@@ -0,0 +1,179 @@
<?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 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.rewrite</groupId>
<artifactId>spring-rewrite-commons</artifactId>
<version>0.1.0-SNAPSHOT</version>
</parent>
<artifactId>spring-rewrite-commons-docs</artifactId>
<name>Docs</name>
<description>Spring Rewrite Commons documentation</description>
<build>
<plugins>
<plugin>
<groupId>io.spring.maven.antora</groupId>
<artifactId>antora-maven-plugin</artifactId>
<version>${io.spring.maven.antora-version}</version>
<extensions>true</extensions>
<configuration>
<playbook>src/main/antora/antora-playbook.yml</playbook>
<packages>
<package>@antora/atlas-extension@1.0.0-alpha.1</package>
<package>@antora/collector-extension@1.0.0-alpha.3</package>
<package>@asciidoctor/tabs@1.0.0-beta.3</package>
<package>@springio/antora-extensions@1.5.0</package>
<package>@springio/asciidoctor-extensions@1.0.0-alpha.9</package>
<package>@djencks/asciidoctor-mathjax@0.0.9</package>
</packages>
</configuration>
</plugin>
<plugin>
<groupId>io.spring.maven.antora</groupId>
<artifactId>antora-component-version-maven-plugin</artifactId>
<version>${io.spring.maven.antora-version}</version>
<executions>
<execution>
<goals>
<goal>antora-component-version</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
<version>${asciidoctor-maven-plugin.version}</version>
<dependencies>
<dependency>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctorj-pdf</artifactId>
<version>${asciidoctorj-pdf.version}</version>
</dependency>
<dependency>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctorj-epub3</artifactId>
<version>${asciidoctorj-epub.version}</version>
</dependency>
<dependency>
<groupId>io.spring.asciidoctor.backends</groupId>
<artifactId>spring-asciidoctor-backends</artifactId>
<version>${spring-asciidoctor-backends.version}</version>
</dependency>
</dependencies>
<configuration>
<sourceDirectory>${project.basedir}/src/main/asciidoc</sourceDirectory>
<outputDirectory>${project.build.directory}/asciidoc</outputDirectory>
</configuration>
<executions>
<execution>
<id>generate-html</id>
<phase>site</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>
<configuration>
<backend>spring-html</backend>
<doctype>book</doctype>
<attributes>
<docinfodir>${project.build.directory}/asciidoc</docinfodir>
<docinfo>shared</docinfo>
<stylesdir>css/</stylesdir>
<stylesheet>site.css</stylesheet>
<linkcss>true</linkcss>
<icons>font</icons>
<sectanchors />
<source-highlighter>highlight.js</source-highlighter>
<highlightjsdir>js/highlight</highlightjsdir>
<highlightjs-theme>github</highlightjs-theme>
<idprefix />
<idseparator>-</idseparator>
<project-name>${project.name}</project-name>
<projectVersion>${project.version}</projectVersion>
<spring-version>${project.version}</spring-version>
<revnumber>${project.version}</revnumber>
<allow-uri-read />
</attributes>
</configuration>
</execution>
<execution>
<id>generate-pdf</id>
<phase>site</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>
<configuration>
<backend>pdf</backend>
<doctype>book</doctype>
<attributes>
<icons>font</icons>
<pagenums />
<sectnums />
<sectanchors />
<toc />
<source-highlighter>coderay</source-highlighter>
<project-version>${project.version}</project-version>
<revnumber>${project.version}</revnumber>
</attributes>
</configuration>
</execution>
<execution>
<id>generate-epub</id>
<phase>site</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>
<configuration>
<backend>epub3</backend>
<doctype>book</doctype>
<attributes>
<icons>font</icons>
<pagenums />
<sectnums />
<sectanchors />
<toc />
<source-highlighter>coderay</source-highlighter>
<project-version>${project.version}</project-version>
<revnumber>${project.version}</revnumber>
</attributes>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>${maven-assembly-plugin.version}</version>
<configuration>
<descriptors>
<descriptor>src/assembly/docs.xml</descriptor>
</descriptors>
<finalName> ${project.artifactId}-${project.version}</finalName>
<appendAssemblyId>true</appendAssemblyId>
</configuration>
<executions>
<execution>
<id>create-distribution</id>
<phase>site</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>${maven-deploy-plugin.version}</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,38 @@
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
<id>docs</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>target/asciidoc</directory>
<outputDirectory>reference/html</outputDirectory>
<includes>
<include>css/*.*</include>
<include>images/*.*</include>
<include>img/*.*</include>
<include>js/**/*.*</include>
<include>*.html</include>
</includes>
</fileSet>
<fileSet>
<directory>../target/site/apidocs</directory>
<outputDirectory>api</outputDirectory>
</fileSet>
</fileSets>
<files>
<file>
<source>target/asciidoc/index-single.pdf</source>
<destName>spring-rewrite-commons-reference.pdf</destName>
<outputDirectory>reference/pdf</outputDirectory>
</file>
<file>
<source>target/asciidoc/index-single.epub</source>
<destName>spring-rewrite-commons-reference.epub</destName>
<outputDirectory>reference/epub</outputDirectory>
</file>
</files>
</assembly>

View File

@@ -0,0 +1,17 @@
<html>
<body>
<p>
This document is the API specification for <a href="https://github.com/spring-projects-experimental/spring-rewrite-commons" target="_top">Spring AI</a>
</p>
<div id="overviewBody">
<p>
For further API reference and developer documentation, see the
<a href="https://spring-projects-experimental.github.io/spring-rewrite-commons/spring-rewrite-commons/" target="_top">
Spring AI reference documentation</a>.
That documentation contains more detailed, developer-targeted
descriptions, with conceptual overviews, definitions of terms,
and working code examples.
</p>
</div>
</body>
</html>

View File

@@ -0,0 +1,39 @@
# PACKAGES antora@3.2.0-alpha.2 @antora/atlas-extension:1.0.0-alpha.1 @antora/collector-extension@1.0.0-alpha.3 @springio/antora-extensions@1.1.0-alpha.2 @asciidoctor/tabs@1.0.0-alpha.12 @opendevise/antora-release-line-extension@1.0.0-alpha.2
#
# The purpose of this Antora playbook is to build the docs in the current branch.
antora:
extensions:
- '@antora/collector-extension'
- require: '@springio/antora-extensions/root-component-extension'
root_component_name: 'ai'
site:
title: Spring AI Reference
url: https://docs.spring.io/spring-rewrite-commons/reference
content:
sources:
- url: ./../../../..
branches: HEAD
start_path: spring-rewrite-commons-docs/src/main/antora
worktrees: true
asciidoc:
attributes:
page-pagination: ''
hide-uri-scheme: '@'
tabs-sync-option: '@'
chomp: 'all'
stem: 'asciimath'
extensions:
- '@asciidoctor/tabs'
- '@springio/asciidoctor-extensions'
- '@djencks/asciidoctor-mathjax'
sourcemap: true
urls:
latest_version_segment: ''
runtime:
log:
failure_level: warn
format: pretty
ui:
bundle:
url: https://github.com/spring-io/antora-ui-spring/releases/download/v0.3.6/ui-bundle.zip
snapshot: true

View File

@@ -0,0 +1,12 @@
name: spring-rewrite-commons
version: true
title: Spring Rewrite Commons
nav:
- modules/ROOT/nav.adoc
ext:
collector:
- run:
command: mvnw process-resources
local: true
scan:
dir: spring-rewrite-commons-docs/target/classes/antora-resources

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

View File

@@ -0,0 +1,8 @@
* xref:index.adoc[Overview]
* xref:getting-started.adoc[Getting Started]
* xref:concepts.adoc[Concepts]
* xref:components.adoc[Components]
* xref:testing.adoc[Testing]
* xref:contributing.adoc[Contributing]
* Appendices
** xref:properties.adoc[]

View File

@@ -0,0 +1,123 @@
= Components
The following components can be used to parse a project, run recipes and write changes back to the filesystem.
These components are provided as Spring beans and can be injected into other Spring beans that require them.
== Injecting Spring Rewrite Commons Components
Spring Rewrite Commons offers components as Spring beans that and can be https://docs.spring.io/spring-framework/reference/core/beans/dependencies/factory-collaborators.html[injected,window=_blank] into existing components.
[source, java]
....
@Autowired
private RewriteProjectParser parser;
....
== ProjectScanner
Scan a given path to a list of ``https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/io/Resource.html[Resource,window=_blank]``s using filter definitions provided through xref:properties.adoc[application properties].
[source, java]
....
Path baseDir = ...
List<Resource> resources = scanner.scan(baseDir);
....
== RewriteExecutionContext
OpenRewrite's `ExecutionContext` gets initialized during parsing.
This `ExecutionContext` is required to run recipes and for the inner workings of OpenRewrite.
== RecipeDiscovery
Discover OpenRewrite recipes on classpath.
These can be custom recipes or recipes provided through https://docs.openrewrite.org/recipes[OpenRewrite's Recipe Catalog]
=== Access the RecipeDiscovery
The `RecipeDiscovery` component is provided as Spring Bean and can be injected as such, e.g. by using `@Autowired`.
[source,java]
....
@Autowired
private RecipeDiscovery discovery;
....
=== Discover recipes by name
A single OpenRewrite recipe can be discovered by name.
[source,java]
....
Optional<Recipe> recipe = discovery.findRecipeByName("recipe name");
....
=== Discover all recipes
All available OpenRewrite recipes can be discovered.
[source,java]
....
List<Recipe> recipes = discovery.findAllRecipes();
....
== ProjectResourceSet
Abstraction of OpenRewrite SourceFiles that allows execution of recipes against the SourceFiles while changes are transparently synchronized with the initial list of SourceFiles.
=== Creating a ProjectResourceSet
`ProjectResourceSet` is not a Spring bean itself.
The `ProjectResourceSetFactory` is provided as Spring bean and can be injected
[source, java]
....
@Autowired
ProjectResourceSetFactory resourceSetFactory;
....
and used to create `ProjectResourceSet` instances
[source, java]
....
ProjectResourceSet resourceSet = resourceSetFactory.create(baseDir, lst);
....
=== Applying recipes
The `ProjectResourceSet` can be used to sequentially apply OpenRewrite recipes. The results from each recipe run is transparently merged back into the initial LST.
[source, java]
....
ProjectResourceSet rs = projectResourceSetFactory.create(baseDir, lst);
rs.apply(firstRecipe);
rs.apply(secondRecipe);
rs.apply(thirdRecipe);
....
== ProjectResourceSetSerializer
`ProjectResourceSetSerializer` helps to synchronize the modified in-memory representation of the scanned project to the filesystem, effectively applying the changes to the codebase (add, update, delete).
[source, java]
....
projectResourceSetSerializer.writeChanges(projectResourceSet);
....
== Listen to ParserEvents
``ParserEvent``s get published during parsing.
The events can be used to provide progress information to users.
This is especially useful when parsing large projects where parsing can take some time.
* `StartedParsingProjectEvent` - Gets published when the parsing started
* `ParsedResourceEvent` - Gets published after every parsed pom or Java file
* `SuccessfullyParsedProjectEvent` - Gets published when the parsing was successful
[source,java]
.....
@EventListener(ParsedResourceEvent.class)
public void onParsedResourceEvent(ParsedResourceEvent event) {
Parser.Input input = event.input();
SourceFile sourceFile = event.sourceFile();
log("parsed %s to %s".formatted(input.getRelativePath(), sourceFile.getClass().getName()));
}
.....

View File

@@ -0,0 +1,61 @@
[[concepts]]
= Spring Rewrite Commons Concepts
This sections describes the important concepts of Spring Rewrite Commons and how they relate to concepts from OpenRewrite.
Running OpenRewrite recipes requires a given project to be parsed to create the LST for it.
== Parsing a Project
Spring Rewrite Commons aims to yield the same parsing result (LST) as OpenRewrite's `rewrite-maven-plugin`.
This allows access to the LST from outside the execution of `rewrite-maven-plugin`.
=== RewriteProjectParser
The `RewriteProjectParser` component is a Spring bean and offers the API to parse projects to OpenRewrite LST.
==== Parse a Path
When the application exists on the local filesystem, the path to the project is enough to parse the project to its LST.
[source, java]
....
Path baseDir = ...
RewriteProjectParsingResult result = parser.parse(baseDir);
List<SourceFile> lst = result.sourceFiles();
....
==== Parse a List of Resources
It is also possible to provide a list of ``https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/io/Resource.html[Resource]``s and their baseDir.
This allows to provide synthetic resources that only exist in-memory which is helpful to test migration recipes without disk IO.
[source, java]
....
Path baseDir = ...
List<Resource> resources = ...
List<SourceFile> lst = parser.parse(baseDir, List<Resource> resources);
List<SourceFile> lst = result.sourceFiles();
....
== Provided Scoped Beans
OpenRewrite initializes some while during parsing a project.
These objects provide information required to execute recipes.
Spring Rewrite Commons provides access to these objects through scoped beans.
The lifetime of these beans starts with the successful parse of a project, and ends with the next parse or when the application is closed.
=== ExecutionContext
OpenRewrite has the concept of an `ExecutionContext`.
The `ExecutionContext` holds information required during recipe execution.
This means the exact same instance needs to be provided to recipe runs.
Spring Rewrite Commons provides the right instance as scoped Spring bean `RewriteExecutionContext`.
This bean can be injected to other Spring Beans in an application and provides access to the `ExecutionContext`.
[source, java]
....
@Component
public class MyComponent {
@Autowired
private ExecutionContext executionContext;
public void runRecipe() {
Recipe recipe = new SomeOpenRewriteRecipe();
}
}
....

View File

@@ -0,0 +1,30 @@
== Contributing
You want to contribute to the Spring Boot Migrator project?
Great! All contributions are welcome.
If you have not previously done so, please sign the https://cla.pivotal.io/sign/spring[Contributor License Agreement]. You will be reminded automatically when you submit the pull request.
Please also see link:../../CONTRIBUTING.adoc[CONTRIBUTING.adoc] for further information.
All files need to have a license header. Please use this copyright text:
[source, text]
....
Copyright 2022 the original author or authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
....
You can configure license headers under `IntelliJ IDEA/Copyright/Copyright Profile`.
See https://www.jetbrains.com/help/idea/copyright.html#configure-copyright-profiles

View File

@@ -0,0 +1,28 @@
[[getting-started]]
= Getting Started
This section offers quick guidance to developers on how to get started using Spring Rewrite Commons.
////
== Create a Simple Spring Boot application
Spring Rewrite Commons is meant to be used in Spring Boot applications.
To create a blank Boot application, go to https://start.spring.io/#!type=maven-project&language=java&platformVersion=3.2.0&packaging=jar&jvmVersion=17&groupId=com.example&artifactId=spring-rewrite-commons-example&name=spring-rewrite-commons-example&description=Demo%20project%20for%20Spring%20Rewrite%20Commons&packageName=com.example.rewrite[start.spring.io,window=_blank] and press "generate" to download a basic Boot application.
////
== Add Repository
include::partials/snapshots-repository.adoc[]
== Add dependency
The dependency to Spring Rewrite Commons must be added to the build file.
include::partials/dependency-code.adoc[]
== Example Application
This dummy code of a Spring application shows how to use the components provided by Spring Rewrite Commons to parse
an application and write back the changes to the filesystem.
include::partials/example-application-code.adoc[]
Read more about the xref:components.adoc[available components].

View File

@@ -0,0 +1,3 @@
[[appendix]]
[[glossary]]
= Glossary

View File

@@ -0,0 +1,58 @@
[[introduction]]
= Spring Rewrite Commons
Fabian Krüger
:revnumber: {projectVersion}
:revdate: {localdate}
:toc: left
:iconfont-fontawesome:
== Overview
Spring Rewrite Commons provides abstractions and parsers for https://github.com/openrewrite/[OpenRewrite].
The project can parse Java projects using Maven and apply OpenRewrite recipes without the need of a build tool plugin.
It aims to become the foundation for Spring Boot applications using OpenRewrite.
https://github.com/openrewrite/[OpenRewrite] is a code refactoring, remediation, and modernization automation tool providing a rich https://docs.openrewrite.org/recipes[catalog of recipes] for tasks like automated code transformations.
These are the main components offered by Spring Rewrite Commons:
* `xref:concepts.adoc#_rewriteprojectparser[RewriteProjectParser]` - Parse a project to an OpenRewrite https://docs.openrewrite.org/concepts-explanations/lossless-semantic-trees[Lossless Semantic Tree] (LST).
* `xref:concepts.adoc#_recipediscovery[RewriteRecipeDiscovery]` - Discover recipes on the classpath.
* `xref:concepts.adoc#_projectresourceset[ProjectResourceSet]` - Encapsulates the LST to run https://github.com/openrewrite/[OpenRewrite] recipes sequentially.
* `xref:concepts.adoc#_projectresourcesetserializer[ProjectResourceSetSerializer]` - Serialize the current state of the `ProjectResourceSet` to the filesystem.
* Some helpers for xref:testing.adoc[testíng] also exist
== Using Spring Rewrite Commons
include::partials/snapshots-repository.adoc[]
Then the dependency can be retrieved.
include::partials/dependency-code.adoc[]
== Examples
Some working examples exist to demo what can be built using Spring Rewrite Commons.
* file://spring-rewrite-commons-examples/boot-3-upgrade-atomic[Atomically upgrade a Spring Boot application]
* file://spring-rewrite-commons-examples/boot-3-upgrade-iterative[Iteratively upgrade a Spring Boot application using PRs]
* file://spring-rewrite-commons-examples/list-applicable-recipes-example[Find applicable recipes by doing a dry-run]
All examples can be found file://spring-rewrite-commons-examples[here].
== Limitations
The project has currently some limitations.
. Only JDK 17 supported and required
. No Gradle support. +
OpenRewrite provides a build tool plugin for Gradle projects.
This project currently only parses Maven projects.
. No Kotlin support. +
OpenRewrite can parse other languages than Java, especially Kotlin. This is not yet supported.
. Inherited version will just be read from direct parent. Meaning a version from a parent with distance > 1 will be empty (`null`)
. Maven profiles are currently ignored and 'default' profile is used
. Styles are not supported +
OpenRewrite styles are currently not supported.
. Migrating projects for Maven plugins might fail +
Maven plugin projects (modules) are currently ignored when building the reactor order.

View File

@@ -0,0 +1,10 @@
[tabs]
======
Maven::
+
include::maven-dependency-snippet.adoc[]
Gradle::
+
include::gradle-dependency-snippet.adoc[]
======

View File

@@ -0,0 +1,55 @@
[source,java]
....
package com.acme.example;
import org.openrewrite.Recipe;
import org.openrewrite.SourceFile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.rewrite.parsers.RewriteProjectParser;
import org.springframework.rewrite.parsers.RewriteProjectParsingResult;
import org.springframework.rewrite.project.resource.ProjectResourceSet;
import org.springframework.rewrite.project.resource.ProjectResourceSetFactory;
import org.springframework.rewrite.project.resource.ProjectResourceSetSerializer;
import org.springframework.rewrite.recipes.RewriteRecipeDiscovery;
import org.springframework.stereotype.Component;
import java.nio.file.Path;
import java.util.List;
@Component
public class MyMigrationApplication {
@Autowired <1>
private RewriteProjectParser parser;
@Autowired
private RewriteRecipeDiscovery discovery; <2>
@Autowired
private ProjectResourceSetFactory resourceSetFactory;
@Autowired
private ProjectResourceSetSerializer serializer;
public void migrateToBoot3_1() {
Path baseDir = Path.of("."); <2>
String recipeName = "org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_1";
Recipe boot3Upgrade = discovery.getByName(recipeName); <3>
RewriteProjectParsingResult result = parser.parse(baseDir); <4>
List<SourceFile> lst = result.sourceFiles(); <5>
ProjectResourceSet resourceSet = resourceSetFactory.create(baseDir, lst); <6>
resourceSet.apply(boot3Upgrade); <7>
serializer.writeChanges(resourceSet); <8>
}
}
....
<1> All components are Spring beans and can be injected as such.
<2> The path of the project that should be migrated.
<3> `RewriteRecipeDiscovery` is used to discover an OpenRewrite recipe by name.
<4> `RewriteProjectParser` parses a given project to OpenRewrite LST.
<5> The result contains the list of ``SourceFile``s (the LST).
<6> `ProjectResourceSetFactory` can be used to create a `ProjectResourceSet`.
<7> The recipe is applied to the `ProjectResourceSet` which wraps the LST.
<8> `ProjectResourceSetSerializer` is used to serialize the changes to disk.

View File

@@ -0,0 +1,4 @@
[source,groovy,indent=0,subs="verbatim,quotes,attributes",role="secondary"s]
----
compile 'org.springframework.rewrite:spring-rewrite-commons-launcher:{projectVersion}'
----

View File

@@ -0,0 +1,8 @@
[source,xml,indent=0,subs="verbatim,quotes,attributes",role="primary"]
----
<dependency>
<groupId>org.springframwork.rewrite</groupId>
<artifactId>spring-rewrite-commons-launcher</artifactId>
<version>{project-version}</version>
</dependency>
----

View File

@@ -0,0 +1,30 @@
Currently only SNAPSHOT releases are available from the https://repo.spring.io[Spring Repository,window=_blank].
The repository information must be added to the project build file.
[tabs]
======
Maven::
+
[source,xml,indent=0,subs="verbatim,quotes",role="primary"]
.....
<repositories>
<repository>
<id>spring-snapshot</id>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
.....
Gradle::
+
[source,groovy,indent=0,subs="verbatim,quotes",role="secondary"]
----
repositories {
mavenCentral()
maven { url "http://repo.spring.io/libs-snapshot" }
}
----
======

View File

@@ -0,0 +1,44 @@
= Appendix
== Appendix A: Spring Rewrite Commons Configuration Properties
|===
|Property |Default Value |Description
| `parser.pomCacheEnabled`
| `false`
| Set to `true` to use a composite cache of `RocksdbMavenPomCache` and `InMemoryMavenPomCache`. Otherwise, use OpenRewrite's `InMemoryMavenPomCache`.
| `parser.pomCacheDirectory`
| `~/.rewrite-cache`
| Defines the cache dir for `RocksdbMavenPomCache` when `parser.pomCacheEnabled` is `true`.
| `parser.skipMavenParsing`
| `false`
|
| `parser.plainTextMasks`
| `*.txt`
|
| `parser.sizeThresholdMb`
| `10`
|
| `parser.runPerSubmodule`
| `false`
|
| `parser.failOnInvalidActiveRecipes`
| `true`
|
| `parser.activeProfiles`
| `default`
|
| `parser.ignoredPathPatterns`
| `**.idea/**,**.git/**,**/target/**,target/**`
|
|===

View File

@@ -0,0 +1,14 @@
[[hugging-face]]
= Hugging Face
One of the easiest ways you can get access to many machine learning and artificial intelligence models is by using the https://en.wikipedia.org/wiki/Hugging_Face[Hugging Face's] https://huggingface.co/inference-endpoints[Inference Endpoints].
Hugging Face Hub is a platform that provides a collaborative environment for creating and sharing tens of thousands of Open Source ML/AI models, data sets, and demo applications.
Inference Endpoints let you deploy AI Models on dedicated infrastructure with a pay-as-you-go billing model.
You can use infrastructure provided by Amazon Web Services, Microsoft Azure, and Google Cloud Platform.
Hugging Face lets you run the models on your own machine, but it is quite common to not have enough CPU/GPU resources to run the larger, more AI-focused models.
It provides access to Meta's recent (August 2023) Llama 2 and CodeLlama 2 models and provides the https://huggingface.co/spaces/HuggingFaceH4/open_llm_leaderboard[Open LLM Leaderboard], where you can quickly discover high quality models.
While Hugging Face has a free hosting tier, which is very useful for quickly evaluating if a specific ML/AI Model fits your needs, they do not let you access many of those models on the free tier by using the https://huggingface.co/docs/text-generation-inference/main/en/index[Text Generation Interface API]. If you want to end up on production anyway, with a stable API, pay a few cents to try out a reliable solution. Prices are as low as $0.06 per CPU core/hr and $0.6 per GPU/hr.

View File

@@ -0,0 +1,10 @@
= Testing
The `RewriteProjectParser`
== Test Helper
=== TestProjectHelper
=== ParserParityTestHelper
=== ParserExecutionHelper
=== RewriteMavenProjectParser

View File

@@ -0,0 +1,7 @@
version: ${antora-component.version}
prerelease: ${antora-component.prerelease}
asciidoc:
attributes:
attribute-missing: 'warn'
version: ${project.version}
projectversion: ${project.version}

View File

@@ -0,0 +1,15 @@
:toc: left
:toclevels: 4
[[configureClient]]
== Configuring an `AiClient`
include::attributes.adoc[]
TBD
[[usingAiClient]]
=== Using AiClient
TBD

View File

@@ -0,0 +1 @@
:ai-asciidoc: ./

View File

@@ -0,0 +1,19 @@
:toc: left
:toclevels: 4
[[domainLanguageOfAi]]
== The Domain Language of AI
include::attributes.adoc[]
TBD
=== Prompt
TBD
==== AiClient
TBD

View File

@@ -0,0 +1,9 @@
'''
Mark Pollack
Copyright © 2023 VMware, Inc. All Rights Reserved.
Copies of this document may be made for your own use and for
distribution to others, provided that you do not charge any fee for such
copies and further provided that each copy contains this Copyright
Notice, whether distributed in print or electronically.

View File

@@ -0,0 +1,6 @@
[[glossary]]
[appendix]
== Glossary
[glossary]
=== Spring AI Glossary

View File

@@ -0,0 +1 @@
= Spring AI - Reference Documentation

View File

@@ -0,0 +1,20 @@
:doctype: book
:toc: left
:toclevels: 4
:sectnums:
include::attributes.adoc[]
include::header/index-header.adoc[]
include::toggle.adoc[]
include::spring-ai-intro.adoc[]
include::domain.adoc[]
include::prompt.adoc[]
include::aiclient.adoc[]
include::glossary.adoc[]

View File

@@ -0,0 +1,27 @@
include::attributes.adoc[]
include::header/index-header.adoc[]
// ======================================================================================
This documentation is also available
as a link:index-single.html[single HTML file] and as link:../pdf/spring-ai-reference.pdf[PDF]
and link:../epub/spring-ai-reference.epub[EPUB] documents.
The reference documentation is divided into several sections:
[horizontal]
<<spring-ai-intro.adoc#spring-ai-intro,Spring AI Introduction>> :: Background, usage
scenarios, and general guidelines.
<<domain.adoc#domainLanguageOfAi,The Domain Language of AI>> :: Core concepts and abstractions
of the AI domain language.
<<prompt.adoc#createPrompt,Creating a Prompt>> :: Prompt creation.
<<aiclient.adoc#configureClient,Configuring an AiClient>> :: AiClient configuration and execution.
The following appendices are available:
[horizontal]
<<glossary.adoc#glossary,Glossary>> :: Glossary of common terms, concepts, and vocabulary of
the AI domain.
include::footer/index-footer.adoc[]

View File

@@ -0,0 +1,76 @@
$(document).ready(function(){
var BATCH_LANGUAGES = ["java", "xml", "both"];
var $xmlButton = $("#xmlButton");
var $javaButton = $("#javaButton");
var $bothButton = $("#bothButton");
var $xmlContent = $("*.xmlContent");
var $xmlContentAll = $("*.xmlContent > *");
var $javaContent = $("*.javaContent");
var $javaContentAll = $("*.javaContent > *");
// Initial cookie handler. This part remembers the
// reader's choice and sets the toggle accordingly.
var lang = window.localStorage.getItem("docToggle");
if (BATCH_LANGUAGES.indexOf(lang) === -1) {
lang = "java";
$javaButton.prop("checked", true);
setJava();
} else {
if (lang === "xml") {
$xmlButton.prop("checked", true);
setXml();
}
if (lang === "java") {
$javaButton.prop("checked", true);
setJava();
}
if (lang === "both") {
$javaButton.prop("checked", true);
setBoth();
}
}
// Click handlers
$xmlButton.on("click", function() {
setXml();
});
$javaButton.on("click", function() {
setJava();
});
$bothButton.on("click", function() {
setBoth();
});
// Functions to do the work of handling the reader's choice, whether through a click
// or through a cookie. 3652 days is 10 years, give or take a leap day.
function setXml() {
$xmlContent.show();
$javaContent.hide();
$javaContentAll.addClass("js-toc-ignore");
$xmlContentAll.removeClass("js-toc-ignore");
window.dispatchEvent(new Event("tocRefresh"));
window.localStorage.setItem('docToggle', 'xml');
}
function setJava() {
$javaContent.show();
$xmlContent.hide();
$xmlContentAll.addClass("js-toc-ignore");
$javaContentAll.removeClass("js-toc-ignore");
window.dispatchEvent(new Event("tocRefresh"));
window.localStorage.setItem('docToggle', 'java');
}
function setBoth() {
$javaContent.show();
$xmlContent.show();
$javaContentAll.removeClass("js-toc-ignore");
$xmlContentAll.removeClass("js-toc-ignore");
window.dispatchEvent(new Event("tocRefresh"));
window.localStorage.setItem('docToggle', 'both');
}
});

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,9 @@
:toc: left
:toclevels: 4
[[createPrompt]]
== Creating a Prompt
include::attributes.adoc[]
TBD

View File

@@ -0,0 +1,47 @@
:toc: left
:toclevels: 4
include::attributes.adoc[]
ifdef::backend-spring-html[]
This documentation is also available
as link:index.html[multiple HTML files] and as link:../pdf/spring-ai-reference.pdf[PDF]
and link:../epub/spring-ai-reference.epub[EPUB] documents.
endif::[]
ifdef::backend-pdf[]
This documentation is also available
as link:index.html[multiple HTML files], a link:index-single.html[single HTML file],
and an link:../epub/spring-ai-reference.epub[EPUB] document.
endif::[]
ifdef::backend-epub3[]
This documentation is also available
as link:index.html[multiple HTML files], a link:index-single.html[single HTML file],
and a link:../pdf/spring-ai-reference.pdf[PDF] document.
endif::[]
[[spring-ai-intro]]
== Spring AI Introduction
TBD
[[springAiBackground]]
=== Background
TBD
[[springAiUsageScenarios]]
=== Usage Scenarios
TBD
==== Business Scenarios
TBD
==== Technical Objectives
TBD

View File

@@ -0,0 +1,15 @@
ifdef::backend-spring-html[]
+++
<div>
<script type="text/javascript" src="js/jquery-3.2.1.min.js"></script>
<script type="text/javascript" src="js/js.cookie.js"></script>
<script type="text/javascript" src="js/DocumentToggle.js"></script>
<script type="text/javascript" src="js/Redirect.js"></script>
<div class="docToggle-button">
<input id="xmlButton" type="radio" name="docToggle" value="XML"><label for="xmlButton">XML</label>
<input id="javaButton" type="radio" name="docToggle" value="Java" checked><label for="javaButton">Java</label>
<input id="bothButton" type="radio" name="docToggle" value="Both" checked><label for="bothButton">Both</label>
</div>
</div>
+++
endif::backend-spring-html[]

View File

@@ -0,0 +1,38 @@
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

View File

@@ -0,0 +1,13 @@
= Atomic Upgrade to Boot 3
This example shows how to implement a simple Boot application that uses `spring-rewrite-commons` to apply a recipe that upgrades a given Spring application (<3.1) to Spring Boot 3.1.
== Running the example
WARNING: The example will change the sources in the provided project.
From the module dir
. run `mvn clean install`
. run `java -jar target/boot-3-upgrade-atomic-0.1.0-SNAPSHOT.jar <path-to-project>`
. Changes were applied to `<path-to-project>`

View File

@@ -0,0 +1,88 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.rewrite</groupId>
<artifactId>spring-rewrite-commons-examples</artifactId>
<version>0.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>com.example</groupId>
<artifactId>boot-3-upgrade-atomic</artifactId>
<name>Boot 3 Atomic Upgrade Example</name>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-boot.version>3.1.3</spring-boot.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<configuration>
<requiresUnpack>
<dependency>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-http</artifactId>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-transport-wagon</artifactId>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-connector-basic</artifactId>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-compat</artifactId>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-embedder</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-cipher</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.sisu</groupId>
<artifactId>org.eclipse.sisu.plexus</artifactId>
</dependency>
</requiresUnpack>
<mainClass>com.acme.example.SpringBoot3Upgrade</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,89 @@
/*
* Copyright 2021 - 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 com.acme.example;
import org.openrewrite.Recipe;
import org.openrewrite.SourceFile;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.rewrite.parsers.RewriteProjectParser;
import org.springframework.rewrite.parsers.RewriteProjectParsingResult;
import org.springframework.rewrite.project.resource.ProjectResourceSet;
import org.springframework.rewrite.project.resource.ProjectResourceSetFactory;
import org.springframework.rewrite.project.resource.ProjectResourceSetSerializer;
import org.springframework.rewrite.recipes.RewriteRecipeDiscovery;
import java.nio.file.Path;
import java.util.List;
import java.util.Optional;
/**
* @author Fabian Krüger
*/
@SpringBootApplication
public class SpringBoot3Upgrade implements CommandLineRunner {
public static final String RECIPE_NAME = "org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_1";
public static void main(String[] args) {
SpringApplication.run(SpringBoot3Upgrade.class, args);
}
private final RewriteProjectParser parser;
private final RewriteRecipeDiscovery discovery;
private final ProjectResourceSetSerializer serializer;
private final ProjectResourceSetFactory projectResourceSetFactory;
public SpringBoot3Upgrade(RewriteProjectParser parser, RewriteRecipeDiscovery discovery,
ProjectResourceSetSerializer serializer, ProjectResourceSetFactory projectResourceSetFactory) {
this.parser = parser;
this.discovery = discovery;
this.serializer = serializer;
this.projectResourceSetFactory = projectResourceSetFactory;
}
@Override
public void run(String... args) {
Path baseDir;
if (args.length == 0) {
throw new IllegalArgumentException("A path must be provided");
}
else {
String pathStr = args[0];
baseDir = Path.of(pathStr);
}
// parse
RewriteProjectParsingResult parsingResult = parser.parse(baseDir);
List<SourceFile> sourceFiles = parsingResult.sourceFiles();
ProjectResourceSet projectResourceSet = projectResourceSetFactory.create(baseDir, sourceFiles);
// discover
List<Recipe> recipes = discovery.discoverRecipes();
Optional<Recipe> recipe = recipes.stream().filter(r -> RECIPE_NAME.equals(r.getName())).findFirst();
// apply
recipe.ifPresent((Recipe r) -> {
projectResourceSet.apply(r);
serializer.writeChanges(projectResourceSet);
});
}
}

View File

@@ -0,0 +1,2 @@
logging.level.root=warn
logging.level.org.springframework.sbm=debug

View File

@@ -0,0 +1,33 @@
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### 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/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/

View File

@@ -0,0 +1,2 @@
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.5/apache-maven-3.9.5-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar

View File

@@ -0,0 +1,4 @@
= Iterative Upgrade to Boot 3 using PRs
This example shows how to implement a simple Boot application that uses `spring-rewrite-commons` to apply recipes that upgrade the Spring Boot PetClinic from 2.3.x to Spring Boot 3.1 by applying recipes to upgrade from minor to minor version by creating PRs for every recipe run.
No new recipes are applied until the last PR has been merged or closed.

View File

@@ -0,0 +1,308 @@
#!/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.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Apache Maven Wrapper startup batch script, version 3.2.0
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
#
# Optional ENV vars
# -----------------
# 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 /usr/local/etc/mavenrc ] ; then
. /usr/local/etc/mavenrc
fi
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
JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME
else
JAVA_HOME="/Library/Java/Home"; export JAVA_HOME
fi
fi
;;
esac
if [ -z "$JAVA_HOME" ] ; then
if [ -r /etc/gentoo-release ] ; then
JAVA_HOME=$(java-config --jre-home)
fi
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -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 "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] &&
JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)"
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="$(\unset -f command 2>/dev/null; \command -v 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
# 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/.." || exit 1; pwd)
fi
# end of workaround
done
printf '%s' "$(cd "$basedir" || exit 1; pwd)"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
# Remove \r in case we run on Windows within Git Bash
# and check out the repository with auto CRLF management
# enabled. Otherwise, we may read lines that are delimited with
# \r\n and produce $'-Xarg\r' rather than -Xarg due to word
# splitting rules.
tr -s '\r\n' ' ' < "$1"
fi
}
log() {
if [ "$MVNW_VERBOSE" = true ]; then
printf '%s\n' "$1"
fi
}
BASE_DIR=$(find_maven_basedir "$(dirname "$0")")
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR
log "$MAVEN_PROJECTBASEDIR"
##########################################################################################
# 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.
##########################################################################################
wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar"
if [ -r "$wrapperJarPath" ]; then
log "Found $wrapperJarPath"
else
log "Couldn't find $wrapperJarPath, downloading it ..."
if [ -n "$MVNW_REPOURL" ]; then
wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
else
wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
fi
while IFS="=" read -r key value; do
# Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' )
safeValue=$(echo "$value" | tr -d '\r')
case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;;
esac
done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
log "Downloading from: $wrapperUrl"
if $cygwin; then
wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
fi
if command -v wget > /dev/null; then
log "Found wget ... using wget"
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet"
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
else
wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
fi
elif command -v curl > /dev/null; then
log "Found curl ... using curl"
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent"
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
else
curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
fi
else
log "Falling back to using Java to download"
javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java"
javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaSource=$(cygpath --path --windows "$javaSource")
javaClass=$(cygpath --path --windows "$javaClass")
fi
if [ -e "$javaSource" ]; then
if [ ! -e "$javaClass" ]; then
log " - Compiling MavenWrapperDownloader.java ..."
("$JAVA_HOME/bin/javac" "$javaSource")
fi
if [ -e "$javaClass" ]; then
log " - Running MavenWrapperDownloader.java ..."
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath"
fi
fi
fi
fi
##########################################################################################
# End of extension
##########################################################################################
# If specified, validate the SHA-256 sum of the Maven wrapper jar file
wrapperSha256Sum=""
while IFS="=" read -r key value; do
case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;;
esac
done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
if [ -n "$wrapperSha256Sum" ]; then
wrapperSha256Result=false
if command -v sha256sum > /dev/null; then
if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then
wrapperSha256Result=true
fi
elif command -v shasum > /dev/null; then
if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then
wrapperSha256Result=true
fi
else
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available."
echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties."
exit 1
fi
if [ $wrapperSha256Result = false ]; then
echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2
echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2
echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2
exit 1
fi
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 "$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
# Provide a "standardized" way to retrieve the CLI args that will
# work with both Windows and non-Windows executions.
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*"
export MAVEN_CMD_LINE_ARGS
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
# shellcheck disable=SC2086 # safe args
exec "$JAVACMD" \
$MAVEN_OPTS \
$MAVEN_DEBUG_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

View File

@@ -0,0 +1,205 @@
@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 Apache Maven Wrapper startup batch script, version 3.2.0
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@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 keystroke 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 by 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 "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\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 WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET WRAPPER_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% (
if "%MVNW_VERBOSE%" == "true" (
echo Found %WRAPPER_JAR%
)
) else (
if not "%MVNW_REPOURL%" == "" (
SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %WRAPPER_URL%
)
powershell -Command "&{"^
"$webclient = new-object System.Net.WebClient;"^
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
"}"^
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^
"}"
if "%MVNW_VERBOSE%" == "true" (
echo Finished downloading %WRAPPER_JAR%
)
)
@REM End of extension
@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file
SET WRAPPER_SHA_256_SUM=""
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B
)
IF NOT %WRAPPER_SHA_256_SUM%=="" (
powershell -Command "&{"^
"$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^
"If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^
" Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^
" Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^
" Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^
" exit 1;"^
"}"^
"}"
if ERRORLEVEL 1 goto error
)
@REM Provide a "standardized" way to retrieve the CLI args that will
@REM work with both Windows and non-Windows executions.
set MAVEN_CMD_LINE_ARGS=%*
%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 "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\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%
cmd /C exit /B %ERROR_CODE%

View File

@@ -0,0 +1,63 @@
<?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.rewrite</groupId>
<artifactId>spring-rewrite-commons-examples</artifactId>
<version>0.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>com.example</groupId>
<artifactId>boot-3-upgrade-iterative</artifactId>
<name>Boot 3 Iterative Upgrade Example</name>
<description>Example of iterative Boot upgrade with PRs</description>
<properties>
<java.version>17</java.version>
<github-api.version>1.317</github-api.version>
</properties>
<dependencies>
<dependency>
<groupId>org.kohsuke</groupId>
<artifactId>github-api</artifactId>
<version>${github-api.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>com.example.bootupgrade.IterativeBoot3UpgradeExample</mainClass>
<image>
<builder>paketobuildpacks/builder-jammy-base:latest</builder>
</image>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2021 - 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 com.example.bootupgrade;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class BootUpgradeIterativeApplication {
public static void main(String[] args) {
SpringApplication.run(BootUpgradeIterativeApplication.class, args);
}
}

View File

@@ -0,0 +1,345 @@
/*
* Copyright 2021 - 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 com.example.bootupgrade;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.kohsuke.github.GHPullRequest;
import org.kohsuke.github.GHRepository;
import org.kohsuke.github.GitHub;
import org.kohsuke.github.GitHubBuilder;
import org.openrewrite.Recipe;
import org.openrewrite.SourceFile;
import org.openrewrite.shaded.jgit.api.CreateBranchCommand;
import org.openrewrite.shaded.jgit.api.Git;
import org.openrewrite.shaded.jgit.api.ListBranchCommand;
import org.openrewrite.shaded.jgit.api.ResetCommand;
import org.openrewrite.shaded.jgit.api.errors.GitAPIException;
import org.openrewrite.shaded.jgit.lib.Ref;
import org.openrewrite.shaded.jgit.revwalk.RevCommit;
import org.openrewrite.shaded.jgit.transport.UsernamePasswordCredentialsProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.event.EventListener;
import org.springframework.core.io.Resource;
import org.springframework.rewrite.parsers.*;
import org.springframework.rewrite.parsers.events.StartedParsingResourceEvent;
import org.springframework.rewrite.project.resource.ProjectResourceSet;
import org.springframework.rewrite.project.resource.ProjectResourceSetFactory;
import org.springframework.rewrite.project.resource.ProjectResourceSetSerializer;
import org.springframework.rewrite.recipes.RewriteRecipeDiscovery;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.util.FileSystemUtils;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
/**
* @author Fabian Krüger
*/
@SpringBootApplication
@EnableScheduling
@Slf4j
public class IterativeBoot3UpgradeExample implements ApplicationRunner {
private static final String MAIN_BRANCH = "main";
public static final String GH_ORG_NAME = "fabapp2";
public static final String GH_REPO_NAME = "spring-petclinic-detached";
public static final String GIT_COMMIT_HASH = "baafc5a80c988cffa0c11e88859143308e850f08";
private String repoUrl;
private String ghToken;
public static void main(String[] args) {
SpringApplication.run(IterativeBoot3UpgradeExample.class, args);
}
private static Map<String, List<String>> versionToRecipeMap = new HashMap<>();
static {
versionToRecipeMap = Map.of("2.3.5.RELEASE", List.of("org.openrewrite.java.spring.boot2.UpgradeSpringBoot_2_4"),
"2.4.13", List.of("org.openrewrite.java.spring.boot2.UpgradeSpringBoot_2_5"),
"2.5.15", List.of("org.openrewrite.java.spring.boot2.UpgradeSpringBoot_2_6"),
"2.6.15", List.of("org.openrewrite.java.spring.boot2.UpgradeSpringBoot_2_7"),
"2.7.17", List.of("org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_0"),
"3.0.12", List.of("org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_1"),
"3.1.5", List.of("org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_2"));
// map.keySet()
// .stream()
// .forEach(keys -> {
// keys.stream()
// .forEach(k -> {
// versionToRecipeMap.put(k, map.get(keys));
// });
// });
}
@Autowired
private RewriteProjectParser parser;
@Autowired
private ProjectScanner scanner;
@Autowired
private RewriteRecipeDiscovery discovery;
@Autowired
private ProjectResourceSetSerializer serializer;
@Autowired
private ProjectResourceSetFactory projectResourceSetFactory;
@EventListener(StartedParsingResourceEvent.class)
public void onStartedParsingResourceEvent(StartedParsingResourceEvent event) {
}
@Override
public void run(ApplicationArguments args) {
repoUrl = getRepoUrl(args);
ghToken = getGitHubToken(args);
}
@Scheduled(fixedDelay = 10_000)
void loop() throws IOException, GitAPIException {
log.info("Scheduling...");
if (repoUrl == null || ghToken == null) {
return;
}
// clone
Path baseDir = cloneFreshRepo(repoUrl);
String pomXml = Files.readString(baseDir.resolve("pom.xml"));
String currentBootVersion = extractSpringBootVersion(pomXml);
if (versionToRecipeMap.containsKey(currentBootVersion)) {
Optional<String> newBootVersionOpt = calculateNextBootVersion(currentBootVersion);
if (newBootVersionOpt.isPresent()) {
String newBootVersion = newBootVersionOpt.get();
log.info("Found migration path to Spring Boot %s".formatted(newBootVersion));
String branchName = calculateBranchName(newBootVersion);
Git git = Git.open(baseDir.resolve(".git").toFile());
if (branchExists(git, branchName)) {
log.info("There might be an open PR? Otherwise please delete this remote branch: " + branchName);
return;
}
// find recipe name
List<String> recipeNames = versionToRecipeMap.get(currentBootVersion);
// parse
ProjectResourceSet projectResourceSet = parseProject(baseDir);
// discover
List<Recipe> recipes = discoverRecipes(recipeNames);
// apply
applyRecipe(projectResourceSet, recipes);
// create branch
Ref branchRef = createBranch(git, branchName);
checkout(git, branchName);
// commit
String message = "Upgrade Spring Boot from %s to %s".formatted(currentBootVersion, newBootVersion);
RevCommit commit = commit(git, message);
log.info("commit: " + commit);
push(git, branchRef, ghToken);
// Create PR
String mainBranch = "main";
createPullRequest(ghToken, message, branchName, mainBranch, message);
}
else {
log.info("No migration path found.");
}
}
else {
log.info("No migration found for Spring Boot version: %s".formatted(currentBootVersion));
}
}
private boolean branchExists(Git git, String branchName) {
try {
git.fetch().call();
// FIXME: This works only in this example. origin could be different
return git.branchList()
.setListMode(ListBranchCommand.ListMode.REMOTE)
.call()
.stream()
.anyMatch(b -> "refs/remotes/origin/%s".formatted(branchName).equals(b.getName()));
}
catch (GitAPIException e) {
throw new RuntimeException(e);
}
}
private String calculateBranchName(String newBootVersion) {
return "app-analyzer/boot-upgrade-%s".formatted(newBootVersion.replace(".", ""));
}
private Optional<String> calculateNextBootVersion(String currentBootVersion) {
List<String> sortedVersions = versionToRecipeMap.keySet().stream().sorted(String::compareTo).toList();
int i = sortedVersions.indexOf(currentBootVersion);
if (i < sortedVersions.size() - 1) {
return Optional.of(sortedVersions.get(i + 1));
}
return Optional.empty();
}
private String extractSpringBootVersion(String pomXml) {
try {
ObjectMapper mm = new XmlMapper();
String version = mm.readTree(pomXml).get("parent").get("version").textValue();
return version;
}
catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
private static void checkout(Git git, String branchName) throws GitAPIException {
git.checkout().setName(branchName).call();
}
private String getGitHubToken(ApplicationArguments args) {
if (args.getNonOptionArgs().size() < 2) {
throw new IllegalArgumentException("The GitHub token must be provided as second parameter.");
}
return args.getNonOptionArgs().get(1);
}
private void push(Git git, Ref branch, String ghToken) throws GitAPIException {
git.push().add(branch).setCredentialsProvider(new UsernamePasswordCredentialsProvider(ghToken, "")).call();
}
private static RevCommit commit(Git git, String message) throws GitAPIException {
git.add().addFilepattern(".").call();
return git.commit().setMessage(message).call();
}
private static Ref createBranch(Git git, String branchName) throws GitAPIException {
Ref branchRef = git.branchCreate()
.setName(branchName)
.setUpstreamMode(CreateBranchCommand.SetupUpstreamMode.SET_UPSTREAM)
.setForce(true)
.call();
return branchRef;
}
private ProjectResourceSet parseProject(Path baseDir) {
// scan
List<Resource> resources = scanner.scan(baseDir);
// parse
RewriteProjectParsingResult parsingResult = parser.parse(baseDir, resources);
List<SourceFile> sourceFiles = parsingResult.sourceFiles();
ProjectResourceSet projectResourceSet = projectResourceSetFactory.create(baseDir, sourceFiles);
return projectResourceSet;
}
@NotNull
private Path cloneFreshRepo(String repoUrl) throws IOException {
Path targetDir = Path.of(System.getProperty("java.io.tmpdir")).resolve(GH_REPO_NAME); // Files.createTempDirectory(GH_REPO_NAME).toAbsolutePath();
if (targetDir.toFile().exists()) {
FileSystemUtils.deleteRecursively(targetDir);
}
String commitHash = null;// GIT_COMMIT_HASH; //
// https://github.com/spring-projects/spring-petclinic/commit/a3294f2
cloneFreshRepo(repoUrl, targetDir, commitHash);
System.out.println("Cloned to %s".formatted(targetDir));
return targetDir;
}
private static String getRepoUrl(ApplicationArguments args) {
if (args.getNonOptionArgs().isEmpty()) {
throw new IllegalArgumentException("A repository URL must be provided.");
}
String repoUrl = args.getNonOptionArgs().get(0);
return repoUrl;
}
private void cloneFreshRepo(String repoUrl, Path targetDir, String gitHash) {
try {
File directory = targetDir.toFile();
Git git = Git.cloneRepository().setDirectory(directory).setURI(repoUrl).call();
if (gitHash != null) {
git.reset().setMode(ResetCommand.ResetType.HARD).setRef(GIT_COMMIT_HASH);
}
}
catch (GitAPIException e) {
throw new RuntimeException(e);
}
}
private GHPullRequest createPullRequest(String ghToken, String name, String head, String base, String body) {
try {
GitHub gitHub = new GitHubBuilder().withOAuthToken(ghToken).build();
GHRepository repo = gitHub
/* .getOrganization(GH_ORG_NAME) */
.getRepository(GH_ORG_NAME + "/" + GH_REPO_NAME);
GHPullRequest pr = repo.createPullRequest(name, head, base, body);
log.info("Created PR '%s'".formatted(name));
return pr;
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
private void applyRecipe(ProjectResourceSet projectResourceSet, List<Recipe> recipes) {
// FIXME: If recipes is a list they need to be provided through
// Recipe.getRecipeList() to not require a new parse
log.info("Applying recipes %s".formatted(recipes.stream().map(Recipe::getDisplayName).toList()));
if (recipes.size() > 1)
throw new UnsupportedOperationException("Can only handle single recipes.");
recipes.forEach(r -> this.applyRecipe(projectResourceSet, r));
}
private void applyRecipe(ProjectResourceSet projectResourceSet, Recipe recipe) {
projectResourceSet.apply(recipe);
serializer.writeChanges(projectResourceSet);
System.out.println("Applied recipe " + recipe.getDisplayName());
}
private List<Recipe> discoverRecipes(List<String> recipeNames) {
List<Recipe> recipes = discovery.discoverRecipes();
List<Recipe> matchingRecipes = recipes.stream().filter(r -> recipeNames.contains(r.getName())).toList();
return matchingRecipes;
}
}

View File

@@ -0,0 +1,33 @@
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### 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/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/

View File

@@ -0,0 +1,2 @@
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.5/apache-maven-3.9.5-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar

View File

@@ -0,0 +1,308 @@
#!/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.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Apache Maven Wrapper startup batch script, version 3.2.0
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
#
# Optional ENV vars
# -----------------
# 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 /usr/local/etc/mavenrc ] ; then
. /usr/local/etc/mavenrc
fi
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
JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME
else
JAVA_HOME="/Library/Java/Home"; export JAVA_HOME
fi
fi
;;
esac
if [ -z "$JAVA_HOME" ] ; then
if [ -r /etc/gentoo-release ] ; then
JAVA_HOME=$(java-config --jre-home)
fi
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -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 "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] &&
JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)"
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="$(\unset -f command 2>/dev/null; \command -v 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
# 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/.." || exit 1; pwd)
fi
# end of workaround
done
printf '%s' "$(cd "$basedir" || exit 1; pwd)"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
# Remove \r in case we run on Windows within Git Bash
# and check out the repository with auto CRLF management
# enabled. Otherwise, we may read lines that are delimited with
# \r\n and produce $'-Xarg\r' rather than -Xarg due to word
# splitting rules.
tr -s '\r\n' ' ' < "$1"
fi
}
log() {
if [ "$MVNW_VERBOSE" = true ]; then
printf '%s\n' "$1"
fi
}
BASE_DIR=$(find_maven_basedir "$(dirname "$0")")
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR
log "$MAVEN_PROJECTBASEDIR"
##########################################################################################
# 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.
##########################################################################################
wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar"
if [ -r "$wrapperJarPath" ]; then
log "Found $wrapperJarPath"
else
log "Couldn't find $wrapperJarPath, downloading it ..."
if [ -n "$MVNW_REPOURL" ]; then
wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
else
wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
fi
while IFS="=" read -r key value; do
# Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' )
safeValue=$(echo "$value" | tr -d '\r')
case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;;
esac
done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
log "Downloading from: $wrapperUrl"
if $cygwin; then
wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
fi
if command -v wget > /dev/null; then
log "Found wget ... using wget"
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet"
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
else
wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
fi
elif command -v curl > /dev/null; then
log "Found curl ... using curl"
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent"
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
else
curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
fi
else
log "Falling back to using Java to download"
javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java"
javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaSource=$(cygpath --path --windows "$javaSource")
javaClass=$(cygpath --path --windows "$javaClass")
fi
if [ -e "$javaSource" ]; then
if [ ! -e "$javaClass" ]; then
log " - Compiling MavenWrapperDownloader.java ..."
("$JAVA_HOME/bin/javac" "$javaSource")
fi
if [ -e "$javaClass" ]; then
log " - Running MavenWrapperDownloader.java ..."
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath"
fi
fi
fi
fi
##########################################################################################
# End of extension
##########################################################################################
# If specified, validate the SHA-256 sum of the Maven wrapper jar file
wrapperSha256Sum=""
while IFS="=" read -r key value; do
case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;;
esac
done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
if [ -n "$wrapperSha256Sum" ]; then
wrapperSha256Result=false
if command -v sha256sum > /dev/null; then
if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then
wrapperSha256Result=true
fi
elif command -v shasum > /dev/null; then
if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then
wrapperSha256Result=true
fi
else
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available."
echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties."
exit 1
fi
if [ $wrapperSha256Result = false ]; then
echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2
echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2
echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2
exit 1
fi
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 "$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
# Provide a "standardized" way to retrieve the CLI args that will
# work with both Windows and non-Windows executions.
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*"
export MAVEN_CMD_LINE_ARGS
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
# shellcheck disable=SC2086 # safe args
exec "$JAVACMD" \
$MAVEN_OPTS \
$MAVEN_DEBUG_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

View File

@@ -0,0 +1,205 @@
@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 Apache Maven Wrapper startup batch script, version 3.2.0
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@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 keystroke 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 by 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 "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\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 WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET WRAPPER_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% (
if "%MVNW_VERBOSE%" == "true" (
echo Found %WRAPPER_JAR%
)
) else (
if not "%MVNW_REPOURL%" == "" (
SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %WRAPPER_URL%
)
powershell -Command "&{"^
"$webclient = new-object System.Net.WebClient;"^
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
"}"^
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^
"}"
if "%MVNW_VERBOSE%" == "true" (
echo Finished downloading %WRAPPER_JAR%
)
)
@REM End of extension
@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file
SET WRAPPER_SHA_256_SUM=""
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B
)
IF NOT %WRAPPER_SHA_256_SUM%=="" (
powershell -Command "&{"^
"$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^
"If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^
" Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^
" Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^
" Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^
" exit 1;"^
"}"^
"}"
if ERRORLEVEL 1 goto error
)
@REM Provide a "standardized" way to retrieve the CLI args that will
@REM work with both Windows and non-Windows executions.
set MAVEN_CMD_LINE_ARGS=%*
%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 "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\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%
cmd /C exit /B %ERROR_CODE%

View File

@@ -0,0 +1,87 @@
<?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.rewrite</groupId>
<artifactId>spring-rewrite-commons-examples</artifactId>
<version>0.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>org.example</groupId>
<artifactId>list-applicable-recipes-example</artifactId>
<name>List Applicable Recipes Example</name>
<description>Example project listing applicable recipes for a given application</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-recipe-bom</artifactId>
<version>2.2.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-migrate-java</artifactId>
</dependency>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-spring</artifactId>
</dependency>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-hibernate</artifactId>
</dependency>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-java-dependencies</artifactId>
</dependency>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-testing-frameworks</artifactId>
</dependency>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-static-analysis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>spring-snapshot</id>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,89 @@
/*
* Copyright 2021 - 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 org.example.app;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Recipe;
import org.openrewrite.RecipeRun;
import org.openrewrite.SourceFile;
import org.openrewrite.config.RecipeDescriptor;
import org.openrewrite.internal.InMemoryLargeSourceSet;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.io.Resource;
import org.springframework.rewrite.parsers.ProjectScanner;
import org.springframework.rewrite.parsers.RewriteProjectParser;
import org.springframework.rewrite.parsers.RewriteProjectParsingResult;
import org.springframework.rewrite.recipes.RewriteRecipeDiscovery;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
@SpringBootApplication
public class ListApplicableRecipesExampleApplication implements ApplicationRunner {
private final RewriteRecipeDiscovery discovery;
private final ProjectScanner scanner;
private final RewriteProjectParser parser;
private final ExecutionContext executionContext;
public ListApplicableRecipesExampleApplication(RewriteRecipeDiscovery discovery, ProjectScanner scanner,
RewriteProjectParser parser, ExecutionContext executionContext) {
this.discovery = discovery;
this.scanner = scanner;
this.parser = parser;
this.executionContext = executionContext;
}
public static void main(String[] args) {
SpringApplication.run(ListApplicableRecipesExampleApplication.class, args);
}
@Override
public void run(ApplicationArguments args) {
Path baseDir = Path.of(args.getNonOptionArgs().get(0));
List<String> recipeNames = Arrays.asList(args.getNonOptionArgs().get(1).split(","));
List<Recipe> recipes = discovery.discoverRecipes();
List<Recipe> matchingRecipes = recipes.stream().filter(r -> recipeNames.contains(r.getName())).toList();
List<Resource> resources = scanner.scan(baseDir);
// parse
RewriteProjectParsingResult parsingResult = parser.parse(baseDir, resources);
List<SourceFile> sourceFiles = parsingResult.sourceFiles();
matchingRecipes.forEach(recipe -> {
RecipeRun recipeRun = recipe.run(new InMemoryLargeSourceSet(sourceFiles), executionContext);
recipeRun.getChangeset().getAllResults().forEach(result -> {
result.getRecipeDescriptorsThatMadeChanges().forEach(rd -> {
printResourceDescriptor(0, rd);
});
});
});
}
private static void printResourceDescriptor(int indent, RecipeDescriptor rd) {
String recipeThatWouldMakeChanges = rd.getName();
System.out.println(" ".repeat(indent) + recipeThatWouldMakeChanges);
rd.getRecipeList().forEach(re -> {
printResourceDescriptor(indent + 1, re);
});
}
}

View File

@@ -0,0 +1,74 @@
<?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.rewrite</groupId>
<artifactId>spring-rewrite-commons</artifactId>
<version>0.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>spring-rewrite-commons-examples</artifactId>
<packaging>pom</packaging>
<name>Spring Rewrite Commons - Examples</name>
<description>Examples using Spring Rewrite Commons</description>
<modules>
<module>boot-3-upgrade-atomic</module>
<module>boot-3-upgrade-iterative</module>
<module>list-applicable-recipes-example</module>
</modules>
<properties>
<java.version>17</java.version>
<rewrite-spring.version>5.0.10</rewrite-spring.version>
<rewrite-migrate-java.version>2.3.0</rewrite-migrate-java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.rewrite</groupId>
<artifactId>spring-rewrite-commons-launcher</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-spring</artifactId>
<version>${rewrite-spring.version}</version>
</dependency>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-migrate-java</artifactId>
<version>${rewrite-migrate-java.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.rewrite</groupId>
<artifactId>spring-rewrite-commons-launcher</artifactId>
</dependency>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-spring</artifactId>
</dependency>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-migrate-java</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,87 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.rewrite</groupId>
<artifactId>spring-rewrite-commons</artifactId>
<version>0.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>spring-rewrite-commons-functional-tests</artifactId>
<packaging>pom</packaging>
<name>Spring Rewrite Commons - Functional Tests</name>
<url>https://github.com/spring-projects/spring-rewrite-commons</url>
<organization>
<name>VMware Inc.</name>
<url>https://spring.io</url>
</organization>
<modules>
<module>private-artifact-repository-tests</module>
</modules>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- prod dependencies -->
<spring-boot.version>3.1.3</spring-boot.version>
<rewrite-maven-plugin.version>5.3.2</rewrite-maven-plugin.version>
<jaxb-api.version>2.3.1</jaxb-api.version>
<rewrite-maven-plugin.version>5.3.2</rewrite-maven-plugin.version>
<jaxb-api.version>2.3.1</jaxb-api.version>
<!-- testing dependencies-->
<maven.version>3.9.1</maven.version>
<maven-resolver.version>1.9.13</maven-resolver.version>
<maven-wagon-http.version>3.5.3</maven-wagon-http.version>
<plexus-cypher.version>1.8</plexus-cypher.version>
<maven-invoker.version>3.2.0</maven-invoker.version>
<junit-pioneer.version>2.1.0</junit-pioneer.version>
<!-- plugins-->
<maven-compiler-plugin.version>3.11.0</maven-compiler-plugin.version>
<maven-surefire-plugin.version>3.0.0-M7</maven-surefire-plugin.version>
<maven-javadoc-plugin.version>3.4.1</maven-javadoc-plugin.version>
<versions-maven-plugin.version>2.16.2</versions-maven-plugin.version>
<maven-jar-plugin.version>3.3.0</maven-jar-plugin.version>
<spring-javaformat-maven-plugin.version>0.0.39</spring-javaformat-maven-plugin.version>
<license-maven-plugin.version>4.1</license-maven-plugin.version>
<artifactory-maven-plugin.version>3.6.1</artifactory-maven-plugin.version>
<!-- Should be same as the Spring managed version -->
<lombok.version.annotationProcessorPath>1.18.28</lombok.version.annotationProcessorPath>
</properties>
<dependencyManagement>
<dependencies>
<!-- <dependency>-->
<!-- <groupId>org.springframework.rewrite</groupId>-->
<!-- <artifactId>spring-rewrite-commons-launcher</artifactId>-->
<!-- <version>0.1.0-SNAPSHOT</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.rewrite</groupId>-->
<!-- <artifactId>spring-rewrite-commons-launcher</artifactId>-->
<!-- <classifier>tests</classifier>-->
<!-- <type>test-jar</type>-->
<!-- <version>0.1.0-SNAPSHOT</version>-->
<!-- <scope>test</scope>-->
<!-- </dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>

View File

@@ -0,0 +1,168 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.rewrite</groupId>
<artifactId>spring-rewrite-commons-functional-tests</artifactId>
<version>0.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>private-artifact-repository-tests</artifactId>
<name>Private Artifact Repo Test</name>
<description>Functional tests for Spring Rewrite Commons using a private artifact repository</description>
<dependencies>
<dependency>
<groupId>org.springframework.rewrite</groupId>
<artifactId>spring-rewrite-commons-launcher</artifactId>
<version>0.1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.rewrite</groupId>
<artifactId>spring-rewrite-commons-launcher</artifactId>
<classifier>test</classifier>
<type>test-jar</type>
<version>0.1.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<!-- prod dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- required by MavenPasswordDecrypter -->
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-sec-dispatcher</artifactId>
<version>2.0</version>
</dependency>
<!-- required by MavenConfigFileParser -->
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-embedder</artifactId>
<version>${maven.version}</version>
<exclusions>
<exclusion>
<groupId>org.sonatype.plexus</groupId>
<artifactId>plexus-cipher</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>org.openrewrite.maven</groupId>
<artifactId>rewrite-maven-plugin</artifactId>
<version>${rewrite-maven-plugin.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-http</artifactId>
<version>${maven-wagon-http.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-transport-wagon</artifactId>
<version>${maven-resolver.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-connector-basic</artifactId>
<version>${maven-resolver.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-impl</artifactId>
<version>${maven-resolver.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-resolver-provider</artifactId>
<version>${maven.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-compat</artifactId>
<version>${maven.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-cipher</artifactId>
<version>${plexus-cypher.version}</version>
</dependency>
<dependency>
<groupId>org.apache.maven.shared</groupId>
<artifactId>maven-invoker</artifactId>
<version>${maven-invoker.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit-pioneer</groupId>
<artifactId>junit-pioneer</artifactId>
<version>${junit-pioneer.version}</version>
<scope>test</scope>
</dependency>
<!-- Required by PrivateArtifactRepositoryTest -->
<!-- TODO: Move into separate module -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.10.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-core</artifactId>
<version>2.0.9</version>
<scope>test</scope>
</dependency>
<!-- END: Required by PrivateArtifactRepositoryTest -->
<!-- get rid of [WARNING] unknown enum constant javax.annotation.meta.When.MAYBE -->
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>3.0.2</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,424 @@
/*
* Copyright 2021 - 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 org.springframework.sbm;
import org.apache.commons.io.FileUtils;
import org.apache.maven.shared.invoker.*;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.io.TempDir;
import org.openrewrite.java.marker.JavaSourceSet;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.JavaType;
import org.openrewrite.maven.cache.LocalMavenArtifactCache;
import org.openrewrite.maven.cache.MavenArtifactCache;
import org.openrewrite.maven.tree.MavenRepository;
import org.powermock.reflect.Whitebox;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.rewrite.boot.autoconfigure.SbmSupportRewriteConfiguration;
import org.springframework.rewrite.parsers.RewriteProjectParser;
import org.springframework.rewrite.parsers.RewriteProjectParsingResult;
import org.springframework.rewrite.parsers.maven.SbmTestConfiguration;
import org.springframework.util.FileSystemUtils;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
import org.testcontainers.utility.MountableFile;
import java.io.*;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Fail.fail;
/**
* Test that dependencies from a private repository can be downloaded with provided
* credentials.
* <p>
* A secured private repository is started as Docker container and a project depending on
* a dependency only available through the repository gets parsed. Verifying the types of
* the dependency were resolved proves that the secured access to the repository was
* successful and thus credentials provided were decrypted and used. All resources for
* this test live under {@code ./testcode/maven-projects/private-repository}.
* <ul>
* <li>{@code dependency-project} provides the code for the dependency
* {@code com.acme.dependency:dependency-project:1.0-SNAPSHOT}.</li>
* <li>{@code dependent-project} provides code that depends on
* {@code dependency-project}.</li>
* <li>{@code user.home} provides {@code .m2} and required Maven files
* {@code settings.xml} and {@code settings-security.xml}</li>
* <li>{@code reposilite-data} provides files used by reposilite to provide the required
* configuration and state (auth + dependency)</li>
* </ul>
* <p>
* The test starts a private repository in a Docker container, removes any cached local
* jars and scans {@code dependent-project}. It then verifies that type information from
* {@code com.acme.dependency:dependency-project:1.0-SNAPSHOT} was retrieved from the
* private repository.
* <p>
* The credentials are provided through {@code ~/.m2/settings.xml} and
* {@code ~/.m2/settings-security.xml}. To not interfere the local Maven installation and
* configuration, the user home directory is redirected to
* {@code ./testcode/maven-projects/private-repository/user.home}. Therefor the Maven
* {@code .m2} is pointing to
* {@code ./testcode/maven-projects/private-repository/user.home/.m2} and configuration
* files are taken from there.
*
* @author Fabian Krüger
*/
@SpringBootTest(classes = { MavenArtifactCacheTestConfig.class, SbmSupportRewriteConfiguration.class,
SbmTestConfiguration.class })
@Testcontainers
public class PrivateArtifactRepositoryTest {
// All test resources live here
public static final String TESTCODE_DIR = "testcode/maven-projects/private-repository";
// The private Artifact repository (reposilite) provides the dependency.
@Container
static GenericContainer reposilite = new GenericContainer(DockerImageName.parse("dzikoysk/reposilite:3.4.10"))
.withExposedPorts(8080)
// copy required config files and cached dependency to repository
.withCopyFileToContainer(MountableFile.forHostPath("./" + TESTCODE_DIR + "/reposilite-data"), "/app/data")
// Create temp user 'user' with password 'secret'
.withEnv("REPOSILITE_OPTS", "--token user:secret --shared-config shared.configuration.json");
public static final String DEPENDENCY_CLASS_FQNAME = "com.example.dependency.DependencyClass";
private static final String NEW_USER_HOME = Path.of(".")
.resolve(TESTCODE_DIR + "/user.home")
.toAbsolutePath()
.normalize()
.toString();
private static final Path DEPENDENCY_PATH_IN_LOCAL_MAVEN_REPO = Path
.of(NEW_USER_HOME + "/.m2/repository/com/example/dependency/dependency-project")
.toAbsolutePath()
.normalize();
private static final File LOCAL_MAVEN_REPOSITORY = Path.of(NEW_USER_HOME + "/.m2/repository").toFile();
private static MavenRepository originalMavenRepository;
private static String originalUserHome;
@Autowired
private RewriteProjectParser parser;
@BeforeAll
static void beforeAll(@TempDir Path tempDir) {
originalUserHome = System.getProperty("user.home");
System.setProperty("user.home", NEW_USER_HOME);
originalMavenRepository = MavenRepository.MAVEN_LOCAL_DEFAULT;
// overwrites MavenRepository.MAVEN_LOCAL_DEFAULT which is statically initialized
// and used previous value of
// 'user.home'. This constant is used elsewhere to retrieve the default local
// Maven repo URI.
// To reflect the new user.home this constant is overwritten using Powermock
// Whitebox class and then set back
// in after the test.
MavenRepository mavenRepository = new MavenRepository("local",
new File(System.getProperty("user.home") + "/.m2/repository").toURI().toString(), "true", "true", true,
null, null, false);
Whitebox.setInternalState(MavenRepository.class, "MAVEN_LOCAL_DEFAULT", mavenRepository);
}
@AfterAll
static void afterAll() {
// set back to initial values
System.setProperty("user.home", originalUserHome);
Whitebox.setInternalState(MavenRepository.class, "MAVEN_LOCAL_DEFAULT", originalMavenRepository);
FileSystemUtils.deleteRecursively(LOCAL_MAVEN_REPOSITORY);
}
@BeforeEach
void beforeEach() throws IOException {
Integer port = reposilite.getMappedPort(8080);
System.out.println("Reposilite: http://localhost:" + port + " login with user:secret");
TestHelper.renderTemplates(port);
TestHelper.clearDependencyFromLocalMavenRepo();
}
@Test
@DisplayName("Maven settings should be read from secured private repo")
void mavenSettingsShouldBeReadFromSecuredPrivateRepo() {
verifyDependencyDoesNotExistInLocalMavenRepo();
RewriteProjectParsingResult parsingResult = parseDependentProject();
verifyDependencyExistsInLocalMavenRepo();
verifyTypesFromDependencyWereResolved(parsingResult);
}
private static void verifyTypesFromDependencyWereResolved(RewriteProjectParsingResult parsingResult) {
J.CompilationUnit cu = (J.CompilationUnit) parsingResult.sourceFiles()
.stream()
.filter(s -> s.getSourcePath().toFile().getName().endsWith(".java"))
.findFirst()
.get();
List<String> fqClassesInUse = cu.getTypesInUse()
.getTypesInUse()
.stream()
.filter(JavaType.FullyQualified.class::isInstance)
.map(JavaType.FullyQualified.class::cast)
.map(JavaType.FullyQualified::getFullyQualifiedName)
.toList();
// DependencyClass must be in list of used types
assertThat(fqClassesInUse).contains(DEPENDENCY_CLASS_FQNAME);
// type should be on classpath
List<String> classpathFqNames = cu.getMarkers()
.findFirst(JavaSourceSet.class)
.get()
.getClasspath()
.stream()
.map(fqn -> fqn.getFullyQualifiedName())
.toList();
assertThat(classpathFqNames).contains(DEPENDENCY_CLASS_FQNAME);
// Type of member should be resolvable
J.ClassDeclaration classDeclaration = cu.getClasses().get(0);
JavaType.Class type = (JavaType.Class) ((J.VariableDeclarations) classDeclaration.getBody()
.getStatements()
.get(0)).getType();
assertThat(type.getFullyQualifiedName()).isEqualTo(DEPENDENCY_CLASS_FQNAME);
}
private static void verifyDependencyExistsInLocalMavenRepo() {
Path snapshotDir = DEPENDENCY_PATH_IN_LOCAL_MAVEN_REPO.resolve("1.0-SNAPSHOT").toAbsolutePath().normalize();
assertThat(snapshotDir).isDirectory();
assertThat(Arrays.stream(snapshotDir.toFile().listFiles()).map(f -> f.getName()).findFirst().get())
.matches("dependency-project-1.0-.*\\.jar");
}
private RewriteProjectParsingResult parseDependentProject() {
Path migrateApplication = Path.of(TESTCODE_DIR + "/dependent-project");
RewriteProjectParsingResult parsingResult = parser.parse(migrateApplication);
return parsingResult;
}
private static void verifyDependencyDoesNotExistInLocalMavenRepo() {
Path dependencyArtifactDir = DEPENDENCY_PATH_IN_LOCAL_MAVEN_REPO.getParent();
assertThat(LOCAL_MAVEN_REPOSITORY).isDirectory();
assertThat(LOCAL_MAVEN_REPOSITORY.listFiles()).isEmpty();
}
class TestHelper {
public static final String $USER_HOME_PLACEHOLDER = "${user.home}";
public static final String $PORT_PLACEHOLDER = "${port}";
private static void renderTemplates(Integer port) throws IOException {
// create pom.xml with correct port for dependency-project
Path dependencyPomTmplPath = Path.of(TESTCODE_DIR + "/dependency-project/pom.xml.template")
.toAbsolutePath()
.normalize();
Path dependencyPomPath = renderPomXml(port, dependencyPomTmplPath);
// create pom.xml with correct port for dependent-project
Path dependentPomTmplPath = Path.of(TESTCODE_DIR + "/dependent-project/pom.xml.template")
.toAbsolutePath()
.normalize();
Path dependentPomPath = renderPomXml(port, dependentPomTmplPath);
// adjust path in settings.xml
Path settingsXmlTmplPath = Path.of("./")
.resolve(NEW_USER_HOME + "/.m2/settings.xml.template")
.toAbsolutePath()
.normalize();
renderSettingsXml(NEW_USER_HOME, settingsXmlTmplPath);
}
private static Path renderSettingsXml(String testcodeDir, Path settingsXmlTmplPath) throws IOException {
String settingsXmlContent = Files.readString(settingsXmlTmplPath);
String replaced = settingsXmlContent.replace($USER_HOME_PLACEHOLDER, testcodeDir);
Path settingsXmlPath = Path.of(settingsXmlTmplPath.toString().replace(".template", ""));
return Files.writeString(settingsXmlPath, replaced);
}
private static Path renderPomXml(Integer port, Path pomXmlTmplPath) throws IOException {
String given = Files.readString(pomXmlTmplPath);
String replaced = given.replace($PORT_PLACEHOLDER, port.toString());
Path pomXmlPath = Path.of(pomXmlTmplPath.toString().replace(".template", ""));
return Files.writeString(pomXmlPath, replaced);
}
static void clearDependencyFromLocalMavenRepo() {
try {
FileSystemUtils.deleteRecursively(DEPENDENCY_PATH_IN_LOCAL_MAVEN_REPO);
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
}
/*
* Currently not used as the dependency is provided to the container (cached). But
* kept in case deployment of the dependency or building the dependent project is
* needed.
*/
class DeploymentHelper {
void deployDependency(Path pomXmlPath) throws MavenInvocationException {
InvocationRequest request = new DefaultInvocationRequest();
request.setPomFile(pomXmlPath.toFile());
request.setShowErrors(true);
request.setUserSettingsFile(Path.of(TESTCODE_DIR + "/user.home/.m2/settings-clear-password.xml").toFile());
request.setGoals(List.of("deploy"));
request.setLocalRepositoryDirectory(LOCAL_MAVEN_REPOSITORY);
request.setBatchMode(true);
Invoker invoker = new DefaultInvoker();
invoker.setMavenHome(Path.of(TESTCODE_DIR + "/user.home/apache-maven-3.9.5").toFile());
InvocationResult result = invoker.execute(request);
if (result.getExitCode() != 0) {
if (result.getExecutionException() != null) {
fail("Maven deploy failed.", result.getExecutionException());
}
else {
fail("Maven deploy failed. Exit code: " + result.getExitCode());
}
}
}
private void buildProject(Path dependentPomPath) throws MavenInvocationException {
InvocationRequest request = new DefaultInvocationRequest();
request.setPomFile(dependentPomPath.toFile());
request.setShowErrors(true);
request.setUserSettingsFile(Path.of(TESTCODE_DIR + "/user.home/.m2/settings.xml").toFile());
request.setGoals(List.of("clean", "package"));
request.setLocalRepositoryDirectory(LOCAL_MAVEN_REPOSITORY);
request.setBatchMode(true);
request.setGlobalChecksumPolicy(InvocationRequest.CheckSumPolicy.Warn);
request.setOutputHandler(s -> System.out.println(s));
Invoker invoker = new DefaultInvoker();
invoker.setMavenHome(Path.of(TESTCODE_DIR + "/user.home/apache-maven-3.9.5").toFile());
InvocationResult result = invoker.execute(request);
if (result.getExitCode() != 0) {
if (result.getExecutionException() != null) {
fail("Maven clean package failed.", result.getExecutionException());
}
else {
fail("Maven clean package. Exit code: " + result.getExitCode());
}
}
}
static void installMavenForTestIfNotExists(Path tempDir) {
if (!Path.of("./testcode/maven-projects/private-repository/user.home/apache-maven-3.9.5/bin/mvn")
.toFile()
.exists()) {
String mavenDownloadUrl = "https://dlcdn.apache.org/maven/maven-3/3.9.5/binaries/apache-maven-3.9.5-bin.zip";
try {
Path mavenInstallDir = Path.of(TESTCODE_DIR + "/user.home");
File downloadedMavenZipFile = tempDir.resolve("apache-maven-3.9.5-bin.zip").toFile();
FileUtils.copyURLToFile(new URL(mavenDownloadUrl), downloadedMavenZipFile, 10000, 30000);
Unzipper.unzip(downloadedMavenZipFile, mavenInstallDir);
File file = mavenInstallDir.resolve("apache-maven-3.9.5/bin/mvn").toFile();
file.setExecutable(true, false);
assertThat(file.canExecute()).isTrue();
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
}
class Unzipper {
private static void unzip(File downloadedMavenZipFile, Path mavenInstallDir) {
try {
byte[] buffer = new byte[1024];
ZipInputStream zis = null;
zis = new ZipInputStream(new FileInputStream(downloadedMavenZipFile));
ZipEntry zipEntry = zis.getNextEntry();
while (zipEntry != null) {
File newFile = newFile(mavenInstallDir.toFile(), zipEntry);
if (zipEntry.isDirectory()) {
if (!newFile.isDirectory() && !newFile.mkdirs()) {
throw new IOException("Failed to create directory " + newFile);
}
}
else {
// fix for Windows-created archives
File parent = newFile.getParentFile();
if (!parent.isDirectory() && !parent.mkdirs()) {
throw new IOException("Failed to create directory " + parent);
}
// write file content
FileOutputStream fos = new FileOutputStream(newFile);
int len;
while ((len = zis.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
fos.close();
}
zipEntry = zis.getNextEntry();
}
zis.closeEntry();
zis.close();
}
catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
public static File newFile(File destinationDir, ZipEntry zipEntry) throws IOException {
File destFile = new File(destinationDir, zipEntry.getName());
String destDirPath = destinationDir.getCanonicalPath();
String destFilePath = destFile.getCanonicalPath();
if (!destFilePath.startsWith(destDirPath + java.io.File.separator)) {
throw new IOException("Entry is outside of the target dir: " + zipEntry.getName());
}
return destFile;
}
}
}
}
// Overwrite MavenArtifactCache to use the modified 'user.home'.
@Configuration
class MavenArtifactCacheTestConfig {
@Bean
MavenArtifactCache mavenArtifactCache() {
return new LocalMavenArtifactCache(Paths.get(System.getProperty("user.home"), ".m2", "repository"));
}
}

View File

@@ -0,0 +1,15 @@
**/target
**/.rewrite-cache
/dependency-project/pom.xml
/dependent-project/pom.xml
/user.home/.config/
/user.home/apache-maven-3.9.5/
/user.home/.m2/repository
/user.home/.m2/settings.xml
!/user.home/.m2/settings.xml.template
!/user.home/.m2/settings-security.xml
/reposilite-data/static
/reposilite-data/.local
/reposilite-data/plugins
/reposilite-data/reposilite.db
/reposilite-data/configuration.cdn

View File

@@ -0,0 +1,36 @@
# Artifact Repository Test
Test that artifacts available in a private artifact repository configured in `~/.m2/settings.xml` can be accessed.
This is important as many enterprise projects use their private artifact repository to retrieve private dependencies.
- A private artifact repository using (https://github.com/dzikoysk/reposilite[reposilite]) is started in a Docker container.
The reposilite instance has a user configured (admin:secret) which can deploy and access artifacts.
- The repositories in the artifact repository (e.g. snapshot) require successful authentication (deploy + download).
- `dependency-project` has a simple class `DependencyClass` and gets deployed to the artifact repository.
- `dependent-project` depends on `dependency-project` and has a class `DependentClass` that uses `DependencyClass`
- `dependent-project` gets parsed
- The resulting AST has the type information of `dependency-project` resolved when the repository information and credentials were read from `settings.xml` and `security-settings.xml`.
Technical requirements:
- The port of the Docker container is dynamic and used in settings.xml and pom.xml.
- The local Maven installation of any system should not be affected by this test.
- The location of the Maven dir `.m2` must therefore point to a different location while the test is running.
This requires temporarily a different `.m2` location, here `testcode/maven-projects/private-repository/user.home/.m2`.
When deploying the `dependency-project` the path to `settings.xml` is provided, pointing to `testcode/maven-projects/private-repository/user.home/.m2/settings.xml`.
This file declares the location of the local Maven repository pointing to the same dir.
Because these paths can't be relative for this test and absolute paths
The `user.home` is set to point to `testcode/maven-projects/private-repository/user.home` which contains a `.m2` directory providing access configuration to the reposilite instance through `.m2/settings.xml` and `.m2/security-settings.xml`,

View File

@@ -0,0 +1,25 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.dependency</groupId>
<artifactId>dependency-project</artifactId>
<version>1.0-SNAPSHOT</version>
<name>dependency-project</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<distributionManagement>
<repository>
<id>repository-snapshots</id>
<name>Snapshots Repository</name>
<url>http://localhost:${port}/snapshots</url>
</repository>
</distributionManagement>
</project>

View File

@@ -0,0 +1,13 @@
package com.example.dependency;
public class DependencyClass
{
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}

View File

@@ -0,0 +1,33 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.dependent</groupId>
<artifactId>dependent-project</artifactId>
<version>1.0-SNAPSHOT</version>
<name>dependent-project</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.example.dependency</groupId>
<artifactId>dependency-project</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>repository-snapshots</id>
<name>Snapshots Repository</name>
<url>http://localhost:${port}/snapshots</url>
</repository>
</repositories>
</project>

View File

@@ -0,0 +1,7 @@
package com.example.dependent;
import com.example.dependency.DependencyClass;
public class DependentClass {
private DependencyClass dependencyClass;
}

View File

@@ -0,0 +1,25 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.dependency</groupId>
<artifactId>dependency-project</artifactId>
<version>1.0-SNAPSHOT</version>
<name>dependency-project</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<distributionManagement>
<repository>
<id>repository-snapshots</id>
<name>Snapshots Repository</name>
<url>http://localhost:52260/snapshots</url>
</repository>
</distributionManagement>
</project>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<metadata modelVersion="1.1.0">
<groupId>com.example.dependency</groupId>
<artifactId>dependency-project</artifactId>
<versioning>
<lastUpdated>20231105102337</lastUpdated>
<snapshot>
<timestamp>20231105.102337</timestamp>
<buildNumber>1</buildNumber>
</snapshot>
<snapshotVersions>
<snapshotVersion>
<extension>pom</extension>
<value>1.0-20231105.102337-1</value>
<updated>20231105102337</updated>
</snapshotVersion>
<snapshotVersion>
<extension>jar</extension>
<value>1.0-20231105.102337-1</value>
<updated>20231105102337</updated>
</snapshotVersion>
</snapshotVersions>
</versioning>
<version>1.0-SNAPSHOT</version>
</metadata>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<groupId>com.example.dependency</groupId>
<artifactId>dependency-project</artifactId>
<versioning>
<versions>
<version>1.0-SNAPSHOT</version>
</versions>
<lastUpdated>20231105102337</lastUpdated>
</versioning>
</metadata>

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