diff --git a/README.md b/README.md
index e412cd17..eadf7d06 100644
--- a/README.md
+++ b/README.md
@@ -45,6 +45,7 @@ systems like Buck and Bazel.
2. [Sample app gold standard](docs/SAMPLE-APP.md) — multi-feature layout to copy
3. [Dependency matrix](docs/DEPENDENCY-MATRIX.md) — what may depend on what
4. [External deps catalogs](docs/DEPS-CATALOG.md) · [Compose](docs/COMPOSE.md) · [Environment](docs/ENV.md)
+5. [Plugin publish path](docs/PLUGIN-PUBLISH.md) — Portal metadata DSL + release notes (F-016)
Configuration made easy:
@@ -188,6 +189,8 @@ Sample multi-feature gold standard: **F-014**
([`docs/SAMPLE-APP.md`](docs/SAMPLE-APP.md)).
Android getting-started tutorial: **F-015**
([`docs/GETTING-STARTED.md`](docs/GETTING-STARTED.md)).
+Plugin Portal publish path: **F-016**
+([`docs/PLUGIN-PUBLISH.md`](docs/PLUGIN-PUBLISH.md)).
Icons made by Freepik
from www.flaticon.com
diff --git a/TICKETS.md b/TICKETS.md
index c40574b5..0b8538e6 100644
--- a/TICKETS.md
+++ b/TICKETS.md
@@ -23,7 +23,7 @@ Update this file when picking or finishing work. Cron workers must pick the **hi
| F-013 | done | Compose support for Android library/ui targets | GH #96; `compose` flags + `composeWidget`; `docs/COMPOSE.md` |
| F-014 | done | Sample app: gold-standard multi-feature structure | packageName + source-root alignment; `docs/SAMPLE-APP.md`; home/characters pattern |
| F-015 | done | Android project tutorial (getting started) | GH #53; `docs/GETTING-STARTED.md` + README entry |
-| F-016 | todo | Plugin publish path (Portal user + target publish config) | GH #132, #133 |
+| F-016 | done | Plugin publish path (Portal user + target publish config) | GH #132 done (`formaPluginConfiguration`/`formaPublishedPlugin`); GH #133 Portal org is human admin — see `docs/PLUGIN-PUBLISH.md` |
| F-017 | todo | Configuration-time performance pass | GH #106, #42 |
## P2 — forma-core extraction
diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md
index b93c331e..6292e251 100644
--- a/docs/ARCHITECTURE.md
+++ b/docs/ARCHITECTURE.md
@@ -105,6 +105,13 @@ compile dep and consumer `agpVersion` in lockstep.
`publishPlugins` on `:android` depends on publishing all sibling plugins.
+**Publish configuration (F-016 / GH #132):** shared metadata lives in
+`plugins/build.gradle.kts` via `formaPluginConfiguration { … }`
+(`plugins/buildSrc`). Each plugin module calls
+`formaPublishedPlugin(name = …)` instead of copying `rootProject.ext` +
+`gradlePlugin { }` blocks. Operator guide: [`docs/PLUGIN-PUBLISH.md`](PLUGIN-PUBLISH.md)
+(Portal org/credentials for GH #133 are human-owned; not stored in-repo).
+
### 2.1 Target templates (suffixes)
Defined in `plugins/android/.../AndroidTargets.kt`:
@@ -269,7 +276,8 @@ F-004 fixes applied (2026-07-11):
4. Gradle setup via `gradle/actions/setup-gradle@v4` (successor of `gradle-build-action`).
5. Dropped unconditional `--scan` (no build-scan account coupling in CI).
-Still optional / later: plugin publish or Plugin Marker validation job; deeper Gradle remote cache.
+Still optional / later: CI job for `publishPlugins --validate-only` (needs no
+keys) or full Portal publish via secrets; deeper Gradle remote cache.
---
@@ -326,7 +334,7 @@ Suggested extraction order (tickets F-020…F-024):
| ~~Compose flag in settings, limited target support~~ → per-target flags + `composeWidget` | F-013 done |
| ~~Missing Android getting-started tutorial~~ → [`docs/GETTING-STARTED.md`](GETTING-STARTED.md) | F-015 done |
| Shared `library` suffix for JVM vs Android library | F-020 |
-| Plugin publish / Portal path | F-016 |
+| Plugin publish / Portal path | F-016 (`docs/PLUGIN-PUBLISH.md`; Portal org GH #133 is human) |
| Configuration-time cost (includer walk, stores) | F-017 |
---
diff --git a/docs/PLUGIN-PUBLISH.md b/docs/PLUGIN-PUBLISH.md
new file mode 100644
index 00000000..cbb0cd5d
--- /dev/null
+++ b/docs/PLUGIN-PUBLISH.md
@@ -0,0 +1,152 @@
+# Publishing Forma plugins (F-016)
+
+How Forma itself is published to the **Gradle Plugin Portal**, and how the
+in-repo publish DSL is structured (GH #132). Creating the shared Portal
+organization account (GH #133) is a human/admin step — this doc records the
+expected ownership model and credential flow so workers do not invent secrets.
+
+## What gets published
+
+| Project | Plugin id | Notes |
+|---------|-----------|--------|
+| `plugins/:android` | `tools.forma.android` | Main product entrypoint |
+| `plugins/:target` | `tools.forma.target` | Target identity |
+| `plugins/:validation` | `tools.forma.validation` | Validators |
+| `plugins/:owners` | `tools.forma.owners` | Ownership metadata |
+| `plugins/:config` | `tools.forma.config` | Settings store |
+| `plugins/:deps` | `tools.forma.deps` | Dep model + catalogs |
+| `includer/` | `tools.forma.includer` | Separate build (own version) |
+| `depgen/` | `tools.forma.depgen` | Separate build |
+
+Current shared version for the `plugins/` multi-project: **`0.1.3`**
+(see `formaPluginConfiguration` in `plugins/build.gradle.kts`).
+
+`:android`’s `publishPlugins` task depends on sibling `publishPlugins` so a
+single `:android:publishPlugins` publishes the whole set.
+
+## Forma-style publish configuration (GH #132)
+
+Duplicated `rootProject.ext[…]` + per-module `gradlePlugin { … }` blocks are
+replaced by two helpers from `plugins/buildSrc`:
+
+### 1. Root: `formaPluginConfiguration { … }`
+
+```kotlin
+// plugins/build.gradle.kts
+formaPluginConfiguration {
+ group = "tools.forma"
+ version = "0.1.3"
+ website = "https://forma.tools/"
+ vcsUrl = "https://github.com/formatools/forma.git"
+ displayName = "Forma - Meta Build System with Gradle and Android support"
+ description = "Best way to structure your Gradle Project"
+ tags = listOf("kotlin", "android", "structure", "target", "rules", "project")
+}
+```
+
+### 2. Subproject: `formaPublishedPlugin(…)`
+
+```kotlin
+// plugins/android/build.gradle.kts (and target, validation, …)
+plugins {
+ id("com.gradle.plugin-publish")
+ // + kotlin-dsl or kotlin("jvm") as needed
+}
+
+formaPublishedPlugin(
+ name = "android",
+ // optional overrides:
+ // description = "…",
+ // extraTags = listOf("agp"),
+ // implementationClass = "tools.forma.android.plugin.FormaPlugin",
+)
+```
+
+Defaults (matching historical Portal metadata):
+
+| Field | Default |
+|-------|---------|
+| `id` | `{group}.{name}` → e.g. `tools.forma.android` |
+| `implementationClass` | `{id}.plugin.FormaPlugin` |
+| `displayName` / `description` / `tags` | from root `formaPluginConfiguration` |
+| `website` / `vcsUrl` | from root config |
+| `group` / `version` | from root config |
+
+Helpers live in:
+
+- `plugins/buildSrc/src/main/kotlin/FormaPluginPublishExtension.kt`
+- `plugins/buildSrc/src/main/kotlin/formaPluginPublish.kt`
+
+`includer` and `depgen` keep standalone `gradlePlugin { … }` blocks for now
+(different versions / release cadence). They can adopt the same helpers later
+if those builds are folded into a shared convention.
+
+## Portal user / credentials (GH #133)
+
+**Goal:** publish under a shared **Forma** Plugin Portal identity so the team
+is not tied to a single personal Gradle account.
+
+| Item | Status / expectation |
+|------|----------------------|
+| Portal account / org for Forma | **Human action** — create/claim on [plugins.gradle.org](https://plugins.gradle.org/) (not automatable without owner login) |
+| Plugin ownership transfer | Existing `tools.forma.*` plugins may need transfer from the historical personal publisher to the Forma org (Portal UI) |
+| Local publish keys | `~/.gradle/gradle.properties` (never commit): `gradle.publish.key`, `gradle.publish.secret` |
+| CI publish | Optional later: GitHub Actions secrets + a `workflow_dispatch` publish job — **not** enabled by default |
+
+Do **not** store Portal keys in the repo, in cron env files, or in
+`docs/PROGRESS.md`. Workers may validate packaging without credentials
+(see below).
+
+### Operator checklist (human)
+
+1. Create or claim the Forma Plugin Portal user/org (GH #133).
+2. Generate a publish key pair for that identity.
+3. Transfer or re-publish `tools.forma.android` (and siblings) under that
+ identity as needed.
+4. Distribute keys to trusted maintainers via password manager / CI secrets —
+ not git.
+5. Bump `formaPluginConfiguration.version` when cutting a release, then run
+ the publish command below.
+
+## Validate packaging (no credentials)
+
+From a machine with JDK 17+ (`source scripts/env-mac.sh` on the worker Mac):
+
+```bash
+cd plugins
+./gradlew build
+# Server-side + local descriptor validation without uploading (plugin-publish 1.x):
+./gradlew :android:publishPlugins --validate-only
+```
+
+`--validate-only` exercises plugin markers / metadata without requiring a
+successful upload. A full release still needs Portal credentials:
+
+```bash
+cd plugins
+./gradlew :android:publishPlugins
+```
+
+## Consumer coordinates
+
+Unchanged for apps:
+
+```kotlin
+plugins {
+ id("tools.forma.android") version "0.1.3"
+}
+```
+
+Badge / maven-metadata still point at the Plugin Portal
+(`tools.forma.android`). Composite include of `plugins/` remains the
+recommended path for Forma development (see
+[`docs/GETTING-STARTED.md`](GETTING-STARTED.md)).
+
+## Related tickets
+
+| ID | Scope |
+|----|--------|
+| F-016 | This doc + `formaPluginConfiguration` / `formaPublishedPlugin` |
+| GH #132 | Target-shaped publish config (implemented) |
+| GH #133 | Shared Portal user (admin; documented, not automated) |
+| F-024 | Coordinate plan when `forma-core` is extracted (`tools.forma:core` vs android plugins) |
diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md
index 33e5711d..1665b824 100644
--- a/docs/PROGRESS.md
+++ b/docs/PROGRESS.md
@@ -2,6 +2,37 @@
Newest entries first.
+## 2026-07-12 — F-016 Plugin publish path (Portal + target publish config)
+
+- **Ticket:** F-016 → `done` (GH #132 code path; GH #133 Portal org remains human admin)
+- **Branch:** `forma/F-016-plugin-publish` (from `origin/v2`)
+- **Code (`plugins/buildSrc` + plugin modules):**
+ - Added `FormaPluginPublishExtension` + top-level helpers:
+ - `formaPluginConfiguration { … }` on plugins root (group/version/website/vcs/tags/…)
+ - `formaPublishedPlugin(name = …)` on each publishable subproject
+ - Replaced duplicated `rootProject.ext` + `gradlePlugin { }` blocks in
+ `:android`, `:target`, `:validation`, `:owners`, `:config`, `:deps`
+ - Root `plugins/build.gradle.kts` now only applies plugin-publish version +
+ `formaPluginConfiguration` (no raw `ext { }` map)
+ - buildSrc depends on `gradleApi()` only (must not put plugin-publish on
+ buildSrc classpath — causes "already on the classpath with unknown version")
+- **Docs:**
+ - `docs/PLUGIN-PUBLISH.md` — DSL usage, validate-only, credential model,
+ GH #133 operator checklist (no secrets in-repo)
+ - README Getting started + Progress pointers; ARCHITECTURE §2 publish note;
+ TICKETS status
+- **Verify (real tool output, OpenJDK 17):**
+ - `plugins/`: `./gradlew build` → **BUILD SUCCESSFUL** (63 tasks)
+ - Plugin descriptors still `tools.forma.{android,target,validation,owners,config,deps}`
+ with `*.plugin.FormaPlugin`; group/version `tools.forma` / `0.1.3`
+ - `./gradlew :android:publishPlugins --validate-only` → fails only on
+ **Missing publishing keys** (expected without Portal credentials; packaging OK)
+ - `application/`: `./gradlew :binary:assembleDebug` → **BUILD SUCCESSFUL**
+- **Commits/PRs:** this run — push + PR base `v2`
+- **Blockers:** GH #133 (create/claim shared Forma Plugin Portal identity +
+ distribute keys) is outside automation
+- **Next step:** F-017 Configuration-time performance pass (GH #106, #42)
+
## 2026-07-12 — F-015 Android project tutorial (getting started)
- **Ticket:** F-015 → `done` (GH #53)
diff --git a/plugins/android/build.gradle.kts b/plugins/android/build.gradle.kts
index 635201ab..537fc667 100644
--- a/plugins/android/build.gradle.kts
+++ b/plugins/android/build.gradle.kts
@@ -7,23 +7,7 @@ plugins {
id("com.gradle.plugin-publish")
}
-group = rootProject.ext["group"] as String
-version = rootProject.ext["version"] as String
-
-gradlePlugin {
- website.set(rootProject.ext["website"] as String)
- vcsUrl.set(rootProject.ext["vcsUrl"] as String)
- plugins {
- create(name) {
- id = "$group.$name"
- displayName = rootProject.ext["displayName"] as String
- description = rootProject.ext["description"] as String
- implementationClass = "$id.plugin.FormaPlugin"
- @Suppress("UNCHECKED_CAST")
- tags.set(rootProject.ext["tags"] as List)
- }
- }
-}
+formaPublishedPlugin(name = "android")
tasks.named("compileKotlin", KotlinCompilationTask::class.java) {
compilerOptions {
diff --git a/plugins/build.gradle.kts b/plugins/build.gradle.kts
index 62511857..875700ce 100644
--- a/plugins/build.gradle.kts
+++ b/plugins/build.gradle.kts
@@ -3,16 +3,14 @@ plugins {
id("com.gradle.plugin-publish") version "1.2.1" apply false
}
-ext {
- set("group", "tools.forma")
- set("version", "0.1.3")
- set("tags", listOf("kotlin", "android", "structure", "target", "rules", "project"))
- set("website", "https://forma.tools/")
- set("vcsUrl", "https://github.com/formatools/forma.git")
- set("displayName", "Forma - Meta Build System with Gradle and Android support")
- set("description", "Best way to structure your Gradle Project")
+// Shared Plugin Portal metadata for all subprojects (F-016 / GH #132).
+// Subprojects call formaPublishedPlugin(name = …) instead of copying gradlePlugin blocks.
+formaPluginConfiguration {
+ group = "tools.forma"
+ version = "0.1.3"
+ website = "https://forma.tools/"
+ vcsUrl = "https://github.com/formatools/forma.git"
+ displayName = "Forma - Meta Build System with Gradle and Android support"
+ description = "Best way to structure your Gradle Project"
+ tags = listOf("kotlin", "android", "structure", "target", "rules", "project")
}
-
-group = ext["group"] as String
-
-version = ext["version"] as String
diff --git a/plugins/buildSrc/build.gradle.kts b/plugins/buildSrc/build.gradle.kts
new file mode 100644
index 00000000..e23ef42d
--- /dev/null
+++ b/plugins/buildSrc/build.gradle.kts
@@ -0,0 +1,15 @@
+plugins {
+ `kotlin-dsl`
+}
+
+repositories {
+ gradlePluginPortal()
+ mavenCentral()
+}
+
+dependencies {
+ // Only gradleApi — do NOT put com.gradle.plugin-publish on the buildSrc
+ // classpath or subprojects fail with "plugin is already on the classpath
+ // with an unknown version" when they apply the same plugin id.
+ implementation(gradleApi())
+}
diff --git a/plugins/buildSrc/src/main/kotlin/FormaPluginPublishExtension.kt b/plugins/buildSrc/src/main/kotlin/FormaPluginPublishExtension.kt
new file mode 100644
index 00000000..a0128d1a
--- /dev/null
+++ b/plugins/buildSrc/src/main/kotlin/FormaPluginPublishExtension.kt
@@ -0,0 +1,29 @@
+/**
+ * Shared metadata for publishing Forma Gradle plugins to the Plugin Portal.
+ *
+ * Configured once on the plugins root via [formaPluginConfiguration], then
+ * consumed by each subproject through [formaPublishedPlugin].
+ *
+ * See GH #132 / F-016 and docs/PLUGIN-PUBLISH.md.
+ */
+open class FormaPluginPublishExtension {
+ /** Maven group / plugin id prefix (e.g. `tools.forma`). */
+ var group: String = "tools.forma"
+
+ /** Shared artifact version for all Forma plugins in this build. */
+ var version: String = "0.0.0"
+
+ var website: String = "https://forma.tools/"
+ var vcsUrl: String = "https://github.com/formatools/forma.git"
+
+ /** Default Portal display name (subprojects may override). */
+ var displayName: String =
+ "Forma - Meta Build System with Gradle and Android support"
+
+ /** Default Portal description (subprojects may override). */
+ var description: String = "Best way to structure your Gradle Project"
+
+ /** Default Portal tags; subprojects may replace or append via extraTags. */
+ var tags: List =
+ listOf("kotlin", "android", "structure", "target", "rules", "project")
+}
diff --git a/plugins/buildSrc/src/main/kotlin/formaPluginPublish.kt b/plugins/buildSrc/src/main/kotlin/formaPluginPublish.kt
new file mode 100644
index 00000000..b026a27f
--- /dev/null
+++ b/plugins/buildSrc/src/main/kotlin/formaPluginPublish.kt
@@ -0,0 +1,104 @@
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.create
+import org.gradle.kotlin.dsl.extra
+import org.gradle.kotlin.dsl.getByType
+import org.gradle.plugin.devel.GradlePluginDevelopmentExtension
+
+private const val EXT_NAME = "formaPluginConfiguration"
+
+/**
+ * Root-level publish metadata for the Forma plugins multi-project.
+ *
+ * Example (`plugins/build.gradle.kts`):
+ * ```
+ * formaPluginConfiguration {
+ * group = "tools.forma"
+ * version = "0.1.3"
+ * website = "https://forma.tools/"
+ * vcsUrl = "https://github.com/formatools/forma.git"
+ * displayName = "Forma - Meta Build System with Gradle and Android support"
+ * description = "Best way to structure your Gradle Project"
+ * tags = listOf("kotlin", "android", "structure", "target", "rules", "project")
+ * }
+ * ```
+ */
+fun Project.formaPluginConfiguration(configure: FormaPluginPublishExtension.() -> Unit) {
+ require(this == rootProject) {
+ "formaPluginConfiguration must be called on the plugins root project"
+ }
+ val extension =
+ extensions.findByType(FormaPluginPublishExtension::class.java)
+ ?: extensions.create(EXT_NAME, FormaPluginPublishExtension::class.java)
+ extension.configure()
+ group = extension.group
+ version = extension.version
+ // Keep legacy ext keys for any residual consumers / debugging.
+ extra["group"] = extension.group
+ extra["version"] = extension.version
+ extra["website"] = extension.website
+ extra["vcsUrl"] = extension.vcsUrl
+ extra["displayName"] = extension.displayName
+ extra["description"] = extension.description
+ extra["tags"] = extension.tags
+}
+
+/**
+ * Registers this project as a published Gradle plugin using root
+ * [formaPluginConfiguration] defaults.
+ *
+ * Replaces the copy-pasted `gradlePlugin { … rootProject.ext[…] }` blocks
+ * (GH #132). Defaults match historical Forma Portal metadata:
+ * - plugin id: `{group}.{name}` (e.g. `tools.forma.android`)
+ * - implementation class: `{id}.plugin.FormaPlugin`
+ *
+ * Example (`plugins/android/build.gradle.kts`):
+ * ```
+ * formaPublishedPlugin(
+ * name = "android",
+ * // optional overrides:
+ * // description = "Android targets for Forma",
+ * // extraTags = listOf("agp"),
+ * )
+ * ```
+ *
+ * @param name short plugin name segment (usually the Gradle project name)
+ * @param id full plugin id; default `{group}.{name}`
+ * @param displayName Portal display name; default from root config
+ * @param description Portal description; default from root config
+ * @param implementationClass FQCN of the plugin implementation class
+ * @param tags full tag list replacement; default from root config
+ * @param extraTags tags appended after [tags] / root defaults
+ */
+fun Project.formaPublishedPlugin(
+ name: String = this.name,
+ id: String? = null,
+ displayName: String? = null,
+ description: String? = null,
+ implementationClass: String? = null,
+ tags: List? = null,
+ extraTags: List = emptyList(),
+) {
+ val rootConfig = rootProject.extensions.getByType()
+ group = rootConfig.group
+ version = rootConfig.version
+
+ val pluginId = id ?: "${rootConfig.group}.$name"
+ val pluginDisplayName = displayName ?: rootConfig.displayName
+ val pluginDescription = description ?: rootConfig.description
+ val pluginImpl = implementationClass ?: "$pluginId.plugin.FormaPlugin"
+ val pluginTags = (tags ?: rootConfig.tags) + extraTags
+
+ extensions.configure(GradlePluginDevelopmentExtension::class.java) {
+ website.set(rootConfig.website)
+ vcsUrl.set(rootConfig.vcsUrl)
+ plugins {
+ create(name) {
+ this.id = pluginId
+ this.displayName = pluginDisplayName
+ this.description = pluginDescription
+ this.implementationClass = pluginImpl
+ this.tags.set(pluginTags)
+ }
+ }
+ }
+}
diff --git a/plugins/config/build.gradle.kts b/plugins/config/build.gradle.kts
index 2bd8c1bc..2202662f 100644
--- a/plugins/config/build.gradle.kts
+++ b/plugins/config/build.gradle.kts
@@ -3,23 +3,7 @@ plugins {
id("com.gradle.plugin-publish")
}
-group = rootProject.ext["group"] as String
-version = rootProject.ext["version"] as String
-
-gradlePlugin {
- website.set(rootProject.ext["website"] as String)
- vcsUrl.set(rootProject.ext["vcsUrl"] as String)
- plugins {
- create(name) {
- id = "$group.$name"
- displayName = rootProject.ext["displayName"] as String
- description = rootProject.ext["description"] as String
- implementationClass = "$id.plugin.FormaPlugin"
- @Suppress("UNCHECKED_CAST")
- tags.set(rootProject.ext["tags"] as List)
- }
- }
-}
+formaPublishedPlugin(name = "config")
dependencies {
implementation(gradleApi())
diff --git a/plugins/deps/build.gradle.kts b/plugins/deps/build.gradle.kts
index d75a2c2b..6ffc7c0a 100644
--- a/plugins/deps/build.gradle.kts
+++ b/plugins/deps/build.gradle.kts
@@ -3,23 +3,7 @@ plugins {
id("com.gradle.plugin-publish")
}
-group = rootProject.ext["group"] as String
-version = rootProject.ext["version"] as String
-
-gradlePlugin {
- website.set(rootProject.ext["website"] as String)
- vcsUrl.set(rootProject.ext["vcsUrl"] as String)
- plugins {
- create(name) {
- id = "$group.$name"
- displayName = rootProject.ext["displayName"] as String
- description = rootProject.ext["description"] as String
- implementationClass = "$id.plugin.FormaPlugin"
- @Suppress("UNCHECKED_CAST")
- tags.set(rootProject.ext["tags"] as List)
- }
- }
-}
+formaPublishedPlugin(name = "deps")
dependencies {
implementation(project(":validation"))
diff --git a/plugins/owners/build.gradle.kts b/plugins/owners/build.gradle.kts
index 2bd8c1bc..d4032895 100644
--- a/plugins/owners/build.gradle.kts
+++ b/plugins/owners/build.gradle.kts
@@ -3,23 +3,7 @@ plugins {
id("com.gradle.plugin-publish")
}
-group = rootProject.ext["group"] as String
-version = rootProject.ext["version"] as String
-
-gradlePlugin {
- website.set(rootProject.ext["website"] as String)
- vcsUrl.set(rootProject.ext["vcsUrl"] as String)
- plugins {
- create(name) {
- id = "$group.$name"
- displayName = rootProject.ext["displayName"] as String
- description = rootProject.ext["description"] as String
- implementationClass = "$id.plugin.FormaPlugin"
- @Suppress("UNCHECKED_CAST")
- tags.set(rootProject.ext["tags"] as List)
- }
- }
-}
+formaPublishedPlugin(name = "owners")
dependencies {
implementation(gradleApi())
diff --git a/plugins/target/build.gradle.kts b/plugins/target/build.gradle.kts
index 2bd8c1bc..6b9912aa 100644
--- a/plugins/target/build.gradle.kts
+++ b/plugins/target/build.gradle.kts
@@ -3,23 +3,7 @@ plugins {
id("com.gradle.plugin-publish")
}
-group = rootProject.ext["group"] as String
-version = rootProject.ext["version"] as String
-
-gradlePlugin {
- website.set(rootProject.ext["website"] as String)
- vcsUrl.set(rootProject.ext["vcsUrl"] as String)
- plugins {
- create(name) {
- id = "$group.$name"
- displayName = rootProject.ext["displayName"] as String
- description = rootProject.ext["description"] as String
- implementationClass = "$id.plugin.FormaPlugin"
- @Suppress("UNCHECKED_CAST")
- tags.set(rootProject.ext["tags"] as List)
- }
- }
-}
+formaPublishedPlugin(name = "target")
dependencies {
implementation(gradleApi())
diff --git a/plugins/validation/build.gradle.kts b/plugins/validation/build.gradle.kts
index 5b26ca53..eda85d77 100644
--- a/plugins/validation/build.gradle.kts
+++ b/plugins/validation/build.gradle.kts
@@ -3,23 +3,7 @@ plugins {
id("com.gradle.plugin-publish")
}
-group = rootProject.ext["group"] as String
-version = rootProject.ext["version"] as String
-
-gradlePlugin {
- website.set(rootProject.ext["website"] as String)
- vcsUrl.set(rootProject.ext["vcsUrl"] as String)
- plugins {
- create(name) {
- id = "$group.$name"
- displayName = rootProject.ext["displayName"] as String
- description = rootProject.ext["description"] as String
- implementationClass = "$id.plugin.FormaPlugin"
- @Suppress("UNCHECKED_CAST")
- tags.set(rootProject.ext["tags"] as List)
- }
- }
-}
+formaPublishedPlugin(name = "validation")
dependencies {
implementation(project(":target"))