From 35be7a766f84d4b179aca437d5579cf6180fe332 Mon Sep 17 00:00:00 2001 From: "(skovati) Luke" Date: Tue, 24 Sep 2024 12:44:30 -0700 Subject: [PATCH 01/13] refactor procedural build logic into convention plugin --- .../examples/foo-procedures/build.gradle | 66 +------------------ procedural/plugin/build.gradle | 27 ++++++++ ....nasa.ammos.aerie.procedural.plugin.gradle | 62 +++++++++++++++++ settings.gradle | 10 +++ 4 files changed, 100 insertions(+), 65 deletions(-) create mode 100644 procedural/plugin/build.gradle create mode 100644 procedural/plugin/src/main/groovy/gov.nasa.ammos.aerie.procedural.plugin.gradle diff --git a/procedural/examples/foo-procedures/build.gradle b/procedural/examples/foo-procedures/build.gradle index 721e290833..448666a576 100644 --- a/procedural/examples/foo-procedures/build.gradle +++ b/procedural/examples/foo-procedures/build.gradle @@ -1,8 +1,6 @@ -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar - plugins { id 'java' - id 'com.gradleup.shadow' version '8.3.0' + id "gov.nasa.ammos.aerie.procedural.plugin" version "0.0.1" } java { @@ -27,68 +25,6 @@ dependencies { testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.0' } -tasks.register('buildAllSchedulingProcedureJars') { - group = 'SchedulingProcedureJars' - - dependsOn "generateSchedulingProcedureJarTasks" - dependsOn { - tasks.findAll { task -> task.name.startsWith('buildSchedulingProcedureJar_') } - } -} - -tasks.create("generateSchedulingProcedureJarTasks") { - group = 'SchedulingProcedureJars' - - final proceduresDir = findFirstMatchingBuildDir("generated/procedures") - - if (proceduresDir == null) { - println "No procedures folder found" - return - } - println "Generating jar tasks for the following procedures directory: ${proceduresDir}" - - final files = file(proceduresDir).listFiles() - if (files.length == 0) { - println "No procedures available within folder ${proceduresDir}" - return - } - - files.toList().each { file -> - final nameWithoutExtension = file.name.replace(".java", "") - final taskName = "buildSchedulingProcedureJar_${nameWithoutExtension}" - - println "Generating ${taskName} task, which will build ${nameWithoutExtension}.jar" - - tasks.create(taskName, ShadowJar) { - group = 'SchedulingProcedureJars' - configurations = [project.configurations.compileClasspath] - from sourceSets.main.output - archiveBaseName = "" // clear - archiveClassifier.set(nameWithoutExtension) // set output jar name - manifest { - attributes 'Main-Class': getMainClassFromGeneratedFile(file) - } - minimize() - } - } -} - -private String findFirstMatchingBuildDir(String pattern) { - String found = null - final generatedDir = file("build/generated/sources") - generatedDir.mkdirs() - generatedDir.eachDirRecurse { dir -> if (dir.path.contains(pattern)) found = dir.path } - return found -} - -private static String getMainClassFromGeneratedFile(File file) { - final fileString = file.toString() - final prefix = "build/generated/sources/annotationProcessor/java/main/" - final index = fileString.indexOf(prefix) + prefix.length() - final trimmed = fileString.substring(index).replace(".java", "") - return trimmed.replace("/", ".") -} - test { useJUnitPlatform() } diff --git a/procedural/plugin/build.gradle b/procedural/plugin/build.gradle new file mode 100644 index 0000000000..6a9772e524 --- /dev/null +++ b/procedural/plugin/build.gradle @@ -0,0 +1,27 @@ +plugins { + id 'groovy-gradle-plugin' + id 'com.gradle.plugin-publish' +} + +// adding this as an implementation dependency here allows usage in our convention plugin +dependencies { + implementation("com.gradleup.shadow:shadow-gradle-plugin:8.3.2") +} + +tasks.publish { + dependsOn("check") +} + +version = '1.0' + +gradlePlugin { + website = 'https://ammos.nasa.gov/aerie' + vcsUrl = 'https://github.com/NASA-AMMOS/aerie' + + plugins { + proceduralPlugin { + + } + } +} + diff --git a/procedural/plugin/src/main/groovy/gov.nasa.ammos.aerie.procedural.plugin.gradle b/procedural/plugin/src/main/groovy/gov.nasa.ammos.aerie.procedural.plugin.gradle new file mode 100644 index 0000000000..6200d471dc --- /dev/null +++ b/procedural/plugin/src/main/groovy/gov.nasa.ammos.aerie.procedural.plugin.gradle @@ -0,0 +1,62 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar + +tasks.register('buildAllSchedulingProcedureJars') { + group = 'SchedulingProcedureJars' + + dependsOn "generateSchedulingProcedureJarTasks" + dependsOn { + tasks.findAll { task -> task.name.startsWith('buildSchedulingProcedureJar_') } + } +} + +tasks.create("generateSchedulingProcedureJarTasks") { + group = 'SchedulingProcedureJars' + + final proceduresDir = findFirstMatchingBuildDir("generated/procedures") + + if (proceduresDir == null) { + println "No generated procedures folder found" + return + } + println "Generating jar tasks for the following procedures directory: ${proceduresDir}" + + final files = file(proceduresDir).listFiles() + if (files.length == 0) { + println "No procedures available within folder ${proceduresDir}" + return + } + + files.toList().each { file -> + final nameWithoutExtension = file.name.replace(".java", "") + final taskName = "buildSchedulingProcedureJar_${nameWithoutExtension}" + + println "Generating ${taskName} task, which will build ${nameWithoutExtension}.jar" + + tasks.create(taskName, ShadowJar) { + group = 'SchedulingProcedureJars' + configurations = [project.configurations.compileClasspath] + from sourceSets.main.output + archiveBaseName = "" // clear + archiveClassifier.set(nameWithoutExtension) // set output jar name + manifest { + attributes 'Main-Class': getMainClassFromGeneratedFile(file) + } + minimize() + } } +} + +private String findFirstMatchingBuildDir(String pattern) { + String found = null + final generatedDir = file("build/generated/sources") + generatedDir.mkdirs() + generatedDir.eachDirRecurse { dir -> if (dir.path.contains(pattern)) found = dir.path } + return found +} + +private static String getMainClassFromGeneratedFile(File file) { + final fileString = file.toString() + final prefix = "build/generated/sources/annotationProcessor/java/main/" + final index = fileString.indexOf(prefix) + prefix.length() + final trimmed = fileString.substring(index).replace(".java", "") + return trimmed.replace("/", ".") +} diff --git a/settings.gradle b/settings.gradle index 1240589c6b..62077a650a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,10 @@ +pluginManagement { + repositories { + mavenLocal() + gradlePluginPortal() + } +} + rootProject.name = 'aerie' // Mission Model support @@ -19,6 +26,9 @@ include 'procedural:constraints' include 'procedural:scheduling' include 'procedural:remote' +// Procedural gradle plugins +include 'procedural:plugin' + // Procedural examples include 'procedural:examples:foo-procedures' From 26a81188b664927c056f183532096c37eef856d0 Mon Sep 17 00:00:00 2001 From: "(skovati) Luke" Date: Tue, 24 Sep 2024 15:33:43 -0700 Subject: [PATCH 02/13] add plugin publishing config --- procedural/plugin/build.gradle | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/procedural/plugin/build.gradle b/procedural/plugin/build.gradle index 6a9772e524..40395ff9ee 100644 --- a/procedural/plugin/build.gradle +++ b/procedural/plugin/build.gradle @@ -1,6 +1,6 @@ plugins { id 'groovy-gradle-plugin' - id 'com.gradle.plugin-publish' + id 'com.gradle.plugin-publish' version '1.3.0' } // adding this as an implementation dependency here allows usage in our convention plugin @@ -12,15 +12,19 @@ tasks.publish { dependsOn("check") } -version = '1.0' +version = '0.0.1' gradlePlugin { website = 'https://ammos.nasa.gov/aerie' vcsUrl = 'https://github.com/NASA-AMMOS/aerie' plugins { - proceduralPlugin { - + matching { it.name == 'gov.nasa.ammos.aerie.procedural.plugin' }.configureEach { + id = "gov.nasa.ammos.aerie.procedural.plugin" + displayName = "NASA AMMOS Aerie Procedural Plugin" + description = "Provides gradle tasks for building scheduling & constraint procedures for the Aerie system" + tags.set(['ammos', 'aerie']) + implementationClass = "GovNasaAmmosAerieProceduralPluginPlugin" } } } From c37f443b9b879c848b73751463dc70571aa3690e Mon Sep 17 00:00:00 2001 From: "(skovati) Luke" Date: Tue, 24 Sep 2024 15:34:01 -0700 Subject: [PATCH 03/13] restore top level settings.gradle --- settings.gradle | 7 ------- 1 file changed, 7 deletions(-) diff --git a/settings.gradle b/settings.gradle index 62077a650a..3989cf5484 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,10 +1,3 @@ -pluginManagement { - repositories { - mavenLocal() - gradlePluginPortal() - } -} - rootProject.name = 'aerie' // Mission Model support From ab51ee27d4430bab3dfd213701e8680fd069236e Mon Sep 17 00:00:00 2001 From: "(skovati) Luke" Date: Mon, 30 Sep 2024 16:24:09 -0700 Subject: [PATCH 04/13] Publish to ideal coordinates with suboptimal resolution strategy --- procedural/plugin/build.gradle | 42 ++++++++++++++++++++++++---------- settings.gradle | 20 ++++++++++++++++ 2 files changed, 50 insertions(+), 12 deletions(-) diff --git a/procedural/plugin/build.gradle b/procedural/plugin/build.gradle index 40395ff9ee..e0628b7631 100644 --- a/procedural/plugin/build.gradle +++ b/procedural/plugin/build.gradle @@ -1,6 +1,7 @@ plugins { id 'groovy-gradle-plugin' - id 'com.gradle.plugin-publish' version '1.3.0' + // id 'com.gradle.plugin-publish' version '1.3.0' + id "maven-publish" } // adding this as an implementation dependency here allows usage in our convention plugin @@ -14,18 +15,35 @@ tasks.publish { version = '0.0.1' -gradlePlugin { - website = 'https://ammos.nasa.gov/aerie' - vcsUrl = 'https://github.com/NASA-AMMOS/aerie' - - plugins { - matching { it.name == 'gov.nasa.ammos.aerie.procedural.plugin' }.configureEach { - id = "gov.nasa.ammos.aerie.procedural.plugin" - displayName = "NASA AMMOS Aerie Procedural Plugin" - description = "Provides gradle tasks for building scheduling & constraint procedures for the Aerie system" - tags.set(['ammos', 'aerie']) - implementationClass = "GovNasaAmmosAerieProceduralPluginPlugin" +publishing { + publications { + maven(MavenPublication) { + artifactId = "plugin" + } + } + repositories { + maven { + name = "GitHubPackages" + url = "https://maven.pkg.github.com/skovati/copie" + credentials { + username = System.getenv("GITHUB_ACTOR") + password = System.getenv("GITHUB_TOKEN") + } } } } +//gradlePlugin { +// website = 'https://ammos.nasa.gov/aerie-docs/' +// vcsUrl = 'https://github.com/NASA-AMMOS/aerie' +// +// plugins { +// matching { it.name == 'gov.nasa.ammos.aerie.procedural.plugin' }.configureEach { +// id = "gov.nasa.ammos.aerie.procedural.plugin" +// displayName = "NASA AMMOS Aerie Procedural Plugin" +// description = "Provides gradle tasks for building scheduling & constraint procedures for the Aerie system" +// tags.set(['ammos', 'aerie']) +// implementationClass = "GovNasaAmmosAerieProceduralPluginPlugin" +// } +// } +//} diff --git a/settings.gradle b/settings.gradle index 3989cf5484..d6bf065edc 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,23 @@ +pluginManagement { + resolutionStrategy { + eachPlugin { + if (requested.id.namespace == 'gov.nasa.ammos.aerie.procedural') { + useModule('gov.nasa.ammos.aerie.procedural:plugin') + } + } + } + repositories { + maven { + name = "GitHubPackages" + url = "https://maven.pkg.github.com/skovati/copie" + credentials { + username = System.getenv("GITHUB_ACTOR") + password = System.getenv("GITHUB_TOKEN") + } + } + gradlePluginPortal() + } +} rootProject.name = 'aerie' // Mission Model support From 6f9c036c1191629c595cbffcd9b4a2fe4d8dbbea Mon Sep 17 00:00:00 2001 From: "(skovati) Luke" Date: Mon, 30 Sep 2024 16:58:49 -0700 Subject: [PATCH 05/13] publish separate plugin POM with redirect --- procedural/plugin/build.gradle | 20 +------------------- settings.gradle | 7 ------- 2 files changed, 1 insertion(+), 26 deletions(-) diff --git a/procedural/plugin/build.gradle b/procedural/plugin/build.gradle index e0628b7631..406b904cce 100644 --- a/procedural/plugin/build.gradle +++ b/procedural/plugin/build.gradle @@ -1,6 +1,5 @@ plugins { id 'groovy-gradle-plugin' - // id 'com.gradle.plugin-publish' version '1.3.0' id "maven-publish" } @@ -17,9 +16,7 @@ version = '0.0.1' publishing { publications { - maven(MavenPublication) { - artifactId = "plugin" - } + maven(MavenPublication) } repositories { maven { @@ -32,18 +29,3 @@ publishing { } } } - -//gradlePlugin { -// website = 'https://ammos.nasa.gov/aerie-docs/' -// vcsUrl = 'https://github.com/NASA-AMMOS/aerie' -// -// plugins { -// matching { it.name == 'gov.nasa.ammos.aerie.procedural.plugin' }.configureEach { -// id = "gov.nasa.ammos.aerie.procedural.plugin" -// displayName = "NASA AMMOS Aerie Procedural Plugin" -// description = "Provides gradle tasks for building scheduling & constraint procedures for the Aerie system" -// tags.set(['ammos', 'aerie']) -// implementationClass = "GovNasaAmmosAerieProceduralPluginPlugin" -// } -// } -//} diff --git a/settings.gradle b/settings.gradle index d6bf065edc..88caa15af9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,11 +1,4 @@ pluginManagement { - resolutionStrategy { - eachPlugin { - if (requested.id.namespace == 'gov.nasa.ammos.aerie.procedural') { - useModule('gov.nasa.ammos.aerie.procedural:plugin') - } - } - } repositories { maven { name = "GitHubPackages" From 18c6f4ce5e4674a5c29bc62a28429dec3b139810 Mon Sep 17 00:00:00 2001 From: "(skovati) Luke" Date: Wed, 9 Oct 2024 08:39:14 -0700 Subject: [PATCH 06/13] add build logic back into examples so CI passes --- .../examples/foo-procedures/build.gradle | 68 ++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/procedural/examples/foo-procedures/build.gradle b/procedural/examples/foo-procedures/build.gradle index 448666a576..e5868fce83 100644 --- a/procedural/examples/foo-procedures/build.gradle +++ b/procedural/examples/foo-procedures/build.gradle @@ -1,6 +1,7 @@ plugins { id 'java' - id "gov.nasa.ammos.aerie.procedural.plugin" version "0.0.1" + // id "gov.nasa.ammos.aerie.procedural.plugin" version "0.0.1" + id 'com.gradleup.shadow' version '8.3.3' // delete once ^ is published } java { @@ -28,3 +29,68 @@ dependencies { test { useJUnitPlatform() } + +// delete below once procedural plugin is published + +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar + +tasks.register('buildAllSchedulingProcedureJars') { + group = 'SchedulingProcedureJars' + + dependsOn "generateSchedulingProcedureJarTasks" + dependsOn { + tasks.findAll { task -> task.name.startsWith('buildSchedulingProcedureJar_') } + } +} + +tasks.create("generateSchedulingProcedureJarTasks") { + group = 'SchedulingProcedureJars' + + final proceduresDir = findFirstMatchingBuildDir("generated/procedures") + + if (proceduresDir == null) { + println "No generated procedures folder found" + return + } + println "Generating jar tasks for the following procedures directory: ${proceduresDir}" + + final files = file(proceduresDir).listFiles() + if (files.length == 0) { + println "No procedures available within folder ${proceduresDir}" + return + } + + files.toList().each { file -> + final nameWithoutExtension = file.name.replace(".java", "") + final taskName = "buildSchedulingProcedureJar_${nameWithoutExtension}" + + println "Generating ${taskName} task, which will build ${nameWithoutExtension}.jar" + + tasks.create(taskName, ShadowJar) { + group = 'SchedulingProcedureJars' + configurations = [project.configurations.compileClasspath] + from sourceSets.main.output + archiveBaseName = "" // clear + archiveClassifier.set(nameWithoutExtension) // set output jar name + manifest { + attributes 'Main-Class': getMainClassFromGeneratedFile(file) + } + minimize() + } } +} + +private String findFirstMatchingBuildDir(String pattern) { + String found = null + final generatedDir = file("build/generated/sources") + generatedDir.mkdirs() + generatedDir.eachDirRecurse { dir -> if (dir.path.contains(pattern)) found = dir.path } + return found +} + +private static String getMainClassFromGeneratedFile(File file) { + final fileString = file.toString() + final prefix = "build/generated/sources/annotationProcessor/java/main/" + final index = fileString.indexOf(prefix) + prefix.length() + final trimmed = fileString.substring(index).replace(".java", "") + return trimmed.replace("/", ".") +} From 5b1c50a428629b19d24be752bc75a2a64c0bc25f Mon Sep 17 00:00:00 2001 From: "(skovati) Luke" Date: Wed, 9 Oct 2024 08:39:32 -0700 Subject: [PATCH 07/13] publish to github packages --- procedural/plugin/build.gradle | 6 +++--- settings.gradle | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/procedural/plugin/build.gradle b/procedural/plugin/build.gradle index 406b904cce..e0d2e910d9 100644 --- a/procedural/plugin/build.gradle +++ b/procedural/plugin/build.gradle @@ -5,7 +5,7 @@ plugins { // adding this as an implementation dependency here allows usage in our convention plugin dependencies { - implementation("com.gradleup.shadow:shadow-gradle-plugin:8.3.2") + implementation("com.gradleup.shadow:shadow-gradle-plugin:8.3.3") } tasks.publish { @@ -20,8 +20,8 @@ publishing { } repositories { maven { - name = "GitHubPackages" - url = "https://maven.pkg.github.com/skovati/copie" + name = findProperty("publishing.name") + url = findProperty("publishing.url") credentials { username = System.getenv("GITHUB_ACTOR") password = System.getenv("GITHUB_TOKEN") diff --git a/settings.gradle b/settings.gradle index 88caa15af9..f6fd960385 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,7 +2,7 @@ pluginManagement { repositories { maven { name = "GitHubPackages" - url = "https://maven.pkg.github.com/skovati/copie" + url = "https://maven.pkg.github.com/NASA-AMMOS/aerie" credentials { username = System.getenv("GITHUB_ACTOR") password = System.getenv("GITHUB_TOKEN") From ec916bcc0e7970e477d745a84a20fea838ed3998 Mon Sep 17 00:00:00 2001 From: "(skovati) Luke" Date: Wed, 9 Oct 2024 11:30:40 -0700 Subject: [PATCH 08/13] expose GITHUB_TOKEN as env var for e2e test workflows in anticipation of needing it for plugin resolution --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a2df13e1c2..18cb2ddfec 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,6 +27,7 @@ env: SCHEDULER_PASSWORD: "${{secrets.SCHEDULER_PASSWORD}}" SEQUENCING_USERNAME: "${{secrets.SEQUENCING_USERNAME}}" SEQUENCING_PASSWORD: "${{secrets.SEQUENCING_PASSWORD}}" + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" jobs: unit-test: From 0f0f93fd70926f287f033b5e8592852e179c9eaa Mon Sep 17 00:00:00 2001 From: "(skovati) Luke" Date: Mon, 14 Oct 2024 13:46:08 -0700 Subject: [PATCH 09/13] include transitive dependencies in procedural plugin this even further simplifies the end users build.gradle scripts --- procedural/plugin/build.gradle | 9 ++++---- ....nasa.ammos.aerie.procedural.plugin.gradle | 21 +++++++++++++++---- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/procedural/plugin/build.gradle b/procedural/plugin/build.gradle index e0d2e910d9..0ccca48b49 100644 --- a/procedural/plugin/build.gradle +++ b/procedural/plugin/build.gradle @@ -12,16 +12,15 @@ tasks.publish { dependsOn("check") } -version = '0.0.1' - publishing { publications { - maven(MavenPublication) + pluginMaven(MavenPublication) } repositories { maven { - name = findProperty("publishing.name") - url = findProperty("publishing.url") + name="GitHubCopiePackages" + url="https://maven.pkg.github.com/skovati/copie" + version=findProperty("publishing.version") credentials { username = System.getenv("GITHUB_ACTOR") password = System.getenv("GITHUB_TOKEN") diff --git a/procedural/plugin/src/main/groovy/gov.nasa.ammos.aerie.procedural.plugin.gradle b/procedural/plugin/src/main/groovy/gov.nasa.ammos.aerie.procedural.plugin.gradle index 6200d471dc..d317f79237 100644 --- a/procedural/plugin/src/main/groovy/gov.nasa.ammos.aerie.procedural.plugin.gradle +++ b/procedural/plugin/src/main/groovy/gov.nasa.ammos.aerie.procedural.plugin.gradle @@ -1,5 +1,18 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +// afterEvaluate ensures these dependencies are passed to projects applying this plugin, not this plugin itself +project.afterEvaluate { + dependencies { + annotationProcessor findProject(':procedural:processor') ?: "gov.nasa.ammos.aerie.procedural:processor:${findProperty("aerieVersion")}" + implementation findProject(':procedural:constraints') ?: "gov.nasa.ammos.aerie.procedural:constraints:${findProperty("aerieVersion")}" + implementation findProject(':procedural:scheduling') ?: "gov.nasa.ammos.aerie.procedural:scheduling:${findProperty("aerieVersion")}" + implementation findProject(':procedural:timeline') ?: "gov.nasa.ammos.aerie.procedural:timeline:${findProperty("aerieVersion")}" + implementation findProject(':merlin-driver') ?: "gov.nasa.jpl.aerie:merlin-driver:${findProperty("aerieVersion")}" + implementation findProject(':type-utils') ?: "gov.nasa.jpl.aerie:type-utils:${findProperty("aerieVersion")}" + implementation findProject(':contrib') ?: "gov.nasa.jpl.aerie:contrib:${findProperty("aerieVersion")}" + } +} + tasks.register('buildAllSchedulingProcedureJars') { group = 'SchedulingProcedureJars' @@ -28,16 +41,16 @@ tasks.create("generateSchedulingProcedureJarTasks") { files.toList().each { file -> final nameWithoutExtension = file.name.replace(".java", "") + final jarPath = nameWithoutExtension + ".jar" final taskName = "buildSchedulingProcedureJar_${nameWithoutExtension}" - println "Generating ${taskName} task, which will build ${nameWithoutExtension}.jar" + println "Generating ${taskName} task, which will build ${jarPath}" tasks.create(taskName, ShadowJar) { group = 'SchedulingProcedureJars' - configurations = [project.configurations.compileClasspath] + configurations = [project.configurations.runtimeClasspath] from sourceSets.main.output - archiveBaseName = "" // clear - archiveClassifier.set(nameWithoutExtension) // set output jar name + archiveFileName = jarPath manifest { attributes 'Main-Class': getMainClassFromGeneratedFile(file) } From 0a8459eac3954de97eca77747e057c9bc9932c0c Mon Sep 17 00:00:00 2001 From: "(skovati) Luke" Date: Mon, 14 Oct 2024 15:02:15 -0700 Subject: [PATCH 10/13] conditionallly publish plugin if this is a new version --- procedural/plugin/build.gradle | 49 +++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/procedural/plugin/build.gradle b/procedural/plugin/build.gradle index 0ccca48b49..c9248541aa 100644 --- a/procedural/plugin/build.gradle +++ b/procedural/plugin/build.gradle @@ -3,6 +3,32 @@ plugins { id "maven-publish" } +import groovy.json.JsonSlurper + +def getLatestMavenPackageVersion(String owner, String packageName, String token) { + def apiUrl = "https://api.github.com/orgs/${owner}/packages/maven/${packageName}/versions" + def conn = apiUrl.toURL().openConnection() + + conn.setRequestProperty("Authorization", "Bearer ${token}") + conn.setRequestProperty("Accept", "application/vnd.github+json") + + def response = conn.inputStream.text + def versions = new JsonSlurper().parseText(response) + + if (versions.isEmpty()) { + return "No versions found" + } + + // Sort versions and get the latest one + def latestVersion = versions.sort { a, b -> + def versionA = a.name.tokenize('.') + def versionB = b.name.tokenize('.') + return versionB <=> versionA + }[0] + + return latestVersion.name +} + // adding this as an implementation dependency here allows usage in our convention plugin dependencies { implementation("com.gradleup.shadow:shadow-gradle-plugin:8.3.3") @@ -12,15 +38,32 @@ tasks.publish { dependsOn("check") } +version = "0.1.0" + +def shouldPublish = { + def latest = getLatestMavenPackageVersion("nasa-ammos", "gov.nasa.ammos.aerie.procedural.plugin", System.getenv("GITHUB_TOKEN")) + println "latest published procedural plugin is ${latest}" + println "current procedural plugin is ${version}" + def should = latest != version + if (should) { + println "publishing..." + } else { + println "not publishing..." + } + return should +} + +tasks.withType(PublishToMavenRepository).configureEach { it.enabled = shouldPublish() } + publishing { publications { pluginMaven(MavenPublication) } repositories { maven { - name="GitHubCopiePackages" - url="https://maven.pkg.github.com/skovati/copie" - version=findProperty("publishing.version") + name="GitHubPackages" + url="https://maven.pkg.github.com/nasa-ammos/aerie" + version=version credentials { username = System.getenv("GITHUB_ACTOR") password = System.getenv("GITHUB_TOKEN") From fea78043a28c4394d49d357817c169c73e5f160c Mon Sep 17 00:00:00 2001 From: "(skovati) Luke" Date: Mon, 14 Oct 2024 15:04:37 -0700 Subject: [PATCH 11/13] refactor e2e test to use gradle plugin --- e2e-tests/build.gradle | 74 +----------------------------------------- 1 file changed, 1 insertion(+), 73 deletions(-) diff --git a/e2e-tests/build.gradle b/e2e-tests/build.gradle index d7d5c9c359..9a8952fa17 100644 --- a/e2e-tests/build.gradle +++ b/e2e-tests/build.gradle @@ -1,9 +1,7 @@ -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar - plugins { id 'java-library' id 'jacoco' - id 'com.gradleup.shadow' version '8.3.0' + id 'gov.nasa.ammos.aerie.procedural.plugin' version '0.1.0' } java { @@ -57,14 +55,6 @@ task e2eTest(type: Test) { } dependencies { - annotationProcessor project(':procedural:processor') - - implementation project(":procedural:scheduling") - implementation project(":procedural:timeline") - implementation project(':merlin-sdk') - implementation project(':type-utils') - implementation project(':contrib') - testImplementation project(":procedural:remote") testImplementation "com.zaxxer:HikariCP:5.1.0" testImplementation("org.postgresql:postgresql:42.6.0") @@ -77,65 +67,3 @@ dependencies { testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.0' testImplementation 'org.junit.jupiter:junit-jupiter-params:5.10.0' } - -tasks.register('buildAllSchedulingProcedureJars') { - group = 'SchedulingProcedureJars' - - dependsOn "generateSchedulingProcedureJarTasks" - dependsOn { - tasks.findAll { task -> task.name.startsWith('buildSchedulingProcedureJar_') } - } -} - -tasks.create("generateSchedulingProcedureJarTasks") { - group = 'SchedulingProcedureJars' - - final proceduresDir = findFirstMatchingBuildDir("generated/procedures") - - if (proceduresDir == null) { - println "No procedures folder found" - return - } - println "Generating jar tasks for the following procedures directory: ${proceduresDir}" - - final files = file(proceduresDir).listFiles() - if (files.length == 0) { - println "No procedures available within folder ${proceduresDir}" - return - } - - files.toList().each { file -> - final nameWithoutExtension = file.name.replace(".java", "") - final taskName = "buildSchedulingProcedureJar_${nameWithoutExtension}" - - println "Generating ${taskName} task, which will build ${nameWithoutExtension}.jar" - - tasks.create(taskName, ShadowJar) { - group = 'SchedulingProcedureJars' - configurations = [project.configurations.compileClasspath] - from sourceSets.main.output - archiveBaseName = "" // clear - archiveClassifier.set(nameWithoutExtension) // set output jar name - manifest { - attributes 'Main-Class': getMainClassFromGeneratedFile(file) - } - minimize() - } - } -} - -private String findFirstMatchingBuildDir(String pattern) { - String found = null - final generatedDir = file("build/generated/sources") - generatedDir.mkdirs() - generatedDir.eachDirRecurse { dir -> if (dir.path.contains(pattern)) found = dir.path } - return found -} - -private static String getMainClassFromGeneratedFile(File file) { - final fileString = file.toString() - final prefix = "build/generated/sources/annotationProcessor/java/main/" - final index = fileString.indexOf(prefix) + prefix.length() - final trimmed = fileString.substring(index).replace(".java", "") - return trimmed.replace("/", ".") -} From cac3ece67135195aced10f3f716ae2731c0534a0 Mon Sep 17 00:00:00 2001 From: "(skovati) Luke" Date: Mon, 14 Oct 2024 15:15:20 -0700 Subject: [PATCH 12/13] add `GITHUB_TOKEN` to security scan build environment --- .github/workflows/security-scan.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml index f2034d59d1..06c05221cf 100644 --- a/.github/workflows/security-scan.yml +++ b/.github/workflows/security-scan.yml @@ -12,6 +12,9 @@ on: - v* workflow_dispatch: +env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + jobs: analyze: name: Analyze @@ -19,6 +22,7 @@ jobs: permissions: actions: read contents: write + packages: read security-events: write strategy: From 78f20f01b2a0aa1a50bd76f57605f7138b55ea04 Mon Sep 17 00:00:00 2001 From: JoelCourtney Date: Tue, 22 Oct 2024 16:00:29 -0700 Subject: [PATCH 13/13] Remove unusefull examples --- .../examples/foo-procedures/build.gradle | 76 +------------------ .../examples/fooprocedures/Helper.java | 7 -- .../fooprocedures/constraints/ConstFruit.java | 20 ----- .../fooprocedures/constraints/Hello.java | 9 --- .../procedures/SampleProcedure.java | 35 --------- .../procedures/SimulationDemo.java | 46 ----------- .../constraints/ProcedureLoader.java | 68 ----------------- 7 files changed, 1 insertion(+), 260 deletions(-) delete mode 100644 procedural/examples/foo-procedures/src/main/java/gov/nasa/ammos/aerie/procedural/examples/fooprocedures/Helper.java delete mode 100644 procedural/examples/foo-procedures/src/main/java/gov/nasa/ammos/aerie/procedural/examples/fooprocedures/constraints/ConstFruit.java delete mode 100644 procedural/examples/foo-procedures/src/main/java/gov/nasa/ammos/aerie/procedural/examples/fooprocedures/constraints/Hello.java delete mode 100644 procedural/examples/foo-procedures/src/main/java/gov/nasa/ammos/aerie/procedural/examples/fooprocedures/procedures/SampleProcedure.java delete mode 100644 procedural/examples/foo-procedures/src/main/java/gov/nasa/ammos/aerie/procedural/examples/fooprocedures/procedures/SimulationDemo.java delete mode 100644 procedural/examples/foo-procedures/src/test/java/gov/nasa/ammos/aerie/procedural/examples/fooprocedures/constraints/ProcedureLoader.java diff --git a/procedural/examples/foo-procedures/build.gradle b/procedural/examples/foo-procedures/build.gradle index e5868fce83..840bff9372 100644 --- a/procedural/examples/foo-procedures/build.gradle +++ b/procedural/examples/foo-procedures/build.gradle @@ -1,7 +1,6 @@ plugins { id 'java' - // id "gov.nasa.ammos.aerie.procedural.plugin" version "0.0.1" - id 'com.gradleup.shadow' version '8.3.3' // delete once ^ is published + id 'gov.nasa.ammos.aerie.procedural.plugin' version '0.1.0' } java { @@ -15,82 +14,9 @@ repositories { } dependencies { - annotationProcessor project(':procedural:processor') - implementation project(':procedural:constraints') - implementation project(':procedural:scheduling') - implementation project(':procedural:timeline') - implementation project(':merlin-driver') - implementation project(':type-utils') - implementation project(':contrib') - testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.0' } test { useJUnitPlatform() } - -// delete below once procedural plugin is published - -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar - -tasks.register('buildAllSchedulingProcedureJars') { - group = 'SchedulingProcedureJars' - - dependsOn "generateSchedulingProcedureJarTasks" - dependsOn { - tasks.findAll { task -> task.name.startsWith('buildSchedulingProcedureJar_') } - } -} - -tasks.create("generateSchedulingProcedureJarTasks") { - group = 'SchedulingProcedureJars' - - final proceduresDir = findFirstMatchingBuildDir("generated/procedures") - - if (proceduresDir == null) { - println "No generated procedures folder found" - return - } - println "Generating jar tasks for the following procedures directory: ${proceduresDir}" - - final files = file(proceduresDir).listFiles() - if (files.length == 0) { - println "No procedures available within folder ${proceduresDir}" - return - } - - files.toList().each { file -> - final nameWithoutExtension = file.name.replace(".java", "") - final taskName = "buildSchedulingProcedureJar_${nameWithoutExtension}" - - println "Generating ${taskName} task, which will build ${nameWithoutExtension}.jar" - - tasks.create(taskName, ShadowJar) { - group = 'SchedulingProcedureJars' - configurations = [project.configurations.compileClasspath] - from sourceSets.main.output - archiveBaseName = "" // clear - archiveClassifier.set(nameWithoutExtension) // set output jar name - manifest { - attributes 'Main-Class': getMainClassFromGeneratedFile(file) - } - minimize() - } } -} - -private String findFirstMatchingBuildDir(String pattern) { - String found = null - final generatedDir = file("build/generated/sources") - generatedDir.mkdirs() - generatedDir.eachDirRecurse { dir -> if (dir.path.contains(pattern)) found = dir.path } - return found -} - -private static String getMainClassFromGeneratedFile(File file) { - final fileString = file.toString() - final prefix = "build/generated/sources/annotationProcessor/java/main/" - final index = fileString.indexOf(prefix) + prefix.length() - final trimmed = fileString.substring(index).replace(".java", "") - return trimmed.replace("/", ".") -} diff --git a/procedural/examples/foo-procedures/src/main/java/gov/nasa/ammos/aerie/procedural/examples/fooprocedures/Helper.java b/procedural/examples/foo-procedures/src/main/java/gov/nasa/ammos/aerie/procedural/examples/fooprocedures/Helper.java deleted file mode 100644 index 0308d22dd5..0000000000 --- a/procedural/examples/foo-procedures/src/main/java/gov/nasa/ammos/aerie/procedural/examples/fooprocedures/Helper.java +++ /dev/null @@ -1,7 +0,0 @@ -package gov.nasa.ammos.aerie.procedural.examples.fooprocedures; - -public class Helper { - public static String greeting() { - return "hello from util"; - } -} diff --git a/procedural/examples/foo-procedures/src/main/java/gov/nasa/ammos/aerie/procedural/examples/fooprocedures/constraints/ConstFruit.java b/procedural/examples/foo-procedures/src/main/java/gov/nasa/ammos/aerie/procedural/examples/fooprocedures/constraints/ConstFruit.java deleted file mode 100644 index 762cc9f1fd..0000000000 --- a/procedural/examples/foo-procedures/src/main/java/gov/nasa/ammos/aerie/procedural/examples/fooprocedures/constraints/ConstFruit.java +++ /dev/null @@ -1,20 +0,0 @@ -package gov.nasa.ammos.aerie.procedural.examples.fooprocedures.constraints; - -import gov.nasa.ammos.aerie.procedural.constraints.GeneratorConstraint; -import gov.nasa.ammos.aerie.procedural.constraints.Violations; -import gov.nasa.ammos.aerie.procedural.timeline.collections.profiles.Real; -import gov.nasa.ammos.aerie.procedural.timeline.plan.Plan; -import gov.nasa.ammos.aerie.procedural.timeline.plan.SimulationResults; -import org.jetbrains.annotations.NotNull; - -public class ConstFruit extends GeneratorConstraint { - @Override - public void generate(@NotNull Plan plan, @NotNull SimulationResults simResults) { - final var fruit = simResults.resource("/fruit", Real.deserializer()); - - violate(Violations.on( - fruit.equalTo(4), - false - )); - } -} diff --git a/procedural/examples/foo-procedures/src/main/java/gov/nasa/ammos/aerie/procedural/examples/fooprocedures/constraints/Hello.java b/procedural/examples/foo-procedures/src/main/java/gov/nasa/ammos/aerie/procedural/examples/fooprocedures/constraints/Hello.java deleted file mode 100644 index 1e36a1d2c1..0000000000 --- a/procedural/examples/foo-procedures/src/main/java/gov/nasa/ammos/aerie/procedural/examples/fooprocedures/constraints/Hello.java +++ /dev/null @@ -1,9 +0,0 @@ -package gov.nasa.ammos.aerie.procedural.examples.fooprocedures.constraints; - -import gov.nasa.ammos.aerie.procedural.examples.fooprocedures.Helper; - -class Hello { - public static void main(String[] args) { - System.out.println(Helper.greeting()); - } -} diff --git a/procedural/examples/foo-procedures/src/main/java/gov/nasa/ammos/aerie/procedural/examples/fooprocedures/procedures/SampleProcedure.java b/procedural/examples/foo-procedures/src/main/java/gov/nasa/ammos/aerie/procedural/examples/fooprocedures/procedures/SampleProcedure.java deleted file mode 100644 index 9a2f1cd290..0000000000 --- a/procedural/examples/foo-procedures/src/main/java/gov/nasa/ammos/aerie/procedural/examples/fooprocedures/procedures/SampleProcedure.java +++ /dev/null @@ -1,35 +0,0 @@ -package gov.nasa.ammos.aerie.procedural.examples.fooprocedures.procedures; - -import gov.nasa.ammos.aerie.procedural.scheduling.plan.EditablePlan; -import gov.nasa.ammos.aerie.procedural.scheduling.Goal; -import gov.nasa.ammos.aerie.procedural.scheduling.annotations.SchedulingProcedure; -import gov.nasa.ammos.aerie.procedural.scheduling.plan.NewDirective; -import gov.nasa.ammos.aerie.procedural.timeline.payloads.activities.AnyDirective; -import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; -import gov.nasa.ammos.aerie.procedural.timeline.payloads.activities.DirectiveStart; -import org.jetbrains.annotations.NotNull; - -import java.util.Map; - -@SchedulingProcedure -public record SampleProcedure(int quantity) implements Goal { - @Override - public void run(@NotNull final EditablePlan plan) { - final var firstTime = Duration.hours(24); - final var step = Duration.hours(6); - - var currentTime = firstTime; - for (var i = 0; i < quantity; i++) { - plan.create( - new NewDirective( - new AnyDirective(Map.of()), - "It's a bite banana activity", - "BiteBanana", - new DirectiveStart.Absolute(currentTime) - ) - ); - currentTime = currentTime.plus(step); - } - plan.commit(); - } -} diff --git a/procedural/examples/foo-procedures/src/main/java/gov/nasa/ammos/aerie/procedural/examples/fooprocedures/procedures/SimulationDemo.java b/procedural/examples/foo-procedures/src/main/java/gov/nasa/ammos/aerie/procedural/examples/fooprocedures/procedures/SimulationDemo.java deleted file mode 100644 index 5ca804d72a..0000000000 --- a/procedural/examples/foo-procedures/src/main/java/gov/nasa/ammos/aerie/procedural/examples/fooprocedures/procedures/SimulationDemo.java +++ /dev/null @@ -1,46 +0,0 @@ -package gov.nasa.ammos.aerie.procedural.examples.fooprocedures.procedures; - -import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; -import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; -import gov.nasa.ammos.aerie.procedural.scheduling.Goal; -import gov.nasa.ammos.aerie.procedural.scheduling.annotations.SchedulingProcedure; -import gov.nasa.ammos.aerie.procedural.scheduling.plan.EditablePlan; -import gov.nasa.ammos.aerie.procedural.timeline.collections.profiles.Real; -import gov.nasa.ammos.aerie.procedural.timeline.payloads.activities.DirectiveStart; -import org.jetbrains.annotations.NotNull; - -import java.util.Map; - -@SchedulingProcedure -public record SimulationDemo(int quantity) implements Goal { - @Override - public void run(@NotNull final EditablePlan plan) { - - var simResults = plan.latestResults(); - if (simResults == null) simResults = plan.simulate(); - - final var lowFruit = simResults.resource("/fruit", Real.deserializer()).lessThan(3.5).isolateTrue(); - final var bites = simResults.instances("BiteBanana"); - - final var connections = lowFruit.starts().shift(Duration.MINUTE.negate()) - .connectTo(bites.ends(), false); - - for (final var connection: connections) { - assert connection.to != null; - plan.create( - "GrowBanana", - new DirectiveStart.Anchor( - connection.to.directiveId, - Duration.minutes(30), - DirectiveStart.Anchor.AnchorPoint.End - ), - Map.of( - "quantity", SerializedValue.of(1), - "growingDuration", SerializedValue.of(Duration.HOUR.dividedBy(Duration.MICROSECOND)) - ) - ); - } - - plan.commit(); - } -} diff --git a/procedural/examples/foo-procedures/src/test/java/gov/nasa/ammos/aerie/procedural/examples/fooprocedures/constraints/ProcedureLoader.java b/procedural/examples/foo-procedures/src/test/java/gov/nasa/ammos/aerie/procedural/examples/fooprocedures/constraints/ProcedureLoader.java deleted file mode 100644 index 4a60866c2b..0000000000 --- a/procedural/examples/foo-procedures/src/test/java/gov/nasa/ammos/aerie/procedural/examples/fooprocedures/constraints/ProcedureLoader.java +++ /dev/null @@ -1,68 +0,0 @@ -package gov.nasa.ammos.aerie.procedural.examples.fooprocedures.constraints; - -import gov.nasa.jpl.aerie.merlin.protocol.model.MerlinPlugin; -import gov.nasa.ammos.aerie.procedural.constraints.Constraint; - -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.nio.file.Path; -import java.util.Objects; -import java.util.jar.JarFile; - -public final class ProcedureLoader { - public static Constraint loadProcedure(final Path path, final String name, final String version) - throws ProcedureLoadException - { - final var className = getImplementingClassName(path, name, version); - final var classLoader = new URLClassLoader(new URL[] {pathToUrl(path)}); - - try { - final var pluginClass$ = classLoader.loadClass(className); - if (!Constraint.class.isAssignableFrom(pluginClass$)) { - throw new ProcedureLoadException(path, name, version); - } - - return (Constraint) pluginClass$.getConstructor().newInstance(); - } catch (final ReflectiveOperationException ex) { - throw new ProcedureLoadException(path, name, version, ex); - } - } - - private static String getImplementingClassName(final Path jarPath, final String name, final String version) - throws ProcedureLoadException { - try (final var jarFile = new JarFile(jarPath.toFile())) { - return Objects.requireNonNull(jarFile.getManifest().getMainAttributes().getValue("Main-Class")); - } catch (final IOException ex) { - throw new ProcedureLoadException(jarPath, name, version, ex); - } - } - - private static URL pathToUrl(final Path path) { - try { - return path.toUri().toURL(); - } catch (final MalformedURLException ex) { - // This exception only happens if there is no URL protocol handler available to represent a Path. - // This is highly unexpected, and indicates a fundamental problem with the system environment. - throw new Error(ex); - } - } - - public static class ProcedureLoadException extends Exception { - private ProcedureLoadException(final Path path, final String name, final String version) { - this(path, name, version, null); - } - - private ProcedureLoadException(final Path path, final String name, final String version, final Throwable cause) { - super( - String.format( - "No implementation found for `%s` at path `%s` wih name \"%s\" and version \"%s\"", - MerlinPlugin.class.getSimpleName(), - path, - name, - version), - cause); - } - } -}