From 65a587b882d1ac15123b41ef4ef9df7bb389522d Mon Sep 17 00:00:00 2001 From: Jonathan Schneider Date: Sun, 14 Jul 2024 22:28:54 -0400 Subject: [PATCH] Initial docker recipe --- README.md | 153 +---------- build.gradle.kts | 68 +---- licenseHeader.txt => gradle/licenseHeader.txt | 0 mvnw | 259 ------------------ mvnw.cmd | 149 ---------- pom.xml | 222 --------------- settings.gradle.kts | 2 +- .../com/yourorg/AppendToReleaseNotes.java | 108 -------- .../com/yourorg/AssertEqualsToAssertThat.java | 89 ------ src/main/java/com/yourorg/ClassHierarchy.java | 73 ----- .../com/yourorg/NoCollectionMutation.java | 155 ----------- .../com/yourorg/NoGuavaListsNewArrayList.java | 111 -------- .../java/com/yourorg/SimplifyTernary.java | 63 ----- .../com/yourorg/UpdateConcoursePipeline.java | 92 ------- .../docker/DockerImageVersion.java} | 19 +- .../openrewrite/docker}/package-info.java | 2 +- .../docker/search/FindDockerImageUses.java | 61 +++++ .../docker/search/package-info.java | 21 ++ .../docker/table/DockerBaseImages.java} | 31 +-- .../docker/table/package-info.java | 21 ++ .../openrewrite/docker/trait/Dockerfile.java | 61 +++++ .../org/openrewrite/docker/trait/Traits.java | 26 ++ .../docker/trait/package-info.java | 21 ++ .../yourorg/AssertEqualsToAssertThatTest.java | 89 ------ .../java/com/yourorg/ClassHierarchyTest.java | 88 ------ .../com/yourorg/NoCollectionMutationTest.java | 221 --------------- .../yourorg/NoGuavaListsNewArrayListTest.java | 179 ------------ .../java/com/yourorg/SimplifyTernaryTest.java | 116 -------- .../java/com/yourorg/StringIsEmptyTest.java | 170 ------------ .../yourorg/UpdateConcoursePipelineTest.java | 57 ---- .../com/yourorg/UseApacheStringUtilsTest.java | 60 ---- .../yourorg/UseOpenRewriteNullableTest.java | 65 ----- .../docker/FindDockerImagesUsedTest.java} | 45 +-- 33 files changed, 267 insertions(+), 2630 deletions(-) rename licenseHeader.txt => gradle/licenseHeader.txt (100%) delete mode 100755 mvnw delete mode 100644 mvnw.cmd delete mode 100644 pom.xml delete mode 100644 src/main/java/com/yourorg/AppendToReleaseNotes.java delete mode 100644 src/main/java/com/yourorg/AssertEqualsToAssertThat.java delete mode 100644 src/main/java/com/yourorg/ClassHierarchy.java delete mode 100644 src/main/java/com/yourorg/NoCollectionMutation.java delete mode 100644 src/main/java/com/yourorg/NoGuavaListsNewArrayList.java delete mode 100644 src/main/java/com/yourorg/SimplifyTernary.java delete mode 100644 src/main/java/com/yourorg/UpdateConcoursePipeline.java rename src/main/java/{com/yourorg/StringIsEmpty.java => org/openrewrite/docker/DockerImageVersion.java} (64%) rename src/main/java/{com/yourorg => org/openrewrite/docker}/package-info.java (96%) create mode 100644 src/main/java/org/openrewrite/docker/search/FindDockerImageUses.java create mode 100644 src/main/java/org/openrewrite/docker/search/package-info.java rename src/main/java/{com/yourorg/table/ClassHierarchyReport.java => org/openrewrite/docker/table/DockerBaseImages.java} (50%) create mode 100644 src/main/java/org/openrewrite/docker/table/package-info.java create mode 100644 src/main/java/org/openrewrite/docker/trait/Dockerfile.java create mode 100644 src/main/java/org/openrewrite/docker/trait/Traits.java create mode 100644 src/main/java/org/openrewrite/docker/trait/package-info.java delete mode 100644 src/test/java/com/yourorg/AssertEqualsToAssertThatTest.java delete mode 100644 src/test/java/com/yourorg/ClassHierarchyTest.java delete mode 100644 src/test/java/com/yourorg/NoCollectionMutationTest.java delete mode 100644 src/test/java/com/yourorg/NoGuavaListsNewArrayListTest.java delete mode 100644 src/test/java/com/yourorg/SimplifyTernaryTest.java delete mode 100644 src/test/java/com/yourorg/StringIsEmptyTest.java delete mode 100644 src/test/java/com/yourorg/UpdateConcoursePipelineTest.java delete mode 100644 src/test/java/com/yourorg/UseApacheStringUtilsTest.java delete mode 100644 src/test/java/com/yourorg/UseOpenRewriteNullableTest.java rename src/test/java/{com/yourorg/AppendToReleaseNotesTest.java => org/openrewrite/docker/FindDockerImagesUsedTest.java} (51%) diff --git a/README.md b/README.md index 534691e..8bcbe8b 100644 --- a/README.md +++ b/README.md @@ -1,152 +1,3 @@ -# Rewrite recipe starter +# Rewrite Docker -This repository serves as a template for building your own recipe JARs and publishing them to a repository where they can be applied on [app.moderne.io](https://app.moderne.io) against all the public OSS code that is included there. - -We've provided a sample recipe (NoGuavaListsNewArray) and a sample test class. Both of these exist as placeholders, and they should be replaced by whatever recipe you are interested in writing. - -To begin, fork this repository and customize it by: - -1. Changing the root project name in `settings.gradle.kts`. -2. Changing the `group` in `build.gradle.kts`. -3. Changing the package structure from `com.yourorg` to whatever you want. - -## Getting started - -Familiarize yourself with the [OpenRewrite documentation](https://docs.openrewrite.org/), in particular the [concepts & explanations](https://docs.openrewrite.org/concepts-explanations) op topics like the [lossless semantic trees](https://docs.openrewrite.org/concepts-explanations/lossless-semantic-trees), [recipes](https://docs.openrewrite.org/concepts-explanations/recipes) and [visitors](https://docs.openrewrite.org/concepts-explanations/visitors). - -You might be interested to watch some of the [videos available on OpenRewrite and Moderne](https://www.youtube.com/@moderne-auto-remediation). - -Once you want to dive into the code there is a [comprehensive getting started guide](https://docs.openrewrite.org/authoring-recipes/recipe-development-environment) -available in the OpenRewrite docs that provides more details than the below README. - -## Reference recipes - -* [META-INF/rewrite/stringutils.yml](./src/main/resources/META-INF/rewrite/stringutils.yml) - A declarative YAML recipe that replaces usages of `org.springframework.util.StringUtils` with `org.apache.commons.lang3.StringUtils`. - * [UseApacheStringUtilsTest](./src/test/java/com/yourorg/UseApacheStringUtilsTest.java) - A test class for the `com.yourorg.UseApacheStringUtils` recipe. -* [NoGuavaListsNewArrayList.java](./src/main/java/com/yourorg/NoGuavaListsNewArrayList.java) - An imperative Java recipe that replaces usages of `com.google.common.collect.Lists` with `new ArrayList<>()`. - * [NoGuavaListsNewArrayListTest.java](./src/test/java/com/yourorg/NoGuavaListsNewArrayListTest.java) - A test class for the `NoGuavaListsNewArrayList` recipe. -* [SimplifyTernary](./src/main/java/com/yourorg/SimplifyTernary.java) - An Refaster style recipe that simplifies ternary expressions. - * [SimplifyTernaryTest](./src/test/java/com/yourorg/SimplifyTernaryTest.java) - A test class for the `SimplifyTernary` recipe. -* [AssertEqualsToAssertThat](./src/main/java/com/yourorg/AssertEqualsToAssertThat.java) - An imperative Java recipe that replaces JUnit's `assertEquals` with AssertJ's `assertThat`, to show how to handle classpath dependencies. - * [AssertEqualsToAssertThatTest](./src/test/java/com/yourorg/AssertEqualsToAssertThatTest.java) - A test class for the `AssertEqualsToAssertThat` recipe. -* [AppendToReleaseNotes](./src/main/java/com/yourorg/AppendToReleaseNotes.java) - A ScanningRecipe that appends a message to the release notes of a project. - * [AppendToReleaseNotesTest](./src/test/java/com/yourorg/AppendToReleaseNotesTest.java) - A test class for the `AppendToReleaseNotes` recipe. -* [ClassHierarchy](./src/main/java/com/yourorg/ClassHierarchy.java) - A recipe that demonstrates how to produce a data table on the class hierarchy of a project. - * [ClassHierarchyTest](./src/test/java/com/yourorg/ClassHierarchyTest.java) - A test class for the `ClassHierarchy` recipe. -* [UpdateConcoursePipeline](./src/main/java/com/yourorg/UpdateConcoursePipeline.java) - A recipe that demonstrates how to update a Concourse pipeline, as an example of operating on Yaml files. - * [UpdateConcoursePipelineTest](./src/test/java/com/yourorg/UpdateConcoursePipelineTest.java) - A test class for the `UpdateConcoursePipeline` recipe. - -## Local Publishing for Testing - -Before you publish your recipe module to an artifact repository, you may want to try it out locally. -To do this on the command line, using `gradle`, run: - -```bash -./gradlew publishToMavenLocal -# or ./gradlew pTML -# or mvn install -``` - -To publish using maven, run: - -```bash -./mvnw install -``` - -This will publish to your local maven repository, typically under `~/.m2/repository`. - -Replace the groupId, artifactId, recipe name, and version in the below snippets with the ones that correspond to your recipe. - -In the pom.xml of a different project you wish to test your recipe out in, make your recipe module a plugin dependency of rewrite-maven-plugin: - -```xml - - - - - org.openrewrite.maven - rewrite-maven-plugin - RELEASE - - - com.yourorg.NoGuavaListsNewArrayList - - - - - com.yourorg - rewrite-recipe-starter - 0.1.0-SNAPSHOT - - - - - - -``` - -Unlike Maven, Gradle must be explicitly configured to resolve dependencies from Maven local. -The root project of your Gradle build, make your recipe module a dependency of the `rewrite` configuration: - -```groovy -plugins { - id("java") - id("org.openrewrite.rewrite") version("latest.release") -} - -repositories { - mavenLocal() - mavenCentral() -} - -dependencies { - rewrite("com.yourorg:rewrite-recipe-starter:latest.integration") -} - -rewrite { - activeRecipe("com.yourorg.NoGuavaListsNewArrayList") -} -``` - -Now you can run `mvn rewrite:run` or `gradlew rewriteRun` to run your recipe. - -## Publishing to Artifact Repositories - -This project is configured to publish to Moderne's open artifact repository (via the `publishing` task at the bottom of -the `build.gradle.kts` file). If you want to publish elsewhere, you'll want to update that task. -[app.moderne.io](https://app.moderne.io) can draw recipes from the provided repository, as well as from [Maven Central](https://search.maven.org). - -Note: -Running the publish task _will not_ update [app.moderne.io](https://app.moderne.io), as only Moderne employees can -add new recipes. If you want to add your recipe to [app.moderne.io](https://app.moderne.io), please ask the -team in [Slack](https://join.slack.com/t/rewriteoss/shared_invite/zt-nj42n3ea-b~62rIHzb3Vo0E1APKCXEA) or in [Discord](https://discord.gg/xk3ZKrhWAb). - -These other docs might also be useful for you depending on where you want to publish the recipe: - -* Sonatype's instructions for [publishing to Maven Central](https://maven.apache.org/repository/guide-central-repository-upload.html) -* Gradle's instructions on the [Gradle Publishing Plugin](https://docs.gradle.org/current/userguide/publishing\_maven.html). - -### From Github Actions - -The `.github` directory contains a Github action that will push a snapshot on every successful build. - -Run the release action to publish a release version of a recipe. - -### From the command line - -To build a snapshot, run `./gradlew snapshot publish` to build a snapshot and publish it to Moderne's open artifact repository for inclusion at [app.moderne.io](https://app.moderne.io). - -To build a release, run `./gradlew final publish` to tag a release and publish it to Moderne's open artifact repository for inclusion at [app.moderne.io](https://app.moderne.io). - -## Applying OpenRewrite recipe development best practices - -We maintain a collection of [best practices for writing OpenRewrite recipes](https://docs.openrewrite.org/recipes/recipes/openrewritebestpractices). -You can apply these recommendations to your recipes by running the following command: - -```bash -./gradlew rewriteRun -Drewrite.activeRecipe=org.openrewrite.recipes.OpenRewriteBestPractices -``` -or -```bash -./mvnw -U org.openrewrite.maven:rewrite-maven-plugin:run -Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-recommendations:RELEASE -Drewrite.activeRecipes=org.openrewrite.recipes.OpenRewriteBestPractices -``` \ No newline at end of file +Docker recipes for studying and transforming Docker usage. diff --git a/build.gradle.kts b/build.gradle.kts index 9d316b0..08a6317 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,64 +1,20 @@ plugins { - id("org.openrewrite.build.recipe-library-base") version "latest.release" - - // This uses the nexus publishing plugin to publish to the moderne-dev repository - // Remove it if you prefer to publish by other means, such as the maven-publish plugin - id("org.openrewrite.build.publish") version "latest.release" - id("nebula.release") version "latest.release" - - // Configures artifact repositories used for dependency resolution to include maven central and nexus snapshots. - // If you are operating in an environment where public repositories are not accessible, we recommend using a - // virtual repository which mirrors both maven central and nexus snapshots. - id("org.openrewrite.build.recipe-repositories") version "latest.release" - - // Only needed when you want to apply the OpenRewriteBestPractices recipe to your recipes through - // ./gradlew rewriteRun -Drewrite.activeRecipe=org.openrewrite.recipes.OpenRewriteBestPractices - id("org.openrewrite.rewrite") version "latest.release" + id("org.openrewrite.build.recipe-library") version "latest.release" } -// Set as appropriate for your organization -group = "com.yourorg" -description = "Rewrite recipes." +group = "org.openrewrite.recipe" +description = "Rewrite Docker recipes." +val rewriteVersion = rewriteRecipe.rewriteVersion.get() dependencies { - // The bom version can also be set to a specific version - // https://github.com/openrewrite/rewrite-recipe-bom/releases - implementation(platform("org.openrewrite.recipe:rewrite-recipe-bom:latest.release")) - - implementation("org.openrewrite:rewrite-java") - implementation("org.openrewrite.recipe:rewrite-java-dependencies") - implementation("org.openrewrite:rewrite-yaml") - implementation("org.openrewrite.meta:rewrite-analysis") - implementation("org.assertj:assertj-core:3.24.2") - runtimeOnly("org.openrewrite:rewrite-java-17") - - // Refaster style recipes need the rewrite-templating annotation processor and dependency for generated recipes - // https://github.com/openrewrite/rewrite-templating/releases - annotationProcessor("org.openrewrite:rewrite-templating:latest.release") - implementation("org.openrewrite:rewrite-templating") - // The `@BeforeTemplate` and `@AfterTemplate` annotations are needed for refaster style recipes - compileOnly("com.google.errorprone:error_prone_core:2.19.1") { - exclude("com.google.auto.service", "auto-service-annotations") - } - - // Need to have a slf4j binding to see any output enabled from the parser. - runtimeOnly("ch.qos.logback:logback-classic:1.2.+") - - // Our recipe converts Guava's `Lists` type - testRuntimeOnly("com.google.guava:guava:latest.release") - testRuntimeOnly("org.apache.commons:commons-lang3:latest.release") - testRuntimeOnly("org.springframework:spring-core:latest.release") - - // Contains the OpenRewriteBestPractices recipe, which you can apply to your recipes - rewrite("org.openrewrite.recipe:rewrite-recommendations:latest.release") + implementation(platform("org.openrewrite.recipe:rewrite-recipe-bom:$rewriteVersion")) + implementation("org.openrewrite:rewrite-core") } signing { - // To enable signing have your CI workflow set the "signingKey" and "signingPassword" Gradle project properties isRequired = false } -// Use maven-style "SNAPSHOT" versioning for non-release builds configure { defaultVersionStrategy = nebula.plugin.release.NetflixOssStrategies.SNAPSHOT(project) } @@ -72,10 +28,10 @@ configure { } publishing { - repositories { - maven { - name = "moderne" - url = uri("https://us-west1-maven.pkg.dev/moderne-dev/moderne-recipe") - } - } + repositories { + maven { + name = "moderne" + url = uri("https://us-west1-maven.pkg.dev/moderne-dev/moderne-recipe") + } + } } diff --git a/licenseHeader.txt b/gradle/licenseHeader.txt similarity index 100% rename from licenseHeader.txt rename to gradle/licenseHeader.txt diff --git a/mvnw b/mvnw deleted file mode 100755 index 19529dd..0000000 --- a/mvnw +++ /dev/null @@ -1,259 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# 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. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Apache Maven Wrapper startup batch script, version 3.3.2 -# -# Optional ENV vars -# ----------------- -# JAVA_HOME - location of a JDK home dir, required when download maven via java source -# MVNW_REPOURL - repo url base for downloading maven distribution -# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven -# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output -# ---------------------------------------------------------------------------- - -set -euf -[ "${MVNW_VERBOSE-}" != debug ] || set -x - -# OS specific support. -native_path() { printf %s\\n "$1"; } -case "$(uname)" in -CYGWIN* | MINGW*) - [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" - native_path() { cygpath --path --windows "$1"; } - ;; -esac - -# set JAVACMD and JAVACCMD -set_java_home() { - # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched - 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" - JAVACCMD="$JAVA_HOME/jre/sh/javac" - else - JAVACMD="$JAVA_HOME/bin/java" - JAVACCMD="$JAVA_HOME/bin/javac" - - if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then - echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 - echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 - return 1 - fi - fi - else - JAVACMD="$( - 'set' +e - 'unset' -f command 2>/dev/null - 'command' -v java - )" || : - JAVACCMD="$( - 'set' +e - 'unset' -f command 2>/dev/null - 'command' -v javac - )" || : - - if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then - echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 - return 1 - fi - fi -} - -# hash string like Java String::hashCode -hash_string() { - str="${1:-}" h=0 - while [ -n "$str" ]; do - char="${str%"${str#?}"}" - h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) - str="${str#?}" - done - printf %x\\n $h -} - -verbose() { :; } -[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } - -die() { - printf %s\\n "$1" >&2 - exit 1 -} - -trim() { - # MWRAPPER-139: - # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. - # Needed for removing poorly interpreted newline sequences when running in more - # exotic environments such as mingw bash on Windows. - printf "%s" "${1}" | tr -d '[:space:]' -} - -# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties -while IFS="=" read -r key value; do - case "${key-}" in - distributionUrl) distributionUrl=$(trim "${value-}") ;; - distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; - esac -done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" -[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" - -case "${distributionUrl##*/}" in -maven-mvnd-*bin.*) - MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ - case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in - *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; - :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; - :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; - :Linux*x86_64*) distributionPlatform=linux-amd64 ;; - *) - echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 - distributionPlatform=linux-amd64 - ;; - esac - distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" - ;; -maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; -*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; -esac - -# apply MVNW_REPOURL and calculate MAVEN_HOME -# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ -[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" -distributionUrlName="${distributionUrl##*/}" -distributionUrlNameMain="${distributionUrlName%.*}" -distributionUrlNameMain="${distributionUrlNameMain%-bin}" -MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" -MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" - -exec_maven() { - unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : - exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" -} - -if [ -d "$MAVEN_HOME" ]; then - verbose "found existing MAVEN_HOME at $MAVEN_HOME" - exec_maven "$@" -fi - -case "${distributionUrl-}" in -*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; -*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; -esac - -# prepare tmp dir -if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then - clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } - trap clean HUP INT TERM EXIT -else - die "cannot create temp dir" -fi - -mkdir -p -- "${MAVEN_HOME%/*}" - -# Download and Install Apache Maven -verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." -verbose "Downloading from: $distributionUrl" -verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" - -# select .zip or .tar.gz -if ! command -v unzip >/dev/null; then - distributionUrl="${distributionUrl%.zip}.tar.gz" - distributionUrlName="${distributionUrl##*/}" -fi - -# verbose opt -__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' -[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v - -# normalize http auth -case "${MVNW_PASSWORD:+has-password}" in -'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; -has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; -esac - -if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then - verbose "Found wget ... using wget" - wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" -elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then - verbose "Found curl ... using curl" - curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" -elif set_java_home; then - verbose "Falling back to use Java to download" - javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" - targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" - cat >"$javaSource" <<-END - public class Downloader extends java.net.Authenticator - { - protected java.net.PasswordAuthentication getPasswordAuthentication() - { - return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); - } - public static void main( String[] args ) throws Exception - { - setDefault( new Downloader() ); - java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); - } - } - END - # For Cygwin/MinGW, switch paths to Windows format before running javac and java - verbose " - Compiling Downloader.java ..." - "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" - verbose " - Running Downloader.java ..." - "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" -fi - -# If specified, validate the SHA-256 sum of the Maven distribution zip file -if [ -n "${distributionSha256Sum-}" ]; then - distributionSha256Result=false - if [ "$MVN_CMD" = mvnd.sh ]; then - echo "Checksum validation is not supported for maven-mvnd." >&2 - echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 - exit 1 - elif command -v sha256sum >/dev/null; then - if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then - distributionSha256Result=true - fi - elif command -v shasum >/dev/null; then - if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then - distributionSha256Result=true - fi - else - echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 - echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 - exit 1 - fi - if [ $distributionSha256Result = false ]; then - echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 - echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 - exit 1 - fi -fi - -# unzip and move -if command -v unzip >/dev/null; then - unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" -else - tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" -fi -printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" -mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" - -clean || : -exec_maven "$@" diff --git a/mvnw.cmd b/mvnw.cmd deleted file mode 100644 index 249bdf3..0000000 --- a/mvnw.cmd +++ /dev/null @@ -1,149 +0,0 @@ -<# : batch portion -@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 Apache Maven Wrapper startup batch script, version 3.3.2 -@REM -@REM Optional ENV vars -@REM MVNW_REPOURL - repo url base for downloading maven distribution -@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven -@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output -@REM ---------------------------------------------------------------------------- - -@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) -@SET __MVNW_CMD__= -@SET __MVNW_ERROR__= -@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% -@SET PSModulePath= -@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( - IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) -) -@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% -@SET __MVNW_PSMODULEP_SAVE= -@SET __MVNW_ARG0_NAME__= -@SET MVNW_USERNAME= -@SET MVNW_PASSWORD= -@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) -@echo Cannot start maven from wrapper >&2 && exit /b 1 -@GOTO :EOF -: end batch / begin powershell #> - -$ErrorActionPreference = "Stop" -if ($env:MVNW_VERBOSE -eq "true") { - $VerbosePreference = "Continue" -} - -# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties -$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl -if (!$distributionUrl) { - Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" -} - -switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { - "maven-mvnd-*" { - $USE_MVND = $true - $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" - $MVN_CMD = "mvnd.cmd" - break - } - default { - $USE_MVND = $false - $MVN_CMD = $script -replace '^mvnw','mvn' - break - } -} - -# apply MVNW_REPOURL and calculate MAVEN_HOME -# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ -if ($env:MVNW_REPOURL) { - $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } - $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" -} -$distributionUrlName = $distributionUrl -replace '^.*/','' -$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' -$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" -if ($env:MAVEN_USER_HOME) { - $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain" -} -$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' -$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" - -if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { - Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" - Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" - exit $? -} - -if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { - Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" -} - -# prepare tmp dir -$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile -$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" -$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null -trap { - if ($TMP_DOWNLOAD_DIR.Exists) { - try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } - catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } - } -} - -New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null - -# Download and Install Apache Maven -Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." -Write-Verbose "Downloading from: $distributionUrl" -Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" - -$webclient = New-Object System.Net.WebClient -if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { - $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) -} -[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null - -# If specified, validate the SHA-256 sum of the Maven distribution zip file -$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum -if ($distributionSha256Sum) { - if ($USE_MVND) { - Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." - } - Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash - if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { - Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." - } -} - -# unzip and move -Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null -Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null -try { - Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null -} catch { - if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { - Write-Error "fail to move MAVEN_HOME" - } -} finally { - try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } - catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } -} - -Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/pom.xml b/pom.xml deleted file mode 100644 index 30dbdc3..0000000 --- a/pom.xml +++ /dev/null @@ -1,222 +0,0 @@ - - - 4.0.0 - com.yourorg - rewrite-recipe-starter - 1.0.1-SNAPSHOT - - - UTF-8 - UTF-8 - - - - - org.projectlombok - lombok - 1.18.34 - provided - true - - - - - org.openrewrite - rewrite-templating - - - - - org.openrewrite.meta - rewrite-analysis - - - - com.google.errorprone - error_prone_core - 2.28.0 - provided - true - - - com.google.auto.service - auto-service-annotations - - - - - - org.openrewrite - rewrite-java - - - - org.openrewrite - rewrite-yaml - - - - org.openrewrite.recipe - rewrite-java-dependencies - - - - org.openrewrite - rewrite-test - test - - - - org.junit.jupiter - junit-jupiter - test - - - - org.assertj - assertj-core - 3.26.3 - test - - - - com.google.guava - guava - 33.2.1-jre - test - - - - org.apache.commons - commons-lang3 - 3.14.0 - test - - - - org.springframework - spring-core - 6.1.10 - test - - - - - - - org.openrewrite.recipe - rewrite-recipe-bom - 2.14.0 - pom - import - - - org.junit - junit-bom - 5.11.0-M2 - pom - import - - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.13.0 - - 8 - 8 - 17 - 17 - - -parameters - - - - org.projectlombok - lombok - 1.18.32 - - - org.openrewrite - rewrite-templating - 1.11.1 - - - - - - org.apache.maven.plugins - maven-surefire-plugin - 3.3.0 - - - org.apache.maven.plugins - maven-failsafe-plugin - 3.3.0 - - - org.apache.maven.plugins - maven-resources-plugin - 3.3.1 - - - jar - - - - - org.apache.maven.plugins - maven-dependency-plugin - 3.7.0 - - - copy - process-sources - - copy - - - - - - junit - junit - 3.8.1 - - - ${project.basedir}/src/main/resources/META-INF/rewrite/classpath - true - - true - - - - - - - org.openrewrite.maven - rewrite-maven-plugin - 5.34.1 - - true - - - - org.openrewrite.recipe - rewrite-recommendations - 1.6.1 - - - - - - diff --git a/settings.gradle.kts b/settings.gradle.kts index 5934121..f8bcd64 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1 +1 @@ -rootProject.name = "rewrite-recipe-starter" +rootProject.name = "rewrite-docker" diff --git a/src/main/java/com/yourorg/AppendToReleaseNotes.java b/src/main/java/com/yourorg/AppendToReleaseNotes.java deleted file mode 100644 index 7a8c38f..0000000 --- a/src/main/java/com/yourorg/AppendToReleaseNotes.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2024 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.yourorg; - -import lombok.EqualsAndHashCode; -import lombok.Value; -import org.openrewrite.*; -import org.openrewrite.internal.lang.Nullable; -import org.openrewrite.text.PlainText; -import org.openrewrite.text.PlainTextParser; -import org.openrewrite.text.PlainTextVisitor; - -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Collection; -import java.util.Collections; -import java.util.stream.Collectors; - -@Value -@EqualsAndHashCode(callSuper = false) -public class AppendToReleaseNotes extends ScanningRecipe { - - @Override - public String getDisplayName() { - return "Append to release notes"; - } - - @Override - public String getDescription() { - return "Adds the specified line to RELEASE.md."; - } - - @Option(displayName = "Message", - description = "Message to append to the bottom of RELEASE.md.", - example = "## 1.0.0\n\n- New feature") - String message; - - // The shared state between the scanner and the visitor. The custom class ensures we can easily extend the recipe. - public static class Accumulator { - boolean found; - } - - @Override - public Accumulator getInitialValue(ExecutionContext ctx) { - return new Accumulator(); - } - - @Override - public TreeVisitor getScanner(Accumulator acc) { - return new TreeVisitor() { - @Override - public @Nullable Tree visit(@Nullable Tree tree, ExecutionContext ctx) { - if (tree instanceof SourceFile) { - Path sourcePath = ((SourceFile) tree).getSourcePath(); - acc.found |= "RELEASE.md".equals(sourcePath.toString()); - } - return tree; - } - }; - } - - @Override - public Collection generate(Accumulator acc, ExecutionContext ctx) { - if (acc.found) { - return Collections.emptyList(); - } - // If the file was not found, create it - return PlainTextParser.builder().build() - // We start with an empty string that we then append to in the visitor - .parse("") - // Be sure to set the source path for any generated file, so that the visitor can find it - .map(it -> (SourceFile) it.withSourcePath(Paths.get("RELEASE.md"))) - .collect(Collectors.toList()); - } - - @Override - public TreeVisitor getVisitor(Accumulator acc) { - return new PlainTextVisitor() { - @Override - public PlainText visitText(PlainText text, ExecutionContext ctx) { - PlainText t = super.visitText(text, ctx); - // If the file is not RELEASE.md, don't modify it - if (!"RELEASE.md".equals(t.getSourcePath().toString())) { - return t; - } - // If the file already contains the message, don't append it again - if (t.getText().contains(message)) { - return t; - } - // Append the message to the end of the file - return t.withText(t.getText() + "\n" + message); - } - }; - } -} diff --git a/src/main/java/com/yourorg/AssertEqualsToAssertThat.java b/src/main/java/com/yourorg/AssertEqualsToAssertThat.java deleted file mode 100644 index 9fec190..0000000 --- a/src/main/java/com/yourorg/AssertEqualsToAssertThat.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2024 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.yourorg; - -import lombok.EqualsAndHashCode; -import lombok.Value; -import org.openrewrite.ExecutionContext; -import org.openrewrite.Preconditions; -import org.openrewrite.Recipe; -import org.openrewrite.TreeVisitor; -import org.openrewrite.java.JavaIsoVisitor; -import org.openrewrite.java.JavaParser; -import org.openrewrite.java.JavaTemplate; -import org.openrewrite.java.MethodMatcher; -import org.openrewrite.java.search.UsesType; -import org.openrewrite.java.tree.Expression; -import org.openrewrite.java.tree.J; - -import java.util.List; - -@Value -@EqualsAndHashCode(callSuper = false) -public class AssertEqualsToAssertThat extends Recipe { - @Override - public String getDisplayName() { - // language=markdown - return "JUnit `assertEquals()` to Assertj `assertThat()`"; - } - - @Override - public String getDescription() { - return "Use AssertJ assertThat instead of JUnit assertEquals()."; - } - - private static MethodMatcher MATCHER = new MethodMatcher("org.junit.jupiter.api.Assertions assertEquals(..)"); - - @Override - public TreeVisitor getVisitor() { - return Preconditions.check(new UsesType<>("org.junit.jupiter.api.Assertions", null), - new JavaIsoVisitor() { - @Override - public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - J.MethodInvocation m = super.visitMethodInvocation(method, ctx); - if (!MATCHER.matches(m)) { - return m; - } - List arguments = m.getArguments(); - maybeAddImport("org.assertj.core.api.Assertions"); - maybeRemoveImport("org.junit.jupiter.api.Assertions"); - if (arguments.size() == 2) { - Expression expected = arguments.get(0); - Expression actual = arguments.get(1); - - m = JavaTemplate.builder("Assertions.assertThat(#{any()}).isEqualTo(#{any()})") - .imports("org.assertj.core.api.Assertions") - .javaParser(JavaParser.fromJavaVersion() - .classpath("assertj-core")) - .build() - .apply(getCursor(), m.getCoordinates().replace(), actual, expected); - } else if (arguments.size() == 3) { - Expression expected = arguments.get(0); - Expression actual = arguments.get(1); - Expression description = arguments.get(2); - - m = JavaTemplate.builder("Assertions.assertThat(#{any()}).as(#{any()}).isEqualTo(#{any()})") - .imports("org.assertj.core.api.Assertions") - .javaParser(JavaParser.fromJavaVersion() - .classpath("assertj-core")) - .build() - .apply(getCursor(), m.getCoordinates().replace(), actual, description, expected); - } - return m; - } - }); - } -} diff --git a/src/main/java/com/yourorg/ClassHierarchy.java b/src/main/java/com/yourorg/ClassHierarchy.java deleted file mode 100644 index 645b0e3..0000000 --- a/src/main/java/com/yourorg/ClassHierarchy.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2024 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.yourorg; - -import com.yourorg.table.ClassHierarchyReport; -import lombok.EqualsAndHashCode; -import lombok.Value; -import org.openrewrite.ExecutionContext; -import org.openrewrite.Recipe; -import org.openrewrite.TreeVisitor; -import org.openrewrite.java.JavaIsoVisitor; -import org.openrewrite.java.tree.J; -import org.openrewrite.java.tree.JavaType; - -@Value -@EqualsAndHashCode(callSuper = false) -public class ClassHierarchy extends Recipe { - - transient ClassHierarchyReport report = new ClassHierarchyReport(this); - - @Override - public String getDisplayName() { - return "Class hierarchy"; - } - - @Override - public String getDescription() { - return "Produces a data table showing inheritance relationships between classes."; - } - - @Override - public TreeVisitor getVisitor() { - return new JavaIsoVisitor() { - - @Override - public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) { - JavaType.FullyQualified type = classDecl.getType(); - // Capture all classes, which all extend java.lang.Object - if (type instanceof JavaType.Class && type.getSupertype() != null) { - JavaType.FullyQualified supertype = type.getSupertype(); - // Capture the direct superclass - report.insertRow(ctx, new ClassHierarchyReport.Row( - type.getFullyQualifiedName(), - ClassHierarchyReport.Relationship.EXTENDS, - supertype.getFullyQualifiedName())); - - // Capture all interfaces - for (JavaType.FullyQualified anInterface : type.getInterfaces()) { - report.insertRow(ctx, new ClassHierarchyReport.Row( - type.getFullyQualifiedName(), - ClassHierarchyReport.Relationship.IMPLEMENTS, - anInterface.getFullyQualifiedName() - )); - } - } - return super.visitClassDeclaration(classDecl, ctx); - } - }; - } -} diff --git a/src/main/java/com/yourorg/NoCollectionMutation.java b/src/main/java/com/yourorg/NoCollectionMutation.java deleted file mode 100644 index 7c30b0f..0000000 --- a/src/main/java/com/yourorg/NoCollectionMutation.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright 2024 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.yourorg; - -import fj.data.Option; -import lombok.EqualsAndHashCode; -import lombok.Value; -import org.openrewrite.*; -import org.openrewrite.analysis.dataflow.DataFlowNode; -import org.openrewrite.analysis.dataflow.DataFlowSpec; -import org.openrewrite.analysis.dataflow.Dataflow; -import org.openrewrite.internal.lang.Nullable; -import org.openrewrite.java.JavaTemplate; -import org.openrewrite.java.JavaVisitor; -import org.openrewrite.java.MethodMatcher; -import org.openrewrite.java.search.UsesType; -import org.openrewrite.java.tree.J; -import org.openrewrite.java.tree.JavaType; -import org.openrewrite.java.tree.TypeUtils; - -@Value -@EqualsAndHashCode(callSuper = false) -public class NoCollectionMutation extends Recipe { - @Override - public String getDisplayName() { - return "Prevent LST collection mutation"; - } - - @Override - public String getDescription() { - return "LST elements should always be treated as immutable, even for fields that are not protected from mutation at runtime. " + - "Adding or removing an element from a collection on an LST element is always a bug. " + - "This recipe uses Dataflow analysis to detect and put defensive copies around collection mutations."; - } - - private static final MethodMatcher ADD_MATCHER = new MethodMatcher("java.util.List add(..)"); - private static final MethodMatcher ADD_ALL_MATCHER = new MethodMatcher("java.util.List addAll(..)"); - private static final MethodMatcher CLEAR_MATCHER = new MethodMatcher("java.util.List clear()"); - private static final MethodMatcher REMOVE_MATCHER = new MethodMatcher("java.util.List remove(..)"); - private static final MethodMatcher REMOVE_ALL_MATCHER = new MethodMatcher("java.util.List removeAll(..)"); - private static final MethodMatcher REPLACE_MATCHER = new MethodMatcher("java.util.List replace(..)"); - private static final MethodMatcher SET_MATCHER = new MethodMatcher("java.util.List set(..)"); - private static final MethodMatcher SORT_MATCHER = new MethodMatcher("java.util.List sort(..)"); - /** - * The "select" of a method is the receiver or target of the invocation. In the method call "aList.add(foo)" the "select" is "aList". - * - * @param cursor a stack of LST elements with parent/child relationships connecting an individual LST element to the root of the tree - * @return true if the cursor points to the "select" of a method invocation that is a list mutation - */ - private static boolean isListMutationSelect(Cursor cursor) { - Object parentValue = cursor.getParentTreeCursor().getValue(); - if (!(parentValue instanceof J.MethodInvocation) - || ((J.MethodInvocation) parentValue).getMethodType() == null - || ((J.MethodInvocation) parentValue).getSelect() != cursor.getValue()) { - return false; - } - JavaType.Method mt = ((J.MethodInvocation) parentValue).getMethodType(); - return ADD_MATCHER.matches(mt) || - ADD_ALL_MATCHER.matches(mt) || - CLEAR_MATCHER.matches(mt) || - REMOVE_MATCHER.matches(mt) || - REMOVE_ALL_MATCHER.matches(mt) || - REPLACE_MATCHER.matches(mt) || - SET_MATCHER.matches(mt) || - SORT_MATCHER.matches(mt); - } - - private static final MethodMatcher NEW_ARRAY_LIST_MATCHER = new MethodMatcher("java.util.ArrayList (java.util.Collection)"); - - /** - * @param cursor a stack of LST elements with parent/child relationships connecting an individual LST element to the root of the tree - * @return true if the cursor points to an LST element contained within the argument list of a constructor or - * function which creates a defensive copy as needed - */ - private static boolean inDefensiveCopy(@Nullable Cursor cursor) { - if(cursor == null) { - return false; - } - Object value = cursor.getValue(); - if (value instanceof J.NewClass && NEW_ARRAY_LIST_MATCHER.matches(((J.NewClass) value).getMethodType())) { - return true; - } - return inDefensiveCopy(cursor.getParent()); - } - - @Override - public TreeVisitor getVisitor() { - JavaVisitor addDefensiveCopy = new JavaVisitor() { - @Override - public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - J j = super.visitMethodInvocation(method, ctx); - if (!(j instanceof J.MethodInvocation)) { - return j; - } - J.MethodInvocation m = (J.MethodInvocation) j; - if (m.getMethodType() == null || !(m.getMethodType().getDeclaringType() instanceof JavaType.Class)) { - return m; - } - JavaType.Method mt = m.getMethodType(); - JavaType.Class declaringType = (JavaType.Class) mt.getDeclaringType(); - if (!TypeUtils.isAssignableTo("org.openrewrite.Tree", declaringType) || !TypeUtils.isAssignableTo("java.util.List", mt.getReturnType())) { - return m; - } - - boolean isMutated = Dataflow.startingAt(getCursor()).findSinks(new DataFlowSpec() { - @Override - public boolean isSource(DataFlowNode srcNode) { - return true; - } - - @Override - public boolean isSink(DataFlowNode sinkNode) { - return isListMutationSelect(sinkNode.getCursor()); - } - }).bind(sinkFlow -> { - for (Cursor sink : sinkFlow.getSinkCursors()) { - if(!inDefensiveCopy(sink)) { - return Option.some(sink); - } - } - return Option.none(); - }) - .isSome(); - if(!isMutated) { - return m; - } - - maybeAddImport("java.util.ArrayList"); - return JavaTemplate.builder("new ArrayList<>(#{any(java.util.List)})") - .imports("java.util.ArrayList") - .build() - .apply(getCursor(), m.getCoordinates().replace(), m); - } - }; - - return Preconditions.check( - Preconditions.or( - new UsesType<>("org.openrewrite.Tree", true), - new UsesType<>("java.util.List", true)), - addDefensiveCopy); - } -} diff --git a/src/main/java/com/yourorg/NoGuavaListsNewArrayList.java b/src/main/java/com/yourorg/NoGuavaListsNewArrayList.java deleted file mode 100644 index 7f49f57..0000000 --- a/src/main/java/com/yourorg/NoGuavaListsNewArrayList.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2021 the original author or authors. - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * https://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yourorg; - -import lombok.EqualsAndHashCode; -import lombok.Value; -import org.openrewrite.ExecutionContext; -import org.openrewrite.Preconditions; -import org.openrewrite.Recipe; -import org.openrewrite.TreeVisitor; -import org.openrewrite.java.JavaTemplate; -import org.openrewrite.java.JavaVisitor; -import org.openrewrite.java.MethodMatcher; -import org.openrewrite.java.TreeVisitingPrinter; -import org.openrewrite.java.search.UsesMethod; -import org.openrewrite.java.tree.J; - -@Value -@EqualsAndHashCode(callSuper = false) -public class NoGuavaListsNewArrayList extends Recipe { - // These matchers use a syntax described on https://docs.openrewrite.org/reference/method-patterns - private static final MethodMatcher NEW_ARRAY_LIST = new MethodMatcher("com.google.common.collect.Lists newArrayList()"); - private static final MethodMatcher NEW_ARRAY_LIST_ITERABLE = new MethodMatcher("com.google.common.collect.Lists newArrayList(java.lang.Iterable)"); - private static final MethodMatcher NEW_ARRAY_LIST_CAPACITY = new MethodMatcher("com.google.common.collect.Lists newArrayListWithCapacity(int)"); - - @Override - public String getDisplayName() { - //language=markdown - return "Use `new ArrayList<>()` instead of Guava"; - } - - @Override - public String getDescription() { - //language=markdown - return "Prefer the Java standard library over third-party usage of Guava in simple cases like this."; - } - - @Override - public TreeVisitor getVisitor() { - return Preconditions.check( - // Any change to the AST made by the preconditions check will lead to the visitor returned by Recipe - // .getVisitor() being applied - // No changes made by the preconditions check will be kept - Preconditions.or(new UsesMethod<>(NEW_ARRAY_LIST), - new UsesMethod<>(NEW_ARRAY_LIST_ITERABLE), - new UsesMethod<>(NEW_ARRAY_LIST_CAPACITY)), - // To avoid stale state persisting between cycles, getVisitor() should always return a new instance of - // its visitor - new JavaVisitor() { - private final JavaTemplate newArrayList = JavaTemplate.builder("new ArrayList<>()") - .imports("java.util.ArrayList") - .build(); - - private final JavaTemplate newArrayListIterable = - JavaTemplate.builder("new ArrayList<>(#{any(java.util.Collection)})") - .imports("java.util.ArrayList") - .build(); - - private final JavaTemplate newArrayListCapacity = - JavaTemplate.builder("new ArrayList<>(#{any(int)})") - .imports("java.util.ArrayList") - .build(); - - // This method override is only here to show how to print the AST for debugging purposes. - // You can remove this method if you don't need it. - @Override - public J visitCompilationUnit(J.CompilationUnit cu, ExecutionContext ctx) { - // This is a useful debugging tool if you're ever unsure what the visitor is visiting - String printed = TreeVisitingPrinter.printTree(cu); - System.out.printf(printed); - // You must always delegate to the super method to ensure the visitor continues to visit deeper - return super.visitCompilationUnit(cu, ctx); - } - - // Visit any method invocation, and replace matches with the new ArrayList instantiation. - @Override - public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - if (NEW_ARRAY_LIST.matches(method)) { - maybeRemoveImport("com.google.common.collect.Lists"); - maybeAddImport("java.util.ArrayList"); - return newArrayList.apply(getCursor(), method.getCoordinates().replace()); - } else if (NEW_ARRAY_LIST_ITERABLE.matches(method)) { - maybeRemoveImport("com.google.common.collect.Lists"); - maybeAddImport("java.util.ArrayList"); - return newArrayListIterable.apply(getCursor(), method.getCoordinates().replace(), - method.getArguments().get(0)); - } else if (NEW_ARRAY_LIST_CAPACITY.matches(method)) { - maybeRemoveImport("com.google.common.collect.Lists"); - maybeAddImport("java.util.ArrayList"); - return newArrayListCapacity.apply(getCursor(), method.getCoordinates().replace(), - method.getArguments().get(0)); - } - return super.visitMethodInvocation(method, ctx); - } - } - ); - } -} diff --git a/src/main/java/com/yourorg/SimplifyTernary.java b/src/main/java/com/yourorg/SimplifyTernary.java deleted file mode 100644 index 2b91676..0000000 --- a/src/main/java/com/yourorg/SimplifyTernary.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2024 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.yourorg; - -import com.google.errorprone.refaster.annotation.AfterTemplate; -import com.google.errorprone.refaster.annotation.BeforeTemplate; -import org.openrewrite.java.template.RecipeDescriptor; - -@SuppressWarnings({"SimplifiableConditionalExpression", "unused"}) -@RecipeDescriptor( - name = "Simplify ternary expressions", - description = "Simplifies various types of ternary expressions to improve code readability." -) -public class SimplifyTernary { // This class should not extend Recipe; a generated class will extend Recipe instead - - @RecipeDescriptor( - name = "Replace `booleanExpression ? true : false` with `booleanExpression`", - description = "Replace ternary expressions like `booleanExpression ? true : false` with `booleanExpression`." - ) - public static class SimplifyTernaryTrueFalse { - - @BeforeTemplate - boolean before(boolean expr) { - return expr ? true : false; - } - - @AfterTemplate - boolean after(boolean expr) { - return expr; - } - } - - @RecipeDescriptor( - name = "Replace `booleanExpression ? false : true` with `!booleanExpression`", - description = "Replace ternary expressions like `booleanExpression ? false : true` with `!booleanExpression`." - ) - public static class SimplifyTernaryFalseTrue { - - @BeforeTemplate - boolean before(boolean expr) { - return expr ? false : true; - } - - @AfterTemplate - boolean after(boolean expr) { - // We wrap the expression in parentheses as the input expression might be a complex expression - return !(expr); - } - } -} diff --git a/src/main/java/com/yourorg/UpdateConcoursePipeline.java b/src/main/java/com/yourorg/UpdateConcoursePipeline.java deleted file mode 100644 index 263ee49..0000000 --- a/src/main/java/com/yourorg/UpdateConcoursePipeline.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2024 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.yourorg; - -import lombok.EqualsAndHashCode; -import lombok.Value; -import org.openrewrite.*; -import org.openrewrite.yaml.ChangePropertyValue; -import org.openrewrite.yaml.YamlIsoVisitor; -import org.openrewrite.yaml.tree.Yaml; - -@Value -@EqualsAndHashCode(callSuper = false) -public class UpdateConcoursePipeline extends Recipe { - @Override - public String getDisplayName() { - return "Update concourse pipeline"; - } - - @Override - public String getDescription() { - return "Update the tag filter on concourse pipelines."; - } - - @Option(displayName = "New tag filter version", - description = "tag filter version.", - example = "8.2.0") - String version; - - @Override - public TreeVisitor getVisitor() { - return Preconditions.check( - Preconditions.or( - new FindSourceFiles("ci/pipeline*.yml").getVisitor(), - new FindSourceFiles("ci/pipeline*.yaml").getVisitor()), - new YamlIsoVisitor() { - - @Override - public Yaml.Mapping.Entry visitMappingEntry(Yaml.Mapping.Entry entry, ExecutionContext ctx) { - Yaml.Mapping.Entry e = super.visitMappingEntry(entry, ctx); - if ("source".equals(e.getKey().getValue())) { - Yaml.Block value = e.getValue(); - if (!(value instanceof Yaml.Mapping)) { - return e; - } - Yaml.Mapping mapping = (Yaml.Mapping) value; - Yaml.Mapping.Entry uriEntry = null; - Yaml.Mapping.Entry tagFilter = null; - for (Yaml.Mapping.Entry mappingEntry : mapping.getEntries()) { - if ("uri".equals(mappingEntry.getKey().getValue())) { - uriEntry = mappingEntry; - } else if ("tag_filter".equals(mappingEntry.getKey().getValue())) { - tagFilter = mappingEntry; - } - } - if (uriEntry == null || tagFilter == null) { - return e; - } - if (!(uriEntry.getValue() instanceof Yaml.Scalar) || !(tagFilter.getValue() instanceof Yaml.Scalar)) { - return e; - } - Yaml.Scalar uriValue = (Yaml.Scalar) uriEntry.getValue(); - if (!uriValue.getValue().contains(".git")) { - return e; - } - Yaml.Scalar tagFilterValue = (Yaml.Scalar) tagFilter.getValue(); - if (version.equals(tagFilterValue.getValue())) { - return e; - } - return (Yaml.Mapping.Entry) new ChangePropertyValue("source.tag_filter", version, null, null, null) - .getVisitor() - .visitNonNull(e, ctx); - } - return e; - } - } - ); - } -} diff --git a/src/main/java/com/yourorg/StringIsEmpty.java b/src/main/java/org/openrewrite/docker/DockerImageVersion.java similarity index 64% rename from src/main/java/com/yourorg/StringIsEmpty.java rename to src/main/java/org/openrewrite/docker/DockerImageVersion.java index 802c91f..b53e824 100644 --- a/src/main/java/com/yourorg/StringIsEmpty.java +++ b/src/main/java/org/openrewrite/docker/DockerImageVersion.java @@ -13,10 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.yourorg; +package org.openrewrite.docker; -// TODO - This is a placeholder for a Refaster recipe. Implement the recipe by adding before and after annotated methods. -// The rule should replace calls to `String.length() == 0` with `String.isEmpty()`, as well as similar variants. -// You're done when all the tests in `StringIsEmptyTest` passes. -public class StringIsEmpty { +import lombok.Value; +import org.openrewrite.internal.lang.Nullable; + +@Value +public class DockerImageVersion { + String imageName; + + @Nullable + String version; + + public String toString() { + return imageName + (version != null ? ":" + version : ""); + } } diff --git a/src/main/java/com/yourorg/package-info.java b/src/main/java/org/openrewrite/docker/package-info.java similarity index 96% rename from src/main/java/com/yourorg/package-info.java rename to src/main/java/org/openrewrite/docker/package-info.java index 845b067..b8f1e8e 100644 --- a/src/main/java/com/yourorg/package-info.java +++ b/src/main/java/org/openrewrite/docker/package-info.java @@ -15,7 +15,7 @@ */ @NonNullApi @NonNullFields -package com.yourorg; +package org.openrewrite.docker; // We annotate the package to indicate that fields and methods in this package are non-null by default. import org.openrewrite.internal.lang.NonNullApi; diff --git a/src/main/java/org/openrewrite/docker/search/FindDockerImageUses.java b/src/main/java/org/openrewrite/docker/search/FindDockerImageUses.java new file mode 100644 index 0000000..a238d61 --- /dev/null +++ b/src/main/java/org/openrewrite/docker/search/FindDockerImageUses.java @@ -0,0 +1,61 @@ +/* + * Copyright 2024 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.openrewrite.docker.search; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.docker.DockerImageVersion; +import org.openrewrite.docker.table.DockerBaseImages; +import org.openrewrite.marker.SearchResult; + +import java.util.List; +import java.util.stream.Collectors; + +import static org.openrewrite.docker.trait.Traits.dockerfile; + +public class FindDockerImageUses extends Recipe { + transient DockerBaseImages dockerBaseImages = new DockerBaseImages(this); + + @Override + public String getDisplayName() { + return "Find uses of docker base images"; + } + + @Override + public String getDescription() { + return "Produce an impact analysis of base images used in Dockerfiles."; + } + + @Override + public TreeVisitor getVisitor() { + return dockerfile().asVisitor((docker, ctx) -> { + List froms = docker.getFroms(); + if (!froms.isEmpty()) { + for (DockerImageVersion from : froms) { + dockerBaseImages.insertRow(ctx, new DockerBaseImages.Row( + from.getImageName(), + from.getVersion() == null ? "" : from.getVersion() + )); + } + return SearchResult.found(docker.getTree(), + froms.stream().map(DockerImageVersion::toString) + .collect(Collectors.joining(", "))); + } + return docker.getTree(); + }); + } +} diff --git a/src/main/java/org/openrewrite/docker/search/package-info.java b/src/main/java/org/openrewrite/docker/search/package-info.java new file mode 100644 index 0000000..2f592af --- /dev/null +++ b/src/main/java/org/openrewrite/docker/search/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2020 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NonNullApi +@NonNullFields +package org.openrewrite.docker.search; + +import org.openrewrite.internal.lang.NonNullApi; +import org.openrewrite.internal.lang.NonNullFields; diff --git a/src/main/java/com/yourorg/table/ClassHierarchyReport.java b/src/main/java/org/openrewrite/docker/table/DockerBaseImages.java similarity index 50% rename from src/main/java/com/yourorg/table/ClassHierarchyReport.java rename to src/main/java/org/openrewrite/docker/table/DockerBaseImages.java index 9be0c34..c8a2766 100644 --- a/src/main/java/com/yourorg/table/ClassHierarchyReport.java +++ b/src/main/java/org/openrewrite/docker/table/DockerBaseImages.java @@ -13,38 +13,29 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.yourorg.table; +package org.openrewrite.docker.table; import lombok.Value; import org.openrewrite.Column; import org.openrewrite.DataTable; import org.openrewrite.Recipe; -public class ClassHierarchyReport extends DataTable { +public class DockerBaseImages extends DataTable { - public ClassHierarchyReport(Recipe recipe) { + public DockerBaseImages(Recipe recipe) { super(recipe, - "Class hierarchy report", - "Records inheritance relationships between classes."); + "Uses of docker images as bases", + "Records the `FROM` block of Dockerfiles."); } @Value public static class Row { - @Column(displayName = "Class name", - description = "Fully qualified name of the class.") - String className; + @Column(displayName = "Image name", + description = "The full name of the image.") + String imageName; - @Column(displayName = "Relationship", - description = "Whether the class implements a super interface or extends a superclass.") - Relationship relationship; - - @Column(displayName = "Super class name", - description = "Fully qualified name of the superclass.") - String superClassName; - } - - public enum Relationship { - EXTENDS, - IMPLEMENTS + @Column(displayName = "Tag", + description = "The tag, if any. If no tag is specified, this will be empty.") + String tag; } } diff --git a/src/main/java/org/openrewrite/docker/table/package-info.java b/src/main/java/org/openrewrite/docker/table/package-info.java new file mode 100644 index 0000000..c35eb6f --- /dev/null +++ b/src/main/java/org/openrewrite/docker/table/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2020 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NonNullApi +@NonNullFields +package org.openrewrite.docker.table; + +import org.openrewrite.internal.lang.NonNullApi; +import org.openrewrite.internal.lang.NonNullFields; diff --git a/src/main/java/org/openrewrite/docker/trait/Dockerfile.java b/src/main/java/org/openrewrite/docker/trait/Dockerfile.java new file mode 100644 index 0000000..a116441 --- /dev/null +++ b/src/main/java/org/openrewrite/docker/trait/Dockerfile.java @@ -0,0 +1,61 @@ +/* + * Copyright 2024 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.openrewrite.docker.trait; + +import lombok.Value; +import org.openrewrite.Cursor; +import org.openrewrite.docker.DockerImageVersion; +import org.openrewrite.internal.lang.Nullable; +import org.openrewrite.text.PlainText; +import org.openrewrite.trait.SimpleTraitMatcher; +import org.openrewrite.trait.Trait; + +import java.util.ArrayList; +import java.util.List; + +@Value +public class Dockerfile implements Trait

{ + Cursor cursor; + + public List<DockerImageVersion> getFroms() { + List<DockerImageVersion> froms = new ArrayList<>(); + for (String line : getTree().getText().split("\\R")) { + if (line.startsWith("FROM")) { + String[] imageVersionStr = line.substring("FROM".length()).trim().split(":"); + froms.add(new DockerImageVersion( + imageVersionStr[0], + imageVersionStr.length > 1 ? imageVersionStr[1] : null + )); + } + } + return froms; + } + + public static class Matcher extends SimpleTraitMatcher<Dockerfile> { + + @Override + protected @Nullable Dockerfile test(Cursor cursor) { + Object value = cursor.getValue(); + if (value instanceof PlainText) { + PlainText text = (PlainText) value; + if (text.getSourcePath().toFile().getName().equals("Dockerfile")) { + return new Dockerfile(cursor); + } + } + return null; + } + } +} diff --git a/src/main/java/org/openrewrite/docker/trait/Traits.java b/src/main/java/org/openrewrite/docker/trait/Traits.java new file mode 100644 index 0000000..d6ba27a --- /dev/null +++ b/src/main/java/org/openrewrite/docker/trait/Traits.java @@ -0,0 +1,26 @@ +/* + * Copyright 2024 the original author or authors. + * <p> + * 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 + * <p> + * https://www.apache.org/licenses/LICENSE-2.0 + * <p> + * 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.openrewrite.docker.trait; + +public class Traits { + + private Traits() { + } + + public static Dockerfile.Matcher dockerfile() { + return new Dockerfile.Matcher(); + } +} diff --git a/src/main/java/org/openrewrite/docker/trait/package-info.java b/src/main/java/org/openrewrite/docker/trait/package-info.java new file mode 100644 index 0000000..06a7b08 --- /dev/null +++ b/src/main/java/org/openrewrite/docker/trait/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2020 the original author or authors. + * <p> + * 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 + * <p> + * https://www.apache.org/licenses/LICENSE-2.0 + * <p> + * 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. + */ +@NonNullApi +@NonNullFields +package org.openrewrite.docker.trait; + +import org.openrewrite.internal.lang.NonNullApi; +import org.openrewrite.internal.lang.NonNullFields; diff --git a/src/test/java/com/yourorg/AssertEqualsToAssertThatTest.java b/src/test/java/com/yourorg/AssertEqualsToAssertThatTest.java deleted file mode 100644 index 76f8b58..0000000 --- a/src/test/java/com/yourorg/AssertEqualsToAssertThatTest.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2024 the original author or authors. - * <p> - * 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 - * <p> - * https://www.apache.org/licenses/LICENSE-2.0 - * <p> - * 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.yourorg; - -import org.junit.jupiter.api.Test; -import org.openrewrite.DocumentExample; -import org.openrewrite.java.JavaParser; -import org.openrewrite.test.RecipeSpec; -import org.openrewrite.test.RewriteTest; - -import static org.openrewrite.java.Assertions.java; - -class AssertEqualsToAssertThatTest implements RewriteTest { - - @Override - public void defaults(RecipeSpec spec) { - spec.recipe(new AssertEqualsToAssertThat()) - .parser(JavaParser.fromJavaVersion() - .classpath("junit-jupiter-api")); - } - - @DocumentExample - @Test - void twoArgument() { - rewriteRun( - //language=java - java( - """ - import org.junit.jupiter.api.Assertions; - - class A { - void foo() { - Assertions.assertEquals(1, 2); - } - } - """, - """ - import org.assertj.core.api.Assertions; - - class A { - void foo() { - Assertions.assertThat(2).isEqualTo(1); - } - } - """ - ) - ); - } - - @Test - void withDescription() { - rewriteRun( - //language=java - java( - """ - import org.junit.jupiter.api.Assertions; - - class A { - void foo() { - Assertions.assertEquals(1, 2, "one equals two, everyone knows that"); - } - } - """, - """ - import org.assertj.core.api.Assertions; - - class A { - void foo() { - Assertions.assertThat(2).as("one equals two, everyone knows that").isEqualTo(1); - } - } - """ - ) - ); - } -} diff --git a/src/test/java/com/yourorg/ClassHierarchyTest.java b/src/test/java/com/yourorg/ClassHierarchyTest.java deleted file mode 100644 index 3c8a306..0000000 --- a/src/test/java/com/yourorg/ClassHierarchyTest.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2024 the original author or authors. - * <p> - * 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 - * <p> - * https://www.apache.org/licenses/LICENSE-2.0 - * <p> - * 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.yourorg; - -import com.yourorg.table.ClassHierarchyReport; -import org.junit.jupiter.api.Test; -import org.openrewrite.test.RecipeSpec; -import org.openrewrite.test.RewriteTest; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.openrewrite.java.Assertions.java; - -class ClassHierarchyTest implements RewriteTest { - - @Override - public void defaults(RecipeSpec spec) { - spec.recipe(new ClassHierarchy()); - } - - @Test - void basic() { - rewriteRun( - spec -> spec.dataTable(ClassHierarchyReport.Row.class, rows -> { - assertThat(rows).containsExactly(new ClassHierarchyReport.Row("A", ClassHierarchyReport.Relationship.EXTENDS, "java.lang.Object")); - }), - //language=java - java( - """ - class A {} - """ - ) - ); - } - - @Test - void bExtendsA() { - rewriteRun( - spec -> spec.dataTable(ClassHierarchyReport.Row.class, rows -> { - assertThat(rows).containsExactly( - new ClassHierarchyReport.Row("A", ClassHierarchyReport.Relationship.EXTENDS, "java.lang.Object"), - new ClassHierarchyReport.Row("B", ClassHierarchyReport.Relationship.EXTENDS, "A")); - }), - //language=java - java( - """ - class A {} - """ - ), - //language=java - java( - """ - class B extends A {} - """ - ) - ); - } - - @Test - void interfaceRelationship() { - rewriteRun( - spec -> spec.dataTable(ClassHierarchyReport.Row.class, rows -> { - assertThat(rows).containsExactly( - new ClassHierarchyReport.Row("A", ClassHierarchyReport.Relationship.EXTENDS, "java.lang.Object"), - new ClassHierarchyReport.Row("A", ClassHierarchyReport.Relationship.IMPLEMENTS, "java.io.Serializable")); - }), - // language=java - java( - """ - import java.io.Serializable; - class A implements Serializable {} - """ - ) - ); - } -} diff --git a/src/test/java/com/yourorg/NoCollectionMutationTest.java b/src/test/java/com/yourorg/NoCollectionMutationTest.java deleted file mode 100644 index d459942..0000000 --- a/src/test/java/com/yourorg/NoCollectionMutationTest.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright 2024 the original author or authors. - * <p> - * 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 - * <p> - * https://www.apache.org/licenses/LICENSE-2.0 - * <p> - * 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.yourorg; - -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.openrewrite.DocumentExample; -import org.openrewrite.java.JavaParser; -import org.openrewrite.test.RecipeSpec; -import org.openrewrite.test.RewriteTest; - -import static org.openrewrite.java.Assertions.java; - - -@SuppressWarnings({"NullableProblems", "WriteOnlyObject", "ResultOfMethodCallIgnored", "DataFlowIssue"}) -class NoCollectionMutationTest implements RewriteTest { - - @Override - public void defaults(RecipeSpec spec) { - spec.recipe(new NoCollectionMutation()).parser(JavaParser.fromJavaVersion().classpath("rewrite-core", "rewrite-java")); - } - - @Test - void nonMutationIsOkay() { - rewriteRun( - //language=java - java( - """ - import org.openrewrite.ExecutionContext; - import org.openrewrite.java.JavaIsoVisitor; - import org.openrewrite.java.tree.J; - import org.openrewrite.internal.ListUtils; - - public class ManipulateMethodArguments extends JavaIsoVisitor<ExecutionContext> { - @Override - public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - method.getArguments().isEmpty(); - method.getSideEffects().indexOf(null); - method.getTypeParameters().toArray(); - return method; - } - } - """) - ); - } - - @DocumentExample - @Test - void inlineMutation() { - rewriteRun( - //language=java - java( - """ - import org.openrewrite.ExecutionContext; - import org.openrewrite.java.JavaIsoVisitor; - import org.openrewrite.java.tree.J; - - public class ManipulateMethodArguments extends JavaIsoVisitor<ExecutionContext> { - @Override - public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - method.getArguments().clear(); - return method; - } - } - """, - """ - import org.openrewrite.ExecutionContext; - import org.openrewrite.java.JavaIsoVisitor; - import org.openrewrite.java.tree.J; - - import java.util.ArrayList; - - public class ManipulateMethodArguments extends JavaIsoVisitor<ExecutionContext> { - @Override - public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - new ArrayList<>(method.getArguments()).clear(); - return method; - } - } - """) - ); - } - - @Test - void subsequentMutation() { - rewriteRun( - //language=java - java( - """ - import org.openrewrite.ExecutionContext; - import org.openrewrite.java.JavaIsoVisitor; - import org.openrewrite.java.tree.Expression; - import org.openrewrite.java.tree.J; - - import java.util.List; - - public class ManipulateMethodArguments extends JavaIsoVisitor<ExecutionContext> { - @Override - public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - List<Expression> args = method.getArguments(); - if(!args.isEmpty()) { - args.remove(0); - } - return method; - } - } - """, - """ - import org.openrewrite.ExecutionContext; - import org.openrewrite.java.JavaIsoVisitor; - import org.openrewrite.java.tree.Expression; - import org.openrewrite.java.tree.J; - - import java.util.ArrayList; - import java.util.List; - - public class ManipulateMethodArguments extends JavaIsoVisitor<ExecutionContext> { - @Override - public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - List<Expression> args = new ArrayList<>(method.getArguments()); - if(!args.isEmpty()) { - args.remove(0); - } - return method; - } - } - """) - ); - } - - @Disabled("Local dataflow is not capable of following what happens to a variable passed into a function") - @Test - void mutationInFunction() { - rewriteRun( - //language=java - java( - """ - import org.openrewrite.ExecutionContext; - import org.openrewrite.java.JavaIsoVisitor; - import org.openrewrite.java.tree.Expression; - import org.openrewrite.java.tree.J; - - import java.util.List; - - public class ManipulateMethodArguments extends JavaIsoVisitor<ExecutionContext> { - @Override - public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - List<Expression> a = method.getArguments(); - removeFirst(a); - return method; - } - - private void removeFirst(List<Expression> args) { - if(!args.isEmpty()) { - args.remove(0); - } - } - } - """, - """ - import org.openrewrite.ExecutionContext; - import org.openrewrite.java.JavaIsoVisitor; - import org.openrewrite.java.tree.Expression; - import org.openrewrite.java.tree.J; - - import java.util.ArrayList; - import java.util.List; - - public class ManipulateMethodArguments extends JavaIsoVisitor<ExecutionContext> { - @Override - public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - List<Expression> a = new ArrayList<>(method.getArguments()); - removeFirst(a); - return method; - } - - private void removeFirst(List<Expression> args) { - if(!args.isEmpty()) { - args.remove(0); - } - } - } - """) - ); - } - - @Test - void listUtilsIsOkay() { - rewriteRun( - //language=java - java( - """ - import org.openrewrite.ExecutionContext; - import org.openrewrite.java.JavaIsoVisitor; - import org.openrewrite.java.tree.J; - import org.openrewrite.internal.ListUtils; - - public class ManipulateMethodArguments extends JavaIsoVisitor<ExecutionContext> { - @Override - public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - ListUtils.map(method.getArguments(), it -> it).clear(); - return method; - } - } - """) - ); - } -} diff --git a/src/test/java/com/yourorg/NoGuavaListsNewArrayListTest.java b/src/test/java/com/yourorg/NoGuavaListsNewArrayListTest.java deleted file mode 100644 index 9eeef4a..0000000 --- a/src/test/java/com/yourorg/NoGuavaListsNewArrayListTest.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright 2021 the original author or authors. - * <p> - * 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 - * <p> - * https://www.apache.org/licenses/LICENSE-2.0 - * <p> - * 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.yourorg; - -import org.junit.jupiter.api.Test; -import org.openrewrite.DocumentExample; -import org.openrewrite.java.JavaParser; -import org.openrewrite.test.RecipeSpec; -import org.openrewrite.test.RewriteTest; - -import static org.openrewrite.java.Assertions.java; - -// This is a test for the NoGuavaListsNewArrayList recipe, as an example of how to write a test for an imperative recipe. -class NoGuavaListsNewArrayListTest implements RewriteTest { - - // Note, you can define defaults for the RecipeSpec and these defaults will be used for all tests. - // In this case, the recipe and the parser are common. See below, on how the defaults can be overridden - // per test. - @Override - public void defaults(RecipeSpec spec) { - // Note how we directly instantiate the recipe class here - spec.recipe(new NoGuavaListsNewArrayList()) - .parser(JavaParser.fromJavaVersion() - .logCompilationWarningsAndErrors(true) - // The before/after examples are using Guava classes, so we need to add the Guava library to the classpath - .classpath("guava")); - } - - @DocumentExample - @Test - void replaceWithNewArrayList() { - rewriteRun( - // There is an overloaded version or rewriteRun that allows the RecipeSpec to be customized specifically - // for a given test. In this case, the parser for this test is configured to not log compilation warnings. - spec -> spec - .parser(JavaParser.fromJavaVersion() - .logCompilationWarningsAndErrors(false) - .classpath("guava")), - // language=java - java( - """ - import com.google.common.collect.*; - - import java.util.List; - - class Test { - List<Integer> cardinalsWorldSeries = Lists.newArrayList(); - } - """, - """ - import java.util.ArrayList; - import java.util.List; - - class Test { - List<Integer> cardinalsWorldSeries = new ArrayList<>(); - } - """ - ) - ); - } - - @Test - void replaceWithNewArrayListIterable() { - rewriteRun( - // language=java - java( - """ - import com.google.common.collect.*; - - import java.util.Collections; - import java.util.List; - - class Test { - List<Integer> l = Collections.emptyList(); - List<Integer> cardinalsWorldSeries = Lists.newArrayList(l); - } - """, - """ - import java.util.ArrayList; - import java.util.Collections; - import java.util.List; - - class Test { - List<Integer> l = Collections.emptyList(); - List<Integer> cardinalsWorldSeries = new ArrayList<>(l); - } - """ - ) - ); - } - - @Test - void replaceWithNewArrayListWithCapacity() { - rewriteRun( - // language=java - java( - """ - import com.google.common.collect.*; - - import java.util.ArrayList; - import java.util.List; - - class Test { - List<Integer> cardinalsWorldSeries = Lists.newArrayListWithCapacity(2); - } - """, - """ - import java.util.ArrayList; - import java.util.List; - - class Test { - List<Integer> cardinalsWorldSeries = new ArrayList<>(2); - } - """) - ); - } - - // This test is to show that the `super.visitMethodInvocation` is needed to ensure that nested method invocations are visited. - @Test - void showNeedForSuperVisitMethodInvocation() { - rewriteRun( - //language=java - java( - """ - import com.google.common.collect.*; - - import java.util.Collections; - import java.util.List; - - class Test { - List<Integer> cardinalsWorldSeries = Collections.unmodifiableList(Lists.newArrayList()); - } - """, - """ - import java.util.ArrayList; - import java.util.Collections; - import java.util.List; - - class Test { - List<Integer> cardinalsWorldSeries = Collections.unmodifiableList(new ArrayList<>()); - } - """ - ) - ); - } - - // Often you want to make sure no changes are made when the target state is already achieved. - // To do so only passs in a before state and no after state to the rewriteRun method SourceSpecs. - @Test - void noChangeNecessary() { - rewriteRun( - //language=java - java( - """ - import java.util.ArrayList; - import java.util.Collections; - import java.util.List; - - class Test { - List<Integer> cardinalsWorldSeries = Collections.unmodifiableList(new ArrayList<>()); - } - """ - ) - ); - } -} diff --git a/src/test/java/com/yourorg/SimplifyTernaryTest.java b/src/test/java/com/yourorg/SimplifyTernaryTest.java deleted file mode 100644 index cf6ac15..0000000 --- a/src/test/java/com/yourorg/SimplifyTernaryTest.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2024 the original author or authors. - * <p> - * 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 - * <p> - * https://www.apache.org/licenses/LICENSE-2.0 - * <p> - * 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.yourorg; - -import org.junit.jupiter.api.Test; -import org.openrewrite.DocumentExample; -import org.openrewrite.test.RecipeSpec; -import org.openrewrite.test.RewriteTest; - -import static org.openrewrite.java.Assertions.java; - -// This is a test for the SimplifyTernary recipe, as an example of how to write a test for a Refaster style recipe. -class SimplifyTernaryTest implements RewriteTest { - - @Override - public void defaults(RecipeSpec spec) { - // Note that we instantiate a generated class here, with `Recipes` appended to the Refaster class name - spec.recipe(new SimplifyTernaryRecipes()); - } - - @Test - @DocumentExample - void simplified() { - rewriteRun( - //language=java - java( - """ - class Test { - boolean trueCondition1 = true ? true : false; - boolean trueCondition2 = false ? false : true; - boolean trueCondition3 = booleanExpression() ? true : false; - boolean trueCondition4 = trueCondition1 && trueCondition2 ? true : false; - boolean trueCondition5 = !true ? false : true; - boolean trueCondition6 = !false ? true : false; - - boolean falseCondition1 = true ? false : true; - boolean falseCondition2 = !false ? false : true; - boolean falseCondition3 = booleanExpression() ? false : true; - boolean falseCondition4 = trueCondition1 && trueCondition2 ? false : true; - boolean falseCondition5 = !false ? false : true; - boolean falseCondition6 = !true ? true : false; - - boolean binary1 = booleanExpression() && booleanExpression() ? true : false; - boolean binary2 = booleanExpression() && booleanExpression() ? false : true; - boolean binary3 = booleanExpression() || booleanExpression() ? true : false; - boolean binary4 = booleanExpression() || booleanExpression() ? false : true; - - boolean booleanExpression() { - return true; - } - } - """, - """ - class Test { - boolean trueCondition1 = true; - boolean trueCondition2 = true; - boolean trueCondition3 = booleanExpression(); - boolean trueCondition4 = trueCondition1 && trueCondition2; - boolean trueCondition5 = true; - boolean trueCondition6 = true; - - boolean falseCondition1 = false; - boolean falseCondition2 = false; - boolean falseCondition3 = !booleanExpression(); - boolean falseCondition4 = !(trueCondition1 && trueCondition2); - boolean falseCondition5 = false; - boolean falseCondition6 = false; - - boolean binary1 = booleanExpression() && booleanExpression(); - boolean binary2 = !(booleanExpression() && booleanExpression()); - boolean binary3 = booleanExpression() || booleanExpression(); - boolean binary4 = !(booleanExpression() || booleanExpression()); - - boolean booleanExpression() { - return true; - } - } - """ - ) - ); - } - - // It's good practice to also include a test that verifies that the recipe doesn't change anything when it shouldn't. - @Test - void unchanged() { - rewriteRun( - //language=java - java( - """ - class Test { - boolean unchanged1 = booleanExpression() ? booleanExpression() : !booleanExpression(); - boolean unchanged2 = booleanExpression() ? true : !booleanExpression(); - boolean unchanged3 = booleanExpression() ? booleanExpression() : false; - - boolean booleanExpression() { - return true; - } - } - """ - ) - ); - } -} diff --git a/src/test/java/com/yourorg/StringIsEmptyTest.java b/src/test/java/com/yourorg/StringIsEmptyTest.java deleted file mode 100644 index 57b759f..0000000 --- a/src/test/java/com/yourorg/StringIsEmptyTest.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright 2024 the original author or authors. - * <p> - * 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 - * <p> - * https://www.apache.org/licenses/LICENSE-2.0 - * <p> - * 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.yourorg; - -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.openrewrite.DocumentExample; -import org.openrewrite.Recipe; -import org.openrewrite.test.RecipeSpec; -import org.openrewrite.test.RewriteTest; - -import static org.openrewrite.java.Assertions.java; - -@Disabled("Remove this annotation to run the tests once you implement the recipe") -class StringIsEmptyTest implements RewriteTest { - - @Override - public void defaults(RecipeSpec spec) { - // Note that we instantiate a generated class here, with `Recipes` appended to the Refaster class name - // You might need to trigger an explicit build of your project to generate this class with Ctrl + F9 - - // TODO: Uncomment the line below once you have implemented the recipe - //spec.recipe(new StringIsEmptyRecipe()); - } - - @DocumentExample - @Test - void standardizeStringIsEmpty() { - // Notice how we pass in both the "before" and "after" code snippets - // This indicates that we expect the recipe to transform the "before" code snippet into the "after" code snippet - // If the recipe does not do this, the test will fail, and a diff will be shown - rewriteRun( - //language=java - java( - """ - class A { - void test(String s, boolean b) { - b = s.length() == 0; - b = 0 == s.length(); - b = s.length() < 1; - b = 1 > s.length(); - b = s.equals(""); - b = "".equals(s); - b = s.isEmpty(); - } - } - """, - """ - class A { - void test(String s, boolean b) { - b = s.isEmpty(); - b = s.isEmpty(); - b = s.isEmpty(); - b = s.isEmpty(); - b = s.isEmpty(); - b = s.isEmpty(); - b = s.isEmpty(); - } - } - """ - ) - ); - } - - @Test - void showStringTypeMatchAndSimplification() { - // Notice how the recipe will match anything that is of type String, not just local variables - // Take a closer look at the last two replacements to `true` and `false`. - // Open up the generated recipe and see if you can work out why those are replaced with booleans! - rewriteRun( - //language=java - java( - """ - class A { - String field; - - String methodCall() { - return "Hello World"; - } - - void test(String argument) { - boolean bool1 = field.length() == 0; - boolean bool2 = methodCall().length() == 0; - boolean bool3 = argument.length() == 0; - boolean bool4 = "".length() == 0; - boolean bool5 = "literal".length() == 0; - } - } - """, - """ - class A { - String field; - - String methodCall() { - return "Hello World"; - } - - void test(String argument) { - boolean bool1 = field.isEmpty(); - boolean bool2 = methodCall().isEmpty(); - boolean bool3 = argument.isEmpty(); - boolean bool4 = true; - boolean bool5 = false; - } - } - """ - ) - ); - } - - @Test - void doNothingForStringIsEmpty() { - // Notice how we only pass in the "before" code snippet, and not the "after" code snippet - // That indicates that we expect the recipe to do nothing in this case, and will fail if it does anything - rewriteRun( - //language=java - java( - """ - class A { - void test(String s, boolean b) { - b = s.isEmpty(); - } - } - """ - ) - ); - } - - @Test - void doNothingForCharSequence() { - // When a different type is used, the recipe should do nothing - // See if you can modify the recipe to handle CharSequence as well, or create a separate recipe for it - rewriteRun( - //language=java - java( - """ - class A { - void test(CharSequence s, boolean b) { - b = s.length() == 0; - } - } - """ - ) - ); - } - - @Test - void recipeDocumentation() { - // This is a test to validate the correctness of the documentation in the recipe - // By default you get generated documentation, but you can customize it through the RecipeDescriptor annotation - Recipe recipe = null; // TODO: = new StringIsEmptyRecipe(); - String displayName = recipe.getDisplayName(); - String description = recipe.getDescription(); - assert "Standardize empty String checks".equals(displayName) : displayName; - assert "Replace calls to `String.length() == 0` with `String.isEmpty()`.".equals(description) : description; - } -} diff --git a/src/test/java/com/yourorg/UpdateConcoursePipelineTest.java b/src/test/java/com/yourorg/UpdateConcoursePipelineTest.java deleted file mode 100644 index ff20087..0000000 --- a/src/test/java/com/yourorg/UpdateConcoursePipelineTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2024 the original author or authors. - * <p> - * 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 - * <p> - * https://www.apache.org/licenses/LICENSE-2.0 - * <p> - * 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.yourorg; - -import org.junit.jupiter.api.Test; -import org.openrewrite.DocumentExample; -import org.openrewrite.test.RewriteTest; - -import java.nio.file.Paths; - -import static org.openrewrite.yaml.Assertions.yaml; - -class UpdateConcoursePipelineTest implements RewriteTest { - - @DocumentExample - @Test - void updateTagFilter() { - rewriteRun( - spec -> spec.recipe(new UpdateConcoursePipeline("8.2.0")), - //language=yaml - yaml( - """ - --- - resources: - - name: tasks - type: git - source: - uri: git@github.com:Example/concourse-tasks.git - tag_filter: 8.1.0 - """, - """ - --- - resources: - - name: tasks - type: git - source: - uri: git@github.com:Example/concourse-tasks.git - tag_filter: 8.2.0 - """, - spec -> spec.path(Paths.get("ci/pipeline.yml")) - ) - ); - } -} diff --git a/src/test/java/com/yourorg/UseApacheStringUtilsTest.java b/src/test/java/com/yourorg/UseApacheStringUtilsTest.java deleted file mode 100644 index 1a34678..0000000 --- a/src/test/java/com/yourorg/UseApacheStringUtilsTest.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2024 the original author or authors. - * <p> - * 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 - * <p> - * https://www.apache.org/licenses/LICENSE-2.0 - * <p> - * 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.yourorg; - -import org.junit.jupiter.api.Test; -import org.openrewrite.DocumentExample; -import org.openrewrite.java.JavaParser; -import org.openrewrite.test.RecipeSpec; -import org.openrewrite.test.RewriteTest; - -import static org.openrewrite.java.Assertions.java; - -class UseApacheStringUtilsTest implements RewriteTest { - @Override - public void defaults(RecipeSpec spec) { - spec.recipeFromResources("com.yourorg.UseApacheStringUtils") - .parser(JavaParser.fromJavaVersion().classpath("commons-lang3", "spring-core")); - } - - @DocumentExample - @Test - void replacesStringEquals() { - rewriteRun( - //language=java - java( - """ - import org.springframework.util.StringUtils; - - class A { - boolean test(String s) { - return StringUtils.containsWhitespace(s); - } - } - """, - """ - import org.apache.commons.lang3.StringUtils; - - class A { - boolean test(String s) { - return StringUtils.containsWhitespace(s); - } - } - """ - ) - ); - } -} diff --git a/src/test/java/com/yourorg/UseOpenRewriteNullableTest.java b/src/test/java/com/yourorg/UseOpenRewriteNullableTest.java deleted file mode 100644 index e1ca70d..0000000 --- a/src/test/java/com/yourorg/UseOpenRewriteNullableTest.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2024 the original author or authors. - * <p> - * 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 - * <p> - * https://www.apache.org/licenses/LICENSE-2.0 - * <p> - * 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.yourorg; - -import org.junit.jupiter.api.Test; -import org.openrewrite.DocumentExample; -import org.openrewrite.java.JavaParser; -import org.openrewrite.test.RecipeSpec; -import org.openrewrite.test.RewriteTest; - -import static org.openrewrite.java.Assertions.java; - -// This is a test for the UseOpenRewriteNullable recipe, as an example of how to write a test for a declarative recipe. -class UseOpenRewriteNullableTest implements RewriteTest { - @Override - public void defaults(RecipeSpec spec) { - spec - // Use the fully qualified class name of the recipe defined in src/main/resources/META-INF/rewrite/rewrite.yml - .recipeFromResources("com.yourorg.UseOpenRewriteNullable") - // The before and after text blocks contain references to annotations from these two classpath entries - .parser(JavaParser.fromJavaVersion().classpath("annotations", "rewrite-core")); - } - - @DocumentExample - @Test - void replacesNullableAnnotation() { - rewriteRun( - // Composite recipes are a hierarchy of recipes that can be applied in a single pass. - // To view what the composite recipe does, you can use the RecipePrinter to print the recipe to the console. - spec -> spec.printRecipe(() -> System.out::println), - //language=java - java( - """ - import org.jetbrains.annotations.Nullable; - - class A { - @Nullable - String s; - } - """, - """ - import org.openrewrite.internal.lang.Nullable; - - class A { - @Nullable - String s; - } - """ - ) - ); - } -} diff --git a/src/test/java/com/yourorg/AppendToReleaseNotesTest.java b/src/test/java/org/openrewrite/docker/FindDockerImagesUsedTest.java similarity index 51% rename from src/test/java/com/yourorg/AppendToReleaseNotesTest.java rename to src/test/java/org/openrewrite/docker/FindDockerImagesUsedTest.java index 5fd121d..24bec56 100644 --- a/src/test/java/com/yourorg/AppendToReleaseNotesTest.java +++ b/src/test/java/org/openrewrite/docker/FindDockerImagesUsedTest.java @@ -13,54 +13,39 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.yourorg; +package org.openrewrite.docker; import org.junit.jupiter.api.Test; -import org.openrewrite.DocumentExample; +import org.openrewrite.docker.search.FindDockerImageUses; import org.openrewrite.test.RecipeSpec; import org.openrewrite.test.RewriteTest; -import java.nio.file.Paths; - import static org.openrewrite.test.SourceSpecs.text; -class AppendToReleaseNotesTest implements RewriteTest { +public class FindDockerImagesUsedTest implements RewriteTest { + @Override public void defaults(RecipeSpec spec) { - spec.recipe(new AppendToReleaseNotes("Hello world")); - } - - @Test - void createNewReleaseNotes() { - // Notice how the before text is null, indicating that the file does not exist yet. - // The after text is the content of the file after the recipe is applied. - rewriteRun( - text( - null, - """ - Hello world - """, - spec -> spec.path(Paths.get("RELEASE.md") - ) - ) - ); + spec.recipe(new FindDockerImageUses()); } - @DocumentExample @Test - void editExistingReleaseNotes() { - // When the file does already exist, we assert the content is modified as expected. + void dockerfile() { rewriteRun( text( """ - You say goodbye, I say + FROM nvidia/cuda:11.8.0-cudnn8-devel-ubuntu20.04 + LABEL maintainer="Hugging Face" + ARG DEBIAN_FRONTEND=noninteractive + SHELL ["sh", "-lc"] """, """ - You say goodbye, I say - Hello world + ~~(nvidia/cuda:11.8.0-cudnn8-devel-ubuntu20.04)~~>FROM nvidia/cuda:11.8.0-cudnn8-devel-ubuntu20.04 + LABEL maintainer="Hugging Face" + ARG DEBIAN_FRONTEND=noninteractive + SHELL ["sh", "-lc"] """, - spec -> spec.path(Paths.get("RELEASE.md") - ) + spec -> spec.path("Dockerfile") ) ); }