Skip to content

Commit

Permalink
rework delete dataset step (#95)
Browse files Browse the repository at this point in the history
Signed-off-by: Anatoli Kalbasin <qwnize@outlook.com>
Signed-off-by: Anatoli Kalbasin <37359814+callbacksin@users.noreply.github.com>
  • Loading branch information
callbacksin authored Jan 22, 2025
1 parent ae8477b commit 240c92d
Show file tree
Hide file tree
Showing 9 changed files with 59 additions and 70 deletions.
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ stage ("stage-name") {
writeFileToFile destFile: "u/USER/myfile", sourceFile: "myfile.txt", binary: "true"
deleteDataset dsn:"EXAMPLE.DATASET", failOnNotExist:"False"
deleteDataset dsn:"EXAMPLE.DATASET", member:"MEMBER", failOnNotExist:"True"
deleteDataset dsn:"EXAMPLE.DATASET(MEMBER)", failOnNotExist:"True"
deleteDatasetsByMask mask:"EXAMPLE.DATASET.*", failOnNotExist:"False"
}
// ...
Expand Down Expand Up @@ -121,19 +121,19 @@ zosmf ("z/os-connection-name") {
### deleteDataset - Represents an action for deleting datasets and members in a declarative style
```groovy
zosmf ("z/os-connection-name") {
deleteDataset dsn: "EXAMPLE.DATASET", member:"MEMBER", failOnNotExist:"False"
deleteDataset dsn: "EXAMPLE.DATASET(MEMBER)", failOnNotExist: false
}
```
**Mandatory Parameters:**
* ```dsn:"EXAMPLE.DATASET"``` - Sequential or library dataset name for deletion
* ```member:"MEMBER"``` - Dataset member name for deletion
* ```failOnNotExist:"False"``` - If the dataset has been deleted and the option is enabled, execution will halt. (Boolean parameter, is set to 'False' by default)
* ```dsn:"EXAMPLE.DATASET"``` - Sequential or library dataset name in the form `HLQ.DSNAME` or `HLQ.DSNAME(MEMNAME)`
**Optional Parameters:**
* `failOnNotExist: false` - Fail the execution if the entity does not exist. Boolean parameter, is set to 'false' by default.

**Expected behavior under various deletion scenarios:**

* To delete a member from the library, the dsn and member parameters must be specified:
* To delete a member from the library, provide dataset member name in the form `HLQ.DSNAME(MEMNAME)`:
```
deleteDataset dsn:"EXAMPLE.DATASET", member:"MEMBER", failOnNotExist:"False"
deleteDataset dsn:"EXAMPLE.DATASET(MEMBER1)", failOnNotExist: false
```
* You cannot delete a VSAM dataset this way. Otherwise, you will get output similar to:
Expand Down
34 changes: 11 additions & 23 deletions src/main/kotlin/org/zowe/zdevops/classic/steps/DeleteDatasetStep.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
/*
* 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.classic.steps
Expand All @@ -21,22 +25,19 @@ import org.zowe.kotlinsdk.zowe.client.sdk.core.ZOSConnection
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.validateMemberName
import org.zowe.zdevops.utils.validateDsnOrDsnMemberName

class DeleteDatasetStep
/**
* Constructs a new instance of the DeleteDatasetStep.
*
* @param connectionName The name of the z/OS connection to use for deleting the dataset.
* @param dsn The name of the dataset to delete.
* @param member The name of the member to delete.
* @param dsn The name of the dataset to delete in the form ZOSMFAD.TEST(MEMNAME).
*/
@DataBoundConstructor
constructor(
connectionName: String,
val dsn: String,
val member: String?,
val failOnNotExist: Boolean = false ,
) : AbstractBuildStep(connectionName) {

Expand All @@ -46,35 +47,22 @@ constructor(
listener: BuildListener,
zosConnection: ZOSConnection
) {
deleteDatasetOrMember(dsn, member, zosConnection, listener, failOnNotExist)
deleteDatasetOrMember(dsn, zosConnection, listener, failOnNotExist)
}

@Extension
class DescriptorImpl :
Companion.DefaultBuildDescriptor(Messages.zdevops_classic_deleteDatasetStep_display_name()) {

/**
* Checks if the dataset name is valid
* Checks if the dataset name or dataset member name is valid
*
* @param dsn The dataset name
* @param dsn The dataset name or dataset member name
* @return FormValidation.ok() if the dataset name is valid, or an error message otherwise
*/
fun doCheckDsn(@QueryParameter dsn: String): FormValidation? {
return validateDatasetName(dsn)
return validateDsnOrDsnMemberName(dsn)
}

/**
* Checks if the member name is valid
*
* @param member The dataset member name
* @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 if (member.isNotBlank()) {
validateMemberName(member)
} else {
FormValidation.ok()
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
/*
* 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
Expand Down Expand Up @@ -38,9 +42,9 @@ import org.zowe.zdevops.logic.deleteDatasetOrMember
* Deleting dataset USER1A.TEST.KSDS with connection 172.20.2.2:10443
* ISRZ002 Deallocation failed - Deallocation failed for data set 'USER1A.TEST.KSDS'
* ```
* To delete a member from the library, the dsn and member parameters must be specified:
* To delete a member from the library, provide dataset member name in the form `HLQ.DSNAME(MEMNAME)`:
* ```
* deleteDataset dsn:"USER1A.TEST.LIB", member:"MEMBER1"
* deleteDataset dsn:"USER1A.TEST.LIB(MEMBER1)"
* ```
* And out will be:
* ```
Expand All @@ -57,23 +61,19 @@ import org.zowe.zdevops.logic.deleteDatasetOrMember
* Deleting dataset USER1A.DS.ISUSED.BY.USER with connection 172.20.2.2:10443
* ISRZ002 Data set in use - Data set 'USER1A.DS.ISUSED.BY.USER' in use by another user, try later or enter HELP for a list of jobs and users allocated to 'USER1A.DS.ISUSED.BY.USER'.
* ```
* It can take 2 params:
* @param dsn dataset name - sequential or library
* @param member dataset member name
* It takes:
* @param dsn dataset name - sequential or library - in the form HLQ.DSNAME or HLQ.DSNAME(MEMNAME) for member
* @param failOnNotExist Fail the execution if the entity does not exist
*/
class DeleteDatasetDeclarative @DataBoundConstructor constructor(
) : AbstractZosmfAction() {

private var dsn: String = ""
private var member: String = ""
private var failOnNotExist: Boolean = false

@DataBoundSetter
fun setDsn(dsn: String) { this.dsn = dsn }

@DataBoundSetter
fun setMember(member: String) { this.member = member }

@DataBoundSetter
fun setFailOnNotExist(failOnNotExist: Boolean) { this.failOnNotExist = failOnNotExist }

Expand All @@ -87,7 +87,7 @@ class DeleteDatasetDeclarative @DataBoundConstructor constructor(
listener: TaskListener,
zosConnection: ZOSConnection
) {
deleteDatasetOrMember(dsn, member, zosConnection, listener, failOnNotExist)
deleteDatasetOrMember(dsn, zosConnection, listener, failOnNotExist)
}

@Symbol("deleteDataset")
Expand Down
31 changes: 21 additions & 10 deletions src/main/kotlin/org/zowe/zdevops/logic/DeleteOperation.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
/*
* 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.logic
Expand All @@ -18,6 +22,7 @@ import org.zowe.kotlinsdk.zowe.client.sdk.zosfiles.ZosDsnList
import org.zowe.kotlinsdk.zowe.client.sdk.zosfiles.input.ListParams
import org.zowe.zdevops.declarative.jobs.zMessages
import org.zowe.zdevops.utils.runMFTryCatchWrappedQuery
import javax.naming.InvalidNameException

private val successMessage: String = zMessages.zdevops_deleting_ds_success()

Expand Down Expand Up @@ -59,27 +64,33 @@ fun deleteDatasetsByMask(mask: String, zosConnection: ZOSConnection, listener: T
/**
* Deletes a dataset or member
*
* @param dsn The dataset name.
* @param member The member name (optional).
* @param dsnWithMemName The dataset name in the form ZOSMFAD.TEST(MEMNAME).
* @param zosConnection The z/OS connection to be used for dataset deletion.
* @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, failOnNotExist: Boolean) {
if (dsn.isEmpty()) {
fun deleteDatasetOrMember(dsnWithMemName: String, zosConnection: ZOSConnection, listener: TaskListener, failOnNotExist: Boolean) {
if (dsnWithMemName.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)
val dsnMemberPattern = Regex("[\\w#\$@.-]{1,}\\([\\w#\$@]+\\)") //means it's a PDS member
var member: String? = null
if (dsnWithMemName.contains(dsnMemberPattern)) {
member = dsnWithMemName.substringAfter('(').substringBefore(')')
}
val logMessage = if (!member.isNullOrEmpty()) zMessages.zdevops_deleting_ds_member(dsnWithMemName, zosConnection.host, zosConnection.zosmfPort)
else zMessages.zdevops_deleting_ds(dsnWithMemName, zosConnection.host, zosConnection.zosmfPort)
listener.logger.println(logMessage)
try {
if (!member.isNullOrEmpty()) {
isMemberNameValid(member)
ZosDsn(zosConnection).deleteDsn(dsn, member)
ZosDsn(zosConnection).deleteDsn(dsnWithMemName, member)
} else {
ZosDsn(zosConnection).deleteDsn(dsn)
ZosDsn(zosConnection).deleteDsn(dsnWithMemName)
}
listener.logger.println(successMessage)
} catch (e: InvalidNameException) {
throw e
} catch (doesNotExistEx: Exception) {
if(failOnNotExist) {
throw doesNotExistEx
Expand All @@ -97,6 +108,6 @@ fun deleteDatasetOrMember(dsn: String, member: String?, zosConnection: ZOSConnec
*/
private fun isMemberNameValid(member: String) {
if (member.length > 8 || member.isEmpty())
throw Exception(zMessages.zdevops_member_name_invalid())
throw InvalidNameException(zMessages.zdevops_member_name_invalid())
}

2 changes: 1 addition & 1 deletion src/main/resources/org/zowe/zdevops/Messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ zdevops_declarative_writing_file_fail=Cannot write to Unix file {0}
zdevops_deleting_ds_fail=Cannot perform deletion
zdevops_deleting_ds_fail_dsn_param_empty=Unable to delete: no dsn keyword present
zdevops_deleting_ds_member=Deleting member {0} from dataset "{1}" with connection {2}:{3}
zdevops_deleting_ds_member=Deleting member {0} with connection {1}:{2}
zdevops_deleting_ds=Deleting dataset {0} with connection {1}:{2}
zdevops_deleting_ds_by_mask=Deleting datasets that match the mask "{0}"
zdevops_deleting_ds_fail_no_matching_mask=No data sets matching the mask were found
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,10 @@
<form:entry field="connectionName" title="${%zdevops.classic.connection.title}">
<form:select/>
</form:entry>
<form:entry field="dsn" title="${%zdevops.classic.dsn.title}">
<form:entry field="dsn" title="${%zdevops.classic.dsn.title}" description="${%zdevops.classic.dsn.desc}">
<form:textbox/>
</form:entry>
<form:entry field="member" title="${%zdevops.classic.member.title}">
<form:textbox/>
</form:entry>
<form:entry field="failOnNotExist" title="failOnNotExist?" description="If the dataset does not exists and the option is enabled, execution will halt.">
<form:entry field="failOnNotExist" title="${%zdevops.classic.failOnNotExist.title}">
<form:checkbox/>
</form:entry>
</jelly:jelly>
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
zdevops.classic.connection.title=z/OS connection
zdevops.classic.dsn.title=Dataset
zdevops.classic.member.title=Member (optional)
zdevops.classic.dsn.desc=Specify a dataset as HLQ.DSNAME or a member name as HLQ.DSNAME(MEMNAME)
zdevops.classic.failOnNotExist.title=Fail the step if the entity does not exist
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ class DeleteDatasetStepSpec : ShouldSpec({
)

val deleteDatasetStep = spyk(
DeleteDatasetStep("test", "TEST.IJMP.DATASET1", member = null)
DeleteDatasetStep("test", "TEST.IJMP.DATASET1")
)
deleteDatasetStep.perform(
build,
Expand Down Expand Up @@ -130,7 +130,7 @@ class DeleteDatasetStepSpec : ShouldSpec({
)

val deleteDatasetStep = spyk(
DeleteDatasetStep("test", "TEST.IJMP.DATASET1", member = null, failOnNotExist = false)
DeleteDatasetStep("test", "TEST.IJMP.DATASET1", failOnNotExist = false)
)
deleteDatasetStep.perform(
build,
Expand All @@ -152,11 +152,5 @@ class DeleteDatasetStepSpec : ShouldSpec({
descriptor.doCheckDsn("") shouldBe FormValidation.error(Messages.zdevops_value_must_not_be_empty_validation())
descriptor.doCheckDsn("MY_DATASET") shouldBe FormValidation.error(Messages.zdevops_dataset_name_is_invalid_validation())
}

should("validate member name") {
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()
}
}
})
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,7 @@ class DeleteDatasetDeclarativeSpec : ShouldSpec({
val deleteDatasetDecl = spyk(
DeleteDatasetDeclarative()
)
deleteDatasetDecl.setDsn("test")
deleteDatasetDecl.setMember("test")
deleteDatasetDecl.setDsn("test(test)")
deleteDatasetDecl.perform(
run,
workspace,
Expand Down Expand Up @@ -210,8 +209,7 @@ class DeleteDatasetDeclarativeSpec : ShouldSpec({
val deleteDatasetDecl = spyk(
DeleteDatasetDeclarative()
)
deleteDatasetDecl.setDsn("test")
deleteDatasetDecl.setMember("testlongmembername")
deleteDatasetDecl.setDsn("test(testlongmembername)")
runCatching {
deleteDatasetDecl.perform(
run,
Expand Down

0 comments on commit 240c92d

Please sign in to comment.