From 9cdd9fbd6bdf189869cb9034d5c4478358c4707b Mon Sep 17 00:00:00 2001 From: Anatoli Kalbasin Date: Fri, 22 Nov 2024 10:07:01 +0100 Subject: [PATCH] implement enhancement Signed-off-by: Anatoli Kalbasin --- README.md | 14 ++++---- .../classic/steps/DeleteDatasetStep.kt | 34 ++++++------------- .../jobs/DeleteDatasetDeclarative.kt | 22 ++++++------ .../org/zowe/zdevops/logic/DeleteOperation.kt | 31 +++++++++++------ .../org/zowe/zdevops/Messages.properties | 2 +- .../steps/DeleteDatasetStep/config.jelly | 7 ++-- .../steps/DeleteDatasetStep/config.properties | 3 +- .../classic/steps/DeleteDatasetStepSpec.kt | 10 ++---- .../jobs/DeleteDatasetDeclarativeSpec.kt | 6 ++-- 9 files changed, 60 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index 2ff73de..32e3f84 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ stage ("stage-name") { writeFileToFile destFile: "u/USER/myfile", sourceFile: "myfile.txt", binary: "true" deleteDataset dsn:"EXAMPLE.DATASET" - deleteDataset dsn:"EXAMPLE.DATASET", member:"MEMBER" + deleteDataset dsn:"EXAMPLE.DATASET(MEMBER)" deleteDatasetsByMask mask:"EXAMPLE.DATASET.*" } // ... @@ -96,17 +96,19 @@ allocateDS dsn:"EXAMPLE.DATASET", dsOrg:"PS", primary:1, secondary:1, recFm:"FB" ### deleteDataset - Represents an action for deleting datasets and members in a declarative style ```groovy -deleteDataset dsn:"EXAMPLE.DATASET" +deleteDataset dsn:"EXAMPLE.DATASET", failOnNotExist: true ``` **Mandatory Parameters:** - * ```dsn:"EXAMPLE.DATASET"``` - Sequential or library dataset name for deletion - * ```member:"MEMBER"``` - Dataset member name for deletion + * ```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 + **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" + deleteDataset dsn:"EXAMPLE.DATASET(MEMBER1)" ``` * You cannot delete a VSAM dataset this way. Otherwise, you will get output similar to: 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 6974e54..239ad72 100644 --- a/src/main/kotlin/org/zowe/zdevops/classic/steps/DeleteDatasetStep.kt +++ b/src/main/kotlin/org/zowe/zdevops/classic/steps/DeleteDatasetStep.kt @@ -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 @@ -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) { @@ -46,7 +47,7 @@ constructor( listener: BuildListener, zosConnection: ZOSConnection ) { - deleteDatasetOrMember(dsn, member, zosConnection, listener, failOnNotExist) + deleteDatasetOrMember(dsn, zosConnection, listener, failOnNotExist) } @Extension @@ -54,27 +55,14 @@ constructor( 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() - } - } } } \ No newline at end of file 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 fc72a4e..2f15342 100644 --- a/src/main/kotlin/org/zowe/zdevops/declarative/jobs/DeleteDatasetDeclarative.kt +++ b/src/main/kotlin/org/zowe/zdevops/declarative/jobs/DeleteDatasetDeclarative.kt @@ -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 @@ -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: * ``` @@ -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 } @@ -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") diff --git a/src/main/kotlin/org/zowe/zdevops/logic/DeleteOperation.kt b/src/main/kotlin/org/zowe/zdevops/logic/DeleteOperation.kt index 6048c5f..d3af445 100644 --- a/src/main/kotlin/org/zowe/zdevops/logic/DeleteOperation.kt +++ b/src/main/kotlin/org/zowe/zdevops/logic/DeleteOperation.kt @@ -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 @@ -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() @@ -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 @@ -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()) } diff --git a/src/main/resources/org/zowe/zdevops/Messages.properties b/src/main/resources/org/zowe/zdevops/Messages.properties index 1f6d285..4350a54 100644 --- a/src/main/resources/org/zowe/zdevops/Messages.properties +++ b/src/main/resources/org/zowe/zdevops/Messages.properties @@ -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 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 aa711c2..44d0497 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 @@ -6,13 +6,10 @@ - + - - - - + \ No newline at end of file diff --git a/src/main/resources/org/zowe/zdevops/classic/steps/DeleteDatasetStep/config.properties b/src/main/resources/org/zowe/zdevops/classic/steps/DeleteDatasetStep/config.properties index ada18a6..b2110cb 100644 --- a/src/main/resources/org/zowe/zdevops/classic/steps/DeleteDatasetStep/config.properties +++ b/src/main/resources/org/zowe/zdevops/classic/steps/DeleteDatasetStep/config.properties @@ -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 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 f110b9d..fa8b3f4 100644 --- a/src/test/kotlin/org/zowe/zdevops/classic/steps/DeleteDatasetStepSpec.kt +++ b/src/test/kotlin/org/zowe/zdevops/classic/steps/DeleteDatasetStepSpec.kt @@ -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, @@ -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, @@ -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() - } } }) \ No newline at end of file diff --git a/src/test/kotlin/org/zowe/zdevops/declarative/jobs/DeleteDatasetDeclarativeSpec.kt b/src/test/kotlin/org/zowe/zdevops/declarative/jobs/DeleteDatasetDeclarativeSpec.kt index e3dab24..a544b80 100644 --- a/src/test/kotlin/org/zowe/zdevops/declarative/jobs/DeleteDatasetDeclarativeSpec.kt +++ b/src/test/kotlin/org/zowe/zdevops/declarative/jobs/DeleteDatasetDeclarativeSpec.kt @@ -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, @@ -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,