Skip to content

Commit 51cbb24

Browse files
committed
Re-introduce artifact promoting
Still experimental. Will only work if the publishing Forge maven is added to the publishing repos. The promotion task will become a finalizer of the relevant publish task (i.e. `publishMavenJavaPublicationToForgeRepository`). You can promote a publication by doing this: ```groovy publishing { repositories { maven gradleutils.publishingForgeMaven } publications.register('pluginMaven', MavenPublication) { gradleutils.promote(it) // ... } } ```
1 parent 897c7ba commit 51cbb24

9 files changed

+233
-8
lines changed

settings.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ plugins {
1313
// NOTE: We need to load this into the classpath before GradleUtils for the service to load correctly
1414
id 'io.freefair.javadoc-links' version '8.14' apply false // https://plugins.gradle.org/plugin/io.freefair.javadoc-links
1515

16-
id 'net.minecraftforge.gradleutils' version '3.0.0-beta.30' // https://plugins.gradle.org/plugin/net.minecraftforge.gradleutils
17-
id 'net.minecraftforge.gitversion' version '3.0.0' // https://plugins.gradle.org/plugin/net.minecraftforge.gitversion
16+
id 'net.minecraftforge.gradleutils' version '3.0.0' // https://plugins.gradle.org/plugin/net.minecraftforge.gradleutils
17+
id 'net.minecraftforge.gitversion' version '3.0.0' // https://plugins.gradle.org/plugin/net.minecraftforge.gitversion
1818
}
1919

2020
rootProject.name = 'gradleutils'

src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsExtension.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
import java.io.File;
1414

1515
/// Contains various utilities for working with Gradle scripts.
16-
public sealed interface GradleUtilsExtension permits GradleUtilsExtensionInternal {
16+
///
17+
/// @see GradleUtilsExtensionForProject
18+
public sealed interface GradleUtilsExtension permits GradleUtilsExtensionForProject, GradleUtilsExtensionInternal {
1719
/// The name for this extension.
1820
String NAME = "gradleutils";
1921

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright (c) Forge Development LLC and contributors
3+
* SPDX-License-Identifier: LGPL-2.1-only
4+
*/
5+
package net.minecraftforge.gradleutils;
6+
7+
import org.gradle.api.publish.maven.MavenPublication;
8+
import org.gradle.api.tasks.TaskProvider;
9+
10+
/// A subset of [GradleUtilsExtension] that is given to projects. Includes additional convenience methods that only
11+
/// apply to projects.
12+
public sealed interface GradleUtilsExtensionForProject extends GradleUtilsExtension permits GradleUtilsExtensionInternal.ForProject {
13+
/// Promotes a publication to the <a href="https://files.minecraftforge.net">Forge Files Site</a>.
14+
///
15+
/// Publications that are promoted will automatically have the relevant task added as a finalizer to the
16+
/// `publishPublicationToForgeRepository` task, where the publication matches the task's publication and the
17+
/// repository name is "forge". The publishing Forge repo added via [GradleUtilsExtension#getPublishingForgeMaven]
18+
/// always sets it with the name "forge".
19+
///
20+
/// @param publication The publication to promote
21+
/// @return The provider for the promotion task
22+
TaskProvider<? extends PromotePublication> promote(MavenPublication publication);
23+
}

src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsExtensionImpl.groovy

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ import org.gradle.api.plugins.ExtensionAware
1818
import org.gradle.api.provider.Property
1919
import org.gradle.api.provider.Provider
2020
import org.gradle.api.provider.ProviderFactory
21+
import org.gradle.api.publish.maven.MavenPublication
22+
import org.gradle.api.publish.maven.tasks.PublishToMavenRepository
23+
import org.gradle.api.tasks.TaskProvider
2124
import org.gradle.authentication.http.BasicAuthentication
2225
import org.gradle.initialization.layout.BuildLayout
2326

@@ -57,10 +60,6 @@ import static net.minecraftforge.gradleutils.GradleUtilsPlugin.LOGGER
5760
parameters.failure.set(this.flowProviders.buildWorkResult.map { it.failure.orElse(null) })
5861
}
5962
}
60-
61-
if (target instanceof Project) {
62-
target.tasks.register(GenerateActionsWorkflow.NAME, GenerateActionsWorkflowImpl)
63-
}
6463
}
6564

6665
@Override
@@ -116,4 +115,31 @@ import static net.minecraftforge.gradleutils.GradleUtilsPlugin.LOGGER
116115
}
117116
}
118117
}
118+
119+
@CompileStatic
120+
@PackageScope static abstract class ForProjectImpl implements GradleUtilsExtensionInternal.ForProject {
121+
private final Project project
122+
123+
@Inject
124+
ForProjectImpl(Project project) {
125+
this.project = project
126+
127+
project.tasks.register(GenerateActionsWorkflow.NAME, GenerateActionsWorkflowImpl)
128+
}
129+
130+
@Override
131+
TaskProvider<? extends PromotePublication> promote(MavenPublication publication) {
132+
this.project.tasks.register('promote' + publication.name.capitalize(), PromotePublicationImpl).tap { promote ->
133+
this.project.tasks.withType(PublishToMavenRepository).configureEach { publish ->
134+
// if the publish task's publication isn't this one and the repo name isn't 'forge', skip
135+
// the name being 'forge' is enforced by gradle utils
136+
if (publish.publication !== publication || publish.repository.name != 'forge')
137+
return
138+
139+
publish.finalizedBy(promote)
140+
promote.configure { it.mustRunAfter(publish) }
141+
}
142+
}
143+
}
144+
}
119145
}

src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsExtensionInternal.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,11 @@ default TypeOf<?> getPublicType() {
2929
repo.setName("Minecraft libraries");
3030
repo.setUrl(Constants.MC_LIBS_MAVEN);
3131
};
32+
33+
non-sealed interface ForProject extends GradleUtilsExtensionForProject, HasPublicType {
34+
@Override
35+
default TypeOf<?> getPublicType() {
36+
return TypeOf.typeOf(GradleUtilsExtensionForProject.class);
37+
}
38+
}
3239
}

src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsPlugin.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package net.minecraftforge.gradleutils;
66

77
import net.minecraftforge.gradleutils.shared.EnhancedPlugin;
8+
import org.gradle.api.Project;
89
import org.gradle.api.logging.Logger;
910
import org.gradle.api.logging.Logging;
1011
import org.gradle.api.plugins.ExtensionAware;
@@ -24,6 +25,9 @@ public GradleUtilsPlugin() {
2425

2526
@Override
2627
public void setup(ExtensionAware target) {
27-
target.getExtensions().create(GradleUtilsExtension.NAME, GradleUtilsExtensionImpl.class, target);
28+
if (target instanceof Project project)
29+
project.getExtensions().create(GradleUtilsExtension.NAME, GradleUtilsExtensionImpl.ForProjectImpl.class);
30+
else
31+
target.getExtensions().create(GradleUtilsExtension.NAME, GradleUtilsExtensionImpl.class, target);
2832
}
2933
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright (c) Forge Development LLC and contributors
3+
* SPDX-License-Identifier: LGPL-2.1-only
4+
*/
5+
package net.minecraftforge.gradleutils;
6+
7+
import org.gradle.api.Task;
8+
import org.gradle.api.provider.Property;
9+
import org.gradle.api.tasks.Input;
10+
import org.jetbrains.annotations.ApiStatus;
11+
12+
/// This task promotes a publication to the <a href="https://files.minecraftforge.net">Forge Files Site</a>.
13+
///
14+
/// @apiNote This task is still [experimental][ApiStatus.Experimental]. It may be buggy and is subject to change.
15+
@ApiStatus.Experimental
16+
public sealed interface PromotePublication extends Task permits PromotePublicationInternal {
17+
/// The publication group to promote.
18+
///
19+
/// By convention, this is [org.gradle.api.Project#getGroup()], but the set value is
20+
/// [org.gradle.api.publish.maven.MavenPublication#getGroupId()].
21+
///
22+
/// @return The property for the artifact group
23+
@Input Property<String> getArtifactGroup();
24+
25+
/// The publication name to promote.
26+
///
27+
/// By convention, this is [org.gradle.api.plugins.BasePluginExtension#getArchivesName()], but the set value is
28+
/// [org.gradle.api.publish.maven.MavenPublication#getArtifactId()].
29+
///
30+
/// @return The property for the artifact name
31+
@Input Property<String> getArtifactName();
32+
33+
/// The publication version to promote.
34+
///
35+
/// By convention, this is [org.gradle.api.Project#getVersion()], but the set value is
36+
/// [org.gradle.api.publish.maven.MavenPublication#getVersion()].
37+
///
38+
/// @return The property for the artifact version
39+
@Input Property<String> getArtifactVersion();
40+
41+
/// The promotion type to use.
42+
///
43+
/// By default, this is `latest`.
44+
///
45+
/// @return The property for the promotion type
46+
@Input Property<String> getPromotionType();
47+
48+
/// The webhook URL to use. If this is not set, this task will not run.
49+
///
50+
/// This is set by the `PROMOTE_ARTIFACT_WEBHOOK` environment variable using
51+
/// [org.gradle.api.provider.ProviderFactory#environmentVariable(String)].
52+
///
53+
/// @return The property for the webhook URL.
54+
@Input Property<String> getWebhookURL();
55+
56+
/// The username to use. If this is not set, this task will not run.
57+
///
58+
/// This is set by the `PROMOTE_ARTIFACT_USERNAME` environment variable using
59+
/// [org.gradle.api.provider.ProviderFactory#environmentVariable(String)].
60+
///
61+
/// @return The property for the username.
62+
@Input Property<String> getUsername();
63+
64+
/// The password to use. If this is not set, this task will not run.
65+
///
66+
/// This is set by the `PROMOTE_ARTIFACT_PASSWORD` environment variable using
67+
/// [org.gradle.api.provider.ProviderFactory#environmentVariable(String)].
68+
///
69+
/// @return The property for the password URL.
70+
@Input Property<String> getPassword();
71+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright (c) Forge Development LLC and contributors
3+
* SPDX-License-Identifier: LGPL-2.1-only
4+
*/
5+
package net.minecraftforge.gradleutils
6+
7+
import groovy.json.JsonBuilder
8+
import groovy.transform.CompileStatic
9+
import groovy.transform.PackageScope
10+
import org.gradle.api.DefaultTask
11+
import org.gradle.api.plugins.BasePluginExtension
12+
import org.gradle.api.provider.ProviderFactory
13+
import org.gradle.api.publish.maven.MavenPublication
14+
import org.gradle.api.tasks.TaskAction
15+
16+
import javax.inject.Inject
17+
import javax.net.ssl.SSLContext
18+
import java.net.http.HttpClient
19+
import java.net.http.HttpRequest
20+
import java.net.http.HttpResponse
21+
import java.time.Duration
22+
23+
@CompileStatic
24+
@PackageScope abstract class PromotePublicationImpl extends DefaultTask implements PromotePublicationInternal {
25+
protected abstract @Inject ProviderFactory getProviders()
26+
27+
@Inject
28+
PromotePublicationImpl(MavenPublication publication) {
29+
this.artifactGroup.convention(this.providers.provider(this.project.&getGroup).map(Object.&toString)).set(this.providers.provider(publication.&getGroupId))
30+
this.artifactName.convention(this.project.extensions.getByType(BasePluginExtension).archivesName).set(this.providers.provider(publication.&getArtifactId))
31+
this.artifactVersion.convention(this.providers.provider(this.project.&getVersion).map(Object.&toString)).set(this.providers.provider(publication.&getVersion))
32+
33+
this.promotionType.convention('latest')
34+
35+
this.webhookURL.set(this.providers.environmentVariable('PROMOTE_ARTIFACT_WEBHOOK'))
36+
this.username.set(this.providers.environmentVariable('PROMOTE_ARTIFACT_USERNAME'))
37+
this.password.set(this.providers.environmentVariable('PROMOTE_ARTIFACT_PASSWORD'))
38+
39+
this.onlyIf('If required info is missing, skip promotion') {
40+
final task = it as PromotePublicationImpl
41+
task.webhookURL.present && task.username.present && task.password.present
42+
}
43+
}
44+
45+
@TaskAction
46+
void exec() {
47+
var client = HttpClient.newBuilder().tap {
48+
sslParameters(SSLContext.default.defaultSSLParameters.tap { protocols = ["TLSv1.3"] })
49+
}.build()
50+
51+
var request = HttpRequest.newBuilder().tap {
52+
uri(URI.create(this.webhookURL.get()))
53+
setHeader('Content-Type', 'application/json')
54+
setHeader('Authorization', "Basic ${Base64.encoder.encodeToString("${this.username.get()}:${this.password.get()}".bytes)}")
55+
timeout(Duration.ofSeconds(10))
56+
POST(HttpRequest.BodyPublishers.ofString(new JsonBuilder(
57+
group: this.artifactGroup.get(),
58+
artifact: this.artifactName.get(),
59+
version: this.artifactVersion.get(),
60+
type: this.promotionType.get()
61+
).toPrettyString()))
62+
}.build()
63+
64+
var response = client.send(request, HttpResponse.BodyHandlers.ofString())
65+
if (response.statusCode() != 200)
66+
throw new RuntimeException("Failed to promote artifact: ${response.statusCode()} ${response.body()}")
67+
}
68+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright (c) Forge Development LLC and contributors
3+
* SPDX-License-Identifier: LGPL-2.1-only
4+
*/
5+
package net.minecraftforge.gradleutils;
6+
7+
import net.minecraftforge.gradleutils.shared.EnhancedPlugin;
8+
import net.minecraftforge.gradleutils.shared.EnhancedTask;
9+
import org.gradle.api.Project;
10+
import org.gradle.api.reflect.HasPublicType;
11+
import org.gradle.api.reflect.TypeOf;
12+
import org.gradle.api.tasks.Internal;
13+
14+
non-sealed interface PromotePublicationInternal extends PromotePublication, EnhancedTask, HasPublicType {
15+
@Override
16+
default Class<? extends EnhancedPlugin<? super Project>> pluginType() {
17+
return GradleUtilsPlugin.class;
18+
}
19+
20+
@Override
21+
default @Internal TypeOf<?> getPublicType() {
22+
return TypeOf.typeOf(PromotePublication.class);
23+
}
24+
}

0 commit comments

Comments
 (0)