diff --git a/README.md b/README.md index 5366596..5379d88 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,26 @@ and as such requires several environment variables to be set: * `AWS_REGION` should be set to, e.g., `us-east-1`. * `CLOUDWATCH_LOG_GROUP_NAME` should be set to a test log group name, which you may need to precreate. +You may configure the above environment variables in your `~/.m2/settings.xml` and they will be applied automatically when running `mvn test`: + +``` + + + pipeline-cloudwatch-logs + + true + + + + + + + + + + +``` + The actual test case are defined a TCK-like [`LogStorageTestBase`](https://github.com/jenkinsci/workflow-api-plugin/blob/907cf64feb2f38e93aebbedf87946b0235c3dc93/src/test/java/org/jenkinsci/plugins/workflow/log/LogStorageTestBase.java#L81-L295) and you may run an individual test case if desired: diff --git a/pom.xml b/pom.xml index 37d49c2..d8e475b 100644 --- a/pom.xml +++ b/pom.xml @@ -14,8 +14,8 @@ 999999-SNAPSHOT - 2.492 - ${jenkins.baseline}.3 + 2.504 + ${jenkins.baseline}.1 true jenkinsci/${project.artifactId}-plugin @@ -54,6 +54,22 @@ import pom + + + + org.jenkins-ci.plugins.workflow + workflow-api + 1397.v02e97a_30f3ce + + + + + org.jenkins-ci.plugins.workflow + workflow-api + 1397.v02e97a_30f3ce + tests + test + @@ -116,6 +132,12 @@ 2.31.33 test + + software.amazon.awssdk + ssooidc + 2.31.33 + test + @@ -140,4 +162,31 @@ + + + cloudwatch-logs-settings + + + CLOUDWATCH_LOG_GROUP_NAME + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + ${AWS_PROFILE} + ${AWS_ROLE} + ${AWS_CHAINED_ROLE} + ${AWS_REGION} + ${CLOUDWATCH_LOG_GROUP_NAME} + + + + + + + diff --git a/src/main/java/io/jenkins/plugins/pipeline_cloudwatch_logs/CloudWatchAwsGlobalConfiguration.java b/src/main/java/io/jenkins/plugins/pipeline_cloudwatch_logs/CloudWatchAwsGlobalConfiguration.java index 25a8822..9aea709 100644 --- a/src/main/java/io/jenkins/plugins/pipeline_cloudwatch_logs/CloudWatchAwsGlobalConfiguration.java +++ b/src/main/java/io/jenkins/plugins/pipeline_cloudwatch_logs/CloudWatchAwsGlobalConfiguration.java @@ -142,7 +142,7 @@ FormValidation validate(String logGroupName, String region, String credentialsId // TODO should also check DescribeLogStreams, and perhaps even CreateLogStream and PutLogEvents, to ensure roles are correct } catch (Exception x) { String msg = processExceptionMessage(x); - return FormValidation.error(StringUtils.abbreviate(msg, 200)); + return FormValidation.error(abbreviate ? StringUtils.abbreviate(msg, 200) : msg); } try { String message = LogStreamState.validate(logGroupName); diff --git a/src/main/java/io/jenkins/plugins/pipeline_cloudwatch_logs/CloudWatchSender.java b/src/main/java/io/jenkins/plugins/pipeline_cloudwatch_logs/CloudWatchSender.java index 0293785..3491552 100644 --- a/src/main/java/io/jenkins/plugins/pipeline_cloudwatch_logs/CloudWatchSender.java +++ b/src/main/java/io/jenkins/plugins/pipeline_cloudwatch_logs/CloudWatchSender.java @@ -151,7 +151,7 @@ public synchronized final void close() throws IOException { } if (nodeId != null && JenkinsJVM.isJenkinsJVM()) { // Note that this does not necessarily shut down the AWSLogs client; that is shared across builds. - PipelineBridge.get().close(logStreamNameBase, buildId); + PipelineBridge.close(logStreamNameBase, buildId); } } diff --git a/src/main/java/io/jenkins/plugins/pipeline_cloudwatch_logs/PipelineBridge.java b/src/main/java/io/jenkins/plugins/pipeline_cloudwatch_logs/PipelineBridge.java index 1fd0af2..fc5d6ed 100644 --- a/src/main/java/io/jenkins/plugins/pipeline_cloudwatch_logs/PipelineBridge.java +++ b/src/main/java/io/jenkins/plugins/pipeline_cloudwatch_logs/PipelineBridge.java @@ -40,27 +40,24 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; import java.util.logging.Logger; +import org.jenkinsci.Symbol; import org.jenkinsci.plugins.workflow.flow.FlowExecutionOwner; import org.jenkinsci.plugins.workflow.graph.FlowNode; import org.jenkinsci.plugins.workflow.log.BrokenLogStorage; import org.jenkinsci.plugins.workflow.log.LogStorage; import org.jenkinsci.plugins.workflow.log.LogStorageFactory; +import org.jenkinsci.plugins.workflow.log.LogStorageFactoryDescriptor; +import org.kohsuke.stapler.DataBoundConstructor; /** * Binds CloudWatch to Pipeline logs. */ -@Extension public final class PipelineBridge implements LogStorageFactory { - static { - // Make sure JENKINS-52165 is enabled, or performance will be awful for remote shell steps. - System.setProperty("org.jenkinsci.plugins.workflow.steps.durable_task.DurableTaskStep.USE_WATCHING", "true"); - } - private static final Logger LOGGER = Logger.getLogger(PipelineBridge.class.getName()); - private final Map timestampTrackers = new ConcurrentHashMap<>(); - private final Map impls = new ConcurrentHashMap<>(); + @DataBoundConstructor + public PipelineBridge() {} @Override public LogStorage forBuild(FlowExecutionOwner owner) { @@ -82,18 +79,38 @@ public LogStorage forBuild(FlowExecutionOwner owner) { return forIDs(logStreamNameBase, buildId); } - static PipelineBridge get() { - return ExtensionList.lookupSingleton(PipelineBridge.class); + static LogStorage forIDs(String logStreamNameBase, String buildId) { + var descriptor = ExtensionList.lookupSingleton(PipelineBridge.DescriptorImpl.class); + return descriptor.impls.computeIfAbsent(logStreamNameBase + "#" + buildId, k -> new LogStorageImpl(logStreamNameBase, buildId, descriptor.timestampTrackers)); } - LogStorage forIDs(String logStreamNameBase, String buildId) { - return impls.computeIfAbsent(logStreamNameBase + "#" + buildId, k -> new LogStorageImpl(logStreamNameBase, buildId, timestampTrackers)); + static void close(String logStreamNameBase, String buildId) { + var descriptor = ExtensionList.lookupSingleton(PipelineBridge.DescriptorImpl.class); + descriptor.impls.remove(logStreamNameBase + "#" + buildId); } - void close(String logStreamNameBase, String buildId) { - impls.remove(logStreamNameBase + "#" + buildId); + @Extension + @Symbol("amazonCloudWatchLogs") + public static class DescriptorImpl extends LogStorageFactoryDescriptor { + static { + // Make sure JENKINS-52165 is enabled, or performance will be awful for remote shell steps. + System.setProperty("org.jenkinsci.plugins.workflow.steps.durable_task.DurableTaskStep.USE_WATCHING", "true"); + } + + private final Map timestampTrackers = new ConcurrentHashMap<>(); + private final Map impls = new ConcurrentHashMap<>(); + + @Override + public String getDisplayName() { + return "Amazon CloudWatch Logs"; + } + + @Override + public PipelineBridge getDefaultInstance() { + return new PipelineBridge(); + } } - + private static class LogStorageImpl implements LogStorage { private final String logStreamNameBase; diff --git a/src/test/java/io/jenkins/plugins/pipeline_cloudwatch_logs/PipelineBridgeTest.java b/src/test/java/io/jenkins/plugins/pipeline_cloudwatch_logs/PipelineBridgeTest.java index db9e3a9..379208e 100644 --- a/src/test/java/io/jenkins/plugins/pipeline_cloudwatch_logs/PipelineBridgeTest.java +++ b/src/test/java/io/jenkins/plugins/pipeline_cloudwatch_logs/PipelineBridgeTest.java @@ -71,7 +71,7 @@ static void globalConfiguration() throws Exception { } @Override protected LogStorage createStorage() { - return PipelineBridge.get().forIDs(LOG_STREAM_NAME, id); + return PipelineBridge.forIDs(LOG_STREAM_NAME, id); } @Override protected Map agentLoggers() {