Add lifecycle smoke test ci plugin
This commit adds a plugin that is heavily based on the one used by the AOT smoke tests. It uses the description of each lifecycle smoke tests to generate a GitHub Actions workflow with the necessary jobs. There is also an additional task that generates or update a status document that list the smoke tests per generation with a link to the code and workflow. See gh-61
This commit is contained in:
21
.github/send-notification/action.yml
vendored
Normal file
21
.github/send-notification/action.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
name: Send notification
|
||||
description: Sends a Google Chat message as a notification of the job's outcome
|
||||
inputs:
|
||||
branch:
|
||||
description: 'The branch on which the failure occurred'
|
||||
required: true
|
||||
failure-url:
|
||||
description: 'The URL to use to link to the failure'
|
||||
required: true
|
||||
task:
|
||||
description: 'The task that has failed'
|
||||
required: true
|
||||
webhook-url:
|
||||
description: 'Google Chat Webhook URL'
|
||||
required: true
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- shell: bash
|
||||
run: |
|
||||
curl -s -o /dev/null -X POST '${{ inputs.webhook-url }}' -H 'Content-Type: application/json' -d '{ text: "<users/all> ${{ inputs.task }} <${{ inputs.failure-url }}|failed> on ${{ inputs.branch }} "}' || true
|
||||
25
gradle/plugins/lifecycle-smoke-test-ci-plugin/build.gradle
Normal file
25
gradle/plugins/lifecycle-smoke-test-ci-plugin/build.gradle
Normal file
@@ -0,0 +1,25 @@
|
||||
plugins {
|
||||
id "checkstyle"
|
||||
id "io.spring.javaformat" version "0.0.41"
|
||||
id "java-gradle-plugin"
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
gradlePlugin {
|
||||
plugins {
|
||||
lifecycleSmokeTestCiPlugin {
|
||||
id = "org.springframework.lifecycle.smoke-test-ci"
|
||||
implementationClass = "org.springframework.lifecycle.gradle.LifecycleSmokeTestCiPlugin"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
checkstyle("io.spring.javaformat:spring-javaformat-checkstyle:0.0.41")
|
||||
}
|
||||
|
||||
sourceCompatibility = "17"
|
||||
targetCompatibility = "17"
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module PUBLIC
|
||||
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
|
||||
"https://checkstyle.org/dtds/configuration_1_3.dtd">
|
||||
<module name="com.puppycrawl.tools.checkstyle.Checker">
|
||||
<module name="io.spring.javaformat.checkstyle.SpringChecks" />
|
||||
</module>
|
||||
@@ -0,0 +1 @@
|
||||
rootProject.name="lifecycle-smoke-test-ci-plugin"
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 2022-2024 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package org.springframework.lifecycle.gradle;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.GradleException;
|
||||
import org.gradle.api.file.DirectoryProperty;
|
||||
import org.gradle.api.provider.ListProperty;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.api.tasks.OutputDirectory;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
|
||||
/**
|
||||
* Task to generate the GitHub Actions workflows for the smoke tests.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public abstract class GenerateGitHubActionsWorkflows extends DefaultTask {
|
||||
|
||||
private static final String GITHUB_REPOSITORY = "spring-projects/spring-lifecycle-smoke-tests";
|
||||
|
||||
@OutputDirectory
|
||||
public abstract DirectoryProperty getOutputDirectory();
|
||||
|
||||
@Input
|
||||
public abstract ListProperty<SmokeTest> getSmokeTests();
|
||||
|
||||
@Input
|
||||
public abstract Property<String> getGitBranch();
|
||||
|
||||
@Input
|
||||
public abstract Property<String> getCronSchedule();
|
||||
|
||||
@Input
|
||||
public abstract Property<String> getSpringBootGeneration();
|
||||
|
||||
public GenerateGitHubActionsWorkflows() {
|
||||
getGitBranch().convention(getSpringBootGeneration());
|
||||
getOutputDirectory().convention(getSpringBootGeneration()
|
||||
.flatMap((generation) -> getProject().getLayout().getBuildDirectory().dir("workflows/" + generation)));
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void generateWorkflows() {
|
||||
getProject().delete(getOutputDirectory());
|
||||
getSmokeTests().get().forEach(this::generateWorkflow);
|
||||
}
|
||||
|
||||
void generateWorkflow(SmokeTest smokeTest) {
|
||||
File workflowFile = getOutputDirectory()
|
||||
.file(getSpringBootGeneration().get() + "-" + smokeTest.group() + "-" + smokeTest.name() + ".yml")
|
||||
.get()
|
||||
.getAsFile();
|
||||
workflowFile.getParentFile().mkdirs();
|
||||
String workflowName = getSpringBootGeneration().get() + " | " + name(smokeTest.group()) + " Smoke Tests | "
|
||||
+ name(smokeTest.name());
|
||||
try (PrintWriter writer = new PrintWriter(new FileWriter(workflowFile))) {
|
||||
writer.println("name: " + workflowName);
|
||||
writer.println("on:");
|
||||
writer.println(" schedule:");
|
||||
writer.println(" - cron : '" + getCronSchedule().get() + "'");
|
||||
writer.println(" workflow_dispatch:");
|
||||
writer.println("jobs:");
|
||||
if (smokeTest.tests()) {
|
||||
writeJob(writer, smokeTest, "test");
|
||||
}
|
||||
if (smokeTest.appTests()) {
|
||||
writeJob(writer, smokeTest, "appTest");
|
||||
writeJob(writer, smokeTest, "checkpointRestoreAppTest");
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new GradleException("Failed to write workflow file '" + workflowFile + "'", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeJob(PrintWriter writer, SmokeTest smokeTest, String taskName) {
|
||||
writer.println(" " + jobId(smokeTest.name(), taskName) + ":");
|
||||
writer.println(" name: " + name(smokeTest.name() + " " + taskName));
|
||||
writer.println(" uses: ./.github/workflows/smoke-test.yml");
|
||||
writer.println(" secrets: inherit");
|
||||
writer.println(" with:");
|
||||
writer.println(" checkout_repository: " + GITHUB_REPOSITORY);
|
||||
writer.println(" checkout_ref: " + getGitBranch().get());
|
||||
writer.println(" project: " + smokeTest.group() + ":" + smokeTest.name());
|
||||
writer.println(" task: " + taskName);
|
||||
}
|
||||
|
||||
private String jobId(String smokeTestName, String taskName) {
|
||||
StringBuilder output = new StringBuilder();
|
||||
output.append(smokeTestName.replace("-", "_"));
|
||||
output.append("_");
|
||||
for (char c : taskName.toCharArray()) {
|
||||
if (Character.isUpperCase(c)) {
|
||||
output.append("_");
|
||||
output.append(Character.toLowerCase(c));
|
||||
}
|
||||
else {
|
||||
output.append(c);
|
||||
}
|
||||
}
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
private String name(String input) {
|
||||
StringBuilder output = new StringBuilder(input.length());
|
||||
char previous = ' ';
|
||||
for (char c : input.replace("-", " ").toCharArray()) {
|
||||
if (previous == ' ') {
|
||||
output.append(Character.toUpperCase(c));
|
||||
}
|
||||
else {
|
||||
if (Character.isUpperCase(c)) {
|
||||
output.append(' ');
|
||||
}
|
||||
output.append(c);
|
||||
}
|
||||
previous = c;
|
||||
}
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2022-2024 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package org.springframework.lifecycle.gradle;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.gradle.api.GradleException;
|
||||
import org.gradle.api.NamedDomainObjectContainer;
|
||||
import org.gradle.api.Plugin;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.tasks.Exec;
|
||||
import org.gradle.api.tasks.Sync;
|
||||
import org.gradle.api.tasks.TaskProvider;
|
||||
|
||||
/**
|
||||
* {@link Plugin} for lifecycle smoke test CI.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class LifecycleSmokeTestCiPlugin implements Plugin<Project> {
|
||||
|
||||
@Override
|
||||
public void apply(Project project) {
|
||||
NamedDomainObjectContainer<SmokeTests> smokeTests = project.getObjects()
|
||||
.domainObjectContainer(SmokeTests.class);
|
||||
project.getExtensions().add("smokeTests", smokeTests);
|
||||
TaskProvider<Sync> syncWorkflows = project.getTasks().register("syncGitHubActionsWorkflows", Sync.class);
|
||||
syncWorkflows.configure((sync) -> {
|
||||
sync.into(".github/workflows");
|
||||
syncFromClasspath("smoke-test.yml", sync);
|
||||
syncFromClasspath("validate-gradle-wrapper.yml", sync);
|
||||
});
|
||||
smokeTests.configureEach((tests) -> {
|
||||
TaskProvider<Exec> describeSmokeTestsForBranch = project.getTasks()
|
||||
.register("describeSmokeTestsFor" + tests.getName(), Exec.class);
|
||||
describeSmokeTestsForBranch.configure((task) -> {
|
||||
task.setWorkingDir(new File(tests.getLocation()));
|
||||
task.commandLine("./gradlew", "describeSmokeTests", "--no-scan");
|
||||
});
|
||||
TaskProvider<GenerateGitHubActionsWorkflows> generateWorkflowsForBranch = project.getTasks()
|
||||
.register("generateGitHubActionsWorkflowsFor" + tests.getName(), GenerateGitHubActionsWorkflows.class);
|
||||
generateWorkflowsForBranch.configure((task) -> {
|
||||
task.dependsOn(describeSmokeTestsForBranch);
|
||||
task.getSpringBootGeneration().set(tests.getName());
|
||||
if (tests.getBranch() != null) {
|
||||
task.getGitBranch().set(tests.getBranch());
|
||||
}
|
||||
task.getSmokeTests().set(project.provider(() -> loadSmokeTests(tests.getLocation())));
|
||||
task.getCronSchedule().set(tests.getCronSchedule());
|
||||
});
|
||||
syncWorkflows.configure((sync) -> sync.from(generateWorkflowsForBranch));
|
||||
});
|
||||
TaskProvider<UpdateStatusPage> updateStatusPage = project.getTasks()
|
||||
.register("updateStatusPage", UpdateStatusPage.class);
|
||||
updateStatusPage.configure((task) -> {
|
||||
task.dependsOn(syncWorkflows);
|
||||
Map<String, List<SmokeTest>> allSmokeTests = new LinkedHashMap<>();
|
||||
smokeTests.forEach((tests) -> {
|
||||
List<SmokeTest> testsForGeneration = loadSmokeTests(tests.getLocation());
|
||||
allSmokeTests.put(tests.getName(), testsForGeneration);
|
||||
});
|
||||
task.getSmokeTests().set(allSmokeTests);
|
||||
task.getOutputFile().set(project.getLayout().getProjectDirectory().file("STATUS.adoc"));
|
||||
});
|
||||
project.getTasks().register("updateInfrastructure", (task) -> task.dependsOn(syncWorkflows, updateStatusPage));
|
||||
}
|
||||
|
||||
private List<SmokeTest> loadSmokeTests(String location) {
|
||||
File[] smokeTests = new File(location + "/build/smoke-tests").listFiles();
|
||||
return Stream.of(smokeTests).map(this::load).map(SmokeTest::new).toList();
|
||||
}
|
||||
|
||||
private Properties load(File file) {
|
||||
Properties properties = new Properties();
|
||||
try (FileInputStream input = new FileInputStream(file)) {
|
||||
properties.load(input);
|
||||
return properties;
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new GradleException("Failed to load smoke test properties from '" + file + "'", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void syncFromClasspath(String name, Sync sync) {
|
||||
sync.from(sync.getProject().getResources().getText().fromUri(getClass().getClassLoader().getResource(name)),
|
||||
(spec) -> spec.rename((temp) -> name));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2022-2024 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package org.springframework.lifecycle.gradle;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* A smoke test.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @param name name of the smoke test
|
||||
* @param group group of the smoke test
|
||||
* @param path path of the smoke test project
|
||||
* @param tests whether the smoke test contains any unit tests
|
||||
* @param appTests whether the smoke test contains any app tests
|
||||
*/
|
||||
public record SmokeTest(String name, String group, String path, boolean tests,
|
||||
boolean appTests) implements Serializable {
|
||||
|
||||
SmokeTest(Properties properties) {
|
||||
this(properties.getProperty("name"), properties.getProperty("group"), properties.getProperty("path"),
|
||||
Boolean.valueOf(properties.getProperty("tests")), Boolean.valueOf(properties.getProperty("appTests")));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2022-2024 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package org.springframework.lifecycle.gradle;
|
||||
|
||||
/**
|
||||
* A branch's smoke tests.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class SmokeTests {
|
||||
|
||||
private final String name;
|
||||
|
||||
private String branch;
|
||||
|
||||
private String location;
|
||||
|
||||
private String cronSchedule;
|
||||
|
||||
public SmokeTests(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getBranch() {
|
||||
return this.branch;
|
||||
}
|
||||
|
||||
public void setBranch(String branch) {
|
||||
this.branch = branch;
|
||||
}
|
||||
|
||||
public String getLocation() {
|
||||
return this.location;
|
||||
}
|
||||
|
||||
public void setLocation(String location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public String getCronSchedule() {
|
||||
return this.cronSchedule;
|
||||
}
|
||||
|
||||
public void setCronSchedule(String cronSchedule) {
|
||||
this.cronSchedule = cronSchedule;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright 2022-2024 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package org.springframework.lifecycle.gradle;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.file.RegularFileProperty;
|
||||
import org.gradle.api.provider.MapProperty;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.api.tasks.OutputFile;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
|
||||
/**
|
||||
* Task to update the {@code STATUS.adoc} with the smoke tests.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public abstract class UpdateStatusPage extends DefaultTask {
|
||||
|
||||
@OutputFile
|
||||
public abstract RegularFileProperty getOutputFile();
|
||||
|
||||
@Input
|
||||
public abstract MapProperty<String, List<SmokeTest>> getSmokeTests();
|
||||
|
||||
@TaskAction
|
||||
void updateStatusPage() throws IOException {
|
||||
List<String> lines = new ArrayList<>();
|
||||
lines.add("= Smoke Tests Status");
|
||||
lines.add(":toc:");
|
||||
lines.add("");
|
||||
lines.add("Check each test for potential configuration guidance.");
|
||||
lines.add("");
|
||||
getSmokeTests().get().forEach((name, tests) -> handleLocation(lines, name, tests));
|
||||
Files.write(getOutputFile().get().getAsFile().toPath(), lines);
|
||||
}
|
||||
|
||||
private void handleLocation(List<String> content, String generation, List<SmokeTest> smokeTests) {
|
||||
content.add(":toc-title: %s Projects".formatted(generation));
|
||||
content.add("== %s Projects".formatted(generation));
|
||||
content.add("");
|
||||
Map<String, SortedSet<SmokeTest>> groupedSmokeTests = new TreeMap<>();
|
||||
for (SmokeTest smokeTest : smokeTests) {
|
||||
groupedSmokeTests
|
||||
.computeIfAbsent(smokeTest.group(), (group) -> new TreeSet<>(Comparator.comparing(SmokeTest::name)))
|
||||
.add(smokeTest);
|
||||
}
|
||||
groupedSmokeTests.forEach((group, tests) -> {
|
||||
content.add("=== " + capitalize(group));
|
||||
content.add("");
|
||||
content.add("[%header,cols=\"2\"]");
|
||||
content.add("|===");
|
||||
content.add("h|Smoke Test");
|
||||
content.add("h|Status");
|
||||
content.add("");
|
||||
for (SmokeTest test : tests) {
|
||||
String name = test.name();
|
||||
String workflowUrl = workflowUrl(generation, name);
|
||||
content.add("|" + testUrl(group, name) + "[" + name + "]");
|
||||
content.add("| image:%s/badge.svg[\"Status\", link=\"%s\"]".formatted(workflowUrl, workflowUrl));
|
||||
content.add("");
|
||||
}
|
||||
content.add("|===");
|
||||
content.add("");
|
||||
});
|
||||
}
|
||||
|
||||
private String workflowUrl(String generation, String name) {
|
||||
return "https://github.com/spring-projects/spring-lifecycle-smoke-tests/actions/workflows/%s-%s.yml"
|
||||
.formatted(generation, name);
|
||||
}
|
||||
|
||||
private String capitalize(String input) {
|
||||
StringBuffer buffer = new StringBuffer(input.length());
|
||||
for (char c : input.toCharArray()) {
|
||||
buffer.append(buffer.isEmpty() ? Character.toUpperCase(c) : c);
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
private String testUrl(String group, String name) {
|
||||
return "https://github.com/spring-projects/spring-lifecycle-smoke-tests/tree/main/" + group + "/" + name;
|
||||
}
|
||||
|
||||
private enum TestType {
|
||||
|
||||
APP_TEST(SmokeTest::appTests, "-app-test", "appTest"),
|
||||
CR_APP_TEST(SmokeTest::appTests, "-cr-app-test", "checkpointRestoreAppTest"),
|
||||
TEST(SmokeTest::tests, "-test", "test");
|
||||
|
||||
private final Predicate<SmokeTest> predicate;
|
||||
|
||||
private final String urlSuffix;
|
||||
|
||||
private final String taskName;
|
||||
|
||||
TestType(Predicate<SmokeTest> predicate, String suffix, String taskName) {
|
||||
this.predicate = predicate;
|
||||
this.urlSuffix = suffix;
|
||||
this.taskName = taskName;
|
||||
}
|
||||
|
||||
String badge(SmokeTest smokeTest) {
|
||||
if (!this.predicate.test(smokeTest)) {
|
||||
return "";
|
||||
}
|
||||
return "image:" + badgeUrl(smokeTest.name(), this.urlSuffix) + "[link="
|
||||
+ jobUrl(smokeTest.name(), this.urlSuffix) + "]";
|
||||
}
|
||||
|
||||
String taskName() {
|
||||
return this.taskName;
|
||||
}
|
||||
|
||||
private String badgeUrl(String name, String suffix) {
|
||||
return workflowUrl(name) + "/badge.svg?branch=main";
|
||||
}
|
||||
|
||||
private String jobUrl(String name, String suffix) {
|
||||
return workflowUrl(name);
|
||||
}
|
||||
|
||||
private String workflowUrl(String name) {
|
||||
return "https://github.com/spring-projects/spring-lifecycle-smoke-tests/workflows/3.3.x-%s.yml"
|
||||
.formatted(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2022-2024 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gradle plugin for CI infrastructure of lifecycle smoke tests.
|
||||
*/
|
||||
package org.springframework.lifecycle.gradle;
|
||||
@@ -0,0 +1,63 @@
|
||||
name: Smoke Test
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
project:
|
||||
required: true
|
||||
type: string
|
||||
task:
|
||||
required: true
|
||||
type: string
|
||||
checkout_repository:
|
||||
required: true
|
||||
type: string
|
||||
checkout_ref:
|
||||
required: true
|
||||
type: string
|
||||
expected_to_fail:
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
jobs:
|
||||
smoke_test:
|
||||
name: ${{ inputs.task }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: ${{ inputs.checkout_repository }}
|
||||
ref: ${{ inputs.checkout_ref }}
|
||||
- name: Set up Java
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: '17'
|
||||
java-package: 'jdk+crac'
|
||||
distribution: 'zulu'
|
||||
- name: Set up Gradle
|
||||
uses: gradle/gradle-build-action@982da8e78c05368c70dac0351bb82647a9e9a5d2
|
||||
- name: Configure Gradle user.name
|
||||
run: |
|
||||
mkdir -p ~/.gradle
|
||||
echo 'systemProp.user.name=spring-builds+github' >> ~/.gradle/gradle.properties
|
||||
- name: Build
|
||||
id: build
|
||||
env:
|
||||
GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }}
|
||||
run: ./gradlew ${{ inputs.project }}:${{ inputs.task }}
|
||||
continue-on-error: ${{ inputs.expected_to_fail }}
|
||||
- name: Check out send notification action
|
||||
uses: actions/checkout@v4
|
||||
if: ${{ failure() }}
|
||||
with:
|
||||
path: ci
|
||||
ref: ci
|
||||
sparse-checkout: .github/actions/send-notification
|
||||
- name: Send notification
|
||||
uses: ./ci/.github/actions/send-notification
|
||||
if: ${{ failure() }}
|
||||
with:
|
||||
webhook-url: ${{ secrets.GOOGLE_CHAT_WEBHOOK_URL }}
|
||||
task: ${{ inputs.project }}:${{ inputs.task }}
|
||||
branch: ${{ inputs.checkout_ref }}
|
||||
failure-url: ${{ steps.build.outputs.build-scan-url || format('{0}/{1}/actions/runs/{2}', github.server_url, github.repository, github.run_id) }}
|
||||
@@ -0,0 +1,11 @@
|
||||
name: "Validate Gradle Wrapper"
|
||||
on: [push, pull_request]
|
||||
permissions:
|
||||
contents: read
|
||||
jobs:
|
||||
validation:
|
||||
name: "Validate Gradle Wrapper"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: gradle/actions/wrapper-validation@6cec5d49d4d6d4bb982fbed7047db31ea6d38f11 #v3.3.0
|
||||
@@ -0,0 +1,3 @@
|
||||
pluginManagement {
|
||||
includeBuild "gradle/plugins/lifecycle-smoke-test-ci-plugin"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user