diff --git a/src/main/kotlin/org/zowe/zdevops/classic/steps/DownloadDatasetStep.kt b/src/main/kotlin/org/zowe/zdevops/classic/steps/DownloadDatasetStep.kt index fe1288d..b997637 100644 --- a/src/main/kotlin/org/zowe/zdevops/classic/steps/DownloadDatasetStep.kt +++ b/src/main/kotlin/org/zowe/zdevops/classic/steps/DownloadDatasetStep.kt @@ -1,11 +1,15 @@ /* + * Copyright (c) 2023-2024 IBA Group. + * * This program and the accompanying materials are made available under the terms of the * Eclipse Public License v2.0 which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-v20.html * * SPDX-License-Identifier: EPL-2.0 * - * Copyright IBA Group 2023 + * Contributors: + * IBA Group + * Zowe Community */ package org.zowe.zdevops.classic.steps @@ -70,7 +74,8 @@ constructor( zosConnection: ZOSConnection ) { val workspace = build.executor?.currentWorkspace!! - downloadDSOrDSMemberByType(dsn, vol, returnEtag, listener, zosConnection, workspace) + val jenkinsJobUrl = build.getEnvironment(listener)["JOB_URL"] + downloadDSOrDSMemberByType(dsn, vol, returnEtag, listener, zosConnection, workspace, jenkinsJobUrl) } diff --git a/src/main/kotlin/org/zowe/zdevops/declarative/jobs/DownloadFileDeclarative.kt b/src/main/kotlin/org/zowe/zdevops/declarative/jobs/DownloadFileDeclarative.kt index fbc61f7..f5231b6 100644 --- a/src/main/kotlin/org/zowe/zdevops/declarative/jobs/DownloadFileDeclarative.kt +++ b/src/main/kotlin/org/zowe/zdevops/declarative/jobs/DownloadFileDeclarative.kt @@ -1,16 +1,23 @@ /* + * Copyright (c) 2022-2024 IBA Group. + * * This program and the accompanying materials are made available under the terms of the * Eclipse Public License v2.0 which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-v20.html * * SPDX-License-Identifier: EPL-2.0 * - * Copyright IBA Group 2022 + * Contributors: + * IBA Group + * Zowe Community */ package org.zowe.zdevops.declarative.jobs -import hudson.* +import hudson.EnvVars +import hudson.Extension +import hudson.FilePath +import hudson.Launcher import hudson.model.Run import hudson.model.TaskListener import org.jenkinsci.Symbol @@ -47,7 +54,8 @@ class DownloadFileDeclarative @DataBoundConstructor constructor(val dsn: String) zosConnection: ZOSConnection ) { val workspacePath = FilePath(null, workspace.remote.replace(workspace.name,"")) - downloadDSOrDSMemberByType(dsn, vol, returnEtag, listener, zosConnection, workspacePath) + val jenkinsJobUrl = env["BUILD_URL"] + "/execution/node/3/" + downloadDSOrDSMemberByType(dsn, vol, returnEtag, listener, zosConnection, workspacePath, jenkinsJobUrl) } diff --git a/src/main/kotlin/org/zowe/zdevops/logic/DownloadOperation.kt b/src/main/kotlin/org/zowe/zdevops/logic/DownloadOperation.kt index 69edb90..e82a05a 100644 --- a/src/main/kotlin/org/zowe/zdevops/logic/DownloadOperation.kt +++ b/src/main/kotlin/org/zowe/zdevops/logic/DownloadOperation.kt @@ -1,17 +1,22 @@ /* + * Copyright (c) 2023-2024 IBA Group. + * * This program and the accompanying materials are made available under the terms of the * Eclipse Public License v2.0 which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-v20.html * * SPDX-License-Identifier: EPL-2.0 * - * Copyright IBA Group 2023 + * Contributors: + * IBA Group + * Zowe Community */ package org.zowe.zdevops.logic import hudson.AbortException import hudson.FilePath +import hudson.console.HyperlinkNote import hudson.model.TaskListener import org.apache.commons.io.IOUtils import org.zowe.kotlinsdk.DatasetOrganization @@ -24,7 +29,8 @@ import org.zowe.zdevops.Messages import java.io.File import java.io.InputStream import java.io.StringWriter - +import java.net.URLEncoder +import java.nio.charset.StandardCharsets /** @@ -36,6 +42,7 @@ import java.io.StringWriter * @param zosConnection The connection to the z/OS system. * @param workspace The workspace where the dataset will be downloaded. * @param listener The listener for capturing task progress and logs. + * @param jenkinsJobUrl The job/pipeline URL */ fun downloadDS( dsn: String, @@ -43,7 +50,8 @@ fun downloadDS( returnEtag: Boolean?, zosConnection: ZOSConnection, workspace: FilePath, - listener: TaskListener + listener: TaskListener, + jenkinsJobUrl: String?, ) { var downloadedDSN: InputStream? try { @@ -55,7 +63,9 @@ fun downloadDS( IOUtils.copy(downloadedDSN, writer, "UTF-8") val file = File("$workspace\\$dsn") file.writeText(writer.toString()) - listener.logger.println(Messages.zdevops_declarative_DSN_downloaded_success(dsn)) + val urlEncodedDsn = URLEncoder.encode(dsn, StandardCharsets.UTF_8.toString()) + listener.logger.println(Messages.zdevops_declarative_DSN_downloaded_success( + HyperlinkNote.encodeTo("${jenkinsJobUrl}ws/$urlEncodedDsn/*view*/", dsn))) } /** @@ -67,6 +77,7 @@ fun downloadDS( * @param listener The listener for capturing task progress and logs. * @param zosConnection The connection to the z/OS system. * @param workspace The workspace where the dataset will be downloaded. + * @param jenkinsJobUrl The job/pipeline URL */ fun downloadDSOrDSMemberByType( dsn: String, @@ -74,23 +85,24 @@ fun downloadDSOrDSMemberByType( returnEtag: Boolean?, listener: TaskListener, zosConnection: ZOSConnection, - workspace: FilePath + workspace: FilePath, + jenkinsJobUrl: String? ) { listener.logger.println(Messages.zdevops_declarative_DSN_downloading(dsn, vol, zosConnection.host, zosConnection.zosmfPort)) val dsnMemberPattern = Regex("[\\w#\$@.-]{1,}\\([\\w#\$@]{1,8}\\)") //means it's a PDS member if (dsn.contains(dsnMemberPattern)) { - downloadDS(dsn, vol, returnEtag, zosConnection, workspace, listener) + downloadDS(dsn, vol, returnEtag, zosConnection, workspace, listener, jenkinsJobUrl) } else { val dsnList = ZosDsnList(zosConnection).listDsn(dsn, ListParams(vol)) if (dsnList.items.isEmpty()) { throw AbortException("Can't find $dsn ${ if(vol.isNullOrBlank()) "" else "on volume $vol"}") } when (dsnList.items.first().datasetOrganization) { - DatasetOrganization.PS -> downloadDS(dsn, vol, returnEtag, zosConnection, workspace, listener) + DatasetOrganization.PS -> downloadDS(dsn, vol, returnEtag, zosConnection, workspace, listener, jenkinsJobUrl) DatasetOrganization.PO, DatasetOrganization.POE -> { listener.logger.println(Messages.zdevops_declarative_DSN_downloading_members(dsn)) ZosDsnList(zosConnection).listDsnMembers(dsn, ListParams(vol)).items.forEach { - downloadDS("${dsn}(${it.name})", vol, returnEtag, zosConnection, workspace, listener) + downloadDS("${dsn}(${it.name})", vol, returnEtag, zosConnection, workspace, listener, jenkinsJobUrl) } } else -> listener.logger.println(Messages.zdevops_declarative_DSN_downloading_invalid_dsorg()) diff --git a/src/main/kotlin/org/zowe/zdevops/logic/SubmitJobOperation.kt b/src/main/kotlin/org/zowe/zdevops/logic/SubmitJobOperation.kt index 8fd19bd..0586d1c 100644 --- a/src/main/kotlin/org/zowe/zdevops/logic/SubmitJobOperation.kt +++ b/src/main/kotlin/org/zowe/zdevops/logic/SubmitJobOperation.kt @@ -25,6 +25,8 @@ import org.zowe.zdevops.Messages import org.zowe.zdevops.utils.extractSubmitJobMessage import org.zowe.zdevops.utils.runMFTryCatchWrappedQuery import java.io.File +import java.net.URLEncoder +import java.nio.charset.StandardCharsets /** * Submits a z/OS job @@ -93,10 +95,11 @@ fun submitJobSync( val logPath = "$workspacePath/${finalResult.jobName}.${finalResult.jobId}" val file = File(logPath) file.writeText(fullLog) + val urlEncodedJobName = URLEncoder.encode(finalResult.jobName, StandardCharsets.UTF_8.toString()) listener.logger.println(Messages.zdevops_declarative_ZOSJobs_got_log( HyperlinkNote.encodeTo( linkBuilder(buildUrl, finalResult.jobName, finalResult.jobId), - "${finalResult.jobName}.${finalResult.jobId}" + "$urlEncodedJobName.${finalResult.jobId}" ) )) } else { diff --git a/src/test/kotlin/org/zowe/zdevops/classic/steps/DownloadDatasetStepSpec.kt b/src/test/kotlin/org/zowe/zdevops/classic/steps/DownloadDatasetStepSpec.kt index 7bf225c..ec2f2a4 100644 --- a/src/test/kotlin/org/zowe/zdevops/classic/steps/DownloadDatasetStepSpec.kt +++ b/src/test/kotlin/org/zowe/zdevops/classic/steps/DownloadDatasetStepSpec.kt @@ -11,9 +11,11 @@ package org.zowe.zdevops.classic.steps import hudson.AbortException +import hudson.EnvVars import hudson.FilePath import hudson.model.Executor import hudson.model.Item +import hudson.model.TaskListener import hudson.util.FormValidation import io.kotest.assertions.assertSoftly import io.kotest.assertions.fail @@ -68,6 +70,12 @@ class DownloadDatasetStepSpec : ShouldSpec({ every { mockInstance.currentWorkspace } returns FilePath(virtualChannel, mockDir.absolutePath) return mockInstance } + + override fun getEnvironment(log: TaskListener): EnvVars { + val env = EnvVars() + env["JOB_URL"] = "TEST" + return env + } } afterEach {