Gradle Plugin to automatically upgrade your gradle project dependencies and send a GitHub pull request with the changes

Overview

Dipien

Releases Hub Gradle Plugin

Gradle Plugin to automatically upgrade your java gradle project dependencies and send a GitHub pull request with the changes.

You can read this blog post for more detailed information.

How it works

  1. Apply and configure the plugin according to your needs
  2. Invoke the upgradeDependencies task on your CI tool (daily, weekly, monthly, as you wish)
  3. If any of your dependencies is out-of-date, the plugin will create a pull request to update it.
  4. Verify that your PR CI checks pass, scan the included release notes, perform manual tests, and merge the PR.

Features

  • Automatic Pull Request creation, including useful information whenever available:
    • new version release notes link
    • library documentation link
    • library source code link
    • library issue tracker link
    • library size
    • new permissions added by the library (only for android libraries)
  • Support to configure which dependencies include and exclude, where to find their definitions, how many pull requests create and more.
  • Support any java based project using Gradle.

Setup

Add the following configuration to your root build.gradle, replacing X.Y.Z by the latest version

Using the plugins DSL:

plugins {
  id "com.dipien.releaseshub.gradle.plugin" version "X.Y.Z"
}

Using legacy plugin application:

buildscript {
    repositories {
        mavenCentral() // or gradlePluginPortal()
    }
    dependencies {
        classpath("com.dipien:releases-hub-gradle-plugin:X.Y.Z")
    }
}
    
apply plugin: "com.dipien.releaseshub.gradle.plugin"

Configure

How to configure the properties

All the plugin configuration properties can be added using any of the following ways:

  • Using the releasesHub extension on the build.gradle. For example:
releasesHub {
    gitHubWriteToken = "123"
}
  • As a command line parameter. For example:
./gradlew listDependencies -PgitHubWriteToken=123
  • As a property on a gradle.properties file. For example:
gitHubWriteToken = "123"
  • As an extra property on the build.gradlee. For example:
ext.gitHubWriteToken = "123"
  • As a System Environment property

Common Properties

Dependencies base path

The base path for the class names where the dependencies are defined. The default value is buildSrc/src/main/kotlin/. This property is required

dependenciesBasePath = "buildSrc/src/main/kotlin/"
Dependencies class names

The class names where the dependencies are defined. The default value is ["Libs.kt", "BuildLibs.kt"]. This property is required

dependenciesClassNames = ["Libs.kt", "BuildLibs.kt"]
Includes

The dependencies to include. You can define a groupId to match all the artifacts for that group id, or groupId:artifactId to match a particular artifact. By default all the dependencies found on dependenciesClassNames are included.

includes = ["com.groupid1", "com.groupid2:artifact1"]
Excludes

The dependencies to exclude. You can define a groupId to match all the artifacts for that group id, or groupId:artifactId to match a particular artifact. By default there aren't excluded dependencies.

excludes = ["com.groupid1", "com.groupid2:artifact1"]

If you need to exclude the Gradle upgrade, use "gradle". For example:

excludes = ["gradle"]

Usage

We suggest to define your dependencies on /buildSrc/src/main/kotlin/Libs.kt and /buildSrc/src/main/kotlin/BuildLibs.kt classes. For example:

Libs.kt
object Libs {
    const val KOTLIN = "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.40"
}
BuildLibs.kt
object BuildLibs {
    const val KOTLIN_PLUGIN = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.41"
}
Root build.gradle
apply plugin: "kotlin"
apply plugin: "com.dipien.releaseshub.gradle.plugin"

buildscript {
    dependencies {
        classpath(BuildLibs.KOTLIN_PLUGIN)
    }
}

dependencies {
    compile(Libs.KOTLIN)
}

See the sample for more details.

Tasks

Validate dependencies

Validate all the dependencies. The following validations are executed:

  • All the dependencies defined on each dependenciesClassNames are sorted alphabetically by groupId:artifactId
  • There are not duplicated dependencies defined on each dependenciesClassNames
  • There are not dependencies with snapshot or dynamic versions assigned
  • There are dependencies on dependenciesClassNames but not used on the project
  • There are declared dependencies on any build.gradle but not defined on dependenciesClassNames classes
./gradlew validateDependencies
Properties
Unused Excludes

The dependencies to exclude from the unused validation. You can define a groupId to match all the artifacts for that group id, or groupId:artifactId to match a particular artifact. By default there aren't excluded dependencies.

unusedExcludes = ["com.groupid1", "com.groupid2:artifact1"]
Unused extensions to search

The file extensions of the files where the artifact's packages will we search to find unused dependendencies. By default [".kt", ".java", ".xml"]

unusedExtensionsToSearch = [".kt", ".java"]

List dependencies

Print all the dependencies that will be analyzed to upgrade.

./gradlew listDependencies

List dependencies to upgrade

Print all the dependencies that are upgradeable. A file build/releasesHub/dependencies_to_upgrade_count.txt is generated with the count of dependencies that are upgradeable. This could be useful for metrics.

./gradlew listDependenciesToUpgrade

Upgrade dependencies

This task creates a Github Pull Request for each groupId that have at least one dependency to upgrade.

The following steps are executed for each groupId:

  • Creates the headBranch (headBranchPrefix + groupId) (if not exists)
  • Merge from the baseBranch to the headBranch
  • Upgrade all the dependencies defined on the dependenciesClassNames for the groupId
  • Create a commit for each dependency upgraded
  • Push the previous commits to the headBranch
  • Create a GitHub pull request from the headBranch to the baseBranch
./gradlew upgradeDependencies
Properties
Pull Request Enabled

Whether a pull request with all the upgrades should be created or not. The default value is true

pullRequestEnabled = false
Pull Requests Max

The maximum amount of pull requests to create during the task execution. This is useful to avoid creating too much pull requests when you still have many dependencies to upgrade. The default value is 5

pullRequestsMax = 10
Pull Request Labels

The list of labels to assign when creating the pull request. Optional list.

pullRequestLabels = ["dependencies"]
Pull Request Reviewers

The list of reviewers to assign when creating the pull request. Optional list.

pullRequestReviewers = ["octocat", "hubot", "other_user"]
Pull Request Team Reviewers

The list of team reviewers to assign when creating the pull request. Optional list.

pullRequestTeamReviewers = ["justice-league"]
Head Branch Prefix

The branch's prefix where the commit will be pushed. Also, the head branch's prefix of the pull request to create. Required String (only if pullRequestEnabled is true). The default value is releases_hub/.

headBranchPrefix = "branch_name_"
Base Branch

The pull request base branch. Optional String. The default value is master.

baseBranch = "master"
GitHub User Name

The GitHub user name used by the commit command. Optional String.

gitHubUserName = "user"
GitHub User Email

The GitHub user email used by the commit command. Optional String.

gitHubUserEmail = "[email protected]"
GitHub Repository Owner

The GitHub repository owner where the pull request will be created. Required String (only if pullRequestEnabled is true).

gitHubRepositoryOwner = "repo_owner"
GitHub Repository Name

The GitHub repository name where the pull request will be created. Required String (only if pullRequestEnabled is true).

gitHubRepositoryName = "repo_name"
GitHub Write Token

The GitHub write token needed to access the GitHub API to create the pull request. Follow these steps to create your token. We strongly recommend to not use the releasesHub extension for this property, to avoid exposing it on the git repository. Required String (only if pullRequestEnabled is true).

gitHubWriteToken = "123"
GitHub Api Host Name

The GitHub api host name needed to access the GitHub Enterprise. Optional String.

gitHubApiHostName = "your.githubenterprise.com"

Versioning

This project uses the Semantic Versioning guidelines for transparency into our release cycle.

Privacy Policy

The listDependenciesToUpgrade & upgradeDependencies tasks send to Releases Hub servers the groupId, artifactId and version of the project dependencies, in order to process and fetch the artifacts updates. That information is sent using SSL and it is NOT stored on the servers. The dependencies excluded through the plugin configuration are not send to the servers.

Sponsor this project

Sponsor this open source project to help us get the funding we need to continue working on it.

Follow us

Comments
  • Gradle version catalogs support

    Gradle version catalogs support

    https://docs.gradle.org/current/userguide/platforms.html

    As part of this issue, the basic notation is supported on the libs.versions.toml file:

    [libraries]
    groovy-core = "org.codehaus.groovy:groovy:3.0.5"
    groovy-json = "org.codehaus.groovy:groovy-json:3.0.5"
    groovy-nio = "org.codehaus.groovy:groovy-nio:3.0.5"
    

    The support for [versions] tag will be implemented as part of this issue: https://github.com/dipien/releases-hub-gradle-plugin/issues/17

    enhancement 
    opened by maxirosson 7
  • Running upgradeDependencies as a GitHub Action

    Running upgradeDependencies as a GitHub Action

    Is your feature request related to a problem? Please describe.

    Running upgradeDependencies should be possible on a cron schedule, using the simplest tooling available. GitHub has Actions, and they have access to a GITHUB_TOKEN for interacting with the GitHub API.

    Describe the solution you'd like

    It is easy to run upgradeDependencies using GitHub Actions on a cron schedule (weekly?)

    Describe alternatives you've considered

    We could run this on Jenkins, but that involves more tooling.

    Additional context

    Example configuration of a GitHub Action:

    ---
    on:
      schedule:
        - cron: '0 09 * * 1-5'
    name: upgradeDependencies
    jobs:
      build:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v1
          - name: set up JDK 1.8
            uses: actions/setup-java@v1
            with:
              java-version: 1.8
          - name: upgradeDependencies
            run: ./gradlew --no-daemon upgradeDependencies -PbaseBranch="master" -PpullRequestEnabled=true -PgitHubWriteToken=${{ secrets.GITHUB_TOKEN }}
    
    feature request 
    opened by KushalP 6
  • Use WeakHashMap for propertyResolverCache

    Use WeakHashMap for propertyResolverCache

    First thanks for creating this useful plugin.😃

    Our project periodically went OOM. After dumping the heap it seems like the global propertyResolverCache caused the leak. I'm not very familiar with the Gradle plugin, maybe change the cache to WeachHashMap can fix this problem. Thanks!

    Screen Shot 2020-10-20 at 16 37 58
    opened by lcdsmao 5
  • Upgraded dependencies for groupId com.gradle.enterprise

    Upgraded dependencies for groupId com.gradle.enterprise

    Dependencies upgrades

    com.gradle.enterprise:com.gradle.enterprise.gradle.plugin

    • Version: 3.7 -> 3.7.1
    • Release Date: Oct 20 2021

    This pull request was automatically generated by Releases Hub Gradle Plugin v3.1.0

    gradle xsmall-diff 
    opened by dipien-ci 4
  • Upgraded gradle from 7.2 to 7.3

    Upgraded gradle from 7.2 to 7.3

    opened by dipien-ci 3
  • com.jdroid.github.client.RequestException: Bad credentials (401)

    com.jdroid.github.client.RequestException: Bad credentials (401)

    Describe the bug upgradDependencies always fails with "com.jdroid.github.client.RequestException: Bad credentials (401)" I have tried using secrets.GITHUB_TOKEN from Github Actions Workflow and even tried hardcoding the personal token with all the permissions But it always result in the same error. The weird thing is I can see that the plugin is creating branches But not able to create Pull requests.

    I am stuck on this error for days, Would be really helpful if someone can tell me what I am doing wrong :( To Reproduce Steps to reproduce the behavior:

    name: UpgradeDependencies
     -uses: actions/checkout@v2     
     - name: UpgradeDependencies        
     - run:  ./gradlew upgradeDependencies -PgitHubWriteToken=${{ secrets.GITHUB_TOKEN }} [email protected] -PgitHubUserName=savvisingh
    

    And My Gradle file has this configuration

    plugins{
        id("com.dipien.releaseshub.gradle.plugin") version "2.0.2"
    }
    
    releasesHub {
        dependenciesClassNames = listOf("Dependencies.kt")
        dependenciesBasePath = "buildSrc/src/main/java/"
        gitHubRepositoryOwner = "savvisingh"
        gitHubRepositoryName = "coil-sample"
    }
    
    bug 
    opened by savvisingh 3
  • Upgraded gradle from 7.2 to 7.4

    Upgraded gradle from 7.2 to 7.4

    opened by dipien-ci 2
  • Allow to skip errors

    Allow to skip errors

    Describe the bug

    When running the command line gradlew upgradeDependencies, some dependency checks fail & the whole workflow stop.

    For an unknown reason, I got an SSL Exception when running the task:

    Caused by: javax.net.ssl.SSLPeerUnverifiedException: Hostname cloud.dipien.com not verified (no certificates)
            at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.kt:396)
            at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.kt:337)
            at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:209)
            at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:226)
            at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:106)
            at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:74)
            at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:255)
            at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
            at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
            at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)
            at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
            at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
            at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
            at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76)
            at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
            at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:201)
            at okhttp3.internal.connection.RealCall.execute(RealCall.kt:154)
            at com.jdroid.java.http.okhttp.ExecuteRequestCommand.doExecute(ExecuteRequestCommand.kt:9)
            at com.jdroid.java.http.okhttp.ExecuteRequestCommand.doExecute(ExecuteRequestCommand.kt:5)
            at com.jdroid.java.http.okhttp.OkHttpCommand.execute(OkHttpCommand.kt:23)
    
    

    & I cant figure out which dependency check throws this error.

    If we cant gete an option to skip those errors or have details about which dependency throw this error, it will be really helpful.

    Expected behavior The task run thru all dependencies that are succesfully fetched.

    bug 
    opened by fleficher 2
  • Add gradle distribution type configuration option

    Add gradle distribution type configuration option

    Thank you for the very useful plugin.

    Default gradle distribution type is bin but type all is used in some projects. So, I added the option to control gradle distribution type when upgrading using --distribution-type command option.

    https://docs.gradle.org/current/userguide/gradle_wrapper.html#sec:adding_wrapper

    opened by chibatching 2
  • Enable to set custom GitHub url

    Enable to set custom GitHub url

    Hi, thanks for your amazing library.

    I want to use this library in the project managed at GitHub Enterprise. So, enabled to set custom GitHub URL via property.

    To connect to GitHub, this library uses https://github.com/maxirosson/jdroid-java-github which I thought it could use custom GitHub URL. So, changed only in this library.

    If not, I will send pull-request to https://github.com/maxirosson/jdroid-java-github!

    opened by mataku 2
  • Tasks fail when Gradle configuration cache is reused

    Tasks fail when Gradle configuration cache is reused

    Describe the bug When running any of upgradeDependencies / listDependenciesToUpgrade / validateDependencies task and Gradle is reusing configuration cache from previous execution, we get this stacktrace:

    Stacktrace

    org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':listDependenciesToUpgrade'.
            at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.lambda$executeIfValid$1(ExecuteActionsTaskExecuter.java:142)
            at org.gradle.internal.Try$Failure.ifSuccessfulOrElse(Try.java:282)
            at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:140)
            at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:128)
            at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:77)
            at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
            at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:51)
            at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
            at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:56)
            at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
            at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
            at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
            at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
            at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
            at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
            at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
            at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73)
            at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
            at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:69)
            at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:327)
            at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:314)
            at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:307)
            at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:293)
            at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:420)
            at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:342)
            at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
            at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
    Caused by: org.gradle.api.UnknownDomainObjectException: Extension with name 'releasesHub' does not exist. Currently registered extension names: [ext]
            at org.gradle.internal.extensibility.ExtensionsStorage.unknownExtensionException(ExtensionsStorage.java:144)
            at org.gradle.internal.extensibility.ExtensionsStorage.getByName(ExtensionsStorage.java:123)
            at org.gradle.internal.extensibility.DefaultConvention.getByName(DefaultConvention.java:174)
            at com.releaseshub.gradle.plugin.common.AbstractTask.getExtension(AbstractTask.kt:67)
            at com.releaseshub.gradle.plugin.task.ListDependenciesToUpgradeTask.onExecute(ListDependenciesToUpgradeTask.kt:24)
            at com.releaseshub.gradle.plugin.common.AbstractTask.doExecute(AbstractTask.kt:62)
            at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
            at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
            at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
            at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:125)
            at org.gradle.api.internal.project.taskfactory.StandardTaskAction.doExecute(StandardTaskAction.java:58)
            at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:51)
            at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:29)
            at org.gradle.api.internal.tasks.execution.TaskExecution$3.run(TaskExecution.java:236)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
            at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
            at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
            at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47)
            at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:68)
            at org.gradle.api.internal.tasks.execution.TaskExecution.executeAction(TaskExecution.java:221)
            at org.gradle.api.internal.tasks.execution.TaskExecution.executeActions(TaskExecution.java:204)
            at org.gradle.api.internal.tasks.execution.TaskExecution.executeWithPreviousOutputFiles(TaskExecution.java:187)
            at org.gradle.api.internal.tasks.execution.TaskExecution.execute(TaskExecution.java:165)
            at org.gradle.internal.execution.steps.ExecuteStep.executeInternal(ExecuteStep.java:89)
            at org.gradle.internal.execution.steps.ExecuteStep.access$000(ExecuteStep.java:40)
            at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:53)
            at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:50)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
            at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
            at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
            at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
            at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73)
            at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:50)
            at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:40)
            at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.execute(RemovePreviousOutputsStep.java:68)
            at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.execute(RemovePreviousOutputsStep.java:38)
            at org.gradle.internal.execution.steps.CancelExecutionStep.execute(CancelExecutionStep.java:41)
            at org.gradle.internal.execution.steps.TimeoutStep.executeWithoutTimeout(TimeoutStep.java:74)
            at org.gradle.internal.execution.steps.TimeoutStep.execute(TimeoutStep.java:55)
            at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:51)
            at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:29)
            at org.gradle.internal.execution.steps.CaptureStateAfterExecutionStep.executeDelegateBroadcastingChanges(CaptureStateAfterExecutionStep.java:124)
            at org.gradle.internal.execution.steps.CaptureStateAfterExecutionStep.execute(CaptureStateAfterExecutionStep.java:80)
            at org.gradle.internal.execution.steps.CaptureStateAfterExecutionStep.execute(CaptureStateAfterExecutionStep.java:58)
            at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:48)
            at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:36)
            at org.gradle.internal.execution.steps.BuildCacheStep.executeWithoutCache(BuildCacheStep.java:181)
            at org.gradle.internal.execution.steps.BuildCacheStep.lambda$execute$1(BuildCacheStep.java:71)
            at org.gradle.internal.Either$Right.fold(Either.java:175)
            at org.gradle.internal.execution.caching.CachingState.fold(CachingState.java:59)
            at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:69)
            at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:47)
            at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:36)
            at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:25)
            at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:36)
            at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:22)
            at org.gradle.internal.execution.steps.SkipUpToDateStep.executeBecause(SkipUpToDateStep.java:110)
            at org.gradle.internal.execution.steps.SkipUpToDateStep.lambda$execute$2(SkipUpToDateStep.java:56)
            at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:56)
            at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:38)
            at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:73)
            at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:44)
            at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:37)
            at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:27)
            at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:89)
            at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:50)
            at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:114)
            at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:57)
            at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:76)
            at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:50)
            at org.gradle.internal.execution.steps.SkipEmptyWorkStep.executeWithNoEmptySources(SkipEmptyWorkStep.java:254)
            at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:91)
            at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:56)
            at org.gradle.internal.execution.steps.RemoveUntrackedExecutionStateStep.execute(RemoveUntrackedExecutionStateStep.java:32)
            at org.gradle.internal.execution.steps.RemoveUntrackedExecutionStateStep.execute(RemoveUntrackedExecutionStateStep.java:21)
            at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsStartedStep.execute(MarkSnapshottingInputsStartedStep.java:38)
            at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:43)
            at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:31)
            at org.gradle.internal.execution.steps.AssignWorkspaceStep.lambda$execute$0(AssignWorkspaceStep.java:40)
            at org.gradle.api.internal.tasks.execution.TaskExecution$4.withWorkspace(TaskExecution.java:281)
            at org.gradle.internal.execution.steps.AssignWorkspaceStep.execute(AssignWorkspaceStep.java:40)
            at org.gradle.internal.execution.steps.AssignWorkspaceStep.execute(AssignWorkspaceStep.java:30)
            at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:37)
            at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:27)
            at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:44)
            at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:33)
            at org.gradle.internal.execution.impl.DefaultExecutionEngine$1.execute(DefaultExecutionEngine.java:76)
            at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:139)
            at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:128)
            at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:77)
            at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
            at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:51)
            at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
            at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:56)
            at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
            at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
            at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
            at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
            at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
            at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
            at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
            at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
            at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73)
            at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
            at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:69)
            at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:327)
            at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:314)
            at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:307)
            at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:293)
            at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:420)
            at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:342)
            at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
            at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
    

    To Reproduce

    1. Enable Gradle configuration cache by adding org.gradle.unsafe.configuration-cache=true in the gradle.properties file
    2. Run ./gradlew listDependenciesToUpgrade - this build should be successful
    3. Run again ./gradlew listDependenciesToUpgrade - this build should fail. Make sure that this run will use configuration cache.

    Expected behavior The task runs without issues.

    Additional context listDependencies doesn't seem to be broken.

    Releases Hub Plugin Version: 3.2.0

    bug 
    opened by francescocervone 1
  • Support specified repositories for plugin DSL

    Support specified repositories for plugin DSL

    Is your feature request related to a problem? Please describe. We have an internal repository behind VPN that this plugin is able to access and update our regular dependencies, but our plugins are not being discovered.

    I am guessing this is related to https://github.com/dipien/releases-hub-gradle-plugin/blob/master/releases-hub-gradle-plugin/src/main/java/com/releaseshub/gradle/plugin/artifacts/fetch/ArtifactUpgradeHelper.kt#L49-L52 (introduced for https://github.com/dipien/releases-hub-gradle-plugin/issues/56).

    Describe the solution you'd like I believe it should use the specified repositories in addition to the Gradle Portal.

    Additional context Here's a trimmed down, made up example of what our settings.gradle.kts looks like:

    pluginManagement {
        plugins {
            id("com.internal.plugin") version "2.0.2"
        }
    
        repositories {
            maven {
                url = uri("https://private.internal.com/repository/maven-releases/")
                mavenContent {
                    releasesOnly()
                }
            }
            gradlePluginPortal()
        }
    }
    
    feature request 
    opened by arssycro 0
  • Fail when a branch is already created but not the pull request

    Fail when a branch is already created but not the pull request

    If the plugin detects that a upgrade branch is present but no PR open, we should fail. Right now the plugin is ignoring those cases, so we could have dependencies never upgraded if a dev close a Upgrade PR without removing the branch.

    bug 
    opened by maxirosson 0
  • Align related dependencies versions

    Align related dependencies versions

    See if BOM can help with this.

    For example, for Android projects, the plugin should align Gradle & Android Gradle Plugin versions. We shouldn't offer the upgrade to a new Gradle major version if AGP is not supporting it yet.

    AGP docs:

    We are updating the version numbering for Android Gradle plugin (AGP) to more closely match the underlying Gradle build tool.
    
    Here are the notable changes:
    
    AGP will now use semantic versioning, and breaking changes will be targeted for major releases.
    
    There will be one major version of AGP released per year, aligned with the Gradle major release.
    
    The release after AGP 4.2 will be version 7.0 and will require an upgrade to Gradle version 7.x. Every major release of AGP will require a major version upgrade in the underlying Gradle tool.
    
    APIs will be deprecated approximately one year in advance, with replacement functionality made available concurrently. Deprecated APIs will be removed approximately one year later during the subsequent major update.
    
    enhancement 
    opened by maxirosson 0
  • Add support for other git providers

    Add support for other git providers

    Motivation I would rather have repository-pr creation config to be abstracted so that I can use it for other git repository providers too. (Bitbucket, GitHub, GitLab, Internal git repository)

    Possible Solution: Maybe start with extracting github related parameters and PR checking logic to another class. Maybe an extension called vcsProvider, where github is a function to preconfigure it. Just like mavenCentral in RepositoryHandler. Then create a task for each repository configured in vcsProvider and make them depend on upgradeDependencies task. Can be named "upgradeDependenciesFor$vcsProviderName"

    vcsProvider {
       github {
           token = ""
       }
    }
    
    
    

    Alternative to consider: Maybe creating an output so other plugins or scripts can depend on this plugin to create their own logic. Such as uploading it to an internal server or in this case upgrading application dependencies and creating their own pr.

    feature request 
    opened by FatihYalmanbas 0
  • Migrate all the command line parameters to

    Migrate all the command line parameters to "--"

    https://mrhaki.blogspot.com/2016/09/gradle-goodness-use-command-line.html https://mrhaki.blogspot.com/2018/05/gradle-goodness-command-line-options.html https://docs.gradle.org/current/userguide/command_line_interface.html https://docs.gradle.org/current/userguide/custom_tasks.html#sec:declaring_and_using_command_line_options

    enhancement breaking change 
    opened by maxirosson 0
Releases(v4.0.0)
  • v4.0.0(Nov 1, 2022)

  • v3.2.0(Oct 24, 2022)

  • v3.1.0(Oct 17, 2021)

    Read this post for more details.

    Implemented enhancements:

    • Validate if a dependency is explicitly declared on a .gradle(.kts) file instead of using buildSrc or Version Catalog #124
    • Support to configure Assignees for pull requests #123
    • Scan any build.gradle & build.gradle.kts files by default #122
    • Scan settings.gradle by default #121
    • Support gitHubRepository property #120
    • Support plugins DSL #56
    Source code(tar.gz)
    Source code(zip)
  • v3.0.0(Oct 9, 2021)

    Read this post for more details.

    Implemented enhancements:

    • Include link to Maven repository on Pull Request description #118
    • New dependenciesPaths extension configuration #116
    • Rename props from gitHubUserName & gitHubUserEmail to gitUserName & gitUserEmail #115
    • Gradle version catalogs support #113
    • Support Gradle Enterprise Gradle Plugin upgrade on settings.gradle #96
    Source code(tar.gz)
    Source code(zip)
  • v2.1.0(Sep 18, 2021)

    Implemented enhancements:

    • Include a link to all the official development resources on the PR description #112
    • Add link to Android permission documentation #83

    Fixed bugs:

    • Gradle Distribution changed as part of other upgrades #105
    Source code(tar.gz)
    Source code(zip)
  • v2.0.3(Aug 30, 2021)

  • v2.0.2(Mar 26, 2021)

  • v2.0.1(Mar 25, 2021)

  • v2.0.0(Mar 1, 2021)

    Closed issues:

    • IMPORTANT: Migrate to new "com.dipien" groupId & "com.dipien.releaseshub.gradle.plugin" plugin id #99

    The new way to setup the plugin

    buildscript {
        repositories {
            mavenCentral() // or gradlePluginPortal()
        }
        dependencies {
            classpath("com.dipien:releases-hub-gradle-plugin:X.Y.Z")
        }
    }
        
    apply plugin: "com.dipien.releaseshub.gradle.plugin"
    
    • Change dependenciesClassNames property to required #100
    • Enable pullRequestEnabled property by default #94
    • Remove headBranch, commitMessage & pullRequestTitle extension properties #86
    • Remove countDependenciesToUpgrade task #85
    Source code(tar.gz)
    Source code(zip)
  • v1.7.0(Mar 1, 2021)

  • v1.6.1(Oct 21, 2020)

  • v1.6.0(May 31, 2020)

  • v1.5.1(May 21, 2020)

  • v1.5.0(May 15, 2020)

  • v1.4.4(May 7, 2020)

  • v1.4.3(Apr 30, 2020)

  • v1.4.2(Apr 11, 2020)

  • v1.4.1(Mar 28, 2020)

  • v1.4.0(Mar 13, 2020)

  • v1.3.1(Dec 12, 2019)

  • v1.3.0(Dec 8, 2019)

    Implemented enhancements:

    • Improve git errors logs #48
    • Support GitHub Enterprise #47
    • Display issue tracker url for artifacts upgrades #41
    • Check for unused libraries #35

    The plugin artifact is not correctly replicated on Jcenter, so we recommend to also declare the Maven Central repository on your build.gradle

    Source code(tar.gz)
    Source code(zip)
  • v1.2.1(Nov 1, 2019)

  • v1.2.0(Oct 15, 2019)

    Implemented enhancements:

    • Support upgrading Gradle version #27
    • Add support to assign labels to the generated PR #26
    • Validate dynamic and snapshot versions #10
    • Add support to assign reviewers to the generated PR #2

    Fixed bugs:

    • Upgrades reverted when upgrading multiples artifacts on same PR #38
    Source code(tar.gz)
    Source code(zip)
  • v1.1.0(Sep 29, 2019)

    Implemented enhancements:

    • Create one commit per dependency upgraded #30
    • New validateDependencies task #28
    • Sort alphabetically the listDependenciesToUpgrade results #24
    • Include releases notes, documentation & source code on listDependenciesToUpgrade task #20
    • Create one PR per groupId instead of one per dependency #14
    • Log not resolved and excluded dependencies on listDependenciesToUpgrade task #12

    Fixed bugs:

    • Fix crash for dependencies without stable releases #29
    Source code(tar.gz)
    Source code(zip)
  • v1.0.2(Sep 20, 2019)

  • v1.0.1(Sep 16, 2019)

  • v1.0.0(Sep 15, 2019)

  • v0.2.0(Sep 13, 2019)

  • v0.1.0(Sep 4, 2019)

Owner
Dipien
Productivity tools & ideas for Android, Kotlin & Gradle developers.
Dipien
Gradle plugin for adds support for integrating Carthage dependencies into a KMM project

Gradle plugin for adds support for integrating Carthage dependencies into a KMM project

Wire Swiss GmbH 34 Sep 27, 2022
Graphfity is a Gradle Plugin which creates a dependency node diagram graph about your internal modules dependencies, specially useful if you are developing a multi-module application

Graphfity creates a dependency nodes diagram graph about your internal modules dependencies, specially useful if you are developing a multi-module app

Iván Carrasco 27 Dec 20, 2022
A Gradle plugin to help analyse the dependency between modules and run tasks only on modules impacted by specific set of changes.

Change Tracker Plugin A Gradle plugin to help analyse the dependency between modules and run tasks only on modules impacted by specific set of changes

Ismael Di Vita 110 Dec 19, 2022
A Gradle plugin that guards against unintentional dependency changes.

??️ Dependency Guard A Gradle plugin that helps you guard against unintentional dependency changes. Surface Transitive Dependency Changes Comparison t

Dropbox 195 Dec 31, 2022
A simple gradle plugin that lets you create a download asset from zeplin and convert them to vector drawables automatically

A simple gradle plugin that lets you create a download asset from zeplin and convert them to vector drawables automatically elephant project using 100% Kotlin and be up and running in a few seconds.

Qifan Yang 21 Sep 21, 2022
A Gradle plugin that generates plugin.yml for Bukkit/BungeeCord/Nukkit plugins based on the Gradle project

plugin-yml is a simple Gradle plugin that generates the plugin.yml plugin description file for Bukkit plugins, bungee.yml for Bungee plugins or nukkit.yml for Nukkit plugins based on the Gradle project. Various properties are set automatically (e.g. project name, version or description) and additional properties can be added using a simple DSL.

Plexus 0 Apr 10, 2022
Gradle plugin to ease Kotlin IR plugin development and usage in multimodule gradle projects

Gradle plugin to ease Kotlin IR plugin development and usage in multimodule gradle projects. Former: kotlin-ir-plugin-adapter-gradle

null 2 Mar 8, 2022
Gradle Plugin that allows you to decompile bytecode compiled with Jetpack Compose Compiler Plugin into Java and check it

decomposer Gradle Plugin that allows you to decompile bytecode compiled with Jetpack Compose Compiler Plugin into Java and check it How to use Run bui

Takahiro Menju 56 Nov 18, 2022
Grazel is a Gradle plugin to automate generation of valid Bazel files for a given Android/Kotlin/Java project.

Grazel Grazel stands for Gradle to Bazel. It is a Gradle plugin that enables you to migrate Android projects to Bazel build system in an incremental a

Grab 228 Jan 2, 2023
A Gradle plugin helps to proxy all the BuildConfig fields in the Android project.

Readme A Gradle plugin helps to proxy all the BuildConfig fields in the Android project. Background In android BuildConfig, We might have different co

Jack Chen 4 Oct 11, 2021
Gradle plugin for updating a project version catalog

Version catalog update plugin This plugin helps to keep the versions in a Gradle version catalog toml file up to date. The version updates are determi

Little Robots 307 Dec 26, 2022
Gradle plugin which validates the licenses of your dependency graph match what you expect

Gradle plugin which validates the licenses of your dependency graph match what you expect

Cash App 502 Dec 31, 2022
EasyVersion is a Gradle plugin that manage your app or library version.

EasyVersion EasyVersion is a Gradle plugin that manage your app or library version. Before Downloading Create easy_version.json in your root project d

Kosh Sergani 8 Nov 26, 2022
Gradle plugin which analyzes the size of your Android apps

Scope is a Gradle plugin which helps you analyze the size of your Android apps. Motivation App size is an important metric which directly correlates w

Nanashi Li 1 Feb 26, 2022
KMP Ready is a Gradle Plugin that provides actionable advice to make your code Kotlin Multiplatform compatible.

KMP Ready IS ?? UNDER DEVELOPMENT ?? Decisioning Logic Positive Signals ✅ Only Kotlin .kt Source Files Using Kotlin JVM Plugin Uses the Kotlin Multipl

Sam Edwards 58 Dec 22, 2022
Gradle Plugin to enable auto-completion and symbol resolution for all Kotlin/Native platforms.

CompleteKotlin Gradle Plugin to enable auto-completion and symbol resolution for all Kotlin/Native platforms. What this plugin provides This zero-conf

Louis CAD 235 Jan 3, 2023
Android Gradle Plugin -- Auto Check big image and compress image in building.

McImage I will continue to update, please rest assured to use 中文文档 Android优雅的打包时自动化获取全部res资源 McImage is a Non-invasive plugin for compress all res in

smallSohoSolo 1.1k Dec 28, 2022
Gradle plugin that generates a Swift Package Manager manifest and an XCFramework to distribute a Kotlin Multiplatform library for Apple platforms.

Multiplatform Swift Package This is a Gradle plugin for Kotlin Multiplatform projects that generates an XCFramework for your native Apple targets and

Georg Dresler 262 Jan 5, 2023
Gradle Plugin for publishing artifacts to Sonatype and Nexus

Introduction Due to Sonatype's strict validation rules, the publishing requirement must be satisfied by every artifact which wants to be published to

Johnson Lee 21 Oct 14, 2022