diff --git a/.github/setup/action.yml b/.github/setup/action.yml
index 0d39adb..802090c 100644
--- a/.github/setup/action.yml
+++ b/.github/setup/action.yml
@@ -5,7 +5,7 @@ inputs:
jdkVersion:
description: "JDK version"
required: false
- default: "11"
+ default: "17"
mavenVersion:
description: "Maven version"
required: false
diff --git a/.github/workflows/hpi-builder.yml b/.github/workflows/hpi-builder.yml
index 987e892..7c5ff09 100644
--- a/.github/workflows/hpi-builder.yml
+++ b/.github/workflows/hpi-builder.yml
@@ -20,7 +20,7 @@ jobs:
uses: actions/setup-java@v4
with:
distribution: 'temurin'
- java-version: '11'
+ java-version: '17'
cache: maven
- name: Build Jenkins Plugin into .hpi
@@ -52,9 +52,9 @@ jobs:
uses: actions/setup-java@v4
with:
distribution: 'temurin'
- java-version: '11'
+ java-version: '17'
cache: maven
- name: Run Unit Tests with Maven
shell: bash
- run: ./mvnw test
\ No newline at end of file
+ run: ./mvnw test
diff --git a/Jenkinsfile b/Jenkinsfile
index 87d1157..12f6a8d 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -8,4 +8,4 @@
* Copyright IBA Group 2022
*/
-buildPlugin(useContainerAgent: true, tests: [[skip: 'true']], configurations: [[ platform: 'linux', jdk: '11' ]])
\ No newline at end of file
+buildPlugin(useContainerAgent: true, tests: [[skip: 'true']], configurations: [[ platform: 'linux', jdk: '17' ]])
diff --git a/pom.xml b/pom.xml
index f14afc6..2a9f4d9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
org.jenkins-ci.plugins
plugin
- 4.78
+ 4.78
@@ -19,21 +19,31 @@
- 0.2.0-
+ 0.2.0
-SNAPSHOT
2.414.3
- 11
- 1.8.21
+ 17
+ 1.9.20
true
1.13
4.10.0
- 0.5.0-rc.1
+ 0.5.0-rc.11
5.6.1
official
- 11
+ 17
UTF-8
High
jenkinsci/${project.artifactId}-plugin
+
+ UTF-8
+ zowe
+ zowe_zowe-zdevops-jenkins-plugin
+ zowe-zdevops-jenkins-plugin
+ project.version
+ kotlin
+ https://github.com/zowe/zowe-zdevops-jenkins-plugin
+
+ 17
@@ -133,10 +143,10 @@
org.apache.maven.plugins
maven-compiler-plugin
- 3.11.0
+ 3.13.0
-
- 11
+
+ 17
@@ -302,19 +312,19 @@
com.squareup.retrofit2
retrofit
- 2.9.0
+ 2.11.0
com.squareup.retrofit2
converter-gson
- 2.9.0
+ 2.11.0
com.squareup.retrofit2
converter-scalars
- 2.9.0
+ 2.11.0
@@ -365,22 +375,12 @@
2.10.1
-
- org.jenkins-ci.plugins
- script-security
-
-
org.apache.commons
commons-lang3
3.12.0
-
- org.jenkins-ci
- annotation-indexer
-
-
com.squareup.okhttp3
okhttp
@@ -429,6 +429,28 @@
test
+
+
+
+ org.jenkins-ci
+ annotation-indexer
+
+
+
+ org.jenkins-ci.plugins
+ script-security
+
+
+
+ org.jenkins-ci.plugins
+ credentials
+
+
+
+ org.jenkins-ci.plugins.workflow
+ workflow-step-api
+
+
diff --git a/src/main/kotlin/org/zowe/zdevops/classic/AbstractBuildStep.kt b/src/main/kotlin/org/zowe/zdevops/classic/AbstractBuildStep.kt
index c64cca0..6aecdba 100644
--- a/src/main/kotlin/org/zowe/zdevops/classic/AbstractBuildStep.kt
+++ b/src/main/kotlin/org/zowe/zdevops/classic/AbstractBuildStep.kt
@@ -24,6 +24,7 @@ import org.kohsuke.stapler.QueryParameter
import org.zowe.kotlinsdk.zowe.client.sdk.core.ZOSConnection
import org.zowe.zdevops.Messages
import org.zowe.zdevops.config.ZOSConnectionList
+import org.zowe.zdevops.utils.validateConnection
import java.io.IOException
import java.io.PrintWriter
import java.io.StringWriter
@@ -71,6 +72,8 @@ abstract class AbstractBuildStep(val connectionName: String) : Builder(), Simple
connURL.host, connURL.port.toString(), connection.username, connection.password, connURL.protocol
)
+ validateConnection(zosConnection)
+
perform(build, launcher, listener, zosConnection)
return true
}
diff --git a/src/main/kotlin/org/zowe/zdevops/classic/steps/AllocateDatasetStep.kt b/src/main/kotlin/org/zowe/zdevops/classic/steps/AllocateDatasetStep.kt
index e12f511..52639e9 100644
--- a/src/main/kotlin/org/zowe/zdevops/classic/steps/AllocateDatasetStep.kt
+++ b/src/main/kotlin/org/zowe/zdevops/classic/steps/AllocateDatasetStep.kt
@@ -55,6 +55,7 @@ constructor(
val primary: Int = 1,
var secondary: Int,
var recFm: RecordFormat,
+ var failOnExist: Boolean = false,
) : AbstractBuildStep(connectionName){
private var volser: String? = null
@@ -177,7 +178,8 @@ constructor(
dataClass,
avgBlk,
dsnType,
- dsModel
+ dsModel,
+ failOnExist,
)
}
diff --git a/src/main/kotlin/org/zowe/zdevops/classic/steps/DeleteDatasetStep.kt b/src/main/kotlin/org/zowe/zdevops/classic/steps/DeleteDatasetStep.kt
index b694865..6974e54 100644
--- a/src/main/kotlin/org/zowe/zdevops/classic/steps/DeleteDatasetStep.kt
+++ b/src/main/kotlin/org/zowe/zdevops/classic/steps/DeleteDatasetStep.kt
@@ -22,7 +22,6 @@ import org.zowe.zdevops.Messages
import org.zowe.zdevops.classic.AbstractBuildStep
import org.zowe.zdevops.logic.deleteDatasetOrMember
import org.zowe.zdevops.utils.validateDatasetName
-import org.zowe.zdevops.utils.validateFieldIsNotEmpty
import org.zowe.zdevops.utils.validateMemberName
class DeleteDatasetStep
@@ -38,6 +37,7 @@ constructor(
connectionName: String,
val dsn: String,
val member: String?,
+ val failOnNotExist: Boolean = false ,
) : AbstractBuildStep(connectionName) {
override fun perform(
@@ -46,7 +46,7 @@ constructor(
listener: BuildListener,
zosConnection: ZOSConnection
) {
- deleteDatasetOrMember(dsn, member, zosConnection, listener)
+ deleteDatasetOrMember(dsn, member, zosConnection, listener, failOnNotExist)
}
@Extension
@@ -67,10 +67,14 @@ constructor(
* Checks if the member name is valid
*
* @param member The dataset member name
- * @return FormValidation.ok() if the member name is valid, or an error message otherwise
+ * @return FormValidation.ok() if either the member name is valid or is not provided, or an error message otherwise
*/
fun doCheckMember(@QueryParameter member: String): FormValidation? {
- return validateMemberName(member)?: validateFieldIsNotEmpty(member)
+ return if (member.isNotBlank()) {
+ validateMemberName(member)
+ } else {
+ FormValidation.ok()
+ }
}
}
}
\ No newline at end of file
diff --git a/src/main/kotlin/org/zowe/zdevops/classic/steps/DeleteDatasetsByMaskStep.kt b/src/main/kotlin/org/zowe/zdevops/classic/steps/DeleteDatasetsByMaskStep.kt
index adf3117..ec82d84 100644
--- a/src/main/kotlin/org/zowe/zdevops/classic/steps/DeleteDatasetsByMaskStep.kt
+++ b/src/main/kotlin/org/zowe/zdevops/classic/steps/DeleteDatasetsByMaskStep.kt
@@ -31,6 +31,7 @@ class DeleteDatasetsByMaskStep
constructor(
connectionName: String,
val dsnMask: String,
+ val failOnNotExist: Boolean = false,
) : AbstractBuildStep(connectionName) {
override fun perform(
@@ -39,7 +40,7 @@ constructor(
listener: BuildListener,
zosConnection: ZOSConnection
) {
- deleteDatasetsByMask(dsnMask, zosConnection, listener)
+ deleteDatasetsByMask(dsnMask, zosConnection, listener, failOnNotExist)
}
@Extension
diff --git a/src/main/kotlin/org/zowe/zdevops/classic/steps/SubmitJobStep.kt b/src/main/kotlin/org/zowe/zdevops/classic/steps/SubmitJobStep.kt
index 65dfd04..6a5e548 100644
--- a/src/main/kotlin/org/zowe/zdevops/classic/steps/SubmitJobStep.kt
+++ b/src/main/kotlin/org/zowe/zdevops/classic/steps/SubmitJobStep.kt
@@ -41,8 +41,8 @@ constructor(
val linkBuilder: (String?, String, String) -> String = { jobUrl, jobName, jobId ->
"${jobUrl}ws/${jobName}.${jobId}/*view*/"
}
- val returnCode = submitJobSync(jobName, zosConnection, listener, workspace, build.getEnvironment(listener)["JOB_URL"], linkBuilder)
- if (checkRC && !returnCode.equals("CC 0000")) {
+ val jobResult = submitJobSync(jobName, zosConnection, listener, workspace, build.getEnvironment(listener)["JOB_URL"], linkBuilder)
+ if (checkRC && !jobResult.equals("CC 0000")) {
throw AbortException("Job RC code is not 0000")
}
} else {
diff --git a/src/main/kotlin/org/zowe/zdevops/config/ZOSConnection.kt b/src/main/kotlin/org/zowe/zdevops/config/ZOSConnection.kt
index 75b68aa..ececb4b 100644
--- a/src/main/kotlin/org/zowe/zdevops/config/ZOSConnection.kt
+++ b/src/main/kotlin/org/zowe/zdevops/config/ZOSConnection.kt
@@ -8,7 +8,7 @@
* Copyright IBA Group 2022
*/
-package org.zowe.zdevops.config;
+package org.zowe.zdevops.config
import com.cloudbees.plugins.credentials.CredentialsMatchers
import com.cloudbees.plugins.credentials.CredentialsProvider
@@ -16,10 +16,6 @@ import com.cloudbees.plugins.credentials.common.StandardCredentials
import com.cloudbees.plugins.credentials.common.StandardListBoxModel
import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials
import com.cloudbees.plugins.credentials.domains.URIRequirementBuilder
-import org.zowe.kotlinsdk.zowe.client.sdk.zosfiles.ZosDsnList
-import org.zowe.kotlinsdk.zowe.client.sdk.zosfiles.input.ListParams
-import org.zowe.zdevops.Messages
-import org.zowe.zdevops.declarative.jobs.zMessages
import hudson.Extension
import hudson.model.AbstractDescribableImpl
import hudson.model.Descriptor
@@ -32,6 +28,9 @@ import net.sf.json.JSONObject
import org.kohsuke.stapler.DataBoundConstructor
import org.kohsuke.stapler.QueryParameter
import org.kohsuke.stapler.StaplerRequest
+import org.zowe.zdevops.Messages
+import org.zowe.zdevops.declarative.jobs.zMessages
+import org.zowe.zdevops.utils.getTestDatasetList
import java.io.IOException
import java.io.ObjectInputStream
import java.io.ObjectOutputStream
@@ -119,9 +118,9 @@ constructor(
val testConnection = org.zowe.kotlinsdk.zowe.client.sdk.core.ZOSConnection(
connURL.host, connURL.port.toString(), credentials.username, credentials.password.plainText, connURL.protocol
)
- ZosDsnList(testConnection).listDsn(zMessages.zdevops_config_ZOSConnection_validation_testDS(), ListParams())
+ getTestDatasetList(testConnection)
}.onFailure {
- return FormValidation.error(zMessages.zdevops_config_ZOSConnection_validation_error());
+ return FormValidation.error("${zMessages.zdevops_config_ZOSConnection_validation_error()}\n(${it.message})");
}
return FormValidation.ok(zMessages.zdevops_config_ZOSConnection_validation_success())
}
diff --git a/src/main/kotlin/org/zowe/zdevops/declarative/AbstractZosmfAction.kt b/src/main/kotlin/org/zowe/zdevops/declarative/AbstractZosmfAction.kt
index 5cf4b4e..e985c1e 100644
--- a/src/main/kotlin/org/zowe/zdevops/declarative/AbstractZosmfAction.kt
+++ b/src/main/kotlin/org/zowe/zdevops/declarative/AbstractZosmfAction.kt
@@ -21,11 +21,9 @@ import hudson.tasks.BuildStepDescriptor
import hudson.tasks.Builder
import jenkins.tasks.SimpleBuildStep
import org.zowe.kotlinsdk.zowe.client.sdk.core.ZOSConnection
-import org.zowe.zdevops.Messages
-import org.zowe.zdevops.config.ZOSConnectionList
+import org.zowe.zdevops.utils.getZoweZosConnection
import java.io.PrintWriter
import java.io.StringWriter
-import java.net.URL
import java.nio.charset.StandardCharsets
abstract class AbstractZosmfAction : Builder(), SimpleBuildStep {
@@ -38,18 +36,8 @@ abstract class AbstractZosmfAction : Builder(), SimpleBuildStep {
override fun perform(run: Run<*, *>, workspace: FilePath, env: EnvVars, launcher: Launcher, listener: TaskListener) {
val connectionName = workspace.read().readBytes().toString(StandardCharsets.UTF_8)
- val connection = ZOSConnectionList.resolve(connectionName) ?: let {
+ val zoweConnection = getZoweZosConnection(connectionName, listener)
- val exception = IllegalArgumentException(Messages.zdevops_config_ZOSConnection_resolve_unknown(connectionName))
- val sw = StringWriter()
- exception.printStackTrace(PrintWriter(sw))
- listener.logger.println(sw.toString())
- throw exception
- }
- val connURL = URL(connection.url)
- val zoweConnection = ZOSConnection(
- connURL.host, connURL.port.toString(), connection.username, connection.password, connURL.protocol
- )
runCatching {
perform(run, workspace, env, launcher, listener, zoweConnection)
}.onFailure {
diff --git a/src/main/kotlin/org/zowe/zdevops/declarative/ZosmfStepDeclarative.kt b/src/main/kotlin/org/zowe/zdevops/declarative/ZosmfStepDeclarative.kt
index d3b3cfc..75349ed 100644
--- a/src/main/kotlin/org/zowe/zdevops/declarative/ZosmfStepDeclarative.kt
+++ b/src/main/kotlin/org/zowe/zdevops/declarative/ZosmfStepDeclarative.kt
@@ -13,17 +13,24 @@ package org.zowe.zdevops.declarative
import hudson.EnvVars
import hudson.Extension
import hudson.FilePath
-import hudson.model.*
import hudson.model.Run
+import hudson.model.TaskListener
import org.jenkinsci.plugins.workflow.steps.Step
import org.jenkinsci.plugins.workflow.steps.StepContext
import org.jenkinsci.plugins.workflow.steps.StepDescriptor
import org.jenkinsci.plugins.workflow.steps.StepExecution
import org.kohsuke.stapler.DataBoundConstructor
+import org.zowe.zdevops.utils.getZoweZosConnection
+import org.zowe.zdevops.utils.validateConnection
class ZosmfStepDeclarative @DataBoundConstructor constructor(private val connectionName: String) : Step() {
override fun start(context: StepContext): StepExecution {
+ val listener: TaskListener? = context.get(TaskListener::class.java)
+ val zosConnection = getZoweZosConnection(connectionName, listener)
+
+ validateConnection(zosConnection)
+
return ZosmfExecution(connectionName, context)
}
diff --git a/src/main/kotlin/org/zowe/zdevops/declarative/jobs/AllocateDatasetDeclarative.kt b/src/main/kotlin/org/zowe/zdevops/declarative/jobs/AllocateDatasetDeclarative.kt
index 27e886c..09c63ed 100644
--- a/src/main/kotlin/org/zowe/zdevops/declarative/jobs/AllocateDatasetDeclarative.kt
+++ b/src/main/kotlin/org/zowe/zdevops/declarative/jobs/AllocateDatasetDeclarative.kt
@@ -46,7 +46,8 @@ constructor(
private val dsOrg: DatasetOrganization,
private val primary: Int,
private var secondary: Int,
- private var recFm: RecordFormat) :
+ private var recFm: RecordFormat,
+ private var failOnExist: Boolean = false) :
AbstractZosmfAction() {
private var volser: String? = null
@@ -126,7 +127,8 @@ constructor(
dataClass,
avgBlk,
dsnType,
- dsModel
+ dsModel,
+ failOnExist,
)
}
diff --git a/src/main/kotlin/org/zowe/zdevops/declarative/jobs/DeleteDatasetDeclarative.kt b/src/main/kotlin/org/zowe/zdevops/declarative/jobs/DeleteDatasetDeclarative.kt
index 5b71e1a..fc72a4e 100644
--- a/src/main/kotlin/org/zowe/zdevops/declarative/jobs/DeleteDatasetDeclarative.kt
+++ b/src/main/kotlin/org/zowe/zdevops/declarative/jobs/DeleteDatasetDeclarative.kt
@@ -66,6 +66,7 @@ class DeleteDatasetDeclarative @DataBoundConstructor constructor(
private var dsn: String = ""
private var member: String = ""
+ private var failOnNotExist: Boolean = false
@DataBoundSetter
fun setDsn(dsn: String) { this.dsn = dsn }
@@ -73,6 +74,9 @@ class DeleteDatasetDeclarative @DataBoundConstructor constructor(
@DataBoundSetter
fun setMember(member: String) { this.member = member }
+ @DataBoundSetter
+ fun setFailOnNotExist(failOnNotExist: Boolean) { this.failOnNotExist = failOnNotExist }
+
override val exceptionMessage: String = zMessages.zdevops_deleting_ds_fail()
override fun perform(
@@ -83,7 +87,7 @@ class DeleteDatasetDeclarative @DataBoundConstructor constructor(
listener: TaskListener,
zosConnection: ZOSConnection
) {
- deleteDatasetOrMember(dsn, member, zosConnection, listener)
+ deleteDatasetOrMember(dsn, member, zosConnection, listener, failOnNotExist)
}
@Symbol("deleteDataset")
diff --git a/src/main/kotlin/org/zowe/zdevops/declarative/jobs/DeleteDatasetsByMaskDeclarative.kt b/src/main/kotlin/org/zowe/zdevops/declarative/jobs/DeleteDatasetsByMaskDeclarative.kt
index 026d1ae..e91566e 100644
--- a/src/main/kotlin/org/zowe/zdevops/declarative/jobs/DeleteDatasetsByMaskDeclarative.kt
+++ b/src/main/kotlin/org/zowe/zdevops/declarative/jobs/DeleteDatasetsByMaskDeclarative.kt
@@ -56,10 +56,14 @@ class DeleteDatasetsByMaskDeclarative @DataBoundConstructor constructor(
) : AbstractZosmfAction() {
private var mask: String = ""
+ private var failOnNotExist: Boolean = false
@DataBoundSetter
fun setMask(mask: String) { this.mask = mask }
+ @DataBoundSetter
+ fun setFailOnNotExist(failOnNotExist: Boolean) { this.failOnNotExist = failOnNotExist }
+
override val exceptionMessage: String = zMessages.zdevops_deleting_ds_fail()
override fun perform(
@@ -70,7 +74,7 @@ class DeleteDatasetsByMaskDeclarative @DataBoundConstructor constructor(
listener: TaskListener,
zosConnection: ZOSConnection
) {
- deleteDatasetsByMask(mask, zosConnection,listener)
+ deleteDatasetsByMask(mask, zosConnection,listener, failOnNotExist)
}
diff --git a/src/main/kotlin/org/zowe/zdevops/logic/AllocateOperation.kt b/src/main/kotlin/org/zowe/zdevops/logic/AllocateOperation.kt
index ad6dc58..ca24225 100644
--- a/src/main/kotlin/org/zowe/zdevops/logic/AllocateOperation.kt
+++ b/src/main/kotlin/org/zowe/zdevops/logic/AllocateOperation.kt
@@ -57,8 +57,8 @@ fun allocateDataset(listener: TaskListener,
dataClass: String?,
avgBlk: Int?,
dsnType: DsnameType?,
- dsModel: String?
-
+ dsModel: String?,
+ failOnExist: Boolean,
) {
listener.logger.println(Messages.zdevops_declarative_DSN_allocating(dsn, zosConnection.host, zosConnection.zosmfPort))
val alcParms = CreateDataset(
@@ -79,6 +79,14 @@ fun allocateDataset(listener: TaskListener,
dsnType,
dsModel
)
- ZosDsn(zosConnection).createDsn(dsn, alcParms)
- listener.logger.println(Messages.zdevops_declarative_DSN_allocated_success(dsn))
+ try {
+ ZosDsn(zosConnection).createDsn(dsn, alcParms)
+ listener.logger.println(Messages.zdevops_declarative_DSN_allocated_success(dsn))
+ } catch (allocateDsEx: Exception) {
+ listener.logger.println("Dataset allocation failed. Reason: $allocateDsEx")
+ if(failOnExist) {
+ throw allocateDsEx
+ }
+ listener.logger.println("The `failOnExist` option is set to false. Continuing with execution.")
+ }
}
diff --git a/src/main/kotlin/org/zowe/zdevops/logic/DeleteOperation.kt b/src/main/kotlin/org/zowe/zdevops/logic/DeleteOperation.kt
index 4f139c2..6048c5f 100644
--- a/src/main/kotlin/org/zowe/zdevops/logic/DeleteOperation.kt
+++ b/src/main/kotlin/org/zowe/zdevops/logic/DeleteOperation.kt
@@ -29,22 +29,31 @@ private val successMessage: String = zMessages.zdevops_deleting_ds_success()
* @param listener The task listener to log information and handle exceptions.
* @throws AbortException If the mask is empty or no matching datasets are found.
*/
-fun deleteDatasetsByMask(mask: String, zosConnection: ZOSConnection, listener: TaskListener) {
+fun deleteDatasetsByMask(mask: String, zosConnection: ZOSConnection, listener: TaskListener, failOnNotExist: Boolean) {
if (mask.isEmpty()) {
throw AbortException(zMessages.zdevops_deleting_datasets_by_mask_but_mask_is_empty())
}
listener.logger.println(zMessages.zdevops_deleting_ds_by_mask(mask))
- val dsnList = ZosDsnList(zosConnection).listDsn(mask, ListParams())
- if (dsnList.items.isEmpty()) {
- throw AbortException(zMessages.zdevops_deleting_ds_fail_no_matching_mask())
- }
- dsnList.items.forEach {
- runMFTryCatchWrappedQuery(listener) {
- listener.logger.println(zMessages.zdevops_deleting_ds(it.name, zosConnection.host, zosConnection.zosmfPort))
- ZosDsn(zosConnection).deleteDsn(it.name)
+ try {
+ val dsnList = ZosDsnList(zosConnection).listDsn(mask, ListParams())
+ if (dsnList.items.isEmpty()) {
+ throw AbortException(zMessages.zdevops_deleting_ds_fail_no_matching_mask())
+ }
+ dsnList.items.forEach {
+ runMFTryCatchWrappedQuery(listener) {
+ listener.logger.println(zMessages.zdevops_deleting_ds(it.name, zosConnection.host, zosConnection.zosmfPort))
+ ZosDsn(zosConnection).deleteDsn(it.name)
+ }
}
+ listener.logger.println(successMessage)
+ } catch (doesNotExistEx: Exception) {
+ if(failOnNotExist) {
+ throw doesNotExistEx
+ }
+ listener.logger.println("Reason: $doesNotExistEx")
+ // TODO I wanna have the dataset name here - it's inside exception message?
+ listener.logger.println("Dataset deletion failed, but the `failOnNotExist` option is set to false. Continuing with execution.")
}
- listener.logger.println(successMessage)
}
/**
@@ -56,22 +65,28 @@ fun deleteDatasetsByMask(mask: String, zosConnection: ZOSConnection, listener: T
* @param listener The task listener to log information and handle exceptions.
* @throws AbortException If the dataset name is empty or the member name is invalid.
*/
-fun deleteDatasetOrMember(dsn: String, member: String?, zosConnection: ZOSConnection, listener: TaskListener) {
+fun deleteDatasetOrMember(dsn: String, member: String?, zosConnection: ZOSConnection, listener: TaskListener, failOnNotExist: Boolean) {
if (dsn.isEmpty()) {
throw AbortException(zMessages.zdevops_deleting_ds_fail_dsn_param_empty())
}
val logMessage = if (!member.isNullOrEmpty()) zMessages.zdevops_deleting_ds_member(member, dsn, zosConnection.host, zosConnection.zosmfPort)
else zMessages.zdevops_deleting_ds(dsn, zosConnection.host, zosConnection.zosmfPort)
listener.logger.println(logMessage)
- runMFTryCatchWrappedQuery(listener) {
+ try {
if (!member.isNullOrEmpty()) {
isMemberNameValid(member)
ZosDsn(zosConnection).deleteDsn(dsn, member)
} else {
ZosDsn(zosConnection).deleteDsn(dsn)
}
+ listener.logger.println(successMessage)
+ } catch (doesNotExistEx: Exception) {
+ if(failOnNotExist) {
+ throw doesNotExistEx
+ }
+ listener.logger.println("Reason: $doesNotExistEx")
+ listener.logger.println("Dataset deletion failed, but the `failOnNotExist` option is set to false. Continuing with execution.")
}
- listener.logger.println(successMessage)
}
/**
diff --git a/src/main/kotlin/org/zowe/zdevops/logic/PerformTsoCommandOperation.kt b/src/main/kotlin/org/zowe/zdevops/logic/PerformTsoCommandOperation.kt
index dabb4c1..c6aeb07 100644
--- a/src/main/kotlin/org/zowe/zdevops/logic/PerformTsoCommandOperation.kt
+++ b/src/main/kotlin/org/zowe/zdevops/logic/PerformTsoCommandOperation.kt
@@ -14,6 +14,7 @@ import hudson.AbortException
import hudson.model.TaskListener
import org.zowe.kotlinsdk.zowe.client.sdk.core.ZOSConnection
import org.zowe.kotlinsdk.zowe.client.sdk.zostso.IssueTso
+import org.zowe.kotlinsdk.zowe.client.sdk.zostso.input.StartTsoParams
import org.zowe.zdevops.Messages
/**
@@ -36,12 +37,12 @@ fun performTsoCommand(
command: String,
) {
listener.logger.println(Messages.zdevops_issue_TSO_command(command))
- runCatching {
- val tsoCommandResponse = IssueTso(zosConnection).issueTsoCommand(acct, command)
+ try {
+ val tsoCommandResponse = IssueTso(zosConnection).issueTsoCommand(acct, command, StartTsoParams(), failOnPrompt = true)
listener.logger.println(tsoCommandResponse.commandResponses)
- }.onFailure {
+ } catch (ex: Exception) {
listener.logger.println(Messages.zdevops_TSO_command_fail())
- throw AbortException(Messages.zdevops_TSO_command_fail())
+ throw ex
}
listener.logger.println(Messages.zdevops_TSO_command_success())
}
\ No newline at end of file
diff --git a/src/main/kotlin/org/zowe/zdevops/utils/ConnectionValidation.kt b/src/main/kotlin/org/zowe/zdevops/utils/ConnectionValidation.kt
new file mode 100644
index 0000000..110479f
--- /dev/null
+++ b/src/main/kotlin/org/zowe/zdevops/utils/ConnectionValidation.kt
@@ -0,0 +1,74 @@
+/*
+ * 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 2024
+ */
+
+package org.zowe.zdevops.utils
+
+import hudson.AbortException
+import hudson.model.TaskListener
+import org.zowe.kotlinsdk.zowe.client.sdk.core.ZOSConnection
+import org.zowe.kotlinsdk.zowe.client.sdk.zosfiles.ZosDsnList
+import org.zowe.kotlinsdk.zowe.client.sdk.zosfiles.input.ListParams
+import org.zowe.zdevops.Messages
+import org.zowe.zdevops.config.ZOSConnectionList
+import java.io.PrintWriter
+import java.io.StringWriter
+import java.net.URL
+
+
+/**
+ * Gets a list of datasets
+ * Calls the listDsn function of ZosDsnList to list data set names.
+ * Passes a test data set name ('HELLO.THERE').
+ *
+ * @param zosConnection The ZOSConnection object representing the connection to the z/OS system.
+ */
+fun getTestDatasetList(zosConnection: ZOSConnection) {
+ ZosDsnList(zosConnection).listDsn(Messages.zdevops_config_ZOSConnection_validation_testDS(), ListParams())
+}
+
+/**
+ * Validates a z/OS connection.
+ *
+ * @param zosConnection The ZOSConnection object representing the connection to the z/OS system.
+ */
+fun validateConnection(zosConnection: ZOSConnection) {
+ try {
+ getTestDatasetList(zosConnection)
+ } catch (connectException: Exception) {
+ val connExMessage = "Failed to connect to z/OS (${zosConnection.user}@${zosConnection.host}:${zosConnection.zosmfPort}): ${connectException.message}"
+ throw AbortException(connExMessage)
+ }
+}
+
+/**
+ * Retrieves zOS connection by its name from the zOS connection list in Jenkins configuration.
+ *
+ * This function attempts to resolve the connection from the ZOSConnectionList
+ * using the provided connection name. If the connection is not found in the list, an
+ * IllegalArgumentException is thrown with a detailed error message, and the stack trace
+ * is logged using the provided TaskListener.
+ *
+ * @param connectionName The name of the connection to resolve.
+ * @param listener The TaskListener used to log messages and exceptions.
+ * @return A ZOSConnection object containing the resolved connection details.
+ * @throws IllegalArgumentException If the connection configuration cannot be resolved.
+ */
+fun getZoweZosConnection(connectionName: String, listener: TaskListener?): ZOSConnection {
+ val connection = ZOSConnectionList.resolve(connectionName) ?: run {
+ val exception = IllegalArgumentException(Messages.zdevops_config_ZOSConnection_resolve_unknown(connectionName))
+ val sw = StringWriter()
+ exception.printStackTrace(PrintWriter(sw))
+ listener?.logger?.println(sw.toString())
+ throw exception
+ }
+
+ val connURL = URL(connection.url)
+ return ZOSConnection(connURL.host, connURL.port.toString(), connection.username, connection.password, connURL.protocol)
+}
diff --git a/src/main/resources/org/zowe/zdevops/classic/steps/AllocateDatasetStep/config.jelly b/src/main/resources/org/zowe/zdevops/classic/steps/AllocateDatasetStep/config.jelly
index f17a368..adca495 100644
--- a/src/main/resources/org/zowe/zdevops/classic/steps/AllocateDatasetStep/config.jelly
+++ b/src/main/resources/org/zowe/zdevops/classic/steps/AllocateDatasetStep/config.jelly
@@ -86,4 +86,7 @@
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/org/zowe/zdevops/classic/steps/DeleteDatasetStep/config.jelly b/src/main/resources/org/zowe/zdevops/classic/steps/DeleteDatasetStep/config.jelly
index bea0c67..aa711c2 100644
--- a/src/main/resources/org/zowe/zdevops/classic/steps/DeleteDatasetStep/config.jelly
+++ b/src/main/resources/org/zowe/zdevops/classic/steps/DeleteDatasetStep/config.jelly
@@ -12,4 +12,7 @@
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/org/zowe/zdevops/classic/steps/DeleteDatasetsByMaskStep/config.jelly b/src/main/resources/org/zowe/zdevops/classic/steps/DeleteDatasetsByMaskStep/config.jelly
index f0ccd34..6fabee9 100644
--- a/src/main/resources/org/zowe/zdevops/classic/steps/DeleteDatasetsByMaskStep/config.jelly
+++ b/src/main/resources/org/zowe/zdevops/classic/steps/DeleteDatasetsByMaskStep/config.jelly
@@ -9,4 +9,7 @@
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/org/zowe/zdevops/config/ZOSConnection/config.jelly b/src/main/resources/org/zowe/zdevops/config/ZOSConnection/config.jelly
index 414507a..8280a21 100644
--- a/src/main/resources/org/zowe/zdevops/config/ZOSConnection/config.jelly
+++ b/src/main/resources/org/zowe/zdevops/config/ZOSConnection/config.jelly
@@ -7,7 +7,7 @@
-
+
diff --git a/src/test/kotlin/org/zowe/zdevops/classic/steps/AllocateDatasetStepSpec.kt b/src/test/kotlin/org/zowe/zdevops/classic/steps/AllocateDatasetStepSpec.kt
index a071ca6..1b2324f 100644
--- a/src/test/kotlin/org/zowe/zdevops/classic/steps/AllocateDatasetStepSpec.kt
+++ b/src/test/kotlin/org/zowe/zdevops/classic/steps/AllocateDatasetStepSpec.kt
@@ -124,6 +124,74 @@ class AllocateDatasetStepSpec : ShouldSpec({
assertSoftly { isDatasetAllocating shouldBe true }
assertSoftly { isDatasetAllocated shouldBe true }
}
+
+ should("fail as such dataset already exists and failOnExist is set to true") {
+ var isDatasetAllocating = false
+ var isFailedToAllocate = false
+ val taskListener = object : TestBuildListener() {
+ override fun getLogger(): PrintStream {
+ val logger = mockk()
+ every {
+ logger.println(any())
+ } answers {
+ if (firstArg().contains("Allocating dataset")) {
+ isDatasetAllocating = true
+ } else if (firstArg().contains("Dataset allocation failed.")) {
+ isFailedToAllocate = true
+ } else {
+ fail("Unexpected logger message: ${firstArg()}")
+ }
+ }
+ return logger
+ }
+ }
+ val launcher = TestLauncher(taskListener, virtualChannel)
+
+ responseDispatcher.injectEndpoint(
+ this.testCase.name.testName,
+ { it?.requestLine?.contains("/zosmf/restfiles/ds/") ?: false },
+ { MockResponse().setResponseCode(409) }
+ )
+
+ val allocateDatasetStepInst = spyk(
+ AllocateDatasetStep(
+ "test",
+ "TEST.IJMP.DATASET1",
+ DatasetOrganization.PS,
+ 1,
+ 0,
+ RecordFormat.F,
+ failOnExist = true
+ )
+ )
+ allocateDatasetStepInst.setAlcUnit(AllocationUnit.CYL)
+ allocateDatasetStepInst.setStorClass("")
+ allocateDatasetStepInst.setStorClass("TEST")
+ allocateDatasetStepInst.setMgntClass("")
+ allocateDatasetStepInst.setMgntClass("TEST")
+ allocateDatasetStepInst.setDataClass("")
+ allocateDatasetStepInst.setDataClass("TEST")
+ allocateDatasetStepInst.setVolser("")
+ allocateDatasetStepInst.setVolser("TEST")
+ allocateDatasetStepInst.setUnit("")
+ allocateDatasetStepInst.setUnit("TEST")
+ allocateDatasetStepInst.setLrecl(3120)
+ allocateDatasetStepInst.setBlkSize(3120)
+ allocateDatasetStepInst.setDsnType(DsnameType.BASIC)
+ try {
+ allocateDatasetStepInst.perform(
+ build,
+ launcher,
+ taskListener,
+ zosConnection
+ )
+ } catch (ex: Exception) {
+ isFailedToAllocate = true
+ }
+ assertSoftly { isDatasetAllocating shouldBe true }
+ assertSoftly { isFailedToAllocate shouldBe true }
+ }
+
}
val descriptor = AllocateDatasetStep.DescriptorImpl()
diff --git a/src/test/kotlin/org/zowe/zdevops/classic/steps/DeleteDatasetStepSpec.kt b/src/test/kotlin/org/zowe/zdevops/classic/steps/DeleteDatasetStepSpec.kt
index c3d3ab5..f110b9d 100644
--- a/src/test/kotlin/org/zowe/zdevops/classic/steps/DeleteDatasetStepSpec.kt
+++ b/src/test/kotlin/org/zowe/zdevops/classic/steps/DeleteDatasetStepSpec.kt
@@ -99,8 +99,52 @@ class DeleteDatasetStepSpec : ShouldSpec({
assertSoftly { isDeletingDataset shouldBe true }
assertSoftly { isSuccessfullyDeleted shouldBe true }
}
+
+ should("succeed as there is no such dataset, but failOnNotExist is set to false") {
+ var isDeletingDataset = false
+ var isContinuingExecution = false
+ val taskListener = object : TestBuildListener() {
+ override fun getLogger(): PrintStream {
+ val logger = mockk()
+ every {
+ logger.println(any())
+ } answers {
+ if (firstArg().contains("Deleting dataset")) {
+ isDeletingDataset = true
+ } else if (firstArg().contains("Dataset deletion failed, but the `failOnNotExist` option is set to false.")
+ || firstArg().contains("Reason")) {
+ isContinuingExecution = true
+ } else {
+ fail("Unexpected logger message: ${firstArg()}")
+ }
+ }
+ return logger
+ }
+ }
+ val launcher = TestLauncher(taskListener, virtualChannel)
+
+ responseDispatcher.injectEndpoint(
+ this.testCase.name.testName,
+ { it?.requestLine?.contains(Regex("DELETE /zosmf/restfiles/ds/.* HTTP/.*")) ?: false },
+ { MockResponse().setBody("{}").setResponseCode(404) }
+ )
+
+ val deleteDatasetStep = spyk(
+ DeleteDatasetStep("test", "TEST.IJMP.DATASET1", member = null, failOnNotExist = false)
+ )
+ deleteDatasetStep.perform(
+ build,
+ launcher,
+ taskListener,
+ zosConnection
+ )
+
+ assertSoftly { isDeletingDataset shouldBe true }
+ assertSoftly { isContinuingExecution shouldBe true }
+ }
}
+
val descriptor = DeleteDatasetStep.DescriptorImpl()
context("classic/steps module: DeleteDatasetStep.DescriptorImpl") {
@@ -110,7 +154,7 @@ class DeleteDatasetStepSpec : ShouldSpec({
}
should("validate member name") {
- descriptor.doCheckMember("") shouldBe FormValidation.error(Messages.zdevops_value_up_to_eight_in_length_validation())
+ descriptor.doCheckMember("") shouldBe FormValidation.ok()
descriptor.doCheckMember("@MY_DS") shouldBe FormValidation.warning(Messages.zdevops_member_name_is_invalid_validation())
descriptor.doCheckMember("DSNAME") shouldBe FormValidation.ok()
}
diff --git a/src/test/kotlin/org/zowe/zdevops/classic/steps/DeleteDatasetsByMaskStepSpec.kt b/src/test/kotlin/org/zowe/zdevops/classic/steps/DeleteDatasetsByMaskStepSpec.kt
index 1b1aeb7..87f0ea8 100644
--- a/src/test/kotlin/org/zowe/zdevops/classic/steps/DeleteDatasetsByMaskStepSpec.kt
+++ b/src/test/kotlin/org/zowe/zdevops/classic/steps/DeleteDatasetsByMaskStepSpec.kt
@@ -132,7 +132,7 @@ class DeleteDatasetsByMaskStepSpec : ShouldSpec({
)
val deleteDatasetDecl = spyk(
- DeleteDatasetsByMaskStep("test", "TEST.IJMP.DATASET%.NONE")
+ DeleteDatasetsByMaskStep("test", "TEST.IJMP.DATASET%.NONE", failOnNotExist = true)
)
shouldThrow {
deleteDatasetDecl.perform(
diff --git a/src/test/kotlin/org/zowe/zdevops/classic/steps/PerformTsoCommandStepSpec.kt b/src/test/kotlin/org/zowe/zdevops/classic/steps/PerformTsoCommandStepSpec.kt
index ea837f8..ff95f15 100644
--- a/src/test/kotlin/org/zowe/zdevops/classic/steps/PerformTsoCommandStepSpec.kt
+++ b/src/test/kotlin/org/zowe/zdevops/classic/steps/PerformTsoCommandStepSpec.kt
@@ -120,7 +120,7 @@ class PerformTsoCommandStepSpec : ShouldSpec({
assertSoftly { isPreExecuteStage shouldBe true }
assertSoftly { isCommandExecuted shouldBe true }
}
- should("fail SubmitJobStep operation") {
+ should("fail PerformTsoCommand operation") {
var isPreExecuteStage = false
var isExecuteCommandFailLogged = false
val taskListener = object : TestBuildListener() {