Skip to content

Examples separate projects#1677

Open
Jolanrensen wants to merge 35 commits intomasterfrom
examples-separate-projects
Open

Examples separate projects#1677
Jolanrensen wants to merge 35 commits intomasterfrom
examples-separate-projects

Conversation

@Jolanrensen
Copy link
Collaborator

@Jolanrensen Jolanrensen commented Feb 6, 2026

Fixes #1614
Step 3 of #1661

  • Introduces example structure like:

    • /examples/projects/1,2,3: release versions of examples
    • /examples/projects/dev/1,2,3: dev versions of examples
      Dev versions of the examples are built using the sources of the project, while release examples use the latest release versions.
      Since any example is a completely separate project, you can attach them to the IDE separately only if you need it :).
      And most importantly, each example could be extracted to a ZIP and runnable by a user without any additional setup (TODO test this)
  • Currently I only moved the android, gradle, and maven example projects into the new folder.

  • Running :promoteDevExamples copies all /dev examples upwards, making them the new "release" versions. :syncExampleFolders is run afterwards.

  • Running :syncAllExampleFolders (run automatically every :assemble) overwrites all relevant versions and properties in the examples from our main libs.versions.toml, gradle-wrapper.properties, .editorconfig, etc. This also works for any maven examples (see build-logic/src/.../buildExampleProjects for the specific implementation).
    GH actions was updated to run this command automatically, keeping our examples up-to-date :)

  • Running the Test task :runBuildAllExampleFolders (run automatically every :test in debug mode, so on TC) builds all example projects using TestBuildingExampleProjects. Each example project folder gets its own auto-generated Junit test so task dependencies can be set properly and TeamCity can run them in parallel.

    • Thanks to the :syncAllExampleFolders task, all dev Gradle Example projects get includeBuild("../../../..") in settings.gradle.kts, which substitutes any DataFrame dependeny with our actual sources. This also makes working inside them from the IDE as easy as if it were a subproject :).
    • The Android examples are ignored if the Gradle property android.sdk.dir is unset. I modified TeamCity to provide -Pandroid.sdk.dir=%env.ANDROID_SDK_HOME% and it seems to work :) This gradle property is passed down to any example containing "android" (in any form) in its name. (This logic can change if needed)
    • The Maven dev project requires a published version of DataFrame. We cannot substitute a Gradle build into Maven in the same way (AFAIK). So for that we use :publishLocal to publish the artifacts to /build/maven before running the tests.

…uild that can build the projects in /example/projects
@Jolanrensen Jolanrensen force-pushed the examples-separate-projects branch from 2ec6075 to a20f5a7 Compare February 6, 2026 13:52
@Jolanrensen Jolanrensen force-pushed the examples-separate-projects branch 2 times, most recently from 253d408 to bc241e6 Compare February 16, 2026 19:08
@Jolanrensen Jolanrensen force-pushed the examples-separate-projects branch from bc241e6 to 96714c6 Compare February 16, 2026 19:20
@Jolanrensen Jolanrensen force-pushed the examples-separate-projects branch from 461e286 to 31256ad Compare February 17, 2026 14:26
@Jolanrensen Jolanrensen force-pushed the examples-separate-projects branch from 31256ad to bd9bd74 Compare February 17, 2026 14:28
@Jolanrensen Jolanrensen force-pushed the examples-separate-projects branch from e9db608 to 296d0f2 Compare February 26, 2026 18:50
@Jolanrensen Jolanrensen force-pushed the examples-separate-projects branch 3 times, most recently from c6d4648 to 6bfabfd Compare February 26, 2026 20:25
@Jolanrensen Jolanrensen force-pushed the examples-separate-projects branch from 6bfabfd to b8b83db Compare February 27, 2026 10:50
@Jolanrensen Jolanrensen force-pushed the examples-separate-projects branch from 0405eb2 to 42fe842 Compare February 27, 2026 14:50
@Jolanrensen Jolanrensen marked this pull request as ready for review February 27, 2026 19:06
@Jolanrensen
Copy link
Collaborator Author

Jolanrensen commented Mar 2, 2026

I might squash some commits later, as there's been a lot of trial-and-error between me and TeamCity, but all seems to build fine now :)
EDIT: Seems like this is too late... Oops. Should've done that before I merged the master into here...

Carefully read the documentation I wrote. It should explain most of the steps in detail.

// Apache Arrow is not supported well on Android.
//
// Either use:
implementation(libs.dataframe.core)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still believe this notation makes lives of users harder. Impossible to copy paste dependency or even remember it

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems that it's needed for easier sync

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's okay, since we will provide them an all-in-one project with libs.versions.toml. This is also the recommended structure by Gradle, so I guess we would just help them this way :)
And indeed, it makes sync way easier!

@koperagen
Copy link
Collaborator

Great! Could i ask you to clone fresh clean repo on this branch and import into IDE? I'll do the same
git clone -b examples-separate-projects --single-branch https://github.com/Kotlin/dataframe.git
Let's verify build is ok

minor: promoteExamples already generates some changes:
image

@koperagen
Copy link
Collaborator

Some invisible changes in mvnw after running runBuildAllExampleFolders:
image

I assume Android examples are disabled because i don't have local.properties android sdk?

- `sync<NameOfFolder(Dev)>`: Syncs and overwrites build settings and versions.
Copies and overwrites versions from the main `libs.versions.toml`, `gradle.properties`, etc.
- `syncAllExampleFolders`: Syncs all example projects. Automatically called on `assemble`.
- `promoteExamples`: Promotes the `/examples/projects/dev` example projects to `/examples/project`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

promoteDevExamples?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, sounds like a better name :)

settingsGradleKts.writeText(newSettingsGradleKtsContent)

// overwrite .editorconfig
folder.resolve(".editorconfig").writeText(sourceEditorConfig.readText())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we bundle editorconfig with our rules to examples projects?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't necessarily have to, but we did tweak the settings to work well with DataFrame. Plus, if we bump KtLint, the version will be synced to the examples as well. If we then need to disable one of the new rules, we will need to do so in each example as well... So yeah

Copy link
Collaborator

@koperagen koperagen Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't it work for us even without these files, re-using root editorconfig for entire dataframe project?
People like freedom to choose codestyle in their projects, i don't see why we should enforce anything beyond what IntelliJ already does

Copy link
Collaborator

@zaleslaw zaleslaw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please answer my comments, also plan the task for the documentation update (and put it in the line of our site updates which should be merged closer to the release)
https://kotlin.github.io/dataframe/guides-and-examples.html#examples

Check references, paths, its description and possible notes for a user


gradlePlugin-gradle-foojayToolchains = { module = "org.gradle.toolchains:foojay-resolver", version.ref = "gradlePlugin-gradle-foojayToolchains" }
typesafe-conventions = { module = "dev.panuszewski:typesafe-conventions-gradle-plugin", version.ref = "typesafe-conventions" }
maven-invoker = { module = "org.apache.maven.shared:maven-invoker", version.ref = "maven-invoker" }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this invoker?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well... maven XD

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's added as dependency to the sourceSet running the build tests. Maven invoker can programmatically run a maven build, so we can even test our non-gradle examples :)

The example projects in [examples/projects](projects) always target the latest stable version of the library.
Projects compatible with the latest dev/master version are located in the [examples/projects/dev](projects/dev) folder.

All examples are tested by the main project in debug mode when `gradlew test` is run
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also could be a useful information for our site https://kotlin.github.io/dataframe/guides-and-examples.html#examples

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure. We could, but then it would be mostly boasting about how well we are looking after our examples. I think most users actually already expect we test our examples (I mean, we expected it ourselves too). What is more interesting for users is that they are kept up-to-date :) meaning they can always download a working, up-to-date example from the latest green-built master :)

<repositories>
<repository>
<id>mavenLocal</id>
<url>file://${user.home}/.m2/repository</url>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will it work on windows? hmmm

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you try?

@@ -0,0 +1,41 @@
root = true
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need this file in each project?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, definitely. Each project should be individually downloadable as Zip. If you don't supply root=true, KtLint will scan the entire system upwards to find all .editorconfig files.

# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it require so much Metasspace?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not entirely sure, but what I am sure is that we need to limit this somehow, as to not exceed TeamCity's memory. This makes it so the test won't use more than 2.5GB

* `dfbuild.buildExampleProjects` convention plugin.
*/
@Suppress("unused")
abstract class TestBuildingExampleProjects {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a feeling that we need to add this to our knowledge library: for example you should demo it for particular version and we will record it

}

tasks.named<JavaCompile>("compile${testBuildingExamples.name.capitalized()}Java") {
sourceCompatibility = JavaVersion.VERSION_21.toString()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we somehow parametrize it to make easier migration on the next Java?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be a good idea indeed :) this is the jvm version of :build-logic itself, but we can access our version catalog from there as well, so we might just be able to put it there :)

typealias Code = String

@Language("kt")
fun generateTestCase(testClassName: String, folder: File, isDev: Boolean, tags: List<String>): Code =
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a feeling that it should be a description of the processes, its goal, why do we need this generation

@Jolanrensen
Copy link
Collaborator Author

Jolanrensen commented Mar 4, 2026

I assume Android examples are disabled because i don't have local.properties android sdk?

@koperagen Exactly :) see gradle.properties or /build-logic/README.md for how to set this up. I thought this was the least invasive way of skipping the tests on platforms that don't (or cannot) have an Android SDK.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make :examples be separate projects and use the compiler plugin

3 participants