From c3839b95aff3b4efc53c355e0570711c8a28580a Mon Sep 17 00:00:00 2001 From: "Daniel A. A. Pelsmaeker" Date: Thu, 25 Jul 2024 17:05:08 +0200 Subject: [PATCH 1/7] Add kotlin serialization dependency --- depman/gradle/libs.versions.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/depman/gradle/libs.versions.toml b/depman/gradle/libs.versions.toml index 2ae8c10..0df26b9 100644 --- a/depman/gradle/libs.versions.toml +++ b/depman/gradle/libs.versions.toml @@ -102,6 +102,7 @@ junit4-benchmarks = "0.7.2" # https://labs.carro [plugins] kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } +kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } gitonium = { id = "org.metaborg.gitonium", version.ref = "gitonium" } coronium-bundle = { id = "org.metaborg.coronium.bundle", version.ref = "coronium" } foojay-resolver-convention = { id = "org.gradle.toolchains.foojay-resolver-convention", version.ref = "foojay" } From c354fd625bded58843fd531b21c90e7d8634a5a2 Mon Sep 17 00:00:00 2001 From: "Daniel A. A. Pelsmaeker" Date: Thu, 25 Jul 2024 17:05:33 +0200 Subject: [PATCH 2/7] Add repoman --- repoman/build.gradle.kts | 57 +++++ repoman/examplemeta.yaml | 2 + repoman/settings.gradle.kts | 19 ++ .../org/metaborg/repoman/GenerateCommand.kt | 116 +++++++++++ .../kotlin/org/metaborg/repoman/Program.kt | 23 ++ .../org/metaborg/repoman/meta/RepoMetadata.kt | 197 ++++++++++++++++++ .../metaborg/repoman/templates/Markdown.kt | 4 + .../repoman/templates/ReadmeTemplate.kt | 10 + .../metaborg/repoman/templates/Template.kt | 28 +++ .../main/resources/templates/.gitignore.kte | 70 +++++++ .../main/resources/templates/CHANGELOG.md.kte | 17 ++ .../templates/CODE_OF_CONDUCT.md.kte | 134 ++++++++++++ .../resources/templates/CONTRIBUTING.md.kte | 59 ++++++ .../main/resources/templates/LICENSE.md.kte | 194 +++++++++++++++++ .../main/resources/templates/README.md.kte | 80 +++++++ settings.gradle.kts | 1 + 16 files changed, 1011 insertions(+) create mode 100644 repoman/build.gradle.kts create mode 100644 repoman/examplemeta.yaml create mode 100644 repoman/settings.gradle.kts create mode 100644 repoman/src/main/kotlin/org/metaborg/repoman/GenerateCommand.kt create mode 100644 repoman/src/main/kotlin/org/metaborg/repoman/Program.kt create mode 100644 repoman/src/main/kotlin/org/metaborg/repoman/meta/RepoMetadata.kt create mode 100644 repoman/src/main/kotlin/org/metaborg/repoman/templates/Markdown.kt create mode 100644 repoman/src/main/kotlin/org/metaborg/repoman/templates/ReadmeTemplate.kt create mode 100644 repoman/src/main/kotlin/org/metaborg/repoman/templates/Template.kt create mode 100644 repoman/src/main/resources/templates/.gitignore.kte create mode 100644 repoman/src/main/resources/templates/CHANGELOG.md.kte create mode 100644 repoman/src/main/resources/templates/CODE_OF_CONDUCT.md.kte create mode 100644 repoman/src/main/resources/templates/CONTRIBUTING.md.kte create mode 100644 repoman/src/main/resources/templates/LICENSE.md.kte create mode 100644 repoman/src/main/resources/templates/README.md.kte diff --git a/repoman/build.gradle.kts b/repoman/build.gradle.kts new file mode 100644 index 0000000..f7083f9 --- /dev/null +++ b/repoman/build.gradle.kts @@ -0,0 +1,57 @@ +import org.metaborg.convention.Developer + +// Workaround for issue: https://youtrack.jetbrains.com/issue/KTIJ-19369 +@Suppress("DSL_SCOPE_VIOLATION") +plugins { + application + id("org.metaborg.convention.java") + id("org.metaborg.convention.maven-publish") + id("org.metaborg.convention.junit") + alias(libs.plugins.kotlin.jvm) + alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.gitonium) +} + +version = gitonium.version +group = "org.metaborg" +description = "Repository manager for Metaborg/Spoofax projects." + +dependencies { + implementation("com.github.ajalt.clikt:clikt:4.4.0") // CLI interface + implementation("gg.jte:jte:3.1.12") // Templating engine + implementation("gg.jte:jte-kotlin:3.1.12") // Templating engine (Kotlin support) + implementation("com.charleskorn.kaml:kaml:0.59.0") // Deserialize YAML files + + testImplementation (libs.kotest) + testImplementation (libs.kotest.assertions) + testImplementation (libs.kotest.datatest) + testImplementation (libs.kotest.property) +} + +application { + mainClass.set("org.metaborg.repoman.Program") +} + +javaConvention { + javaVersion.set(JavaLanguageVersion.of(17)) +} + +publishing { + publications { + create("mavenJava") { + from(components["java"]) + } + } +} + +mavenPublishConvention { + repoOwner.set("metaborg") + repoName.set("metaborg-git") + + metadata { + inceptionYear.set("2024") + developers.set(listOf( + Developer("Virtlink", "Daniel A. A. Pelsmaeker", "developer@pelsmaeker.net"), + )) + } +} diff --git a/repoman/examplemeta.yaml b/repoman/examplemeta.yaml new file mode 100644 index 0000000..ef7363d --- /dev/null +++ b/repoman/examplemeta.yaml @@ -0,0 +1,2 @@ +--- +name: "My name" \ No newline at end of file diff --git a/repoman/settings.gradle.kts b/repoman/settings.gradle.kts new file mode 100644 index 0000000..e6efa3b --- /dev/null +++ b/repoman/settings.gradle.kts @@ -0,0 +1,19 @@ +dependencyResolutionManagement { + repositories { + maven("https://artifacts.metaborg.org/content/groups/public/") + mavenCentral() + } +} + +pluginManagement { + repositories { + maven("https://artifacts.metaborg.org/content/groups/public/") + gradlePluginPortal() + } +} + +plugins { + id("org.metaborg.convention.settings") version "latest.integration" +} + +rootProject.name = "repoman" diff --git a/repoman/src/main/kotlin/org/metaborg/repoman/GenerateCommand.kt b/repoman/src/main/kotlin/org/metaborg/repoman/GenerateCommand.kt new file mode 100644 index 0000000..2680e12 --- /dev/null +++ b/repoman/src/main/kotlin/org/metaborg/repoman/GenerateCommand.kt @@ -0,0 +1,116 @@ +package org.metaborg.repoman + +import com.charleskorn.kaml.Yaml +import com.charleskorn.kaml.decodeFromStream +import com.github.ajalt.clikt.core.CliktCommand +import com.github.ajalt.clikt.parameters.options.option +import com.github.ajalt.clikt.parameters.types.path +import gg.jte.ContentType +import gg.jte.TemplateEngine +import gg.jte.output.FileOutput +import gg.jte.resolve.ResourceCodeResolver +import org.metaborg.repoman.meta.RepoMetadata +import java.nio.file.Path +import kotlin.io.path.exists +import kotlin.io.path.inputStream + +/** + * Generates or updates the files in a repository, including: + * - README.md + * - LICENSE.md + * - CONTRIBUTING.md + * - CODE_OF_CONDUCT.md + * - CHANGELOG.md + * - .gitignore + * - ./gradlew (Gradle wrapper) + * - docs/ (MkDocs Material) + * - .github/workflows/ (GitHub CI/CD) + */ +object GenerateCommand: CliktCommand( + name = "generate", + help = "Generates a README.md file for a specific repository." +) { + /** The file with the repository metadata. */ + val metadataFile: Path? by option("-m", "--meta", help = "The file with the repository metadata") + .path(canBeFile = true, canBeDir = false, mustExist = true) + + /** The directory with the repository. */ + val repoDir: Path? by option("-r", "--repo", help = "The directory with the repository") + .path(canBeFile = false, canBeDir = true, mustExist = true) + + + override fun run() { + val repoDir = repoDir ?: Path.of(System.getProperty("user.dir")) + val metadata = readMetadata(repoDir) + val resolver = ResourceCodeResolver("templates", Program::class.java.classLoader) + val engine = TemplateEngine.create(resolver, ContentType.Plain) + val generator = Generator(repoDir, engine, metadata) + + generator.generateReadme() + generator.generateLicense() + generator.generateContributing() + generator.generateCodeOfConduct() + generator.generateChangelog() + generator.generateGitignore() + println("Done!") + } + + private fun readMetadata(repoDir: Path): RepoMetadata { + println("Reading metadata...") + + val metadataFile = metadataFile ?: repoDir.resolve("repo.yaml") + val metadata = Yaml.default.decodeFromStream(metadataFile.inputStream()) + + return metadata + } + + class Generator( + private val repoDir: Path, + private val engine: TemplateEngine, + private val metadata: RepoMetadata, + ) { + fun generateReadme() { + generate("README.md", metadata.files.readme.generate, metadata.files.readme.update) + } + + fun generateLicense() { + generate("LICENSE.md", metadata.files.license.generate, metadata.files.license.update) + } + + fun generateContributing() { + generate("CONTRIBUTING.md", metadata.files.contributing.generate, metadata.files.contributing.update) + } + + fun generateCodeOfConduct() { + generate("CODE_OF_CONDUCT.md", metadata.files.codeOfConduct.generate, metadata.files.codeOfConduct.update) + } + + fun generateChangelog() { + generate("CHANGELOG.md", metadata.files.changelog.generate, metadata.files.changelog.update) + } + + fun generateGitignore() { + generate(".gitignore", metadata.files.gitignore.generate, metadata.files.gitignore.update) + } + + fun generate(filename: String, generate: Boolean, update: Boolean) { + val outputFile = repoDir.resolve(filename) + val outputFileExisted = outputFile.exists() + if (!outputFileExisted && !generate) { + println("$filename: Not generated") + return + } else if (outputFileExisted && !update) { + println("$filename: Not updated") + return + } + + engine.render("$filename.kte", metadata, FileOutput(outputFile)) + + if (!outputFileExisted) { + println("$filename: Generated") + } else { + println("$filename: Updated") + } + } + } +} \ No newline at end of file diff --git a/repoman/src/main/kotlin/org/metaborg/repoman/Program.kt b/repoman/src/main/kotlin/org/metaborg/repoman/Program.kt new file mode 100644 index 0000000..999e02a --- /dev/null +++ b/repoman/src/main/kotlin/org/metaborg/repoman/Program.kt @@ -0,0 +1,23 @@ +package org.metaborg.repoman + +import com.github.ajalt.clikt.core.NoOpCliktCommand +import com.github.ajalt.clikt.core.subcommands + +object Program { + @JvmStatic + fun main(args: Array) { + CLI.main(args) + } +} + +/** The command-line root base class. */ +object CLI: NoOpCliktCommand(name = "repoman") { + init { + // TODO: Set versionOption() + subcommands( + GenerateCommand, + ) + } +} + + diff --git a/repoman/src/main/kotlin/org/metaborg/repoman/meta/RepoMetadata.kt b/repoman/src/main/kotlin/org/metaborg/repoman/meta/RepoMetadata.kt new file mode 100644 index 0000000..dbe988a --- /dev/null +++ b/repoman/src/main/kotlin/org/metaborg/repoman/meta/RepoMetadata.kt @@ -0,0 +1,197 @@ +package org.metaborg.repoman.meta + +import kotlinx.serialization.Serializable +import org.metaborg.repoman.templates.Markdown + +@Serializable +data class RepoMetadata( + /** The owner of the repo on GitHub. For example: `"metaborg"` */ + val repoOwner: String = "metaborg", + /** The name of the repo on GitHub (required). For example: `"resource"` */ + val repoName: String, + /** The name of the main branch. For example: `"master"` */ + val mainBranch: String = "main", + + /** The title of the repo (required). For example: `"Metaborg Resource"` */ + val title: String, + /** A short description of the repo; or `null`. For example: `"A utility library for working with resources."` */ + val description: Markdown? = null, + /** A link to the hosted documentation of the repo; or `null`. For example: `"https://spoofax.dev/gitonium/"` */ + val documentationLink: String? = null, + /** The inception year of the repository (required). */ + val inceptionYear: String, + /** The current year in which the repository is still maintained. */ + val currentYear: String = "2024", + + /** A list of Maven libraries published by the repo. */ + val libraries: List = emptyList(), + /** A list of Spoofax languages published by the repo. */ + val languages: List = emptyList(), + /** A list of Gradle plugins published by the repo. */ + val plugins: List = emptyList(), + + /** An ordered list of (main) developers that worked on the repo. */ + val developers: List = emptyList(), + + /** The configurations for the generated files. */ + val files: Files = Files(), +) + +/** Metadata for the files to generate. */ +@Serializable +data class Files( + /** The metadata for the README.md file. */ + val readme: Readme = Readme(), + /** The metadata for the LICENSE.md file. */ + val license: License = License(), + /** The metadata for the CONTRIBUTING.md file. */ + val contributing: Contributing = Contributing(), + /** The metadata for the CODE_OF_CONDUCT.md file. */ + val codeOfConduct: CodeOfConduct = CodeOfConduct(), + /** The metadata for the CHANGELOG.md file. */ + val changelog: Changelog = Changelog(), + /** The metadata for the .gitignore file. */ + val gitignore: Gitignore = Gitignore(), + /** The metadata for the Gradle wrapper files. */ + val gradleWrapper: GradleWrapper = GradleWrapper(), + /** The metadata for the Gradle root project files. */ + val gradleRootProject: GradleRootProject = GradleRootProject(), + /** The metadata for the documentation (not generated by default). */ + val docs: Docs = Docs(), + /** The metadata for the GitHub workflows. */ + val githubWorkflows: GithubWorkflows = GithubWorkflows(), +) + +/** Metadata for the README.md file. */ +@Serializable +data class Readme( + /** Whether to generate the file. */ + val generate: Boolean = true, + /** Whether to update the file. */ + val update: Boolean = true, + /** Content to include in the main body of the readme; or `null`. */ + val body: Markdown? = null, +) + +/** Metadata for the LICENSE.md file. */ +@Serializable +data class License( + /** Whether to generate the file. */ + val generate: Boolean = true, + /** Whether to update the file. */ + val update: Boolean = true, +) + +/** Metadata for the CONTRIBUTING.md file. */ +@Serializable +data class Contributing( + /** Whether to generate the file. */ + val generate: Boolean = true, + /** Whether to update the file. */ + val update: Boolean = true, +) + +/** Metadata for the CODE_OF_CONDUCT.md file. */ +@Serializable +data class CodeOfConduct( + /** Whether to generate the file. */ + val generate: Boolean = true, + /** Whether to update the file. */ + val update: Boolean = true, +) + +/** Metadata for the CHANGELOG.md file. */ +@Serializable +data class Changelog( + /** Whether to generate the file. */ + val generate: Boolean = true, + /** Whether to update the file. */ + val update: Boolean = false, +) + +/** Metadata for the .gitignore file. */ +@Serializable +data class Gitignore( + /** Whether to generate the file. */ + val generate: Boolean = true, + /** Whether to update the file. */ + val update: Boolean = true, +) + +/** Metadata for the .gradlew files. */ +@Serializable +data class GradleWrapper( + /** Whether to generate the files. */ + val generate: Boolean = true, + /** Whether to update the file. */ + val update: Boolean = true, + /** The version of the Gradle wrapper to generate. */ + val gradleVersion: String = "7.6.4", +) + +/** Metadata for the Gradle root project files. */ +@Serializable +data class GradleRootProject( + /** Whether to generate the files. */ + val generate: Boolean = true, + /** Whether to update the file. */ + val update: Boolean = true, + /** The version of the Metaborg Gradle convention to use. */ + val conventionVersion: String = "latest.integration", + /** Whether to create `publish` tasks that delegate to the included builds and subprojects. */ + val createPublishTasks: Boolean = false, +) + +/** Metadata for the MkDocs documentation files. */ +@Serializable +data class Docs( + /** Whether to generate the files. */ + val generate: Boolean = true, + /** Whether to update the file. */ + val update: Boolean = false, +) + +/** Metadata for the GitHub workflows. */ +@Serializable +data class GithubWorkflows( + /** Whether to generate the files. */ + val generate: Boolean = false, + /** Whether to update the file. */ + val update: Boolean = true, + /** Whether to publish releases using GitHub CI (instead of Jenkins or something else). */ + val releaseOnGitHub: Boolean = false, + /** Whether to publish snapshots using GitHub CI. */ + val snapshotOnGitHub: Boolean = false, + /** Whether to build and publish the documentation using GitHub CI. */ + val buildDocs: Boolean = false, +) + +/** A Maven artifact. */ +@Serializable +data class MavenArtifact( + /** The group ID of the artifact. For example: `"org.metaborg"` */ + val group: String, + /** The name of the artifact. For example: `"resource"` */ + val name: String, + /** A short description. For example: `"Resource management library."` */ + val description: Markdown? = null, +) + +/** A Gradle plugin. */ +@Serializable +data class GradlePlugin( + /** The ID of the plugin. For example: `"org.metaborg.convention.maven-publish"`. */ + val id: String, + /** A short description. For example: `"Resource management library."` */ + val description: Markdown? = null, +) + +@Serializable +data class Developer( + /** The ID of the developer, usually their GitHub nickname. */ + val id: String, + /** The (full) name of the developer. */ + val name: String, + /** The e-mail address of the developer. */ + val email: String, +) \ No newline at end of file diff --git a/repoman/src/main/kotlin/org/metaborg/repoman/templates/Markdown.kt b/repoman/src/main/kotlin/org/metaborg/repoman/templates/Markdown.kt new file mode 100644 index 0000000..50be646 --- /dev/null +++ b/repoman/src/main/kotlin/org/metaborg/repoman/templates/Markdown.kt @@ -0,0 +1,4 @@ +package org.metaborg.repoman.templates + +/** A Markdown string. */ +typealias Markdown = String \ No newline at end of file diff --git a/repoman/src/main/kotlin/org/metaborg/repoman/templates/ReadmeTemplate.kt b/repoman/src/main/kotlin/org/metaborg/repoman/templates/ReadmeTemplate.kt new file mode 100644 index 0000000..86b1d8d --- /dev/null +++ b/repoman/src/main/kotlin/org/metaborg/repoman/templates/ReadmeTemplate.kt @@ -0,0 +1,10 @@ +package org.metaborg.repoman.templates + +/** Template info for the `README.md` file. */ +data class ReadmeTemplate( + /** The human-readable name of the repository. For example: `"Metaborg Resource"` */ + val title: String, + /** A short one-line description of the repository. For example: `"A utility library for working with resources."` */ + val description: Markdown, +) : Template("README.md.kte") + diff --git a/repoman/src/main/kotlin/org/metaborg/repoman/templates/Template.kt b/repoman/src/main/kotlin/org/metaborg/repoman/templates/Template.kt new file mode 100644 index 0000000..dba8d8a --- /dev/null +++ b/repoman/src/main/kotlin/org/metaborg/repoman/templates/Template.kt @@ -0,0 +1,28 @@ +package org.metaborg.repoman.templates + +import gg.jte.ContentType +import gg.jte.TemplateEngine +import gg.jte.TemplateOutput +import gg.jte.resolve.DirectoryCodeResolver +import gg.jte.resolve.ResourceCodeResolver +import org.metaborg.repoman.Program +import java.nio.file.Path + +/** Base class for templates. */ +abstract class Template( + /** The path in the resources templates/ directory to the template file. */ + private val templatePath: String, +) { + /** + * Renders the template to the specified output. + * + * @param output The output to render to. + * @param templatePath The path to the template file; or `null` to use the default template in the JAR's resources. + */ + fun renderTo(output: TemplateOutput, templatePath: Path? = null) { + val resolver = if (templatePath != null) DirectoryCodeResolver(templatePath) + else ResourceCodeResolver("templates/${this.templatePath}", Program::class.java.classLoader) + val engine = TemplateEngine.create(resolver, ContentType.Plain) + engine.render("", this, output) + } +} \ No newline at end of file diff --git a/repoman/src/main/resources/templates/.gitignore.kte b/repoman/src/main/resources/templates/.gitignore.kte new file mode 100644 index 0000000..569ad27 --- /dev/null +++ b/repoman/src/main/resources/templates/.gitignore.kte @@ -0,0 +1,70 @@ +# Java +*.class +*.log +*.jar +*.war +*.nar +*.ear + + +# Gradle +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + + +# IntelliJ +.idea/* +!.idea/icon.svg +!.idea/icon_dark.svg +*.iws +out/ +*.iml +*.ipr +!**/src/main/**/out/ +!**/src/test/**/out/ + + +# Eclipse +.metadata +.classpath +.project +.apt_generated +.settings +.springBeans +.sts4-cache +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.recommenders +.factorypath +.recommenders/ +.apt_generated/ +.apt_generated_test/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + + +# NetBeans +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + + +# VS Code +.vscode/ + +# Misc +.cache +.DS_Store +*.lock diff --git a/repoman/src/main/resources/templates/CHANGELOG.md.kte b/repoman/src/main/resources/templates/CHANGELOG.md.kte new file mode 100644 index 0000000..27e9776 --- /dev/null +++ b/repoman/src/main/resources/templates/CHANGELOG.md.kte @@ -0,0 +1,17 @@ +@import org.metaborg.repoman.meta.RepoMetadata +@param meta: RepoMetadata +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). + +## [Unreleased] + + +## [0.0.1] - 2000-01-01 + + +[unreleased]: https://github.com/${meta.repoOwner}/${meta.repoName}/compare/release-0.0.1...HEAD +[0.0.1]: https://github.com/${meta.repoOwner}/${meta.repoName}/releases/tag/release-0.0.1 + diff --git a/repoman/src/main/resources/templates/CODE_OF_CONDUCT.md.kte b/repoman/src/main/resources/templates/CODE_OF_CONDUCT.md.kte new file mode 100644 index 0000000..cbf1ea1 --- /dev/null +++ b/repoman/src/main/resources/templates/CODE_OF_CONDUCT.md.kte @@ -0,0 +1,134 @@ + +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, +and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall +community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of +any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, +without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a +professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official email address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +[INSERT CONTACT METHOD]. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations + diff --git a/repoman/src/main/resources/templates/CONTRIBUTING.md.kte b/repoman/src/main/resources/templates/CONTRIBUTING.md.kte new file mode 100644 index 0000000..69e2414 --- /dev/null +++ b/repoman/src/main/resources/templates/CONTRIBUTING.md.kte @@ -0,0 +1,59 @@ +@import org.metaborg.repoman.meta.RepoMetadata + +@param meta: RepoMetadata + +# ${meta.title} + +## How to Contribute +Thank you for wanting to contribute to this project! :tada::+1: + +> **Note**: +> We may not deal with your issue or pull request in a timely manner, or at all. +> We also reserve the right to change your contribution in any way we deem fit +> for this project, or even outright reject it. + +#### **You have a question?** +Search the [Discussions][1] and [Stackoverflow][3] to see whether your question +has already been answered, or ask your question there. +Please do **not** make an issue on the Github repository. + + +#### **You found a bug** +Search the [Issues][2] to ensure the bug has not been reported before. + +If the bug is new, open a new issue with a _clear title and description_. +Please indicate: +- what you did, +- what you expected to happen, and +- what actually happened. + +Try to include as much relevant information as you have. +For example, a code sample or executable test case are very helpful. + + +#### **You wrote a patch with a cosmetic change** +Please do not submit pull requests for cosmetic changes, +such as whitespace and formatting changes. +We will reject them. + + +#### **You wrote a patch with a bug fix** +Thank you! Please open a GitHub pull request with the patch. + + +#### **You wrote a patch that adds a new feature or changes an existing one** +Please open an issue _first_, so we can discuss the change. + + +#### **You want to contribute to the documentation or test suite** +Thank you! Please open a GitHub pull request with the patch. + +--- + +Thanks! :heart: :heart: :heart: + +[Programming Languages Group](https://pl.ewi.tudelft.nl/), [Delft University of Technology](https://www.tudelft.nl/) + +[1]: https://github.com/${meta.repoOwner}/${meta.repoName}/discussions +[2]: https://github.com/${meta.repoOwner}/${meta.repoName}/issues +[3]: https://stackoverflow.com/ diff --git a/repoman/src/main/resources/templates/LICENSE.md.kte b/repoman/src/main/resources/templates/LICENSE.md.kte new file mode 100644 index 0000000..870644e --- /dev/null +++ b/repoman/src/main/resources/templates/LICENSE.md.kte @@ -0,0 +1,194 @@ +Apache License +============== + +_Version 2.0, January 2004_ +_<>_ + +### Terms and Conditions for use, reproduction, and distribution + +#### 1. Definitions + +“License” shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +“Licensor” shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +“Legal Entity” shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, “control” means **(i)** the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the +outstanding shares, or **(iii)** beneficial ownership of such entity. + +“You” (or “Your”) shall mean an individual or Legal Entity exercising +permissions granted by this License. + +“Source” form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +“Object” form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +“Work” shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +“Derivative Works” shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +“Contribution” shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +“submitted” means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as “Not a Contribution.” + +“Contributor” shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +#### 2. Grant of Copyright License + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +#### 3. Grant of Patent License + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +#### 4. Redistribution + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +* **(a)** You must give any other recipients of the Work or Derivative Works a copy of +this License; and +* **(b)** You must cause any modified files to carry prominent notices stating that You +changed the files; and +* **(c)** You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +* **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. + +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +#### 5. Submission of Contributions + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +#### 6. Trademarks + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +#### 7. Disclaimer of Warranty + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an “AS IS” BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +#### 8. Limitation of Liability + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +#### 9. Accepting Warranty or Additional Liability + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +_END OF TERMS AND CONDITIONS_ + +### APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets `[]` replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same “printed page” as the copyright notice for easier identification within +third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/repoman/src/main/resources/templates/README.md.kte b/repoman/src/main/resources/templates/README.md.kte new file mode 100644 index 0000000..4e637c4 --- /dev/null +++ b/repoman/src/main/resources/templates/README.md.kte @@ -0,0 +1,80 @@ +@import org.metaborg.repoman.meta.RepoMetadata + +@param meta: RepoMetadata + +# ${meta.title} +[![Build][github-badge:build]][github:build] +[![License][license-badge]][license] +[![GitHub Release][github-badge:release]][github:release] +@if(documentationLink != null) +[![Documentation][documentation-badge]][documentation] +@endif + +${meta.description} + +@if(documentationLink != null) +[![Documentation][documentation-button]][documentation] +@endif + +@if(meta.languages.isNotEmpty()) +| Language | Latest Release | Latest Snapshot | +|----------|----------------|-----------------| +@for(entry in meta.languages) +| `${entry.group}:${entry.name}` | [![Release][mvn-rel-badge:${entry.group}:${entry.name}]][mvn:${entry.group}:${entry.name}] | [![Snapshot][mvn-snap-badge:${entry.group}:${entry.name}]][mvn:${entry.group}:${entry.name}] | +@endfor +@endif + +@if(meta.libraries.isNotEmpty()) +| Artifact | Latest Release | Latest Snapshot | +|----------|----------------|-----------------| +@for(entry in meta.libraries) +| `${entry.group}:${entry.name}` | [![Release][mvn-rel-badge:${entry.group}:${entry.name}]][mvn:${entry.group}:${entry.name}] | [![Snapshot][mvn-snap-badge:${entry.group}:${entry.name}]][mvn:${entry.group}:${entry.name}] | +@endfor +@endif + +@if(meta.plugins.isNotEmpty()) +| Gradle Plugin | Latest Release | Latest Snapshot | +|---------------|----------------|-----------------| +@for(entry in meta.plugins) +| `${entry.id}` | [![Release][mvn-rel-badge:${entry.id}:${entry.id}.gradle.plugin]][mvn:${entry.id}:${entry.id}.gradle.plugin] | [![Snapshot][mvn-snap-badge:${entry.id}:${entry.id}.gradle.plugin]][mvn:${entry.id}:${entry.id}.gradle.plugin] | +@endfor +@endif + +@if(meta.files.readme.body != null) +${meta.files.readme.body} +@endif + +## License +Copyright ${meta.inceptionYear}-${meta.currentYear} [Programming Languages Group](https://pl.ewi.tudelft.nl/), [Delft University of Technology](https://www.tudelft.nl/) + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an **"as is" basis, without warranties or conditions of any kind**, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +[github-badge:build]: https://img.shields.io/github/actions/workflow/status/${meta.repoOwner}/pie/build.yaml +[github:build]: https://github.com/${meta.repoOwner}/${meta.repoName}/actions +[license-badge]: https://img.shields.io/github/license/${meta.repoOwner}/${meta.repoName} +[license]: https://github.com/${meta.repoOwner}/${meta.repoName}/blob/${meta.mainBranch}/LICENSE.md +[github-badge:release]: https://img.shields.io/github/v/release/${meta.repoOwner}/${meta.repoName} +[github:release]: https://github.com/${meta.repoOwner}/${meta.repoName}/releases +@if(documentationLink != null) +[documentation-badge]: https://img.shields.io/badge/docs-latest-brightgreen +[documentation]: ${documentationLink} +[documentation-button]: https://img.shields.io/badge/Documentation-blue?style=for-the-badge&logo=googledocs&logoColor=white +@endif + +@for(entry in meta.languages) +[mvn:${entry.group}:${entry.name}]: https://artifacts.metaborg.org/#nexus-search;gav~${entry.group}~${entry.name}~~~ +[mvn-rel-badge:${entry.group}:${entry.name}]: https://img.shields.io/nexus/r/${entry.group}/${entry.name}?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 +[mvn-snap-badge:${entry.group}:${entry.name}]: https://img.shields.io/nexus/s/${entry.group}/${entry.name}?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 +@endfor +@for(entry in meta.libraries) +[mvn:${entry.group}:${entry.name}]: https://artifacts.metaborg.org/#nexus-search;gav~${entry.group}~${entry.name}~~~ +[mvn-rel-badge:${entry.group}:${entry.name}]: https://img.shields.io/nexus/r/${entry.group}/${entry.name}?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 +[mvn-snap-badge:${entry.group}:${entry.name}]: https://img.shields.io/nexus/s/${entry.group}/${entry.name}?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 +@endfor +@for(entry in meta.plugins) +[mvn:${entry.id}:${entry.id}.gradle.plugin]: https://artifacts.metaborg.org/#nexus-search;gav~${entry.id}~${entry.id}.gradle.plugin~~~ +[mvn-rel-badge:${entry.id}:${entry.id}.gradle.plugin]: https://img.shields.io/nexus/r/${entry.id}/${entry.id}.gradle.plugin?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 +[mvn-snap-badge:${entry.id}:${entry.id}.gradle.plugin]: https://img.shields.io/nexus/s/${entry.id}/${entry.id}.gradle.plugin?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 +@endfor diff --git a/settings.gradle.kts b/settings.gradle.kts index 94e472e..b575dc9 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -21,3 +21,4 @@ plugins { includeBuild("convention-plugin/") includeBuild("depman/") includeBuild("example/") +includeBuild("repoman/") From 8115547a1cbdf61db24d8111f4604fce7a4d7b2b Mon Sep 17 00:00:00 2001 From: "Daniel A. A. Pelsmaeker" Date: Thu, 25 Jul 2024 17:05:41 +0200 Subject: [PATCH 3/7] Add repo description yaml --- repo.yaml | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 repo.yaml diff --git a/repo.yaml b/repo.yaml new file mode 100644 index 0000000..64b39cd --- /dev/null +++ b/repo.yaml @@ -0,0 +1,32 @@ +--- +repoOwner: "metaborg" +repoName: "metaborg-gradle" +mainBranch: "main" + +title: "Metaborg Gradle" +description: | + The Metaborg Gradle convention and development plugins, and the Metaborg dependency management and Gradle platform. +documentationLink: https://spoofax.dev/metaborg-gradle/ +inceptionYear: "2024" + +libraries: + - group: "org.metaborg" + name: "catalog" + description: "Version catalog" + - group: "org.metaborg" + name: "platform" + description: "Spoofax platform" +plugins: + - id: "org.metaborg.convention.settings" + description: "Settings convention plugin" + - id: "org.metaborg.convention.java" + description: "Java convention plugin" + - id: "org.metaborg.convention.maven-publish" + description: "Maven publish convention plugin" + - id: "org.metaborg.convention.root-project" + description: "Root project convention plugin" + +developers: + - id: "Virtlink" + name: "Daniel A. A. Pelsmaeker" + email: "developer@pelsmaeker.net" From ddcac0e18027a64d59586edb74c053bb15bf02be Mon Sep 17 00:00:00 2001 From: "Daniel A. A. Pelsmaeker" Date: Thu, 25 Jul 2024 17:21:14 +0200 Subject: [PATCH 4/7] Fix templates --- .../org/metaborg/repoman/GenerateCommand.kt | 5 +- .../repoman/{templates => }/Markdown.kt | 2 +- .../org/metaborg/repoman/meta/RepoMetadata.kt | 2 +- .../repoman/templates/ReadmeTemplate.kt | 10 ---- .../metaborg/repoman/templates/Template.kt | 28 ---------- .../main/resources/templates/.gitignore.kte | 1 + .../templates/CODE_OF_CONDUCT.md.kte | 1 - .../resources/templates/CONTRIBUTING.md.kte | 2 - .../main/resources/templates/LICENSE.md.kte | 54 +++++++++---------- .../main/resources/templates/README.md.kte | 26 +++++---- 10 files changed, 51 insertions(+), 80 deletions(-) rename repoman/src/main/kotlin/org/metaborg/repoman/{templates => }/Markdown.kt (58%) delete mode 100644 repoman/src/main/kotlin/org/metaborg/repoman/templates/ReadmeTemplate.kt delete mode 100644 repoman/src/main/kotlin/org/metaborg/repoman/templates/Template.kt diff --git a/repoman/src/main/kotlin/org/metaborg/repoman/GenerateCommand.kt b/repoman/src/main/kotlin/org/metaborg/repoman/GenerateCommand.kt index 2680e12..2a96105 100644 --- a/repoman/src/main/kotlin/org/metaborg/repoman/GenerateCommand.kt +++ b/repoman/src/main/kotlin/org/metaborg/repoman/GenerateCommand.kt @@ -44,6 +44,7 @@ object GenerateCommand: CliktCommand( val metadata = readMetadata(repoDir) val resolver = ResourceCodeResolver("templates", Program::class.java.classLoader) val engine = TemplateEngine.create(resolver, ContentType.Plain) + engine.setTrimControlStructures(true) val generator = Generator(repoDir, engine, metadata) generator.generateReadme() @@ -104,7 +105,9 @@ object GenerateCommand: CliktCommand( return } - engine.render("$filename.kte", metadata, FileOutput(outputFile)) + FileOutput(outputFile).use { output -> + engine.render("$filename.kte", metadata, output) + } if (!outputFileExisted) { println("$filename: Generated") diff --git a/repoman/src/main/kotlin/org/metaborg/repoman/templates/Markdown.kt b/repoman/src/main/kotlin/org/metaborg/repoman/Markdown.kt similarity index 58% rename from repoman/src/main/kotlin/org/metaborg/repoman/templates/Markdown.kt rename to repoman/src/main/kotlin/org/metaborg/repoman/Markdown.kt index 50be646..73b3b01 100644 --- a/repoman/src/main/kotlin/org/metaborg/repoman/templates/Markdown.kt +++ b/repoman/src/main/kotlin/org/metaborg/repoman/Markdown.kt @@ -1,4 +1,4 @@ -package org.metaborg.repoman.templates +package org.metaborg.repoman /** A Markdown string. */ typealias Markdown = String \ No newline at end of file diff --git a/repoman/src/main/kotlin/org/metaborg/repoman/meta/RepoMetadata.kt b/repoman/src/main/kotlin/org/metaborg/repoman/meta/RepoMetadata.kt index dbe988a..3426502 100644 --- a/repoman/src/main/kotlin/org/metaborg/repoman/meta/RepoMetadata.kt +++ b/repoman/src/main/kotlin/org/metaborg/repoman/meta/RepoMetadata.kt @@ -1,7 +1,7 @@ package org.metaborg.repoman.meta import kotlinx.serialization.Serializable -import org.metaborg.repoman.templates.Markdown +import org.metaborg.repoman.Markdown @Serializable data class RepoMetadata( diff --git a/repoman/src/main/kotlin/org/metaborg/repoman/templates/ReadmeTemplate.kt b/repoman/src/main/kotlin/org/metaborg/repoman/templates/ReadmeTemplate.kt deleted file mode 100644 index 86b1d8d..0000000 --- a/repoman/src/main/kotlin/org/metaborg/repoman/templates/ReadmeTemplate.kt +++ /dev/null @@ -1,10 +0,0 @@ -package org.metaborg.repoman.templates - -/** Template info for the `README.md` file. */ -data class ReadmeTemplate( - /** The human-readable name of the repository. For example: `"Metaborg Resource"` */ - val title: String, - /** A short one-line description of the repository. For example: `"A utility library for working with resources."` */ - val description: Markdown, -) : Template("README.md.kte") - diff --git a/repoman/src/main/kotlin/org/metaborg/repoman/templates/Template.kt b/repoman/src/main/kotlin/org/metaborg/repoman/templates/Template.kt deleted file mode 100644 index dba8d8a..0000000 --- a/repoman/src/main/kotlin/org/metaborg/repoman/templates/Template.kt +++ /dev/null @@ -1,28 +0,0 @@ -package org.metaborg.repoman.templates - -import gg.jte.ContentType -import gg.jte.TemplateEngine -import gg.jte.TemplateOutput -import gg.jte.resolve.DirectoryCodeResolver -import gg.jte.resolve.ResourceCodeResolver -import org.metaborg.repoman.Program -import java.nio.file.Path - -/** Base class for templates. */ -abstract class Template( - /** The path in the resources templates/ directory to the template file. */ - private val templatePath: String, -) { - /** - * Renders the template to the specified output. - * - * @param output The output to render to. - * @param templatePath The path to the template file; or `null` to use the default template in the JAR's resources. - */ - fun renderTo(output: TemplateOutput, templatePath: Path? = null) { - val resolver = if (templatePath != null) DirectoryCodeResolver(templatePath) - else ResourceCodeResolver("templates/${this.templatePath}", Program::class.java.classLoader) - val engine = TemplateEngine.create(resolver, ContentType.Plain) - engine.render("", this, output) - } -} \ No newline at end of file diff --git a/repoman/src/main/resources/templates/.gitignore.kte b/repoman/src/main/resources/templates/.gitignore.kte index 569ad27..1f314c7 100644 --- a/repoman/src/main/resources/templates/.gitignore.kte +++ b/repoman/src/main/resources/templates/.gitignore.kte @@ -68,3 +68,4 @@ local.properties .cache .DS_Store *.lock +jte-classes/ \ No newline at end of file diff --git a/repoman/src/main/resources/templates/CODE_OF_CONDUCT.md.kte b/repoman/src/main/resources/templates/CODE_OF_CONDUCT.md.kte index cbf1ea1..7a152d8 100644 --- a/repoman/src/main/resources/templates/CODE_OF_CONDUCT.md.kte +++ b/repoman/src/main/resources/templates/CODE_OF_CONDUCT.md.kte @@ -1,4 +1,3 @@ - # Contributor Covenant Code of Conduct ## Our Pledge diff --git a/repoman/src/main/resources/templates/CONTRIBUTING.md.kte b/repoman/src/main/resources/templates/CONTRIBUTING.md.kte index 69e2414..dacca16 100644 --- a/repoman/src/main/resources/templates/CONTRIBUTING.md.kte +++ b/repoman/src/main/resources/templates/CONTRIBUTING.md.kte @@ -1,7 +1,5 @@ @import org.metaborg.repoman.meta.RepoMetadata - @param meta: RepoMetadata - # ${meta.title} ## How to Contribute diff --git a/repoman/src/main/resources/templates/LICENSE.md.kte b/repoman/src/main/resources/templates/LICENSE.md.kte index 870644e..362ac12 100644 --- a/repoman/src/main/resources/templates/LICENSE.md.kte +++ b/repoman/src/main/resources/templates/LICENSE.md.kte @@ -90,26 +90,26 @@ in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: * **(a)** You must give any other recipients of the Work or Derivative Works a copy of -this License; and + this License; and * **(b)** You must cause any modified files to carry prominent notices stating that You -changed the files; and + changed the files; and * **(c)** You must retain, in the Source form of any Derivative Works that You distribute, -all copyright, patent, trademark, and attribution notices from the Source form -of the Work, excluding those notices that do not pertain to any part of the -Derivative Works; and + all copyright, patent, trademark, and attribution notices from the Source form + of the Work, excluding those notices that do not pertain to any part of the + Derivative Works; and * **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any -Derivative Works that You distribute must include a readable copy of the -attribution notices contained within such NOTICE file, excluding those notices -that do not pertain to any part of the Derivative Works, in at least one of the -following places: within a NOTICE text file distributed as part of the -Derivative Works; within the Source form or documentation, if provided along -with the Derivative Works; or, within a display generated by the Derivative -Works, if and wherever such third-party notices normally appear. The contents of -the NOTICE file are for informational purposes only and do not modify the -License. You may add Your own attribution notices within Derivative Works that -You distribute, alongside or as an addendum to the NOTICE text from the Work, -provided that such additional attribution notices cannot be construed as -modifying the License. + Derivative Works that You distribute must include a readable copy of the + attribution notices contained within such NOTICE file, excluding those notices + that do not pertain to any part of the Derivative Works, in at least one of the + following places: within a NOTICE text file distributed as part of the + Derivative Works; within the Source form or documentation, if provided along + with the Derivative Works; or, within a display generated by the Derivative + Works, if and wherever such third-party notices normally appear. The contents of + the NOTICE file are for informational purposes only and do not modify the + License. You may add Your own attribution notices within Derivative Works that + You distribute, alongside or as an addendum to the NOTICE text from the Work, + provided that such additional attribution notices cannot be construed as + modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or @@ -179,16 +179,16 @@ recommend that a file or class name and description of purpose be included on the same “printed page” as the copyright notice for easier identification within third-party archives. -Copyright [yyyy] [name of copyright owner] + Copyright [yyyy] [name of copyright owner] -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at -http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/repoman/src/main/resources/templates/README.md.kte b/repoman/src/main/resources/templates/README.md.kte index 4e637c4..a18d063 100644 --- a/repoman/src/main/resources/templates/README.md.kte +++ b/repoman/src/main/resources/templates/README.md.kte @@ -1,19 +1,19 @@ @import org.metaborg.repoman.meta.RepoMetadata - @param meta: RepoMetadata - # ${meta.title} [![Build][github-badge:build]][github:build] [![License][license-badge]][license] [![GitHub Release][github-badge:release]][github:release] -@if(documentationLink != null) +@if(meta.documentationLink != null) [![Documentation][documentation-badge]][documentation] @endif + ${meta.description} -@if(documentationLink != null) +@if(meta.documentationLink != null) [![Documentation][documentation-button]][documentation] + @endif @if(meta.languages.isNotEmpty()) @@ -22,47 +22,55 @@ ${meta.description} @for(entry in meta.languages) | `${entry.group}:${entry.name}` | [![Release][mvn-rel-badge:${entry.group}:${entry.name}]][mvn:${entry.group}:${entry.name}] | [![Snapshot][mvn-snap-badge:${entry.group}:${entry.name}]][mvn:${entry.group}:${entry.name}] | @endfor + @endif + @if(meta.libraries.isNotEmpty()) | Artifact | Latest Release | Latest Snapshot | |----------|----------------|-----------------| @for(entry in meta.libraries) | `${entry.group}:${entry.name}` | [![Release][mvn-rel-badge:${entry.group}:${entry.name}]][mvn:${entry.group}:${entry.name}] | [![Snapshot][mvn-snap-badge:${entry.group}:${entry.name}]][mvn:${entry.group}:${entry.name}] | @endfor + @endif + @if(meta.plugins.isNotEmpty()) | Gradle Plugin | Latest Release | Latest Snapshot | |---------------|----------------|-----------------| @for(entry in meta.plugins) | `${entry.id}` | [![Release][mvn-rel-badge:${entry.id}:${entry.id}.gradle.plugin]][mvn:${entry.id}:${entry.id}.gradle.plugin] | [![Snapshot][mvn-snap-badge:${entry.id}:${entry.id}.gradle.plugin]][mvn:${entry.id}:${entry.id}.gradle.plugin] | @endfor + @endif + @if(meta.files.readme.body != null) ${meta.files.readme.body} + @endif ## License -Copyright ${meta.inceptionYear}-${meta.currentYear} [Programming Languages Group](https://pl.ewi.tudelft.nl/), [Delft University of Technology](https://www.tudelft.nl/) +Copyright ${if (meta.inceptionYear != meta.currentYear) meta.inceptionYear + "-" + meta.currentYear else meta.inceptionYear} [Programming Languages Group](https://pl.ewi.tudelft.nl/), [Delft University of Technology](https://www.tudelft.nl/) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an **"as is" basis, without warranties or conditions of any kind**, either express or implied. See the License for the specific language governing permissions and limitations under the License. -[github-badge:build]: https://img.shields.io/github/actions/workflow/status/${meta.repoOwner}/pie/build.yaml +[github-badge:build]: https://img.shields.io/github/actions/workflow/status/${meta.repoOwner}/${meta.repoName}/build.yaml [github:build]: https://github.com/${meta.repoOwner}/${meta.repoName}/actions [license-badge]: https://img.shields.io/github/license/${meta.repoOwner}/${meta.repoName} [license]: https://github.com/${meta.repoOwner}/${meta.repoName}/blob/${meta.mainBranch}/LICENSE.md -[github-badge:release]: https://img.shields.io/github/v/release/${meta.repoOwner}/${meta.repoName} +[github-badge:release]: https://img.shields.io/github/v/release/${meta.repoOwner}/${meta.repoName}?display_name=release [github:release]: https://github.com/${meta.repoOwner}/${meta.repoName}/releases -@if(documentationLink != null) +@if(meta.documentationLink != null) [documentation-badge]: https://img.shields.io/badge/docs-latest-brightgreen -[documentation]: ${documentationLink} +[documentation]: ${meta.documentationLink} [documentation-button]: https://img.shields.io/badge/Documentation-blue?style=for-the-badge&logo=googledocs&logoColor=white @endif + @for(entry in meta.languages) [mvn:${entry.group}:${entry.name}]: https://artifacts.metaborg.org/#nexus-search;gav~${entry.group}~${entry.name}~~~ [mvn-rel-badge:${entry.group}:${entry.name}]: https://img.shields.io/nexus/r/${entry.group}/${entry.name}?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 From b1263e13c77cbfb633861c2a70bd0fbd416a5402 Mon Sep 17 00:00:00 2001 From: "Daniel A. A. Pelsmaeker" Date: Thu, 25 Jul 2024 17:25:20 +0200 Subject: [PATCH 5/7] Update Readme and gitignore --- .gitignore | 1 + CODE_OF_CONDUCT.md | 133 +++++++++++++++++++++++++++++++++++++++++++++ CONTRIBUTING.md | 55 +++++++++++++++++++ README.md | 90 +++++++++++------------------- 4 files changed, 220 insertions(+), 59 deletions(-) create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md diff --git a/.gitignore b/.gitignore index 569ad27..1f314c7 100644 --- a/.gitignore +++ b/.gitignore @@ -68,3 +68,4 @@ local.properties .cache .DS_Store *.lock +jte-classes/ \ No newline at end of file diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..7a152d8 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,133 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, +and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall +community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of +any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, +without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a +professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official email address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +[INSERT CONTACT METHOD]. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..6ee1fa3 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,55 @@ +# Metaborg Gradle + +## How to Contribute +Thank you for wanting to contribute to this project! :tada::+1: + +> **Note**: +> We may not deal with your issue or pull request in a timely manner, or at all. +> We also reserve the right to change your contribution in any way we deem fit +> for this project, or even outright reject it. + +#### **You have a question?** +Search the [Discussions][1] and [Stackoverflow][3] to see whether your question +has already been answered, or ask your question there. +Please do **not** make an issue on the Github repository. + + +#### **You found a bug** +Search the [Issues][2] to ensure the bug has not been reported before. + +If the bug is new, open a new issue with a _clear title and description_. +Please indicate: +- what you did, +- what you expected to happen, and +- what actually happened. + +Try to include as much relevant information as you have. +For example, a code sample or executable test case are very helpful. + + +#### **You wrote a patch with a cosmetic change** +Please do not submit pull requests for cosmetic changes, +such as whitespace and formatting changes. +We will reject them. + + +#### **You wrote a patch with a bug fix** +Thank you! Please open a GitHub pull request with the patch. + + +#### **You wrote a patch that adds a new feature or changes an existing one** +Please open an issue _first_, so we can discuss the change. + + +#### **You want to contribute to the documentation or test suite** +Thank you! Please open a GitHub pull request with the patch. + +--- + +Thanks! :heart: :heart: :heart: + +[Programming Languages Group](https://pl.ewi.tudelft.nl/), [Delft University of Technology](https://www.tudelft.nl/) + +[1]: https://github.com/metaborg/metaborg-gradle/discussions +[2]: https://github.com/metaborg/metaborg-gradle/issues +[3]: https://stackoverflow.com/ diff --git a/README.md b/README.md index 6970097..2e43fae 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Metaborg Gradle Plugins +# Metaborg Gradle [![Build][github-badge:build]][github:build] [![License][license-badge]][license] [![GitHub Release][github-badge:release]][github:release] @@ -6,39 +6,21 @@ The Metaborg Gradle convention and development plugins, and the Metaborg dependency management and Gradle platform. -[![Documentation][documentation-button]][documentation] - -| Gradle Plugin | Latest Release | Latest Snapshot | -|-----------------------------------------|------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------| -| `org.metaborg.convention.settings` | [![Release][mvn-rel-badge:convention.settings]][mvn:convention.settings] | [![Snapshot][mvn-snap-badge:convention.settings]][mvn:convention.settings] | -| `org.metaborg.convention.java` | [![Release][mvn-rel-badge:convention.java]][mvn:convention.java] | [![Snapshot][mvn-snap-badge:convention.java]][mvn:convention.java] | -| `org.metaborg.convention.maven-publish` | [![Release][mvn-rel-badge:convention.maven-publish]][mvn:convention.maven-publish] | [![Snapshot][mvn-snap-badge:convention.maven-publish]][mvn:convention.maven-publish] | -| `org.metaborg.convention.root-project` | [![Release][mvn-rel-badge:convention.root-project]][mvn:convention.root-project] | [![Snapshot][mvn-snap-badge:convention.root-project]][mvn:convention.root-project] | - -| Artifact | Latest Release | Latest Snapshot | -|----------------------------------|----------------------------------------------------------------------|------------------------------------------------------------------------| -| `org.metaborg:catalog` | [![Release][mvn-rel-badge:catalog]][mvn:catalog] | [![Snapshot][mvn-snap-badge:catalog]][mvn:catalog] | -| `org.metaborg:platform` | [![Release][mvn-rel-badge:platform]][mvn:platform] | [![Snapshot][mvn-snap-badge:platform]][mvn:platform] | -| `org.metaborg:platform-latest` | [![Release][mvn-rel-badge:platform-latest]][mvn:platform-latest] | [![Snapshot][mvn-snap-badge:platform-latest]][mvn:platform-latest] | -| `org.metaborg:platform-snapshot` | [![Release][mvn-rel-badge:platform-snapshot]][mvn:platform-snapshot] | [![Snapshot][mvn-snap-badge:platform-snapshot]][mvn:platform-snapshot] | - - -## Gradle Convention -The `org.metaborg.convention` plugins applies any conventional configuration to Metaborg build and projects. It has the following plugins: - -- `org.metaborg.convention.settings`: Configures a build (in `settings.gradle.kts`) by applying a version catalog and the Develocity plugin. -- `org.metaborg.convention.java`: Configures a project as a Java project (library or application). -- `org.metaborg.convention.maven-publish`: Configures the Maven publications for a project. -- `org.metaborg.convention.root-project`: Configures the root project of a Gradle multi-project build. - -## Gradle Dependency Management -The `org.metaborg:catalog` artifact provides recommended versions for dependencies, and should be used in projects that are part of Spoofax. +[![Documentation][documentation-button]][documentation] -The `org.metaborg:platform` artifact enforces particular versions for Spoofax dependencies, and should be used by consumers of Spoofax libraries. -For special use cases, the `org.metaborg:platform-latest` and `org.metaborg:platform-snapshot` artifacts provide any latest releases and snapshots of Spoofax dependencies, respectively. These may not have been tested together. Therefore, it is recommended to use a particular release of `org.metaborg:platform` in production instead. +| Artifact | Latest Release | Latest Snapshot | +|----------|----------------|-----------------| +| `org.metaborg:catalog` | [![Release][mvn-rel-badge:org.metaborg:catalog]][mvn:org.metaborg:catalog] | [![Snapshot][mvn-snap-badge:org.metaborg:catalog]][mvn:org.metaborg:catalog] | +| `org.metaborg:platform` | [![Release][mvn-rel-badge:org.metaborg:platform]][mvn:org.metaborg:platform] | [![Snapshot][mvn-snap-badge:org.metaborg:platform]][mvn:org.metaborg:platform] | +| Gradle Plugin | Latest Release | Latest Snapshot | +|---------------|----------------|-----------------| +| `org.metaborg.convention.settings` | [![Release][mvn-rel-badge:org.metaborg.convention.settings:org.metaborg.convention.settings.gradle.plugin]][mvn:org.metaborg.convention.settings:org.metaborg.convention.settings.gradle.plugin] | [![Snapshot][mvn-snap-badge:org.metaborg.convention.settings:org.metaborg.convention.settings.gradle.plugin]][mvn:org.metaborg.convention.settings:org.metaborg.convention.settings.gradle.plugin] | +| `org.metaborg.convention.java` | [![Release][mvn-rel-badge:org.metaborg.convention.java:org.metaborg.convention.java.gradle.plugin]][mvn:org.metaborg.convention.java:org.metaborg.convention.java.gradle.plugin] | [![Snapshot][mvn-snap-badge:org.metaborg.convention.java:org.metaborg.convention.java.gradle.plugin]][mvn:org.metaborg.convention.java:org.metaborg.convention.java.gradle.plugin] | +| `org.metaborg.convention.maven-publish` | [![Release][mvn-rel-badge:org.metaborg.convention.maven-publish:org.metaborg.convention.maven-publish.gradle.plugin]][mvn:org.metaborg.convention.maven-publish:org.metaborg.convention.maven-publish.gradle.plugin] | [![Snapshot][mvn-snap-badge:org.metaborg.convention.maven-publish:org.metaborg.convention.maven-publish.gradle.plugin]][mvn:org.metaborg.convention.maven-publish:org.metaborg.convention.maven-publish.gradle.plugin] | +| `org.metaborg.convention.root-project` | [![Release][mvn-rel-badge:org.metaborg.convention.root-project:org.metaborg.convention.root-project.gradle.plugin]][mvn:org.metaborg.convention.root-project:org.metaborg.convention.root-project.gradle.plugin] | [![Snapshot][mvn-snap-badge:org.metaborg.convention.root-project:org.metaborg.convention.root-project.gradle.plugin]][mvn:org.metaborg.convention.root-project:org.metaborg.convention.root-project.gradle.plugin] | ## License Copyright 2024 [Programming Languages Group](https://pl.ewi.tudelft.nl/), [Delft University of Technology](https://www.tudelft.nl/) @@ -47,41 +29,31 @@ Licensed under the Apache License, Version 2.0 (the "License"); you may not use Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an **"as is" basis, without warranties or conditions of any kind**, either express or implied. See the License for the specific language governing permissions and limitations under the License. - - [github-badge:build]: https://img.shields.io/github/actions/workflow/status/metaborg/metaborg-gradle/build.yaml [github:build]: https://github.com/metaborg/metaborg-gradle/actions [license-badge]: https://img.shields.io/github/license/metaborg/metaborg-gradle -[license]: https://github.com/metaborg/metaborg-gradle/blob/main/LICENSE +[license]: https://github.com/metaborg/metaborg-gradle/blob/main/LICENSE.md [github-badge:release]: https://img.shields.io/github/v/release/metaborg/metaborg-gradle?display_name=release [github:release]: https://github.com/metaborg/metaborg-gradle/releases [documentation-badge]: https://img.shields.io/badge/docs-latest-brightgreen [documentation]: https://spoofax.dev/metaborg-gradle/ [documentation-button]: https://img.shields.io/badge/Documentation-blue?style=for-the-badge&logo=googledocs&logoColor=white -[mvn:convention.settings]: https://artifacts.metaborg.org/#nexus-search;gav~org.metaborg.convention.settings~org.metaborg.convention.settings.gradle.plugin~~~ -[mvn:convention.java]: https://artifacts.metaborg.org/#nexus-search;gav~org.metaborg.convention.java~org.metaborg.convention.java.gradle.plugin~~~ -[mvn:convention.maven-publish]: https://artifacts.metaborg.org/#nexus-search;gav~org.metaborg.convention.maven-publish~org.metaborg.convention.maven-publish.gradle.plugin~~~ -[mvn:convention.root-project]: https://artifacts.metaborg.org/#nexus-search;gav~org.metaborg.convention.root-project~org.metaborg.convention.root-project.gradle.plugin~~~ -[mvn:catalog]: https://artifacts.metaborg.org/#nexus-search;gav~org.metaborg~catalog~~~ -[mvn:platform]: https://artifacts.metaborg.org/#nexus-search;gav~org.metaborg~platform~~~ -[mvn:platform-latest]: https://artifacts.metaborg.org/#nexus-search;gav~org.metaborg~platform-latest~~~ -[mvn:platform-snapshot]: https://artifacts.metaborg.org/#nexus-search;gav~org.metaborg~platform-snapshot~~~ - -[mvn-rel-badge:convention.settings]: https://img.shields.io/nexus/r/org.metaborg.convention.settings/org.metaborg.convention.settings.gradle.plugin?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 -[mvn-rel-badge:convention.java]: https://img.shields.io/nexus/r/org.metaborg.convention.java/org.metaborg.convention.java.gradle.plugin?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 -[mvn-rel-badge:convention.maven-publish]: https://img.shields.io/nexus/r/org.metaborg.convention.maven-publish/org.metaborg.convention.maven-publish.gradle.plugin?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 -[mvn-rel-badge:convention.root-project]: https://img.shields.io/nexus/r/org.metaborg.convention.root-project/org.metaborg.convention.root-project.gradle.plugin?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 -[mvn-rel-badge:catalog]: https://img.shields.io/nexus/r/org.metaborg/catalog?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 -[mvn-rel-badge:platform]: https://img.shields.io/nexus/r/org.metaborg/platform?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 -[mvn-rel-badge:platform-latest]: https://img.shields.io/nexus/r/org.metaborg/platform-latest?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 -[mvn-rel-badge:platform-snapshot]: https://img.shields.io/nexus/r/org.metaborg/platform-snapshot?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 - -[mvn-snap-badge:convention.settings]: https://img.shields.io/nexus/s/org.metaborg.convention.settings/org.metaborg.convention.settings.gradle.plugin?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 -[mvn-snap-badge:convention.java]: https://img.shields.io/nexus/s/org.metaborg.convention.java/org.metaborg.convention.java.gradle.plugin?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 -[mvn-snap-badge:convention.maven-publish]: https://img.shields.io/nexus/s/org.metaborg.convention.maven-publish/org.metaborg.convention.maven-publish.gradle.plugin?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 -[mvn-snap-badge:convention.root-project]: https://img.shields.io/nexus/s/org.metaborg.convention.root-project/org.metaborg.convention.root-project.gradle.plugin?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 -[mvn-snap-badge:catalog]: https://img.shields.io/nexus/s/org.metaborg/catalog?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 -[mvn-snap-badge:platform]: https://img.shields.io/nexus/s/org.metaborg/platform?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 -[mvn-snap-badge:platform-latest]: https://img.shields.io/nexus/s/org.metaborg/platform-latest?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 -[mvn-snap-badge:platform-snapshot]: https://img.shields.io/nexus/s/org.metaborg/platform-snapshot?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 +[mvn:org.metaborg:catalog]: https://artifacts.metaborg.org/#nexus-search;gav~org.metaborg~catalog~~~ +[mvn-rel-badge:org.metaborg:catalog]: https://img.shields.io/nexus/r/org.metaborg/catalog?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 +[mvn-snap-badge:org.metaborg:catalog]: https://img.shields.io/nexus/s/org.metaborg/catalog?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 +[mvn:org.metaborg:platform]: https://artifacts.metaborg.org/#nexus-search;gav~org.metaborg~platform~~~ +[mvn-rel-badge:org.metaborg:platform]: https://img.shields.io/nexus/r/org.metaborg/platform?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 +[mvn-snap-badge:org.metaborg:platform]: https://img.shields.io/nexus/s/org.metaborg/platform?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 +[mvn:org.metaborg.convention.settings:org.metaborg.convention.settings.gradle.plugin]: https://artifacts.metaborg.org/#nexus-search;gav~org.metaborg.convention.settings~org.metaborg.convention.settings.gradle.plugin~~~ +[mvn-rel-badge:org.metaborg.convention.settings:org.metaborg.convention.settings.gradle.plugin]: https://img.shields.io/nexus/r/org.metaborg.convention.settings/org.metaborg.convention.settings.gradle.plugin?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 +[mvn-snap-badge:org.metaborg.convention.settings:org.metaborg.convention.settings.gradle.plugin]: https://img.shields.io/nexus/s/org.metaborg.convention.settings/org.metaborg.convention.settings.gradle.plugin?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 +[mvn:org.metaborg.convention.java:org.metaborg.convention.java.gradle.plugin]: https://artifacts.metaborg.org/#nexus-search;gav~org.metaborg.convention.java~org.metaborg.convention.java.gradle.plugin~~~ +[mvn-rel-badge:org.metaborg.convention.java:org.metaborg.convention.java.gradle.plugin]: https://img.shields.io/nexus/r/org.metaborg.convention.java/org.metaborg.convention.java.gradle.plugin?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 +[mvn-snap-badge:org.metaborg.convention.java:org.metaborg.convention.java.gradle.plugin]: https://img.shields.io/nexus/s/org.metaborg.convention.java/org.metaborg.convention.java.gradle.plugin?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 +[mvn:org.metaborg.convention.maven-publish:org.metaborg.convention.maven-publish.gradle.plugin]: https://artifacts.metaborg.org/#nexus-search;gav~org.metaborg.convention.maven-publish~org.metaborg.convention.maven-publish.gradle.plugin~~~ +[mvn-rel-badge:org.metaborg.convention.maven-publish:org.metaborg.convention.maven-publish.gradle.plugin]: https://img.shields.io/nexus/r/org.metaborg.convention.maven-publish/org.metaborg.convention.maven-publish.gradle.plugin?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 +[mvn-snap-badge:org.metaborg.convention.maven-publish:org.metaborg.convention.maven-publish.gradle.plugin]: https://img.shields.io/nexus/s/org.metaborg.convention.maven-publish/org.metaborg.convention.maven-publish.gradle.plugin?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 +[mvn:org.metaborg.convention.root-project:org.metaborg.convention.root-project.gradle.plugin]: https://artifacts.metaborg.org/#nexus-search;gav~org.metaborg.convention.root-project~org.metaborg.convention.root-project.gradle.plugin~~~ +[mvn-rel-badge:org.metaborg.convention.root-project:org.metaborg.convention.root-project.gradle.plugin]: https://img.shields.io/nexus/r/org.metaborg.convention.root-project/org.metaborg.convention.root-project.gradle.plugin?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 +[mvn-snap-badge:org.metaborg.convention.root-project:org.metaborg.convention.root-project.gradle.plugin]: https://img.shields.io/nexus/s/org.metaborg.convention.root-project/org.metaborg.convention.root-project.gradle.plugin?server=https%3A%2F%2Fartifacts.metaborg.org&label=%20 From 1b93705aec8b5dd164c4217c196505dd1f3b80ac Mon Sep 17 00:00:00 2001 From: "Daniel A. A. Pelsmaeker" Date: Fri, 26 Jul 2024 11:26:17 +0200 Subject: [PATCH 6/7] Generate Gradle wrapper --- .gitignore | 3 +- repo.yaml | 6 + .../org/metaborg/repoman/GenerateCommand.kt | 143 ++++++++++++++++-- .../org/metaborg/repoman/meta/RepoMetadata.kt | 69 +++++++-- .../resources/templates/build.gradle.kts.kte | 56 +++++++ .../templates/github/workflows/build.yaml.kte | 51 +++++++ .../github/workflows/documentation.yaml.kte | 14 ++ .../{.gitignore.kte => gitignore.kte} | 9 +- .../templates/settings.gradle.kts.kte | 38 +++++ 9 files changed, 356 insertions(+), 33 deletions(-) create mode 100644 repoman/src/main/resources/templates/build.gradle.kts.kte create mode 100644 repoman/src/main/resources/templates/github/workflows/build.yaml.kte create mode 100644 repoman/src/main/resources/templates/github/workflows/documentation.yaml.kte rename repoman/src/main/resources/templates/{.gitignore.kte => gitignore.kte} (80%) create mode 100644 repoman/src/main/resources/templates/settings.gradle.kts.kte diff --git a/.gitignore b/.gitignore index 1f314c7..c3b0106 100644 --- a/.gitignore +++ b/.gitignore @@ -68,4 +68,5 @@ local.properties .cache .DS_Store *.lock -jte-classes/ \ No newline at end of file +jte-classes/ + diff --git a/repo.yaml b/repo.yaml index 64b39cd..eadb382 100644 --- a/repo.yaml +++ b/repo.yaml @@ -16,6 +16,7 @@ libraries: - group: "org.metaborg" name: "platform" description: "Spoofax platform" + plugins: - id: "org.metaborg.convention.settings" description: "Settings convention plugin" @@ -30,3 +31,8 @@ developers: - id: "Virtlink" name: "Daniel A. A. Pelsmaeker" email: "developer@pelsmaeker.net" + +files: + githubWorkflows: + publishRelease: true + publishSnapshot: true \ No newline at end of file diff --git a/repoman/src/main/kotlin/org/metaborg/repoman/GenerateCommand.kt b/repoman/src/main/kotlin/org/metaborg/repoman/GenerateCommand.kt index 2a96105..c6ca570 100644 --- a/repoman/src/main/kotlin/org/metaborg/repoman/GenerateCommand.kt +++ b/repoman/src/main/kotlin/org/metaborg/repoman/GenerateCommand.kt @@ -3,6 +3,8 @@ package org.metaborg.repoman import com.charleskorn.kaml.Yaml import com.charleskorn.kaml.decodeFromStream import com.github.ajalt.clikt.core.CliktCommand +import com.github.ajalt.clikt.parameters.options.default +import com.github.ajalt.clikt.parameters.options.flag import com.github.ajalt.clikt.parameters.options.option import com.github.ajalt.clikt.parameters.types.path import gg.jte.ContentType @@ -10,9 +12,9 @@ import gg.jte.TemplateEngine import gg.jte.output.FileOutput import gg.jte.resolve.ResourceCodeResolver import org.metaborg.repoman.meta.RepoMetadata +import java.io.IOException import java.nio.file.Path -import kotlin.io.path.exists -import kotlin.io.path.inputStream +import kotlin.io.path.* /** * Generates or updates the files in a repository, including: @@ -38,6 +40,15 @@ object GenerateCommand: CliktCommand( val repoDir: Path? by option("-r", "--repo", help = "The directory with the repository") .path(canBeFile = false, canBeDir = true, mustExist = true) + /** The Gradle binary to invoke. */ + val gradleBin: String? by option("--gradle-bin", help = "The Gradle binary to invoke") + .default("gradle") + + /** Whether to force updating files even if they exist. Use this to just update all files and manually + * use version control to sort out what to actually update. */ + val forceUpdate: Boolean by option("-f", "--force-update", help = "Force updating files even if they exist") + .flag(default = false) + override fun run() { val repoDir = repoDir ?: Path.of(System.getProperty("user.dir")) @@ -53,6 +64,9 @@ object GenerateCommand: CliktCommand( generator.generateCodeOfConduct() generator.generateChangelog() generator.generateGitignore() + generator.generateGradleWrapper() + generator.generateGradleRootProject() + generator.generateGithubWorkflows() println("Done!") } @@ -71,48 +85,147 @@ object GenerateCommand: CliktCommand( private val metadata: RepoMetadata, ) { fun generateReadme() { - generate("README.md", metadata.files.readme.generate, metadata.files.readme.update) + val generate = metadata.files.readme.generate + val update = metadata.files.readme.update || forceUpdate + generate("README.md", generate, update) } fun generateLicense() { - generate("LICENSE.md", metadata.files.license.generate, metadata.files.license.update) + val generate = metadata.files.license.generate + val update = metadata.files.license.update || forceUpdate + generate("LICENSE.md", generate, update) } fun generateContributing() { - generate("CONTRIBUTING.md", metadata.files.contributing.generate, metadata.files.contributing.update) + val generate = metadata.files.contributing.generate + val update = metadata.files.contributing.update || forceUpdate + generate("CONTRIBUTING.md", generate, update) } fun generateCodeOfConduct() { - generate("CODE_OF_CONDUCT.md", metadata.files.codeOfConduct.generate, metadata.files.codeOfConduct.update) + val generate = metadata.files.codeOfConduct.generate + val update = metadata.files.codeOfConduct.update || forceUpdate + generate("CODE_OF_CONDUCT.md", generate, update) } fun generateChangelog() { - generate("CHANGELOG.md", metadata.files.changelog.generate, metadata.files.changelog.update) + val generate = metadata.files.changelog.generate + val update = metadata.files.changelog.update || forceUpdate + generate("CHANGELOG.md", generate, update) } fun generateGitignore() { - generate(".gitignore", metadata.files.gitignore.generate, metadata.files.gitignore.update) + val generate = metadata.files.gitignore.generate + val update = metadata.files.gitignore.update || forceUpdate + generate("gitignore", generate, update, path = ".gitignore") + } + + fun generateGradleWrapper() { + val generate = metadata.files.gradleWrapper.generate + val update = metadata.files.gradleWrapper.update || forceUpdate + generateGradleWrapper(generate, update) } - fun generate(filename: String, generate: Boolean, update: Boolean) { - val outputFile = repoDir.resolve(filename) + fun generateGradleRootProject() { + val generate = metadata.files.gradleRootProject.generate + val update = metadata.files.gradleRootProject.update || forceUpdate + generate("settings.gradle.kts", generate, update) + generate("build.gradle.kts", generate, update) + } + + fun generateGithubWorkflows() { + val generate = metadata.files.githubWorkflows.generate + val update = metadata.files.githubWorkflows.update || forceUpdate + generate("github/workflows/build.yaml", generate, update, path = ".github/workflows/build.yaml") + if (metadata.files.githubWorkflows.buildDocs) { + generate("github/workflows/documentation.yaml", generate, update, path = ".github/workflows/documentation.yaml") + } + } + + private fun generate(templateName: String, generate: Boolean, update: Boolean, path: String = templateName) { + val outputFile = repoDir.resolve(path) val outputFileExisted = outputFile.exists() if (!outputFileExisted && !generate) { - println("$filename: Not generated") + println("$path: Not generated") return } else if (outputFileExisted && !update) { - println("$filename: Not updated") + println("$path: Not updated") return } FileOutput(outputFile).use { output -> - engine.render("$filename.kte", metadata, output) + engine.render("$templateName.kte", metadata, output) } if (!outputFileExisted) { - println("$filename: Generated") + println("$path: Generated") + } else { + println("$path: Updated") + } + } + + @OptIn(ExperimentalPathApi::class) + private fun generateGradleWrapper(generate: Boolean, update: Boolean) { + // We use the gradle/wrapper/gradle-wrapper.properties file to determine whether a Gradle wrapper + // is present and configured, as this is the file that might be customized by the user. The other + // files can safely be regenerated. + val gradleWrapperProperties = repoDir.resolve("gradle/wrapper/gradle-wrapper.properties") + val gradleWrapperPropertiesExisted = gradleWrapperProperties.exists() + if (!gradleWrapperPropertiesExisted && !generate) { + println("Gradle wrapper: Not generated") + return + } else if (gradleWrapperPropertiesExisted && !update) { + println("Gradle wrapper: Not updated") + return + } + + // Generate the wrapper in a temporary directory and copy it to the repository + val tmpDir = createTempDirectory() + val settingsFile = tmpDir.resolve("settings.gradle.kts") + settingsFile.createFile() + val processBuilder = ProcessBuilder().apply { + command( + gradleBin, + "wrapper", + "--gradle-version=${metadata.files.gradleWrapper.gradleVersion}", + "--distribution-type=${metadata.files.gradleWrapper.gradleDistributionType}", + "--quiet", + ) + directory(tmpDir.toFile()) + // Merge STDERR into STDOUT + redirectErrorStream(true) + } + try { + // THROWS: IOException, SecurityException, UnsupportedOperationException + val process = processBuilder.start() + // NOTE: We don't close streams that we didn't open. + val stdout = process.inputStream.bufferedReader().readText() + // THROWS: InterruptedException + val exitCode = process.waitFor() + if (exitCode != 0) throw IOException(stdout.trim()) + } catch (ex: IOException) { + println("Gradle wrapper: Failed to generate: ${ex.message}") + return + } catch (ex: SecurityException) { + println("Gradle wrapper: Failed to generate: ${ex.message}") + return + } catch (ex: UnsupportedOperationException) { + println("Gradle wrapper: Failed to generate: ${ex.message}") + return + } catch (ex: InterruptedException) { + println("Gradle wrapper: Failed to generate: ${ex.message}") + return + } + + // Remove the temporary Gradle settings file + settingsFile.deleteExisting() + // Copy the generated files back to the repository directory, overwriting what's there + tmpDir.copyToRecursively(repoDir, followLinks = false, overwrite = true) + + if (!gradleWrapperPropertiesExisted) { + println("Gradle wrapper: Generated") } else { - println("$filename: Updated") + println("Gradle wrapper: Updated") } } } diff --git a/repoman/src/main/kotlin/org/metaborg/repoman/meta/RepoMetadata.kt b/repoman/src/main/kotlin/org/metaborg/repoman/meta/RepoMetadata.kt index 3426502..69c3b5e 100644 --- a/repoman/src/main/kotlin/org/metaborg/repoman/meta/RepoMetadata.kt +++ b/repoman/src/main/kotlin/org/metaborg/repoman/meta/RepoMetadata.kt @@ -3,6 +3,15 @@ package org.metaborg.repoman.meta import kotlinx.serialization.Serializable import org.metaborg.repoman.Markdown +/** Default values. */ +object Defaults { + /** The default main branch in Gitonium. */ + const val MAIN_BRANCH = "main" + /** THe default release tag prefix in Gitonium. */ + const val RELEASE_TAG_PREFIX = "release-" +} + +/** Repository metadata. */ @Serializable data class RepoMetadata( /** The owner of the repo on GitHub. For example: `"metaborg"` */ @@ -10,7 +19,11 @@ data class RepoMetadata( /** The name of the repo on GitHub (required). For example: `"resource"` */ val repoName: String, /** The name of the main branch. For example: `"master"` */ - val mainBranch: String = "main", + val mainBranch: String = Defaults.MAIN_BRANCH, + /** The release tag prefix to use. For example: `"devenv-release/"` */ + val releaseTagPrefix: String = Defaults.RELEASE_TAG_PREFIX, + /** The default Maven group of the artifacts in the build. For example: `"org.metaborg.devenv"` */ + val mavenGroup: String = "org.metaborg", /** The title of the repo (required). For example: `"Metaborg Resource"` */ val title: String, @@ -56,8 +69,6 @@ data class Files( val gradleWrapper: GradleWrapper = GradleWrapper(), /** The metadata for the Gradle root project files. */ val gradleRootProject: GradleRootProject = GradleRootProject(), - /** The metadata for the documentation (not generated by default). */ - val docs: Docs = Docs(), /** The metadata for the GitHub workflows. */ val githubWorkflows: GithubWorkflows = GithubWorkflows(), ) @@ -116,6 +127,8 @@ data class Gitignore( val generate: Boolean = true, /** Whether to update the file. */ val update: Boolean = true, + /** Extra entries to include at the bottom of the .gitignore file; or `null`. */ + val extra: String? = null, ) /** Metadata for the .gradlew files. */ @@ -127,6 +140,8 @@ data class GradleWrapper( val update: Boolean = true, /** The version of the Gradle wrapper to generate. */ val gradleVersion: String = "7.6.4", + /** The kind of Gradle distribution type to use, either `"bin"` or `"all"`. */ + val gradleDistributionType: String = "bin", ) /** Metadata for the Gradle root project files. */ @@ -135,33 +150,36 @@ data class GradleRootProject( /** Whether to generate the files. */ val generate: Boolean = true, /** Whether to update the file. */ - val update: Boolean = true, + val update: Boolean = false, + /** The name of the root project. */ + val rootProjectName: String? = null, + /** Included builds. */ + val includedBuilds: List = emptyList(), + /** Included projects. */ + val includedProjects: List = emptyList(), /** The version of the Metaborg Gradle convention to use. */ val conventionVersion: String = "latest.integration", /** Whether to create `publish` tasks that delegate to the included builds and subprojects. */ val createPublishTasks: Boolean = false, ) -/** Metadata for the MkDocs documentation files. */ -@Serializable -data class Docs( - /** Whether to generate the files. */ - val generate: Boolean = true, - /** Whether to update the file. */ - val update: Boolean = false, -) - /** Metadata for the GitHub workflows. */ @Serializable data class GithubWorkflows( /** Whether to generate the files. */ - val generate: Boolean = false, + val generate: Boolean = true, /** Whether to update the file. */ val update: Boolean = true, /** Whether to publish releases using GitHub CI (instead of Jenkins or something else). */ - val releaseOnGitHub: Boolean = false, + val publishRelease: Boolean = false, /** Whether to publish snapshots using GitHub CI. */ - val snapshotOnGitHub: Boolean = false, + val publishSnapshot: Boolean = false, + /** The Gradle `:build` task to use. */ + val buildTask: String = "build", // NOTE: No `:` prefix to allow Gradle to figure it out itself. + /** The Gradle `:publish` task to use. */ + val publishTask: String = "publish", // NOTE: No `:` prefix to allow Gradle to figure it out itself. + /** The Gradle `:printVersion` task to use. */ + val printVersionTask: String = ":printVersion", /** Whether to build and publish the documentation using GitHub CI. */ val buildDocs: Boolean = false, ) @@ -186,6 +204,7 @@ data class GradlePlugin( val description: Markdown? = null, ) +/** A developer. */ @Serializable data class Developer( /** The ID of the developer, usually their GitHub nickname. */ @@ -194,4 +213,22 @@ data class Developer( val name: String, /** The e-mail address of the developer. */ val email: String, +) + +/** An included build. */ +@Serializable +data class IncludedBuild( + /** The name of the included build; or `null` to use the default. */ + val name: String? = null, + /** The path to the included build. */ + val path: String, +) + +/** An included project. */ +@Serializable +data class IncludedProject( + /** The name of the included project. */ + val name: String, + /** The path to the included project; or `null` to use the default. */ + val path: String? = null, ) \ No newline at end of file diff --git a/repoman/src/main/resources/templates/build.gradle.kts.kte b/repoman/src/main/resources/templates/build.gradle.kts.kte new file mode 100644 index 0000000..7ed0f40 --- /dev/null +++ b/repoman/src/main/resources/templates/build.gradle.kts.kte @@ -0,0 +1,56 @@ +@import org.metaborg.repoman.meta.Defaults +@import org.metaborg.repoman.meta.RepoMetadata +@param meta: RepoMetadata +import org.metaborg.convention.Developer +import org.metaborg.convention.MavenPublishConventionExtension + +// Workaround for issue: https://youtrack.jetbrains.com/issue/KTIJ-19369 +@Suppress("DSL_SCOPE_VIOLATION") +plugins { + id("org.metaborg.convention.root-project") + alias(libs.plugins.gitonium) +} + +@if(meta.files.gradleRootProject.createPublishTasks) +rootProjectConvention { + // Add `publishAll` and `publish` tasks that delegate to the subprojects and included builds. + registerPublishTasks.set(true) +} +@endif + +allprojects { + apply(plugin = "org.metaborg.gitonium") + +@if(meta.mainBranch != Defaults.MAIN_BRANCH || meta.releaseTagPrefix != Defaults.RELEASE_TAG_PREFIX) + // Configure Gitonium before setting the version + gitonium { + @if(meta.mainBranch != Defaults.MAIN_BRANCH) + mainBranch.set("${meta.mainBranch}") + @endif + @if(meta.releaseTagPrefix != Defaults.RELEASE_TAG_PREFIX) + tagPrefix.set("${meta.releaseTagPrefix}") + @endif + } +@endif + + version = gitonium.version + group = "${meta.mavenGroup}" + + pluginManager.withPlugin("org.metaborg.convention.maven-publish") { + extensions.configure(MavenPublishConventionExtension::class.java) { + repoOwner.set("${meta.repoOwner}") + repoName.set("${meta.repoName}") + + metadata { + inceptionYear.set("${meta.inceptionYear}") +@if(meta.developers.isNotEmpty()) + developers.set(listOf( + @for(entry in meta.developers) + Developer("${entry.id}", "${entry.name}", "${entry.email}"), + @endfor + )) +@endif + } + } + } +} diff --git a/repoman/src/main/resources/templates/github/workflows/build.yaml.kte b/repoman/src/main/resources/templates/github/workflows/build.yaml.kte new file mode 100644 index 0000000..59229fe --- /dev/null +++ b/repoman/src/main/resources/templates/github/workflows/build.yaml.kte @@ -0,0 +1,51 @@ +@import org.metaborg.repoman.meta.RepoMetadata +@param meta: RepoMetadata +--- +name: 'Build & Publish' + +on: # yamllint disable-line rule:truthy + push: + pull_request: + branches: + - ${meta.mainBranch} + +jobs: + build: + uses: metaborg/actions/.github/workflows/gradle-build-matrix.yaml@main + with: + gradle-command: | + gradle ${meta.files.githubWorkflows.buildTask} +@if(meta.files.githubWorkflows.publishSnapshot) + + publish-snapshot: + uses: metaborg/actions/.github/workflows/gradle-publish.yaml@main + with: + gradle-command: | + gradle ${meta.files.githubWorkflows.publishTask} -Pgitonium.isSnapshot=true + gradle-version-command: | + gradle -q ${meta.files.githubWorkflows.printVersionTask} -Pgitonium.isSnapshot=true + if: "github.event_name == 'push' && github.ref == 'refs/heads/${meta.mainBranch}'" + needs: [build] + secrets: + @raw + METABORG_ARTIFACTS_USERNAME: ${{ secrets.METABORG_ARTIFACTS_USERNAME }} + METABORG_ARTIFACTS_PASSWORD: ${{ secrets.METABORG_ARTIFACTS_PASSWORD }} + @endraw +@endif +@if(meta.files.githubWorkflows.publishRelease) + + publish-release: + uses: metaborg/actions/.github/workflows/gradle-publish.yaml@main + with: + gradle-command: | + gradle ${meta.files.githubWorkflows.publishTask} + gradle-version-command: | + gradle -q ${meta.files.githubWorkflows.printVersionTask} + if: "github.event_name == 'push' && startsWith(github.ref, 'refs/tags/${meta.releaseTagPrefix}')" + needs: [build] + secrets: + @raw + METABORG_ARTIFACTS_USERNAME: ${{ secrets.METABORG_ARTIFACTS_USERNAME }} + METABORG_ARTIFACTS_PASSWORD: ${{ secrets.METABORG_ARTIFACTS_PASSWORD }} + @endraw +@endif \ No newline at end of file diff --git a/repoman/src/main/resources/templates/github/workflows/documentation.yaml.kte b/repoman/src/main/resources/templates/github/workflows/documentation.yaml.kte new file mode 100644 index 0000000..cda4fba --- /dev/null +++ b/repoman/src/main/resources/templates/github/workflows/documentation.yaml.kte @@ -0,0 +1,14 @@ +@import org.metaborg.repoman.meta.RepoMetadata +@param meta: RepoMetadata +--- +name: 'Documentation' + +on: # yamllint disable-line rule:truthy + push: + branches: + - ${meta.mainBranch} + workflow_dispatch: {} # Allow running this workflow manually (Actions tab) + +jobs: + documentation: + uses: metaborg/actions/.github/workflows/mkdocs-material.yaml@main diff --git a/repoman/src/main/resources/templates/.gitignore.kte b/repoman/src/main/resources/templates/gitignore.kte similarity index 80% rename from repoman/src/main/resources/templates/.gitignore.kte rename to repoman/src/main/resources/templates/gitignore.kte index 1f314c7..76d70b9 100644 --- a/repoman/src/main/resources/templates/.gitignore.kte +++ b/repoman/src/main/resources/templates/gitignore.kte @@ -1,3 +1,5 @@ +@import org.metaborg.repoman.meta.RepoMetadata +@param meta: RepoMetadata # Java *.class *.log @@ -68,4 +70,9 @@ local.properties .cache .DS_Store *.lock -jte-classes/ \ No newline at end of file +jte-classes/ + +@if(meta.files.gitignore.extra != null) +# Extra +${meta.files.gitignore.extra} +@endif \ No newline at end of file diff --git a/repoman/src/main/resources/templates/settings.gradle.kts.kte b/repoman/src/main/resources/templates/settings.gradle.kts.kte new file mode 100644 index 0000000..5920185 --- /dev/null +++ b/repoman/src/main/resources/templates/settings.gradle.kts.kte @@ -0,0 +1,38 @@ +@import org.metaborg.repoman.meta.RepoMetadata +@param meta: RepoMetadata +dependencyResolutionManagement { + repositories { + maven("https://artifacts.metaborg.org/content/groups/public/") + mavenCentral() + } +} + +pluginManagement { + repositories { + maven("https://artifacts.metaborg.org/content/groups/public/") + gradlePluginPortal() + } +} + +plugins { + id("org.metaborg.convention.settings") version "${meta.files.gradleRootProject.conventionVersion}" +} + +@if(meta.files.gradleRootProject.rootProjectName != null) +rootProject.name = "${meta.files.gradleRootProject.rootProjectName}" +@endif + +@for(entry in meta.files.gradleRootProject.includedProjects) +include(":${entry.name}") + @if(entry.path != null) +project(":${entry.name}").projectDir = file("${entry.path}") + @endif +@endfor + +@for(entry in meta.files.gradleRootProject.includedBuilds) + @if(entry.name != null) +includeBuild("${entry.path}") { name = "${entry.name}" } + @else +includeBuild("${entry.path}") + @endif +@endfor \ No newline at end of file From 15f9e04399c4f75cb7a2fb1075ffd86dfbdbeb33 Mon Sep 17 00:00:00 2001 From: "Daniel A. A. Pelsmaeker" Date: Fri, 26 Jul 2024 15:50:14 +0200 Subject: [PATCH 7/7] Fix github build workflow --- .github/workflows/build.yaml | 10 +++++++--- repo.yaml | 3 ++- .../templates/github/workflows/build.yaml.kte | 16 ++++++---------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 497d2e5..5c33c26 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -10,11 +10,15 @@ on: # yamllint disable-line rule:truthy jobs: build: uses: metaborg/actions/.github/workflows/gradle-build-matrix.yaml@main + with: + gradle-command: | + gradle build +# Publish snapshots publish-snapshot: uses: metaborg/actions/.github/workflows/gradle-publish.yaml@main with: gradle-command: | - gradle :publish -Pgitonium.isSnapshot=true + gradle publish -Pgitonium.isSnapshot=true gradle-version-command: | gradle -q :convention-plugin:printVersion -Pgitonium.isSnapshot=true if: "github.event_name == 'push' && github.ref == 'refs/heads/main'" @@ -22,11 +26,12 @@ jobs: secrets: METABORG_ARTIFACTS_USERNAME: ${{ secrets.METABORG_ARTIFACTS_USERNAME }} METABORG_ARTIFACTS_PASSWORD: ${{ secrets.METABORG_ARTIFACTS_PASSWORD }} +# Publish releases publish-release: uses: metaborg/actions/.github/workflows/gradle-publish.yaml@main with: gradle-command: | - gradle :publish + gradle publish gradle-version-command: | gradle -q :convention-plugin:printVersion if: "github.event_name == 'push' && startsWith(github.ref, 'refs/tags/release-')" @@ -34,4 +39,3 @@ jobs: secrets: METABORG_ARTIFACTS_USERNAME: ${{ secrets.METABORG_ARTIFACTS_USERNAME }} METABORG_ARTIFACTS_PASSWORD: ${{ secrets.METABORG_ARTIFACTS_PASSWORD }} - diff --git a/repo.yaml b/repo.yaml index eadb382..9b41cf5 100644 --- a/repo.yaml +++ b/repo.yaml @@ -35,4 +35,5 @@ developers: files: githubWorkflows: publishRelease: true - publishSnapshot: true \ No newline at end of file + publishSnapshot: true + printVersionTask: ":convention-plugin:printVersion" \ No newline at end of file diff --git a/repoman/src/main/resources/templates/github/workflows/build.yaml.kte b/repoman/src/main/resources/templates/github/workflows/build.yaml.kte index 59229fe..030c5a5 100644 --- a/repoman/src/main/resources/templates/github/workflows/build.yaml.kte +++ b/repoman/src/main/resources/templates/github/workflows/build.yaml.kte @@ -16,7 +16,7 @@ jobs: gradle-command: | gradle ${meta.files.githubWorkflows.buildTask} @if(meta.files.githubWorkflows.publishSnapshot) - +# Publish snapshots publish-snapshot: uses: metaborg/actions/.github/workflows/gradle-publish.yaml@main with: @@ -27,13 +27,11 @@ jobs: if: "github.event_name == 'push' && github.ref == 'refs/heads/${meta.mainBranch}'" needs: [build] secrets: - @raw - METABORG_ARTIFACTS_USERNAME: ${{ secrets.METABORG_ARTIFACTS_USERNAME }} - METABORG_ARTIFACTS_PASSWORD: ${{ secrets.METABORG_ARTIFACTS_PASSWORD }} - @endraw + METABORG_ARTIFACTS_USERNAME: ${'$'}{{ secrets.METABORG_ARTIFACTS_USERNAME }} + METABORG_ARTIFACTS_PASSWORD: ${'$'}{{ secrets.METABORG_ARTIFACTS_PASSWORD }} @endif @if(meta.files.githubWorkflows.publishRelease) - +# Publish releases publish-release: uses: metaborg/actions/.github/workflows/gradle-publish.yaml@main with: @@ -44,8 +42,6 @@ jobs: if: "github.event_name == 'push' && startsWith(github.ref, 'refs/tags/${meta.releaseTagPrefix}')" needs: [build] secrets: - @raw - METABORG_ARTIFACTS_USERNAME: ${{ secrets.METABORG_ARTIFACTS_USERNAME }} - METABORG_ARTIFACTS_PASSWORD: ${{ secrets.METABORG_ARTIFACTS_PASSWORD }} - @endraw + METABORG_ARTIFACTS_USERNAME: ${'$'}{{ secrets.METABORG_ARTIFACTS_USERNAME }} + METABORG_ARTIFACTS_PASSWORD: ${'$'}{{ secrets.METABORG_ARTIFACTS_PASSWORD }} @endif \ No newline at end of file