diff --git a/.github/scripts/holddata_verification/package-lock.json b/.github/scripts/holddata_verification/package-lock.json new file mode 100644 index 0000000000..4f52d5a057 --- /dev/null +++ b/.github/scripts/holddata_verification/package-lock.json @@ -0,0 +1,253 @@ +{ + "name": "holddata_verification", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "holddata_verification", + "version": "1.0.0", + "license": "EPL-2.0", + "dependencies": { + "@actions/core": "1.10.1", + "@actions/github": "6.0.0" + } + }, + "node_modules/@actions/core": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.1.tgz", + "integrity": "sha512-3lBR9EDAY+iYIpTnTIXmWcNbX3T2kCkAEQGIQx4NVQ0575nk2k3GRZDTPQG+vVtS2izSLmINlxXf0uLtnrTP+g==", + "dependencies": { + "@actions/http-client": "^2.0.1", + "uuid": "^8.3.2" + } + }, + "node_modules/@actions/github": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@actions/github/-/github-6.0.0.tgz", + "integrity": "sha512-alScpSVnYmjNEXboZjarjukQEzgCRmjMv6Xj47fsdnqGS73bjJNDpiiXmp8jr0UZLdUB6d9jW63IcmddUP+l0g==", + "dependencies": { + "@actions/http-client": "^2.2.0", + "@octokit/core": "^5.0.1", + "@octokit/plugin-paginate-rest": "^9.0.0", + "@octokit/plugin-rest-endpoint-methods": "^10.0.0" + } + }, + "node_modules/@actions/http-client": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.3.tgz", + "integrity": "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==", + "dependencies": { + "tunnel": "^0.0.6", + "undici": "^5.25.4" + } + }, + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@octokit/auth-token": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz", + "integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/core": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.0.tgz", + "integrity": "sha512-1LFfa/qnMQvEOAdzlQymH0ulepxbxnCYAKJZfMci/5XJyIHWgEYnDmgnKakbTh7CH2tFQ5O60oYDvns4i9RAIg==", + "dependencies": { + "@octokit/auth-token": "^4.0.0", + "@octokit/graphql": "^7.1.0", + "@octokit/request": "^8.3.1", + "@octokit/request-error": "^5.1.0", + "@octokit/types": "^13.0.0", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/endpoint": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.5.tgz", + "integrity": "sha512-ekqR4/+PCLkEBF6qgj8WqJfvDq65RH85OAgrtnVp1mSxaXF03u2xW/hUdweGS5654IlC0wkNYC18Z50tSYTAFw==", + "dependencies": { + "@octokit/types": "^13.1.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/graphql": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.1.0.tgz", + "integrity": "sha512-r+oZUH7aMFui1ypZnAvZmn0KSqAUgE1/tUXIWaqUCa1758ts/Jio84GZuzsvUkme98kv0WFY8//n0J1Z+vsIsQ==", + "dependencies": { + "@octokit/request": "^8.3.0", + "@octokit/types": "^13.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "23.0.1", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz", + "integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g==" + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.2.1.tgz", + "integrity": "sha512-wfGhE/TAkXZRLjksFXuDZdmGnJQHvtU/joFQdweXUgzo1XwvBCD4o4+75NtFfjfLK5IwLf9vHTfSiU3sLRYpRw==", + "dependencies": { + "@octokit/types": "^12.6.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": "5" + } + }, + "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/openapi-types": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz", + "integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==" + }, + "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/types": { + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz", + "integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==", + "dependencies": { + "@octokit/openapi-types": "^20.0.0" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-10.4.1.tgz", + "integrity": "sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg==", + "dependencies": { + "@octokit/types": "^12.6.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": "5" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/openapi-types": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz", + "integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==" + }, + "node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/types": { + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz", + "integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==", + "dependencies": { + "@octokit/openapi-types": "^20.0.0" + } + }, + "node_modules/@octokit/request": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.4.0.tgz", + "integrity": "sha512-9Bb014e+m2TgBeEJGEbdplMVWwPmL1FPtggHQRkV+WVsMggPtEkLKPlcVYm/o8xKLkpJ7B+6N8WfQMtDLX2Dpw==", + "dependencies": { + "@octokit/endpoint": "^9.0.1", + "@octokit/request-error": "^5.1.0", + "@octokit/types": "^13.1.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/request-error": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.1.0.tgz", + "integrity": "sha512-GETXfE05J0+7H2STzekpKObFe765O5dlAKUTLNGeH+x47z7JjXHfsHKo5z21D/o/IOZTUEI6nyWyR+bZVP/n5Q==", + "dependencies": { + "@octokit/types": "^13.1.0", + "deprecation": "^2.0.0", + "once": "^1.4.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/types": { + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.7.0.tgz", + "integrity": "sha512-BXfRP+3P3IN6fd4uF3SniaHKOO4UXWBfkdR3vA8mIvaoO/wLjGN5qivUtW0QRitBHHMcfC41SLhNVYIZZE+wkA==", + "dependencies": { + "@octokit/openapi-types": "^23.0.1" + } + }, + "node_modules/before-after-hook": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", + "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==" + }, + "node_modules/deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, + "node_modules/undici": { + "version": "5.28.5", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.5.tgz", + "integrity": "sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA==", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/universal-user-agent": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", + "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==" + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + } + } +} diff --git a/.github/scripts/holddata_verification/package.json b/.github/scripts/holddata_verification/package.json new file mode 100644 index 0000000000..b3779b594e --- /dev/null +++ b/.github/scripts/holddata_verification/package.json @@ -0,0 +1,15 @@ +{ + "name": "holddata_verification", + "version": "1.0.0", + "description": "Script to verify Zowe HOLDDATA syntax", + "main": "validate_holddata.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "EPL-2.0", + "dependencies": { + "@actions/core": "1.10.1", + "@actions/github": "6.0.0" + } +} diff --git a/.github/scripts/holddata_verification/validate_holddata.js b/.github/scripts/holddata_verification/validate_holddata.js new file mode 100644 index 0000000000..1caeb90c94 --- /dev/null +++ b/.github/scripts/holddata_verification/validate_holddata.js @@ -0,0 +1,64 @@ + + + +const core = require('@actions/core'); + +if (process.env['HOLDDATA_FILES'] == null || + process.env['HOLDDATA_FILES'].trim().length == 0) { + core.setFailed('This script requires the HOLDDATA_FILES env to be set.'); + return; +} + +core.info(`Checking HOLDDATA: ${process.env.HOLDDATA_FILES}`); + +const errors = []; +for (const holdDataFile of process.env.HOLDDATA_FILES.trim().split(' ')) { + + const fs = require('fs'); + + core.info(`Testing ${holdDataFile}`); + const lines = fs.readFileSync(holdDataFile, 'utf-8').split('\n'); + + const openParens = []; + + for (let i = 0; i < lines.length; i++) { + + const rawLine = lines[i]; + const line = lines[i].trim(); + + if (rawLine.length > 64) { + errors.push({file: holdDataFile, error: `Line ${i+1} is too long. It has ${line.length} characters, but should have no more than 64.` }); + } + + if (line.startsWith('*')) { + continue; + } + if (line.includes('/*') || line.includes('*/')) { + errors.push({file: holdDataFile, error: `HOLDDATA has the invalid comment sequence on line ${i+1}. Either '/*' or '*/'`}); + } + if (line.includes('~')) { + errors.push({file: holdDataFile, error: `HOLDDATA has the invalid character '~' on line ${i+1}. This character is reserved by automation for use in sed and should not be used.`}); + } + for (let j = 0; j < line.length; j++) { + if (line.charAt(j) === '(') { + openParens.push(j); + } + if (line.charAt(j) === ')') { + if (openParens.pop() == null) { + errors.push({file: holdDataFile, error: `HOLDDATA has a ')' without a matching '(' on line ${i+1}.`}); + } + } + } + } + + if (openParens.length > 0) { + errors.push({file: holdDataFile, error: `HOLDDATA has a '(' without a matching ')'.`}); + } +} + +if (errors.length > 0) { + core.error(JSON.stringify(errors)); + core.setFailed(`HOLDDATA has errors. See above.`); +} else { + core.info(`HOLDDATA has no errors.`); +} diff --git a/.github/workflows/holddata-warn.yml b/.github/workflows/holddata-warn.yml new file mode 100644 index 0000000000..806963beae --- /dev/null +++ b/.github/workflows/holddata-warn.yml @@ -0,0 +1,63 @@ +name: Discover HOLDDATA + +permissions: read-all + +on: + pull_request: + types: [opened, synchronize] + branches: + - v3.x/staging + - v3.x/rc + - v2.x/staging + - v2.x/rc + +jobs: + check-holddata: + runs-on: ubuntu-latest + steps: + + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install Dependencies for verification script + run: npm install + working-directory: .github/scripts/holddata_verification + + - name: List changed files which are candidates for HOLDDATA + id: changed-files-yaml + uses: tj-actions/changed-files@v45 + with: + files_yaml: | + hold: + - smpe/bld/service/current-hold-*.txt + src: + - example-zowe.yaml + - files/defaults.yaml + - files/sca/zowe_base_sca.json + - files/SZWEEXEC/** + - files/SZWESAMP/** + - schemas/** + - smpe/bld/SMPMCS.txt + - workflows/files/ZWEKRIN* + - workflows/templates/ZWESECU* + + # If there's a change to SAMP or EXEC files and no matching holddata, fail workflow. + # We can't know if there must be HOLDDATA in this case, so this WF can never be a required check. + - name: Check for changed files without matching holddata + if: ${{ steps.changed-files-yaml.outputs.src_any_changed == 'true' && steps.changed-files-yaml.outputs.hold_any_changed == 'false' }} + env: + TEST_ALL_CHANGED_FILES: ${{ steps.changed-files-yaml.outputs.src_all_changed_files }} + run: | + echo "One or more SAMP or EXEC file(s) have changed." + echo "This may require HOLDDATA to be created." + echo "Files changed: $TEST_ALL_CHANGED_FILES" + exit 1 + + - name: Check HOLDDATA is in a valid format + if: ${{ steps.changed-files-yaml.outputs.hold_any_changed == 'true' }} + env: + HOLDDATA_FILES: ${{ steps.changed-files-yaml.outputs.hold_all_changed_files }} + id: verify-holddata-format + run: node .github/scripts/holddata_verification/validate_holddata.js + + \ No newline at end of file diff --git a/README.md b/README.md index 29203e277b..5c15d0b563 100644 --- a/README.md +++ b/README.md @@ -180,6 +180,12 @@ If your changes are in components, it may depend on how the Zowe build picks you }, ``` +### Writing HOLDDATA + +If your changes require end-users to take action on their system beyond applying maintenance and recycling the Zowe address space, you will need to write HOLDDATA detailing what steps the user should take once the maintenance is applied. + +HOLDDATA should be written in a `smpe/bld/service/current-hold-*.txt` file. More details on this file format can be found in [the SMP/e service doc](./smpe/bld/service/_README.txt). + ## Automate Install / Uninstall of Zowe with Ansible Please check details in [playbooks folder](playbooks/README.md).