Gradle release composite build with a release order - gradle

I have a gradle composite build in following directory structure.
.
├── component-1
├── component-2
├── component-3
└── composite-build
Here, all components are multi-project builds. Each component has implemented the release plugin and can be released individually. The composite-build has following settings.gradle.
rootProject.name = 'composite-build'
includeBuild '../component-1'
includeBuild '../component-2'
includeBuild '../component-3'
I want to execute release task of each component in a specific order but I couldn't find a proper way. Following are some cases that I tried and failed. In these cases individual release tasks are also failing due to conflicting git tag commits done by release plugin.
Case 1:
In build.gradle
task releaseAll {
dependsOn gradle.includedBuild('component-1').task(':release')
dependsOn gradle.includedBuild('component-2').task(':release')
dependsOn gradle.includedBuild('component-3').task(':release')
}
Case 2:
In build.gradle
task releaseComponent1 {
dependsOn gradle.includedBuild('component-1').task(':release')
}
task releaseComponent2 {
dependsOn gradle.includedBuild('component-2').task(':release')
}
task releaseComponent3 {
dependsOn gradle.includedBuild('component-3').task(':release')
}
releaseComponent2.configure {
mustRunAfter releaseComponent1
}
releaseComponent3.configure {
mustRunAfter releaseComponent2
}
task releaseAll {
dependsOn releaseComponent1
dependsOn releaseComponent2
dependsOn releaseComponent3
}
Sample error message:
> Task :component-1:component-1-release:preTagCommit FAILED
Running [git, commit, -m, [Gradle Release Plugin] - pre tag commit: 'component-1-0.1.10'., -a] produced an error: []
Running [git, push, --porcelain, origin, main] produced an error: [error: failed to push some refs to 'https://github.com/<username>/<repo-name>.git']
> Task :component-1:release FAILED
Release process failed, reverting back any changes made by Release Plugin.
Running [git, checkout, gradle.properties] produced an error: [error: pathspec 'gradle.properties' did not match any file(s) known to git]
1: Task failed with an exception.
-----------
* What went wrong:
Execution failed for task ':component-1:component-1-release:preTagCommit'.
> Failed to push to remote - [To https://github.com/<username>/<repo-name>.git
! refs/heads/main:refs/heads/main [remote rejected] (cannot lock ref 'refs/heads/main': is at <xxxx> but expected <yyyy>)
Done
][error: failed to push some refs to 'https://github.com/<username>/<repo-name>.git'
]

There is always an option with gradle where you can automate and link task execution with finalizedBy and you can test this simple code to check how it work :
task A() {
println 'taskA'
}
task B() {
println 'taskB'
}
tasks.named("B") { finalizedBy("A") }
task C() {
println 'taskC'
}
tasks.named("C") { finalizedBy("B") }
This way, by calling gradle C it will backtrack to execute A then B then C
Same way, You can do 3 tasks to get the desired ordered execution like this
task c1release(type:Exec) {
workingDir '.\\component-1'
commandLine("cmd", "/c", "gradle", "release")
doLast {
println "component-1 release is being excuted"
}
}
tasks.named("c1release") { finalizedBy("c2release") }
task c2release(type:Exec) {
workingDir '.\\component-2'
commandLine("cmd", "/c", "gradle", "release")
doLast {
println "component-2 release is being excuted"
}
}
tasks.named("c2release") { finalizedBy("c3release") }
task c3release(type:Exec) {
workingDir '.\\component-3'
commandLine("cmd", "/c", "gradle", "release")
doLast {
println "component-3 release is being excuted"
}
}
tasks.named("releaseAll") { finalizedBy("c1release") }
task releaseAll() {
println "Start releasing"
}
by calling gradle releaseAll it will execute c1release first then c2release then c3release
But I still wish ti know what kind of error you got with the cases you have included in your question.

Related

How to run certain task with gradle

I try to investigate a Gradle and follows some tutorials, but I have confused with the following:
I created are a couple of simple tasks:
task startProcess{
println 'startProcess'
}
task doStep2{
println 'Step2'
}
task doStep3{
println 'Step3'
}
task finishProcess{
println 'finishProcesss'
}
And try to execute one of them:
gradle finishProcess
Or with defaultTasks with command gradle build:
defaultTasks `finishProcess`
task startProcess{
println 'startProcess'
}
task doStep2{
println 'Step2'
}
task doStep3{
println 'Step3'
}
task finishProcess{
println 'finishProcesss'
}
In both options, I got the same result:
> Configure project :
startProcess
Step2
Step3
finishProcesss
BUILD SUCCESSFUL in 1s
How to execute exactly one of them?
You have to use register, I think if you did not use it, You're only asking Gradle to execute these tasks.
for example
tasks.register('startProcess') {
doLast {
println 'startProcess'
}
}
tasks.register('doStep2') {
doLast {
println 'Step2'
}
}
tasks.register('doStep3') {
doLast {
println 'Step3'
}
}
tasks.register('finishProcess') {
doLast {
println 'finishProcesss'
}
}
tasks.named("build") { finalizedBy("finishProcess") }
Registering these tasks, you will be able to call each one indivadually.
If you want to link a specific task, with a build task for example.
Then you can use finalizedBy like the following.
tasks.named("build") { finalizedBy("finishProcess") }
This will call the finishProcess task, whenever build is triggered.
I strongly recommend the official gradle documintation for more information about tasks.

How is it possible that Gradle task's `outputFiles` differ when run for the first time and when it has run once already?

When I run the below build.gradle.kts script, invoking target downloadAndUnzipFile for the first time, when I run with clean build directory, I get an error.
> Task :downloadZipFile
Download https://github.com/michel-kraemer/gradle-download-task/archive/1.0.zip
[...]
Execution failed for task ':downloadAndUnzipFile'.
> Cannot expand ZIP '/home/jdanek/repos/testing/gradle-infer-deps/build/downloads' as it is not a file.
If I rerun the same task immediately, I get success now
> Task :downloadZipFile
Download https://github.com/michel-kraemer/gradle-download-task/archive/1.0.zip
> Task :downloadAndUnzipFile
BUILD SUCCESSFUL in 1s
2 actionable tasks: 2 executed
1:16:14 PM: Task execution finished 'downloadAndUnzipFile'.
Is this expected, or is it a bug? If it is a bug, then where? In my script?
My build.gradle.kts looks like this
import de.undercouch.gradle.tasks.download.Download
group = "org.example"
version = "1.0-SNAPSHOT"
plugins {
id("de.undercouch.download").version("4.0.4")
}
tasks {
val downloadZipFile by registering(Download::class) {
val destDir = buildDir.resolve("downloads")
doFirst {
destDir.mkdirs()
}
src("https://github.com/michel-kraemer/gradle-download-task/archive/1.0.zip")
dest(destDir)
}
val downloadAndUnzipFile by registering(Copy::class) {
dependsOn(downloadZipFile)
from(downloadZipFile.get().outputFiles.map { zipTree(it) })
into(buildDir)
}
}

Gradle Task dependencies Execution issue

I am facing an issue related to gradle task dependencies. One of my gradle task is calling another task successfully but it is not executing dependencies on which my second task depends. Please go through the following code to understand the problem statement:
My code is:
task callGradleDeploy <<{
tasks.deployComp.execute()
}
task deployComp (dependsOn: ['setEnvParameter', 'installWeb', 'installService']) <<{
println "Deployment Done"
}
task setEnvParameter {
//parameter Setting for deployement
}
task installWeb {
//install Web Code
}
task installService {
//install Services Code
}
Now when I run task callGradleDeploy, it is calling deployComp task but it is not installing Web or Service content (Not doing anything with setEnvParameter, installWeb, installService ). and Just printing Deployment Done
Just to notify, when I am individually calling(running) deployComp task, it is installing Web and Service part without any issue.
Please help me to understand how to manage this dependsOn thing while calling a gradle task into another.
Second part:
*//******************* Edited part below, For clear understanding *****************//*
#Opal I have done configuration like below after your suggestion.
For the cases, where only deployService should work. It is still calling deployWeb and deployWebAndService both.
Code is here:
task deploy (dependsOn : ['deployWeb', 'deployService', 'deployWebAndService']) <<{
println "\n\tExecuting respective task"
}
task deployWeb (dependsOn : ['configureWebApp','stopWebApp','uninstallWebApp','installWebApp','startWebApp']) <<{
println "\n\tExecuting deploy for Web Content"
}
task deployService (dependsOn : ['configureService','stopService','uninstallService','installService','startService']) <<{
println "\n\tExecuting deploy for Service Content"
}
task deployWebAndService (dependsOn : ['configureWebApp','configureService','stopWebApp','uninstallWebApp','installWebApp','startWebApp','stopService','uninstallService','installService'/*,'startService'*/]) <<{
println "\n\tExecuting deploy for Web and Service Content"
}
deployWeb.onlyIf{
(WebContent.equals("Yes") && ServiceContent.equals("No")) //fetching "Yes"/"No" values from a separate function
}
deployService.onlyIf{
(WebContent.equals("No") && ServiceContent.equals("Yes"))
}
deployWebAndService.onlyIf{
(WebContent.equals("Yes") && ServiceContent.equals("Yes"))
}
TL;DR Your build.gradle should look as follows:
task callGradleDeploy(dependsOn: ['deployComp']) {
}
task deployComp (dependsOn: ['setEnvParameter', 'installWeb', 'installService']) <<{
println "Deployment Done"
}
task setEnvParameter{
//parameter Setting for deployement
}
task installWeb{
//install Web Code
}
task installService{
//install Services Code
}
First of all you should never call task's execute() method manually, since this highly discouraged and interferes gradle's internal logic (directed acyclic graph). To define dependencies between tasks the following methods should be used:
mustRunAfter
shouldRunAfter
dependsOn
In your particular case it's enough to substitute execute invocation with dependsOn and it works perfectly. Also please note the << to indicate action is deprecated and scheduled to be removed in version 5.0. Instead use doLast:
task callGradleDeploy {
doLast { println 'action' }
}
EDIT
See the solution below. The advantage is that you configure dependencies between tasks once. To check if it works correctly run gradle deploy -Pwc or gradle deploy -Psc
task explodeWarContent {
doLast {
println 'Code to explode war'
}
}
task configureWebApp(dependsOn: explodeWarContent) {
doLast {
println 'Code to configure web app'
}
}
task stopWebApp {
doLast {
println 'Code to stop web app'
}
}
task uninstallWebApp(dependsOn: stopWebApp) {
doLast {
println 'Code to uninstall web app'
}
}
task installWebApp(dependsOn: configureWebApp) {
mustRunAfter uninstallWebApp
doLast {
println 'Code to install web app'
}
}
task startWebApp(dependsOn: installWebApp) {
mustRunAfter stopWebApp
doLast {
println 'Code to start web app'
}
}
task deployWebApp(dependsOn: [uninstallWebApp, startWebApp]) {
onlyIf { project.hasProperty('wc')}
}
task configureService {
doLast {
println 'Code to configure service'
}
}
task stopService {
doLast {
println 'Code to stop service'
}
}
task uninstallService(dependsOn: stopService) {
doLast {
println 'Code to uninstall service'
}
}
task installService(dependsOn: configureService) {
mustRunAfter uninstallService
doLast {
println 'Code to install service'
}
}
task startService(dependsOn: installService) {
mustRunAfter stopService
doLast {
println 'Code to start service'
}
}
task deployService(dependsOn: [uninstallService, startService]) {
onlyIf { project.hasProperty('sc')}
}
task deploy {
dependsOn deployWebApp, deployService
}

How to run a Gradle task after apks are produced in Android Studio?

The following task (in build.gradle of an app's module) seems to run always before the apk is produced:
android.applicationVariants.all { variant ->
if (variant.buildType.name == 'release') {
def releaseBuildTask = tasks.create(name: "debug") {
println(".................... test ..............................")
}
releaseBuildTask.mustRunAfter variant.assemble
}
}
Could anyone offer a tip on how to run a task after the apks are produced?
Android tasks are typically created in the "afterEvaluate" phase.
Starting from gradle 2.2, those tasks also include "assembleDebug" and
"assembleRelease". To access such tasks, the user will need to use an
afterEvaluate closure:
afterEvaluate {
assembleDebug.dependsOn someTask
}
source: https://code.google.com/p/android/issues/detail?id=219732#c32
try add this in you app/build.gradle
assembleDebug.doLast {
android.applicationVariants.all { variant ->
if (variant.buildType.name == 'release') {
def releaseBuildTask = tasks.create(name: "debug") {
println(".................... test ..............................")
}
releaseBuildTask.mustRunAfter variant.assemble
}
}
println "build finished"
}
invoke the build command and specify the task assembleDebug
./gradlew assembleDebug
I found a solution that works, to copy the release APK into the project root automatically on build completion.
android {
...
task copyReleaseApk(type: Copy) {
from 'build/outputs/apk'
into '..' // Into the project root, one level above the app folder
include '**/*release.apk'
}
afterEvaluate {
packageRelease.finalizedBy(copyReleaseApk)
}
}

whenReady not setting gradle property before task runs

I have a a version property in my gradle.properties file that gives the version I am building. I have a task in the build called release that if present in the task graph will upload to the snapshot repo. However what is happening is that even though I include the release task in the build tasks, snapshot is not appended to my version property when uploadArchives runs so it attempts to upload to the wrong repository and fails. The when ready runs, but it does not seem to run before uploadArchives. Can anyone explain what is happening here?
uploadArchives {
repositories {
ivy {
credentials {
username nexusUser
password nexusPassword
}
if (version.endsWith("-SNAPSHOT")) {
url nexusSnapshotRepository
} else {
url nexusReleaseRepository
}
}
}
}
gradle.taskGraph.whenReady {taskGraph ->
if (!taskGraph.hasTask(release)) {
version = version + '-SNAPSHOT'
}
println "release task not included - version set to $version"
}
task release(){
doLast{
println "Releasing"
}
}
This is very similar to the example on the gradle site so I don't see what is going wrong.
http://www.gradle.org/docs/current/userguide/tutorial_using_tasks.html
The script is checking the project.version value in the configuration phase (not when the task executes), but only modifying it after the task execution graph has been built. One way to fix this is to override the repository url from inside the taskGraph.whenReady callback:
uploadArchives {
repositories {
ivy {
name "nexus"
url nexusReleaseRepository
...
}
}
}
gradle.taskGraph.whenReady { taskGraph ->
if (!taskGraph.hasTask(release)) {
version += '-SNAPSHOT'
uploadArchives.repositories.nexus.url nexusSnapshotRepository
// ps: println has to go inside here
}
}

Resources