How to set a flattened test/source folder structure? - gradle

Using gradle for a Java+Groovy+JUnit project, I get this source folder structure by default:
prjroot-src
├── main
│ ├── groovy
│ └── java
└── test
├── groovy
└── java
I wanted to have Java and Groovy sources in one folder, so I set the sourceSets like this:
sourceSets.main.java.srcDirs = []
sourceSets.main.groovy.srcDirs += ["src/main/java"]
Which resulted in the same directory structure with the difference that I could put my .groovy files in the java folder. Also, the unused Groovy folder still is there.
I'd like a much flatter, cleaner directory structure that looks like this:
prjroot
├── src
└── test
The packages, .groovy and .java files should be directly under src, and the test sources accordingly under test.
How can I achieve this using gradle?

Replace your sourceSets code with:
sourceSets.main.groovy.srcDirs = ["src"]
sourceSets.test.groovy.srcDirs = ["test"]

Related

What is a proper way to include runtime classpath in compile classpath in Gradle?

I have a following Gradle project structure:
project-root/
├── adapters/
│ ├── adapter1/
│ │ ├── main
│ │ └── test
│ ├── adapter2/
│ │ ├── main
│ │ └── test
│ └── adapter3/
│ ├── main
│ └── test
└── app-spring-boot/
├── main
├── test
└── integrationTest
In the app-spring-boot module, the adapters are included only as runtime dependency:
// project-root/app-spring-boot/build.gradle.kts
dependencies {
runtimeOnly(project(":adapters:adapter1")
runtimeOnly(project(":adapters:adapter2")
runtimeOnly(project(":adapters:adapter3")
}
In the app-spring-boot module for integrationTest source set, I would like to be able to access all dependencies at compile time not only directly from app-spring-boot, but from all of the included :adapters projects as well.
I've used following configuration:
// project-root/app-spring-boot/build.gradle.kts
plugins {
`jvm-test-suite`
}
testing {
suites {
val test by getting(JvmTestSuite::class)
val integrationTest by registering(JvmTestSuite::class) {
useJUnitJupiter()
dependencies {
implementation(project())
}
sources {
compileClasspath += sourceSets.main.get().runtimeClasspath
}
}
}
}
compileClasspath += sourceSets.main.get().runtimeClasspath does the trick and all dependencies from included runtimeOnly projects are accessible at compile time, but I'm wondering what it is the correct and idiomatic Gradle way of doing it, especially since I saw #chalimartines comment.
I agree with the comment you found, saying that adding to the compile classpath is not the right way as you end up with duplicated dependencies.
When applying the test suites plugin, it will create a set of configurations similar to the ones from the main and test source sets, prefixed with the name of the test suite. Because your test suite is called integrationTest, the "implementation" configuration is named integrationTestImplementation.
With this, you can add the runtime dependencies to the compile classpath by making this implementation configuration of the test suite extend the regular runtimeClasspath configuration from the main source set. E.g.:
testing {
// ...
}
configurations["integrationTestImplementation"].extendsFrom(configurations["runtimeClasspath"])

How to tell Gradle and Intellij that the project's folder structure is different?

I'm using Gradle with the wrapper, and the folder structure by default is like so:
.
├── settings.gradle
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
└── gradlew.bat
However, I would like to change it to so:
.
├── gradle
| ├── build.gradle
│ ├── settings.gradle
│ ├── gradle.properties
│ └── wrapper
│ ├── gradlew
│ ├── gradlew.bat
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
└── src
├── main
└── test
Other than the fact that I don't know how to tell IntelliJ about the folder structure, I don't know how to change it for Gradle since the Environment Options related with changing the folder structure are deprecated:
-b, --build-file (deprecated)
Specifies the build file. For example: gradle --build-file=foo.gradle. The default is build.gradle, then build.gradle.kts.
-c, --settings-file (deprecated)
Specifies the settings file. For example: gradle --settings-file=somewhere/else/settings.gradle
You can't tell Gradle and Intellij IDEA that you use a non-standard Gradle build layout. And in all honesty, you shouldn't even consider that unless you have strong reasons to do so. There are mainly two reasons for that:
Developers familiar with one Gradle project feel immediately at home when starting with your Gradle project.
A non-standard build file and directory layout requires additional logic in IDE's (which is not present) and requires to provide extra parameters when building on the command line.
To put things into context, please have look at Gradle issue #16402.
Deprecate command-line options that describe the build layout
The -b and -c command-line options are effectively used to describe a non-standard build layout to Gradle. This is problematic because it means that a specific combination of options must be used whenever Gradle is used on that build, for example whenever invoked from the IDE, CI, command-line or some other tool. These command-line options also have some potentially surprising behaviours, such as running a settings script present in the target directory.
We don't think there are any use cases that are strong enough to justify keeping these options, and we should remove them (via deprecation). If we discover there are some use cases, we might consider replacing the options with more self-describing contracts, for example conventions for build script names.

Make gradle point to subdirectory and treat it as a rootProject

I encountered a problem with gradle project structure. I have a task that needs to be realized and some tests are meant to be executed to check whether my project structure is correct and the tasks in gradle execute correctly. However I think I misunderstood instruction a bit and I'm wondering whether I can do something with my current folders structure or If I will have to rewrite the whole project. My current project structure looks like this:
main-repo-folder/
├── docker-related-file
├── rootProject
│ ├── sub-project-1
│ ├── build(output from tasks is created here)
│ ├── build.gradle
│ ├── sub-project-2
│ ├── gradle
│ ├── gradlew
│ ├── gradlew.bat
│ ├── settings.gradle
│ └── src
As you can see, the root project is a directory inside a repo. In order for my tests to execute I think the repo itself must be a root folder (or act as one) because the tests seem to be trying executing there. And here is my question, is it possible to add f.e settings.gradle file in main-repo-folder (at the same level as rootProject folder) to "point" gradle to build from rootProject and treat that folder as the root?(I mean f.e if I call gradle clean build task_name in main-repo-folder I want to make gradle execute it as I would be in rootProject folder)
I've tried to find some information but I'm at the path of learning gradle and I don't know if it is even possible :/ .
Rename main-repo-folder/rootProject to main-repo-folder.

Bash: automatically add a file to a Xcode project?

I am creating a script.sh file that creates a Test.swift file and adds it into a Xcode project. However, I would like to know if there is a way to add this file to Xcode (in the project.pbxproj file) from this script? Instead of doing it manually in Xcode (Add files to Project...).
Thank you
3/05 Update
I tried #Johnykutty answer, here is my current Xcode project before executing the ruby script:
I have already generated a A folder with a Sample.swift file located in test, but these files are not linked to my Xcode project yet:
Now here is the script that I'm executing:
require 'xcodeproj'
project_path = '../TestCodeProjTest.xcodeproj'
project = Xcodeproj::Project.open(project_path)
file_group = project["TestCodeProjTest"]["test"]
file_group.new_file("#{project.project_dir}/TestCodeProjTest/test/A")
project.save()
This almost works fine, except that it creates a folder reference instead of a group, and it doesn't link it to my target:
Hence the content of Sample.swift is unreachable.
Its hard to achieve by bash. But really easy if you use Ruby and xcodeproj gem from Cocoapods
Consider you have file structure like
├── GeneratedFiles
│   └── Sample1.swift
├── MyProject
│   ├── AppDelegate.swift
│   ├── ... all other files
│   ├── SceneDelegate.swift
│   └── ViewController.swift
├── MyProject.xcodeproj
│   ├── project.pbxproj
│   ├── .....
└── add_file.rb
Then you can add files like
require 'xcodeproj'
project_path = 'MyProject.xcodeproj'
project = Xcodeproj::Project.open(project_path)
file_group = project["MyProject"]
file_group.new_file("../GeneratedFiles/Sample1.swift")
project.save()
UPDATE:
project["MyProject"] returns a file group which is a group named MyProject in the root of the project, you can select another group inside MyProject by file_group = project["MyProject"]["MyGroup"]
Then the generated file path should be either related to that group like file_group.new_file("../../GeneratedFiles/Sample1.swift") or full path like file_group.new_file("#{project.project_dir}/GeneratedFiles/Sample1.swift")
More details about Xcodeproj here

How to copy file and rename depending on subfolder

I am trying to copy a file in gradle and rename it at the same time, where the new name of the file should be dependent of the name of the subfolder it was in.
My file structure looks like this for example:
├── apk
│   └── app-envTest-normalBuild-release.apk
├── logs
│   └── manifest-merger-envTest-normalBuild-release-report.txt
└── mapping
└── envTestNormalBuild
└── release
├── dump.txt
├── mapping.txt
├── seeds.txt
└── usage.txt
I'd like to copy the mapping.txt and rename it. The new name should be mapping-envTestNormalBuild.txt - i.e. should include the name of the subdirectory it was released in.
Can someone tell me if/how this is possible using the gradle copy+rename feature?
I have seen that the reverse is possible, i.e. copying a file like foo-bar.txt to a directory/path foo/bar.txt and similar.
You can try e.g.:
task clean {
doLast {
project.file('dest').deleteDir()
}
}
task cp(type: Copy) {
dependsOn clean
from 'mapping/envTestNormalBuild/release'
into 'dest'
include 'mapping.txt'
eachFile { fcp ->
fcp.name = "$fcp.file.parentFile.parentFile.name-$fcp.name"
}
}
A demo can be found here.

Resources