Development and Pipeline

Development and Pipeline

Development and Pipeline

Connecting mainframe application developers to discuss efficiently creating and maintaining z/OS applications

 View Only

Customizing a menu item in IDz on VS Code (Part 2)

By Lauren Li posted 19 days ago

  

Welcome to Part 2 of the Customizing a menu item in IDz on VS Code blog series, where we are exploring how you can create and customize menu items in IBM Developer for z/OS® (IDz) on VS Code to connect to z/OS and perform tasks and execute scripts. Part 1 introduced this capability with a bit of background context and a basic tutorial. Today's blog post, Part 2, will build upon the tutorial from Part 1 to demonstrate how we can apply a combination of VS Code's task creation and execution capabilities plus IDz on VS Code's z/OS capabilities to a more practical scenario such as JCL validation.

Keep in mind that you can apply similar concepts and steps to other scenarios that involve customizing VS Code menu items to connect with z/OS and invoke scripts and utilities there.

JCL validation tutorial: A practical example of menu item customization

Many shops have a JCL validation tool set up on their z/OS, which helps check JCL statements, procedures, and jobs. Today's tutorial scenario shows how a developer can add validating a locally-opened JCL file into their workflow on top of IDz on VS Code's built-in JCL editing capabilities such as syntax highlighting, code completion, and hover previews of include files and PROCs.

In IDz on Eclipse, one might invoke the JCL validation tool from the right-click context menu - perhaps with the help of the Menu Manager feature (the inspiration for this blog series), depending on the specific tool. To set up JCL validation to be accessed in a similarly convenient way in IDz on VS Code using VS Code task customization, the steps would at a high level be similar to those from the basic tutorial in Part 1, with a couple extra considerations:

  1. The JCL to be validated needs to be available on z/OS.

    • In this scenario, we will upload the JCL file that is active in VS Code's local editor window to MVS as a PDS member. (This was the basic tutorial scenario covered in Part 1, which we are building on today - so if you have not read Part 1 yet or would like a refresher, feel free to check it out first! )

  2. The JCL validation tool needs to be invoked with the appropriate parameters.

    • We will invoke the JCL validation tool using a REXX script with the PDS member name of the JCL to be validated.

Prerequisites

As today's tutorial scenario builds on the tutorial from Part 1, you'll want to be sure you have the prerequisites from Part 1 in place before proceeding. Full details can be found in Part 1's Prerequisites section, but a quick review is also shown below for convenience:

  1. The latest version of VS Code with the Zowe Explorer extension, recommended to be installed with the IBM Z Open Editor extension or IDz on VS Code as per its installation documentation page.
  2. Zowe CLI
  3. IBM RSE API Plug-in for Zowe CLI (RSE CLI plug-in)
  4. A working connection from your local workstation to z/OS that uses your default Zowe profile for either a Remote System Explorer (RSE) connection (supported in the main body of this tutorial), or a z/OSMF connection (modifications detailed in the Appendix of this blog post).
    • You can test your connection to z/OS with your default Zowe RSE profile by entering the following command in your VS Code Terminal, replacing <user> with your z/OS RACF ID:

      
      zowe rse list uss /u/<user>
      
      
      This command should output a list of the files and folders under your z/OS UNIX System Services home directory.

In addition to the fundamental prerequisites listed above, this tutorial scenario will also require the following:

  1. A JCL validation tool set up on z/OS: This tutorial scenario uses a JCL validation tool called JCL Expert.

    • (Note: JCL Expert happens to have its own Zowe CLI plug-in, which could be used to simplify some steps that will be presented in this specific tutorial, but it will not be used in this example in order to illustrate a broader range of capabilities that could be applied to other user cases, as well - for example, to run a different JCL or invoke other validation tools that sit on z/OS.)

  2. A REXX script to invoke the JCL validation tool: A sample REXX script for invoking JCL Expert is provided later in this section of the tutorial.

  3. A local JCL file to be validated: Any local JCL file could be used here. For this tutorial's example, we will just be using a short, simple sample JCL in a local repository.

  4. A predefined sequential dataset (PS) that will hold the validated JCL output.

For this example, we will use the following REXX script to invoke JCL Expert.

  • Note: The following script is only for the purpose of demonstrating the functionality in this example. For actual implementation usage, further logic should be added for input validation and error handling.
                
/* REXX to invoke JCL Expert for JCL validation */
parse arg jclInputDsn outputDsn

/*
/* ---- User inputs ---- */
jclInputDsn: PDS member to hold uploaded JCL to be validated
outputDsn: PS for validated JCL output
*/

/* ---- Basic configuration ---- */
JCL_EXPERT_PATH = "/var/jclexpert/V2R1M0" /* UNIX path to JCL Expert install */
JCL_EXPERT_HLQ = "JCLEXP.V2R1" /* HLQ for JCL Expert MVS components */
TEMP_JCL_DSN = "'" || USERID() || ".TEMP.JCLEXP.JCL'" /* Temporary data set for
 storing case-sensitive JCL to invoke JCL Expert; will be deleted at the end */

/* ---- Build JCL in stem ---- */
jcl.1 = "//JCLEXPE JOB NOTIFY=&SYSUID,REGION=0M"
jcl.2 = "//* RUN JCL EXPERT ON A SINGLE MEMBER"
jcl.3 = "// SET HLQ="JCL_EXPERT_HLQ
jcl.4 = "//JCLXPERT EXEC PGM=CXPJCLB,PARM='POSIX(ON)/OUTPUT=TEXT'"
jcl.5 = "//STEPLIB DD DSN=&HLQ..SCXPLOAD,DISP=SHR"
jcl.6 = "//CXPHOME DD PATH='" || JCL_EXPERT_PATH || "',PATHOPTS=ORDONLY"
jcl.7 = "//INDD DD DSN="jclInputDsn",DISP=SHR"
jcl.8 = "//SYSPRINT DD DSN="outputDsn",DISP=SHR"
jcl.9 = "/*"
jcl.0 = 9

/* ---- Create temporary dataset ---- */
"ALLOC F(TEMPJCL) DA("TEMP_JCL_DSN") NEW ",
      "RECFM(F,B) LRECL(80) BLKSIZE(0)",
      "SPACE(1,1) CYL DSORG(PS) reuse"

if rc <> 0 then do
   say "ALLOC failed RC=" rc
   exit 8
end

/* ---- Write JCL to dataset ---- */
"EXECIO" jcl.0 "DISKW TEMPJCL (STEM jcl. FINIS)"

if rc <> 0 then do
   say "EXECIO failed RC=" rc
   exit 8
end

"FREE F(TEMPJCL)"

/* ---- Submit ---- */
"SUBMIT" TEMP_JCL_DSN

if rc <> 0 then
   say "SUBMIT failed RC=" rc

"DELETE " TEMP_JCL_DSN

exit
                
            

The REXX script accepts two parameters as inputs:

  1. jclInputDsn: The PDS member that will hold the JCL to be validated (once it is uploaded).
  2. outputDsn: A predefined sequential dataset (PS) that will hold the validated JCL output.

The REXX script also defines some variables with basic configuration information for the JCL validation tool, which will be used when invoking the tool. In this example, this information is hard-coded, as we do not expect the information to need to change during normal usage of our JCL validation task.

The two input parameters are then built with the configuration information into a JCL script that will invoke the JCL validation tool on the jclInputDsn PDS member, and output the JCL validation results to the outputDsn PS.

  • Note: In this example REXX script, stems are used to write the JCL script to a temporary data set to help preserve the mixed case of a USS file path (pointing to the JCL Expert install folder), but queuing can also be used to build the JCL script if case sensitivity is not a concern.

The REXX script submits the temporary data set with the generated JCL to invoke the JCL validation tool on jclInputDsn and output the validated JCL result to outputDsn. At the end of the REXX script, the temporary data set is deleted as it is no longer needed.

Step 1: Create a shell script that connects to z/OS and runs the task command with the necessary parameters

As we have already covered creating and running a basic task in VS Code in Part 1's tutorial, for today's tutorial, we will focus our first step on creating the shell script that connects to z/OS and runs the REXX script to invoke JCL Expert with the necessary parameters. We will then both create and customize the VS Code task in the next step.

  1. In your VS Code workspace, create a new shell script by right-clicking an empty spot in the Explorer view and selecting New File…. Enter a filename with the .sh extension to describe the task. For this example, you can name it scripts/run-jcl-validation.sh, to add a new shell file named run-jcl-validation.sh under the scripts folder. The file should automatically open in VS Code's editor pane, but if not, you can double-click on the new file in VS Code's Explorer view to open it in the editor.

  2. Customize the new shell script for the task. The following sample shell script builds upon the script from Part 1's tutorial to upload a local open file to a PDS member, then lists the contents of the remote destination PDS in z/OS via VS Code's Terminal. It then invokes the REXX script to perform the JCL validation on the newly-uploaded PDS member.

    • Note: The following script is only for the purpose of demonstrating the functionality in this example. For actual implementation usage, further logic should be added for input validation and error handling.
                            
    #!/bin/sh
    #========================
    # NAME: run-jcl-validation.sh
    # DESCRIPTION: Script to upload a currently-active local file in VS Code's 
    #     editor to a z/OS PDS member on MVS, then perform JCL validation on it.
    # USAGE: run-jcl-validation.sh localFile pdsName memberName outputDsn
    # PARAMETERS:
    #    localFile        - The filepath to the local file to upload.
    #    pdsName     - The name of the destination PDS.
    #    memberName  - The name of the destination PDS member.
    #    outputDsn   - The name of the predefined PS for validated JCL output.
    #========================
    
    # Constants and input
    JCL_EXPERT_REXX="LAURENL.REXX(JCLEXPNZ)" #Location of REXX for JCL validation
    localFile=$1
    pdsName=$2
    memberName=$3
    outputDsn=$4
    
    # PDS member to hold uploaded JCL to be validated
    jclInputDsn="${pdsName}(${memberName})"
    
    echo "Local file: ${localFile}"
    echo "Remote destination PDS name: ${pdsName}"
    echo "Remote destination PDS member name: ${memberName}"
    
    # Upload the local currently-open file
    echo "Uploading file..."
    zowe rse upload file-to-data-set "${localFile}" "${jclInputDsn}"
    
    # List the contents in the remote PDS
    echo "Listing files in ${pdsName}:"
    zowe rse list all-members "${pdsName}"
    
    # Issue TSO command to invoke REXX for JCL validation
    echo "Performing JCL validation on ${jclInputDsn}"
    echo "Validated JCL output will be located at ${outputDsn}"
    zowe rse issue command "ex '${JCL_EXPERT_REXX}' '${jclInputDsn} ${outputDsn}'"
                            
                        

    As the above shell script builds upon the previous example scenario used in Part 1, it has the same three arguments as part of its input, plus an added fourth argument that is new to this example:

    • Arguments shared with the previous example:
      • localFile: The filepath of the local file to upload. (We will set this to the currently-open local file in VS Code in the next step.)
      • pdsName: The name of the destination PDS.
      • memberName: The name of the destination PDS member.
    • New argument:
      • outputDsn: The name of a predefined sequential data set (PS) where the validated JCL output will go.

    The script starts out much like Part 1's tutorial sample script, using Zowe CLI with the IBM RSE CLI plug-in to upload a local JCL file (localFile) to the user-designated destination PDS member location (pdsName(memberName)) on z/OS and listing the members of the destination PDS. In order to make the PDS member name easier to reference and reuse later in the script, it is represented in the script by jclInputDsn, which is a combination of the user-input pdsName and memberName variables.

    The script then goes on to invoke the REXX script that runs the JCL validation tool on the newly-uploaded JCL file. In this case, the input for the REXX script is fairly simple - it needs the PDS member name of the JCL to validated (jclInputDsn), as well as the name of the sequential data set where it should output the results of the JCL validation (outputDsn). It then passes these as arguments to the REXX script, which in turn invokes the JCL validation tool. The result of the JCL validation is printed to the specified output dataset, outputDsn.

Step 2: Create and customize the task to invoke the shell script from the previous step

Modify the tasks.json file (in the .vscode folder) to add a new task and run the shell script from Step 1 with its arguments. In the following updated tasks.json file snippet (where other task(s) are represented by the ,), the "label" of the new task has been updated to "Validate open JCL file", while the command has been updated to invoke the run-jcl-validation.sh script we defined in the previous step:

                
"tasks": [
    …,
    {
        "label": "Validate open JCL file",
        "type": "shell",
        "command": "scripts/run-jcl-validation.sh",
        "problemMatcher": [],
            "args": ["${file}", "${input:pdsName}", "${input:memberName}", "${input:outputDsn}"]
    }
],
                
            

The args in the above snippet are similar to those used in Part 1's “Upload open file to z/OS” task example, but there is an additional "${input:outputDsn} item because run-jcl-validation.sh takes an additional argument (outputDsn), as described when we were creating the shell script in the previous step. This means that the "inputs" property in the tasks.json file will also need to be updated to define this additional input, alongside the pre-existing input definitions for pdsName and memberName as follows:

                
"inputs": [
    {
        "id": "pdsName",
        "type": "promptString",
        "description": "Name of destination PDS"
    },
    {
        "id": "memberName",
        "type": "promptString",
        "description": "Name of destination PDS member"
    },
    {
        "id": "outputDsn",
        "type": "promptString",
        "description": "Name of PS for validated JCL output"
    }
]
                
            

In the example "inputs" above, "outputDsn" is defined as a "promptString" type of input variable, similar to the other input variables. It represents the name of the PS where the validated JCL output will be stored.

Optionally, you can also assign a keyboard shortcut to this task by adding an entry into your keybindings.json file. If you opt for this, ensure that the new entry's value of "args" matches the task's "label" value from the tasks.json file. (For the example in this tutorial, the keybindings.json entry's "args" value would be "Validate open JCL file".) The new keybindings.json entry might look similar to the following:

                
{
    "key": "cmd+shift+j",
    "command": "workbench.action.tasks.runTask",
    "args": "Validate open JCL file"
}
                
            

Step 3: Run the task

You can run your new customized task using any of the methods of running VS Code tasks previously mentioned in Part 1. With the local JCL file you want to validate open and active (in-focus) in your VS Code editor window, some of the ways you can run your newly-customized task include:

  • A. From VS Code's Quick Open (Windows: Ctrl+P; Mac: Cmd+P), start typing task followed by the task name (for example, task Validate open JCL file). Use the up/down arrow keys to navigate through VS Code's suggestions (if necessary), or press Enter to select the task.

  • B. If you set a keyboard shortcut for your task, you can press the key or combination of keys that you assigned to the task. (For example, if you used the same key combination as in this tutorial's example, you would press Cmd+Shift+J.)

  • C. If you set up the Task Explorer VS Code extension, in the Task Explorer panel, click on the "Play" triangle to the right of the task named "Validate open JCL file":

    Screenshot of Run button in Task Explorer VS Code extension

If the task runs successfully, you should be prompted for a PDS name followed by a member name, and then an output data set name. The local JCL file opened in your editor should then be uploaded to the specified PDS member on z/OS, and the JCL validation tool will run on the newly-uploaded PDS member. The console log output will look similar to the following screenshot, where a local JCL file named test.jcl was uploaded to the PDS member LAURENL.TEST.JCL(TEST), with the validated JCL output stored on the PS LAURENL.VALIDATE.SYSPRINT.DATA:

Console output of the 'Validate open JCL file' task

You can also view the output of the JCL validation by using Zowe Explorer's Data Sets view to navigate to and open the output PS you specified for holding the JCL validation results:

JCL validation results in a sequential data set

To compare the JCL validation output with the original local JCL file, you can open both files and drag-and-drop the tabs so they are side-by-side as shown in the following screenshot (original local JCL on the left, validated JCL output on the right):

Side-by-side comparison of the original JCL (left) and validated JCL output (right)

Wrap up: Best practices and useful extensions to help with task writing.

This blog series introduced how you can create and customize menu items in IDz on VS Code to connect to z/OS and perform tasks and execute scripts on z/OS. In addition to the provided tutorial scenarios of uploading a local file to a PDS member and validating a local open JCL file, the same steps can conceptually be applied to other use cases, such running JCLs or invoking other scripts or tools that sit on z/OS. Some parting tips are shared in the following “Best practices” and “Useful extensions” sections.

Best practices

The tutorial examples in this blog configured VS Code tasks to interact with z/OS from the currently-open workspace. In this case, the tasks were managed from the same Git repository as the application source code, which allows the tasks' scripts to be tailored to this specific project.

To increase the reusability of VS Code tasks, it is also possible to manage them in a separate Git repository so they can be used for multiple projects. However, this approach means the tasks would need to be defined in a more generic way, potentially requiring more prompting for the end user's input.

Useful extensions

In the tutorials for Part 1 and Part 2 of this blog series, we have already seen an example of how a VS Code extension such as Task Explorer can enhance the VS Code user interface with a nice graphical browser to help manage and run VS Code tasks.

An additional VS Code extension that may help in creating and customizing a task in VS Code is the Command Variable extension. This extension helps calculate command variables for launch.json and tasks.json, as well as access utilities such as the local file picker interface, giving you more options and possibilities when designing and configuring your task in VS Code.

For another example of menu item customization with IDz on VS Code and the third-party VS Code extensions mentioned above, check out Peter Haumer's JZOS with Maven example repository.

Conclusion

In addition to the tips mentioned above, you can expand your horizon of ways to configure menu items in IDz on VS Code to interact with z/OS by exploring the wide array of documented IBM RSE CLI plug-in commands. Equipped with your new foundational task-building skills from Part 1 and today's tutorials, your creativity is the limit!


Acknowledgements

Special thanks to my colleagues Anjali Abraham and Nelson Lopez for their assistance in developing the REXX sample script for this blog post.


Resources

The following resources are listed in order of first appearance as grouped by product family.

IDz on VS Code resources

VS Code and third-party VS Code extension resources

IDz on Eclipse resources


Appendix: Connecting with z/OSMF instead of RSE

If you are connecting to z/OS with z/OSMF instead of RSE, you can test your connection with your z/OSMF profile by opening your Terminal in VS Code, and entering the following command, replacing <user> with your z/OS RACF ID:

                
zowe files list uss /u/<user>
            

To have the run-jcl-validation.sh shell script in the tutorial example use a z/OSMF connection rather than RSE, you can modify the following commands in the script:

  • Replace zowe rse upload file-to-data-set, with zowe files upload file-to-data-set.
  • Replace zowe rse list all-members with zowe files list all-members.
  • Replace the instance of zowe rse issue command with zowe tso issue command, and at the end of the whole command in the script (after the end double-quotes), add a space followed by --account <tso account info>, replacing <tso account info> with your z/OS TSO/E accounting information.

You can find additional commands for both RSE and z/OSMF connections in the IDz on VS Code reference documentation for IBM RSE CLI plug-in commands.

0 comments
25 views

Permalink