diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 0b5f41f0e6..d98dcf7be5 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,8 +1,10 @@ # Change Log All notable changes to the Zowe CLI package will be documented in this file. -## `8.10.4` +## Recent Changes +- Enhancement: The `zowe zos-files copy data-set` command no longer requires the target data set to be preallocated. [##2349] (https://github.com/zowe/zowe-cli/issues/2349) +## `8.10.4` - BugFix: Fixed an issue where the `zowe files upload dir-to-uss` command was missing progress bar to track progress of file uploads. [#2344](https://github.com/zowe/zowe-cli/issues/2344) ## `8.10.3` diff --git a/packages/cli/__tests__/zosfiles/__integration__/copy/ds/__snapshots__/cli.files.copy.ds.integration.test.ts.snap b/packages/cli/__tests__/zosfiles/__integration__/copy/ds/__snapshots__/cli.files.copy.ds.integration.test.ts.snap index 6a4e1020b7..63dd437f15 100644 --- a/packages/cli/__tests__/zosfiles/__integration__/copy/ds/__snapshots__/cli.files.copy.ds.integration.test.ts.snap +++ b/packages/cli/__tests__/zosfiles/__integration__/copy/ds/__snapshots__/cli.files.copy.ds.integration.test.ts.snap @@ -27,8 +27,7 @@ exports[`Copy Data Set should display the help 1`] = ` toDataSetName (string) - The name of the data set that you want to copy to (data set must be - preallocated) + The name of the data set that you want to copy to OPTIONS ------- @@ -171,8 +170,8 @@ exports[`Copy Data Set should display the help in json format 1`] = ` \\"success\\": true, \\"exitCode\\": 0, \\"message\\": \\"The help was constructed for command: data-set.\\", - \\"stdout\\": \\"\\\\n COMMAND NAME\\\\n ------------\\\\n\\\\n data-set | ds\\\\n\\\\n DESCRIPTION\\\\n -----------\\\\n\\\\n Copy a data set/partitioned data set to another data set/partitioned data set.\\\\n\\\\n USAGE\\\\n -----\\\\n\\\\n zowe zos-files copy data-set [options]\\\\n\\\\n POSITIONAL ARGUMENTS\\\\n --------------------\\\\n\\\\n fromDataSetName\\\\t\\\\t (string)\\\\n\\\\n The name of the data set that you want to copy from\\\\n\\\\n toDataSetName\\\\t\\\\t (string)\\\\n\\\\n The name of the data set that you want to copy to (data set must be\\\\n preallocated)\\\\n\\\\n OPTIONS\\\\n -------\\\\n\\\\n --replace | --rep (boolean)\\\\n\\\\n Specify this option as true if you wish to replace like-named members in the\\\\n target data set\\\\n\\\\n --response-timeout | --rto (number)\\\\n\\\\n The maximum amount of time in seconds the z/OSMF Files TSO servlet should run\\\\n before returning a response. Any request exceeding this amount of time will be\\\\n terminated and return an error. Allowed values: 5 - 600\\\\n\\\\n ZOSMF CONNECTION OPTIONS\\\\n ------------------------\\\\n\\\\n --host | -H (string)\\\\n\\\\n The z/OSMF server host name.\\\\n\\\\n --port | -P (number)\\\\n\\\\n The z/OSMF server port.\\\\n\\\\n Default value: 443\\\\n\\\\n --user | -u (string)\\\\n\\\\n Mainframe (z/OSMF) user name, which can be the same as your TSO login.\\\\n\\\\n --password | --pass | --pw (string)\\\\n\\\\n Mainframe (z/OSMF) password, which can be the same as your TSO password.\\\\n\\\\n --reject-unauthorized | --ru (boolean)\\\\n\\\\n Reject self-signed certificates.\\\\n\\\\n Default value: true\\\\n\\\\n --base-path | --bp (string)\\\\n\\\\n The base path for your API mediation layer instance. Specify this option to\\\\n prepend the base path to all z/OSMF resources when making REST requests. Do not\\\\n specify this option if you are not using an API mediation layer.\\\\n\\\\n --protocol (string)\\\\n\\\\n The protocol used (HTTP or HTTPS)\\\\n\\\\n Default value: https\\\\n Allowed values: http, https\\\\n\\\\n --cert-file (local file path)\\\\n\\\\n The file path to a certificate file to use for authentication\\\\n\\\\n --cert-key-file (local file path)\\\\n\\\\n The file path to a certificate key file to use for authentication\\\\n\\\\n PROFILE OPTIONS\\\\n ---------------\\\\n\\\\n --zosmf-profile | --zosmf-p (string)\\\\n\\\\n The name of a (zosmf) profile to load for this command execution.\\\\n\\\\n --base-profile | --base-p (string)\\\\n\\\\n The name of a (base) profile to load for this command execution.\\\\n\\\\n BASE CONNECTION OPTIONS\\\\n -----------------------\\\\n\\\\n --token-type | --tt (string)\\\\n\\\\n The type of token to get and use for the API. Omit this option to use the\\\\n default token type, which is provided by 'zowe auth login'.\\\\n\\\\n --token-value | --tv (string)\\\\n\\\\n The value of the token to pass to the API.\\\\n\\\\n GLOBAL OPTIONS\\\\n --------------\\\\n\\\\n --show-inputs-only (boolean)\\\\n\\\\n Show command inputs and do not run the command\\\\n\\\\n --response-format-json | --rfj (boolean)\\\\n\\\\n Produce JSON formatted data from a command\\\\n\\\\n --help | -h (boolean)\\\\n\\\\n Display help text\\\\n\\\\n --help-web | --hw (boolean)\\\\n\\\\n Display HTML help in browser\\\\n\\\\n EXAMPLES\\\\n --------\\\\n\\\\n - Copy the data set named 'USER.FROM.SET' to the data set\\\\n named 'USER.TO.SET':\\\\n\\\\n $ zowe zos-files copy data-set \\\\\\"USER.FROM.SET\\\\\\" \\\\\\"USER.TO.SET\\\\\\"\\\\n\\\\n - Copy the data set member named 'USER.FROM.SET(MEM1)' to the\\\\n data set member named 'USER.TO.SET(MEM2)':\\\\n\\\\n $ zowe zos-files copy data-set \\\\\\"USER.FROM.SET(mem1)\\\\\\" \\\\\\"USER.TO.SET(mem2)\\\\\\"\\\\n\\\\n - Copy the data set named 'USER.FROM.SET' to the data set\\\\n member named 'USER.TO.SET(MEM2)':\\\\n\\\\n $ zowe zos-files copy data-set \\\\\\"USER.FROM.SET\\\\\\" \\\\\\"USER.TO.SET(mem2)\\\\\\"\\\\n\\\\n - Copy the data set member named 'USER.FROM.SET(MEM1)' to the\\\\n data set named 'USER.TO.SET':\\\\n\\\\n $ zowe zos-files copy data-set \\\\\\"USER.FROM.SET(mem1)\\\\\\" \\\\\\"USER.TO.SET\\\\\\"\\\\n\\\\n - Copy the data set named 'USER.FROM.SET' to the data set\\\\n named 'USER.TO.SET' and replace like-named members:\\\\n\\\\n $ zowe zos-files copy data-set \\\\\\"USER.FROM.SET\\\\\\" \\\\\\"USER.TO.SET\\\\\\" --replace\\\\n\\\\n\\", + \\"stdout\\": \\"\\\\n COMMAND NAME\\\\n ------------\\\\n\\\\n data-set | ds\\\\n\\\\n DESCRIPTION\\\\n -----------\\\\n\\\\n Copy a data set/partitioned data set to another data set/partitioned data set.\\\\n\\\\n USAGE\\\\n -----\\\\n\\\\n zowe zos-files copy data-set [options]\\\\n\\\\n POSITIONAL ARGUMENTS\\\\n --------------------\\\\n\\\\n fromDataSetName\\\\t\\\\t (string)\\\\n\\\\n The name of the data set that you want to copy from\\\\n\\\\n toDataSetName\\\\t\\\\t (string)\\\\n\\\\n The name of the data set that you want to copy to\\\\n\\\\n OPTIONS\\\\n -------\\\\n\\\\n --replace | --rep (boolean)\\\\n\\\\n Specify this option as true if you wish to replace like-named members in the\\\\n target data set\\\\n\\\\n --response-timeout | --rto (number)\\\\n\\\\n The maximum amount of time in seconds the z/OSMF Files TSO servlet should run\\\\n before returning a response. Any request exceeding this amount of time will be\\\\n terminated and return an error. Allowed values: 5 - 600\\\\n\\\\n ZOSMF CONNECTION OPTIONS\\\\n ------------------------\\\\n\\\\n --host | -H (string)\\\\n\\\\n The z/OSMF server host name.\\\\n\\\\n --port | -P (number)\\\\n\\\\n The z/OSMF server port.\\\\n\\\\n Default value: 443\\\\n\\\\n --user | -u (string)\\\\n\\\\n Mainframe (z/OSMF) user name, which can be the same as your TSO login.\\\\n\\\\n --password | --pass | --pw (string)\\\\n\\\\n Mainframe (z/OSMF) password, which can be the same as your TSO password.\\\\n\\\\n --reject-unauthorized | --ru (boolean)\\\\n\\\\n Reject self-signed certificates.\\\\n\\\\n Default value: true\\\\n\\\\n --base-path | --bp (string)\\\\n\\\\n The base path for your API mediation layer instance. Specify this option to\\\\n prepend the base path to all z/OSMF resources when making REST requests. Do not\\\\n specify this option if you are not using an API mediation layer.\\\\n\\\\n --protocol (string)\\\\n\\\\n The protocol used (HTTP or HTTPS)\\\\n\\\\n Default value: https\\\\n Allowed values: http, https\\\\n\\\\n --cert-file (local file path)\\\\n\\\\n The file path to a certificate file to use for authentication\\\\n\\\\n --cert-key-file (local file path)\\\\n\\\\n The file path to a certificate key file to use for authentication\\\\n\\\\n PROFILE OPTIONS\\\\n ---------------\\\\n\\\\n --zosmf-profile | --zosmf-p (string)\\\\n\\\\n The name of a (zosmf) profile to load for this command execution.\\\\n\\\\n --base-profile | --base-p (string)\\\\n\\\\n The name of a (base) profile to load for this command execution.\\\\n\\\\n BASE CONNECTION OPTIONS\\\\n -----------------------\\\\n\\\\n --token-type | --tt (string)\\\\n\\\\n The type of token to get and use for the API. Omit this option to use the\\\\n default token type, which is provided by 'zowe auth login'.\\\\n\\\\n --token-value | --tv (string)\\\\n\\\\n The value of the token to pass to the API.\\\\n\\\\n GLOBAL OPTIONS\\\\n --------------\\\\n\\\\n --show-inputs-only (boolean)\\\\n\\\\n Show command inputs and do not run the command\\\\n\\\\n --response-format-json | --rfj (boolean)\\\\n\\\\n Produce JSON formatted data from a command\\\\n\\\\n --help | -h (boolean)\\\\n\\\\n Display help text\\\\n\\\\n --help-web | --hw (boolean)\\\\n\\\\n Display HTML help in browser\\\\n\\\\n EXAMPLES\\\\n --------\\\\n\\\\n - Copy the data set named 'USER.FROM.SET' to the data set\\\\n named 'USER.TO.SET':\\\\n\\\\n $ zowe zos-files copy data-set \\\\\\"USER.FROM.SET\\\\\\" \\\\\\"USER.TO.SET\\\\\\"\\\\n\\\\n - Copy the data set member named 'USER.FROM.SET(MEM1)' to the\\\\n data set member named 'USER.TO.SET(MEM2)':\\\\n\\\\n $ zowe zos-files copy data-set \\\\\\"USER.FROM.SET(mem1)\\\\\\" \\\\\\"USER.TO.SET(mem2)\\\\\\"\\\\n\\\\n - Copy the data set named 'USER.FROM.SET' to the data set\\\\n member named 'USER.TO.SET(MEM2)':\\\\n\\\\n $ zowe zos-files copy data-set \\\\\\"USER.FROM.SET\\\\\\" \\\\\\"USER.TO.SET(mem2)\\\\\\"\\\\n\\\\n - Copy the data set member named 'USER.FROM.SET(MEM1)' to the\\\\n data set named 'USER.TO.SET':\\\\n\\\\n $ zowe zos-files copy data-set \\\\\\"USER.FROM.SET(mem1)\\\\\\" \\\\\\"USER.TO.SET\\\\\\"\\\\n\\\\n - Copy the data set named 'USER.FROM.SET' to the data set\\\\n named 'USER.TO.SET' and replace like-named members:\\\\n\\\\n $ zowe zos-files copy data-set \\\\\\"USER.FROM.SET\\\\\\" \\\\\\"USER.TO.SET\\\\\\" --replace\\\\n\\\\n\\", \\"stderr\\": \\"\\", - \\"data\\": \\"\\\\n COMMAND NAME\\\\n ------------\\\\n\\\\n data-set | ds\\\\n\\\\n DESCRIPTION\\\\n -----------\\\\n\\\\n Copy a data set/partitioned data set to another data set/partitioned data set.\\\\n\\\\n USAGE\\\\n -----\\\\n\\\\n zowe zos-files copy data-set [options]\\\\n\\\\n POSITIONAL ARGUMENTS\\\\n --------------------\\\\n\\\\n fromDataSetName\\\\t\\\\t (string)\\\\n\\\\n The name of the data set that you want to copy from\\\\n\\\\n toDataSetName\\\\t\\\\t (string)\\\\n\\\\n The name of the data set that you want to copy to (data set must be\\\\n preallocated)\\\\n\\\\n OPTIONS\\\\n -------\\\\n\\\\n --replace | --rep (boolean)\\\\n\\\\n Specify this option as true if you wish to replace like-named members in the\\\\n target data set\\\\n\\\\n --response-timeout | --rto (number)\\\\n\\\\n The maximum amount of time in seconds the z/OSMF Files TSO servlet should run\\\\n before returning a response. Any request exceeding this amount of time will be\\\\n terminated and return an error. Allowed values: 5 - 600\\\\n\\\\n ZOSMF CONNECTION OPTIONS\\\\n ------------------------\\\\n\\\\n --host | -H (string)\\\\n\\\\n The z/OSMF server host name.\\\\n\\\\n --port | -P (number)\\\\n\\\\n The z/OSMF server port.\\\\n\\\\n Default value: 443\\\\n\\\\n --user | -u (string)\\\\n\\\\n Mainframe (z/OSMF) user name, which can be the same as your TSO login.\\\\n\\\\n --password | --pass | --pw (string)\\\\n\\\\n Mainframe (z/OSMF) password, which can be the same as your TSO password.\\\\n\\\\n --reject-unauthorized | --ru (boolean)\\\\n\\\\n Reject self-signed certificates.\\\\n\\\\n Default value: true\\\\n\\\\n --base-path | --bp (string)\\\\n\\\\n The base path for your API mediation layer instance. Specify this option to\\\\n prepend the base path to all z/OSMF resources when making REST requests. Do not\\\\n specify this option if you are not using an API mediation layer.\\\\n\\\\n --protocol (string)\\\\n\\\\n The protocol used (HTTP or HTTPS)\\\\n\\\\n Default value: https\\\\n Allowed values: http, https\\\\n\\\\n --cert-file (local file path)\\\\n\\\\n The file path to a certificate file to use for authentication\\\\n\\\\n --cert-key-file (local file path)\\\\n\\\\n The file path to a certificate key file to use for authentication\\\\n\\\\n PROFILE OPTIONS\\\\n ---------------\\\\n\\\\n --zosmf-profile | --zosmf-p (string)\\\\n\\\\n The name of a (zosmf) profile to load for this command execution.\\\\n\\\\n --base-profile | --base-p (string)\\\\n\\\\n The name of a (base) profile to load for this command execution.\\\\n\\\\n BASE CONNECTION OPTIONS\\\\n -----------------------\\\\n\\\\n --token-type | --tt (string)\\\\n\\\\n The type of token to get and use for the API. Omit this option to use the\\\\n default token type, which is provided by 'zowe auth login'.\\\\n\\\\n --token-value | --tv (string)\\\\n\\\\n The value of the token to pass to the API.\\\\n\\\\n GLOBAL OPTIONS\\\\n --------------\\\\n\\\\n --show-inputs-only (boolean)\\\\n\\\\n Show command inputs and do not run the command\\\\n\\\\n --response-format-json | --rfj (boolean)\\\\n\\\\n Produce JSON formatted data from a command\\\\n\\\\n --help | -h (boolean)\\\\n\\\\n Display help text\\\\n\\\\n --help-web | --hw (boolean)\\\\n\\\\n Display HTML help in browser\\\\n\\\\n EXAMPLES\\\\n --------\\\\n\\\\n - Copy the data set named 'USER.FROM.SET' to the data set\\\\n named 'USER.TO.SET':\\\\n\\\\n $ zowe zos-files copy data-set \\\\\\"USER.FROM.SET\\\\\\" \\\\\\"USER.TO.SET\\\\\\"\\\\n\\\\n - Copy the data set member named 'USER.FROM.SET(MEM1)' to the\\\\n data set member named 'USER.TO.SET(MEM2)':\\\\n\\\\n $ zowe zos-files copy data-set \\\\\\"USER.FROM.SET(mem1)\\\\\\" \\\\\\"USER.TO.SET(mem2)\\\\\\"\\\\n\\\\n - Copy the data set named 'USER.FROM.SET' to the data set\\\\n member named 'USER.TO.SET(MEM2)':\\\\n\\\\n $ zowe zos-files copy data-set \\\\\\"USER.FROM.SET\\\\\\" \\\\\\"USER.TO.SET(mem2)\\\\\\"\\\\n\\\\n - Copy the data set member named 'USER.FROM.SET(MEM1)' to the\\\\n data set named 'USER.TO.SET':\\\\n\\\\n $ zowe zos-files copy data-set \\\\\\"USER.FROM.SET(mem1)\\\\\\" \\\\\\"USER.TO.SET\\\\\\"\\\\n\\\\n - Copy the data set named 'USER.FROM.SET' to the data set\\\\n named 'USER.TO.SET' and replace like-named members:\\\\n\\\\n $ zowe zos-files copy data-set \\\\\\"USER.FROM.SET\\\\\\" \\\\\\"USER.TO.SET\\\\\\" --replace\\\\n\\\\n\\" + \\"data\\": \\"\\\\n COMMAND NAME\\\\n ------------\\\\n\\\\n data-set | ds\\\\n\\\\n DESCRIPTION\\\\n -----------\\\\n\\\\n Copy a data set/partitioned data set to another data set/partitioned data set.\\\\n\\\\n USAGE\\\\n -----\\\\n\\\\n zowe zos-files copy data-set [options]\\\\n\\\\n POSITIONAL ARGUMENTS\\\\n --------------------\\\\n\\\\n fromDataSetName\\\\t\\\\t (string)\\\\n\\\\n The name of the data set that you want to copy from\\\\n\\\\n toDataSetName\\\\t\\\\t (string)\\\\n\\\\n The name of the data set that you want to copy to\\\\n\\\\n OPTIONS\\\\n -------\\\\n\\\\n --replace | --rep (boolean)\\\\n\\\\n Specify this option as true if you wish to replace like-named members in the\\\\n target data set\\\\n\\\\n --response-timeout | --rto (number)\\\\n\\\\n The maximum amount of time in seconds the z/OSMF Files TSO servlet should run\\\\n before returning a response. Any request exceeding this amount of time will be\\\\n terminated and return an error. Allowed values: 5 - 600\\\\n\\\\n ZOSMF CONNECTION OPTIONS\\\\n ------------------------\\\\n\\\\n --host | -H (string)\\\\n\\\\n The z/OSMF server host name.\\\\n\\\\n --port | -P (number)\\\\n\\\\n The z/OSMF server port.\\\\n\\\\n Default value: 443\\\\n\\\\n --user | -u (string)\\\\n\\\\n Mainframe (z/OSMF) user name, which can be the same as your TSO login.\\\\n\\\\n --password | --pass | --pw (string)\\\\n\\\\n Mainframe (z/OSMF) password, which can be the same as your TSO password.\\\\n\\\\n --reject-unauthorized | --ru (boolean)\\\\n\\\\n Reject self-signed certificates.\\\\n\\\\n Default value: true\\\\n\\\\n --base-path | --bp (string)\\\\n\\\\n The base path for your API mediation layer instance. Specify this option to\\\\n prepend the base path to all z/OSMF resources when making REST requests. Do not\\\\n specify this option if you are not using an API mediation layer.\\\\n\\\\n --protocol (string)\\\\n\\\\n The protocol used (HTTP or HTTPS)\\\\n\\\\n Default value: https\\\\n Allowed values: http, https\\\\n\\\\n --cert-file (local file path)\\\\n\\\\n The file path to a certificate file to use for authentication\\\\n\\\\n --cert-key-file (local file path)\\\\n\\\\n The file path to a certificate key file to use for authentication\\\\n\\\\n PROFILE OPTIONS\\\\n ---------------\\\\n\\\\n --zosmf-profile | --zosmf-p (string)\\\\n\\\\n The name of a (zosmf) profile to load for this command execution.\\\\n\\\\n --base-profile | --base-p (string)\\\\n\\\\n The name of a (base) profile to load for this command execution.\\\\n\\\\n BASE CONNECTION OPTIONS\\\\n -----------------------\\\\n\\\\n --token-type | --tt (string)\\\\n\\\\n The type of token to get and use for the API. Omit this option to use the\\\\n default token type, which is provided by 'zowe auth login'.\\\\n\\\\n --token-value | --tv (string)\\\\n\\\\n The value of the token to pass to the API.\\\\n\\\\n GLOBAL OPTIONS\\\\n --------------\\\\n\\\\n --show-inputs-only (boolean)\\\\n\\\\n Show command inputs and do not run the command\\\\n\\\\n --response-format-json | --rfj (boolean)\\\\n\\\\n Produce JSON formatted data from a command\\\\n\\\\n --help | -h (boolean)\\\\n\\\\n Display help text\\\\n\\\\n --help-web | --hw (boolean)\\\\n\\\\n Display HTML help in browser\\\\n\\\\n EXAMPLES\\\\n --------\\\\n\\\\n - Copy the data set named 'USER.FROM.SET' to the data set\\\\n named 'USER.TO.SET':\\\\n\\\\n $ zowe zos-files copy data-set \\\\\\"USER.FROM.SET\\\\\\" \\\\\\"USER.TO.SET\\\\\\"\\\\n\\\\n - Copy the data set member named 'USER.FROM.SET(MEM1)' to the\\\\n data set member named 'USER.TO.SET(MEM2)':\\\\n\\\\n $ zowe zos-files copy data-set \\\\\\"USER.FROM.SET(mem1)\\\\\\" \\\\\\"USER.TO.SET(mem2)\\\\\\"\\\\n\\\\n - Copy the data set named 'USER.FROM.SET' to the data set\\\\n member named 'USER.TO.SET(MEM2)':\\\\n\\\\n $ zowe zos-files copy data-set \\\\\\"USER.FROM.SET\\\\\\" \\\\\\"USER.TO.SET(mem2)\\\\\\"\\\\n\\\\n - Copy the data set member named 'USER.FROM.SET(MEM1)' to the\\\\n data set named 'USER.TO.SET':\\\\n\\\\n $ zowe zos-files copy data-set \\\\\\"USER.FROM.SET(mem1)\\\\\\" \\\\\\"USER.TO.SET\\\\\\"\\\\n\\\\n - Copy the data set named 'USER.FROM.SET' to the data set\\\\n named 'USER.TO.SET' and replace like-named members:\\\\n\\\\n $ zowe zos-files copy data-set \\\\\\"USER.FROM.SET\\\\\\" \\\\\\"USER.TO.SET\\\\\\" --replace\\\\n\\\\n\\" }" `; diff --git a/packages/cli/src/zosfiles/-strings-/en.ts b/packages/cli/src/zosfiles/-strings-/en.ts index 803eb27554..176e035729 100644 --- a/packages/cli/src/zosfiles/-strings-/en.ts +++ b/packages/cli/src/zosfiles/-strings-/en.ts @@ -192,7 +192,7 @@ export default { DESCRIPTION: "Copy a data set/partitioned data set to another data set/partitioned data set.", POSITIONALS: { FROMDSNAME: "The name of the data set that you want to copy from", - TODSNAME: "The name of the data set that you want to copy to (data set must be preallocated)" + TODSNAME: "The name of the data set that you want to copy to" }, OPTIONS: { REPLACE: "Specify this option as true if you wish to replace like-named members in the target data set" @@ -203,7 +203,8 @@ export default { EX3: "Copy the data set named 'USER.FROM.SET' to the data set member named 'USER.TO.SET(MEM2)'", EX4: "Copy the data set member named 'USER.FROM.SET(MEM1)' to the data set named 'USER.TO.SET'", EX5: "Copy the data set named 'USER.FROM.SET' to the data set named 'USER.TO.SET' and replace like-named members", - EX6: "Copy the partitioned data set named 'TEST.PDS1' to the partitioned data set named 'TEST.PDS2'" + EX6: "Copy the partitioned data set named 'TEST.PDS1' to the partitioned data set named 'TEST.PDS2'", + EX7: "Copy the partitioned data set named 'EXISTING.PDS' to a non-existent target 'NEW.PDS'" } }, DATA_SET_CROSS_LPAR: { diff --git a/packages/zosfiles/CHANGELOG.md b/packages/zosfiles/CHANGELOG.md index e72cf748c9..d8d9c25b63 100644 --- a/packages/zosfiles/CHANGELOG.md +++ b/packages/zosfiles/CHANGELOG.md @@ -2,8 +2,11 @@ All notable changes to the Zowe z/OS files SDK package will be documented in this file. -## `8.10.3` +## Recent Changes +- Enhancement: The `Copy.dataset` function now creates a new data set if the entered target data set does not exist. [#2349](https://github.com/zowe/zowe-cli/issues/2349) + +## `8.10.3` - BugFix: The `Copy.dataset` method no longer copies all partitioned data set members if a member is passed to the function. [#2402](https://github.com/zowe/zowe-cli/pull/2402) ## `8.10.0` diff --git a/packages/zosfiles/__tests__/__system__/methods/copy/Copy.system.test.ts b/packages/zosfiles/__tests__/__system__/methods/copy/Copy.system.test.ts index 893b40f268..bccc37a439 100644 --- a/packages/zosfiles/__tests__/__system__/methods/copy/Copy.system.test.ts +++ b/packages/zosfiles/__tests__/__system__/methods/copy/Copy.system.test.ts @@ -280,6 +280,54 @@ describe("Copy", () => { }); }); }); + describe("dataSetsIdentical", () => { + beforeEach(async () => { + try { + await Create.dataSet(REAL_SESSION, CreateDataSetTypeEnum.DATA_SET_SEQUENTIAL, fromDataSetName); + await Create.dataSet(REAL_SESSION, CreateDataSetTypeEnum.DATA_SET_SEQUENTIAL, fromDataSetName); + } catch (err) { + Imperative.console.info(`Error: ${inspect(err)}`); + } + }); + it("should return false when the source and target data sets are indentical", async () => { + let error; + let response; + try { + response = await Copy.dataSet( + REAL_SESSION, + {dsn: fromDataSetName}, + {"from-dataset": { + dsn:fromDataSetName + }} + ); + } + catch(err) { + error = err; + Imperative.console.info(`Error: ${inspect(err)}`); + } + expect(error).toBeFalsy(); + + expect(response).toBeTruthy(); + expect(response.success).toBe(false); + expect(response.commandResponse).toContain(ZosFilesMessages.identicalDataSets.message); + + }); + }); + describe("dataSetExists", () => { + it("should return true when the dataset exists", async () => { + try { + await Create.dataSet(REAL_SESSION, CreateDataSetTypeEnum.DATA_SET_SEQUENTIAL, fromDataSetName); + } catch (err) { + Imperative.console.info(`Error: ${inspect(err)}`); + } + const exists = await Copy["dataSetExists"](REAL_SESSION, fromDataSetName); + expect(exists).toBe(true); + }); + it("should return false when the dataset does not exist", async () => { + const exists = await Copy["dataSetExists"](REAL_SESSION, fromDataSetName); + expect(exists).toBe(false); + }); + }); describe("Enq option", () => { beforeEach(async () => { try { diff --git a/packages/zosfiles/__tests__/__unit__/methods/copy/Copy.unit.test.ts b/packages/zosfiles/__tests__/__unit__/methods/copy/Copy.unit.test.ts index e082069894..2cfbf762ff 100644 --- a/packages/zosfiles/__tests__/__unit__/methods/copy/Copy.unit.test.ts +++ b/packages/zosfiles/__tests__/__unit__/methods/copy/Copy.unit.test.ts @@ -13,7 +13,7 @@ import { Session, ImperativeError, IO } from "@zowe/imperative"; import { posix } from "path"; import * as fs from "fs"; import { error } from "console"; - +import * as util from "util"; import { Copy, Create, Get, List, Upload, ZosFilesConstants, ZosFilesMessages, IZosFilesResponse, Download, ZosFilesUtils } from "../../../../src"; import { ZosmfHeaders, ZosmfRestClient } from "@zowe/core-for-zowe-sdk"; @@ -35,14 +35,18 @@ describe("Copy", () => { const toDataSetName = "USER.DATA.TO"; const toMemberName = "mem2"; const isPDSSpy = jest.spyOn(Copy as any, "isPDS"); + let dataSetExistsSpy: jest.SpyInstance; beforeEach(() => { copyPDSSpy.mockClear(); copyExpectStringSpy.mockClear().mockImplementation(async () => { return ""; }); isPDSSpy.mockClear().mockResolvedValue(false); + dataSetExistsSpy = jest.spyOn(Copy as any, "dataSetExists").mockResolvedValue(true); + }); afterAll(() => { isPDSSpy.mockRestore(); + dataSetExistsSpy.mockRestore(); }); describe("Success Scenarios", () => { describe("Sequential > Sequential", () => { @@ -456,13 +460,24 @@ describe("Copy", () => { }); }); describe("Partitioned > Partitioned", () => { + let createSpy: jest.SpyInstance; + let dataSetExistsSpy: jest.SpyInstance; beforeEach(() => { isPDSSpy.mockClear().mockResolvedValue(true); copyPDSSpy.mockClear().mockResolvedValue({success: true, commandResponse: ZosFilesMessages.datasetCopiedSuccessfully.message}); + createSpy = jest.spyOn(Create, "dataSetLike").mockResolvedValue({ + success: true, + commandResponse: ZosFilesMessages.dataSetCreatedSuccessfully.message + }); + dataSetExistsSpy = jest.spyOn(Copy as any, "dataSetExists"); }); afterAll(() => { copyPDSSpy.mockRestore(); }); + afterEach(() => { + createSpy.mockRestore(); + dataSetExistsSpy.mockRestore(); + }); it("should call copyPDS to copy members of source PDS to target PDS", async () => { const response = await Copy.dataSet( dummySession, @@ -524,6 +539,50 @@ describe("Copy", () => { expectedPayload ); }); + it("should call Create.dataSetLike and create a new data set if the target data set inputted does not exist", async() => { + dataSetExistsSpy.mockResolvedValue(false); + const response = await Copy.dataSet( + dummySession, + {dsn: toDataSetName}, + {"from-dataset": { + dsn:fromDataSetName + }} + ); + expect(createSpy).toHaveBeenCalled(); + expect(response).toEqual({ + success: true, + commandResponse: util.format(ZosFilesMessages.dataSetCopiedIntoNew.message, toDataSetName) + }); + }); + it("should not create a new data set if the target data set inputted exists", async() => { + dataSetExistsSpy.mockResolvedValue(true); + const response = await Copy.dataSet( + dummySession, + {dsn: toDataSetName}, + {"from-dataset": { + dsn:fromDataSetName + }} + ); + expect(createSpy).not.toHaveBeenCalled(); + expect(response).toEqual({ + success: true, + commandResponse: ZosFilesMessages.datasetCopiedSuccessfully.message + }); + }); + }); + it("should return early if the source and target data sets are identical", async () => { + const response = await Copy.dataSet( + dummySession, + {dsn: fromDataSetName}, + {"from-dataset": { + dsn: fromDataSetName + }} + ); + + expect(response).toEqual({ + success: false, + commandResponse: `The source and target data sets are identical.` + }); }); }); describe("Failure Scenarios", () => { @@ -662,7 +721,47 @@ describe("Copy", () => { expect(response).toEqual(false); expect(listDatasetSpy).toHaveBeenCalledWith(dummySession, dsPS.dsname, { attributes: true }); }); + it("should return true if the data set exists", async () => { + let caughtError; + let response; + listDatasetSpy.mockImplementation(async (): Promise => { + return { + apiResponse: { + returnedRows: 1, + items: [dsPO] + } + }; + }); + try { + response = await (Copy as any).dataSetExists(dummySession, dsPO.dsname); + } + catch(e) { + caughtError = e; + } + expect(response).toEqual(true); + expect(listDatasetSpy).toHaveBeenCalledWith(dummySession, dsPO.dsname, {start: dsPO.dsname}); + }); + it("should return false if the data set does not exist", async () => { + let caughtError; + let response; + listDatasetSpy.mockImplementation(async (): Promise => { + return { + apiResponse: { + returnedRows: 0, + items: [] + } + }; + }); + try { + response = await (Copy as any).dataSetExists(dummySession, dsPO.dsname); + } + catch(e) { + caughtError = e; + } + expect(response).toEqual(false); + expect(listDatasetSpy).toHaveBeenCalledWith(dummySession, dsPO.dsname, {start: dsPO.dsname}); + }); it("should successfully copy members from source to target PDS", async () => { let caughtError; let response; @@ -675,7 +774,6 @@ describe("Copy", () => { } }; const fileList = ["mem1", "mem2"]; - listAllMembersSpy.mockImplementation(async (): Promise => sourceResponse); downloadAllMembersSpy.mockImplementation(async (): Promise => undefined); fileListPathSpy.mockReturnValue(fileList); diff --git a/packages/zosfiles/__tests__/__unit__/utils/__snapshots__/ZosFilesUtils.unit.test.ts.snap b/packages/zosfiles/__tests__/__unit__/utils/__snapshots__/ZosFilesUtils.unit.test.ts.snap index 33e8c2f747..59245f88cb 100644 --- a/packages/zosfiles/__tests__/__unit__/utils/__snapshots__/ZosFilesUtils.unit.test.ts.snap +++ b/packages/zosfiles/__tests__/__unit__/utils/__snapshots__/ZosFilesUtils.unit.test.ts.snap @@ -66,6 +66,9 @@ Object { "commonWithValue": Object { "message": "with value", }, + "dataSetCopiedIntoNew": Object { + "message": "Source contents were successfully copied into a new data set - %s", + }, "dataSetCreatedSuccessfully": Object { "message": "Data set created successfully.", }, @@ -140,6 +143,9 @@ Destination: %s", "fsUnmountedSuccessfully": Object { "message": "File system unmounted successfully.", }, + "identicalDataSets": Object { + "message": "The source and target data sets are identical.", + }, "invalidAlcunitOption": Object { "message": "Invalid zos-files create command 'alcunit' option: ", }, diff --git a/packages/zosfiles/src/constants/ZosFiles.messages.ts b/packages/zosfiles/src/constants/ZosFiles.messages.ts index 8e6abc4cf8..33d74079ec 100644 --- a/packages/zosfiles/src/constants/ZosFiles.messages.ts +++ b/packages/zosfiles/src/constants/ZosFiles.messages.ts @@ -37,7 +37,13 @@ export const ZosFilesMessages: { [key: string]: IMessageDefinition } = { unsupportedDataType: { message: "Unsupported data type 'record' specified for USS file operation." }, - + /** + * Message indicating that the source and target data sets are identical + * @type {IMessageDefinition} + */ + identicalDataSets: { + message: "The source and target data sets are identical." + }, /** * Message indicating that the data set type is required * @type {IMessageDefinition} @@ -135,6 +141,14 @@ export const ZosFilesMessages: { [key: string]: IMessageDefinition } = { message: "Specify the input directory path." }, + /** + * Message indicating that a new target data set was created and copied into + * @type {IMessageDefinition} + */ + dataSetCopiedIntoNew: { + message: `Source contents were successfully copied into a new data set - %s` + }, + /** * Message indicating that the data set was created successfully * @type {IMessageDefinition} diff --git a/packages/zosfiles/src/methods/copy/Copy.ts b/packages/zosfiles/src/methods/copy/Copy.ts index 2a1e460d0d..cce57fd5fd 100644 --- a/packages/zosfiles/src/methods/copy/Copy.ts +++ b/packages/zosfiles/src/methods/copy/Copy.ts @@ -30,6 +30,7 @@ import { Download } from "../download"; import { ZosFilesUtils } from "../../utils/ZosFilesUtils"; import { tmpdir } from "os"; import path = require("path"); +import * as util from "util"; /** * This class holds helper functions that are used to copy the contents of datasets through the * z/OSMF APIs. @@ -57,14 +58,32 @@ export class Copy { ImperativeExpect.toBeDefinedAndNonBlank(options["from-dataset"].dsn, "fromDataSetName"); ImperativeExpect.toBeDefinedAndNonBlank(toDataSetName, "toDataSetName"); + if(options["from-dataset"].dsn === toDataSetName) { + return { + success: false, + commandResponse: ZosFilesMessages.identicalDataSets.message + }; + } + + const targetDataSetExists = await this.dataSetExists(session, toDataSetName); + + const newDataSet = !targetDataSetExists; + if (newDataSet) { + await Create.dataSetLike(session, toDataSetName, options["from-dataset"].dsn); + } if(!toMemberName && !options["from-dataset"].member) { const sourceIsPds = await this.isPDS(session, options["from-dataset"].dsn); const targetIsPds = await this.isPDS(session, toDataSetName); if (sourceIsPds && targetIsPds) { - return await this.copyPDS(session, options["from-dataset"].dsn, toDataSetName); + const response = await this.copyPDS(session, options["from-dataset"].dsn, toDataSetName); + return { + success: true, + commandResponse: newDataSet + ? util.format(ZosFilesMessages.dataSetCopiedIntoNew.message, toDataSetName) + : response.commandResponse + }; } } - const endpoint: string = posix.join( ZosFilesConstants.RESOURCE, ZosFilesConstants.RES_DS_FILES, @@ -97,7 +116,9 @@ export class Copy { return { success: true, - commandResponse: ZosFilesMessages.datasetCopiedSuccessfully.message + commandResponse: newDataSet + ? util.format(ZosFilesMessages.dataSetCopiedIntoNew.message, toDataSetName) + : ZosFilesMessages.datasetCopiedSuccessfully.message }; } catch (error) { Logger.getAppLogger().error(error); @@ -106,7 +127,7 @@ export class Copy { } /** - * Private function that checks if a dataset is type PDS + * Function that checks if a dataset is type PDS **/ public static async isPDS( session: AbstractSession, @@ -123,6 +144,22 @@ export class Copy { } } + /** + * Function that checks if the data set exists + **/ + private static async dataSetExists( + session: AbstractSession, + dataSetName: string + ): Promise { + let dsnameIndex; + const dataSetList = await List.dataSet(session, dataSetName, {start: dataSetName}); + if(dataSetList.apiResponse != null && dataSetList.apiResponse.returnedRows != null && dataSetList.apiResponse.items != null) { + dsnameIndex = dataSetList.apiResponse.returnedRows === 0 ? -1 : + dataSetList.apiResponse.items.findIndex((ds: any) => ds.dsname.toUpperCase() === dataSetName.toUpperCase()); + } + return dsnameIndex !== -1; + } + /** * Copy the members of a Partitioned dataset into another Partitioned dataset * @@ -139,10 +176,7 @@ export class Copy { */ public static async copyPDS ( - session: AbstractSession, - fromPds: string, - toPds: string - ): Promise { + session: AbstractSession, fromPds: string, toPds: string): Promise { try { const sourceResponse = await List.allMembers(session, fromPds); const sourceMemberList: Array<{ member: string }> = sourceResponse.apiResponse.items;