From a6f894fa38d4dfa24c2c8f866158dc79df5916af Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Fri, 5 Dec 2025 09:15:10 -0500 Subject: [PATCH 01/20] Add Jenkinsfile, GitHub Actions workflows, and Ruff checks/formatting. Signed-off-by: Leonard Carcaramo --- .github/workflows/clang-format.yml | 15 ++ .github/workflows/cppcheck.yml | 15 ++ .github/workflows/ruff.yml | 17 ++ CONTRIBUTING.md | 10 +- Jenkinsfile | 410 +++++++++++++++++++++++++++++ README.md | 3 + pyproject.toml | 26 +- python/cbxp/_C.pyi | 4 +- python/cbxp/__init__.py | 2 +- python/cbxp/cbxp.py | 20 +- setup.py | 6 +- tests/test.py | 53 ++-- 12 files changed, 541 insertions(+), 40 deletions(-) create mode 100644 .github/workflows/clang-format.yml create mode 100644 .github/workflows/cppcheck.yml create mode 100644 .github/workflows/ruff.yml create mode 100644 Jenkinsfile diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml new file mode 100644 index 0000000..8ea30ce --- /dev/null +++ b/.github/workflows/clang-format.yml @@ -0,0 +1,15 @@ +name: clang-format +on: [push, pull_request] +jobs: + build: + strategy: + fail-fast: false + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install clang-format + run: sudo apt install -y cmake clang-format + - name: clang-format + run: | + cmake . + make lint diff --git a/.github/workflows/cppcheck.yml b/.github/workflows/cppcheck.yml new file mode 100644 index 0000000..1f40e94 --- /dev/null +++ b/.github/workflows/cppcheck.yml @@ -0,0 +1,15 @@ +name: cppcheck +on: [push, pull_request] +jobs: + build: + strategy: + fail-fast: false + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install cppcheck + run: sudo apt-get install -y cmake cppcheck + - name: Run cppcheck + run: | + cmake . + make check diff --git a/.github/workflows/ruff.yml b/.github/workflows/ruff.yml new file mode 100644 index 0000000..e4f7b77 --- /dev/null +++ b/.github/workflows/ruff.yml @@ -0,0 +1,17 @@ +name: ruff +on: [push, pull_request] +jobs: + build: + strategy: + fail-fast: false + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.x" + - name: Install ruff + run: python3 -m pip install --upgrade pip ruff + - name: Run ruff + run: ruff check diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 51762aa..fea64f9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -110,9 +110,9 @@ CBXP is tested using automated functional tests. Test cases for new functionalit :bulb: _`clang-format` can be setup to run automatically using the [pre-commit Hooks](#pre-commit-hooks)._ -The use of the `clang-format` code formatter is required. +The use of the `clang-format` code formatter is required. All Python code also must pass `ruff` style checks. -The following code style conventions should be followed: +The following C/C++ code style conventions should be followed: * Varible names should use snake case *(i.e., `my_variable`)*. * Pointer variables should start with `p_` *(i.e., `p_my_pointer`)*. * Class variables should end with an `_` to help differentiate between class variables and local function variables *(i.e., `my_class_variable_`)*. @@ -146,9 +146,11 @@ When contributing to CBXP, make sure to complete all applicable tasks in the fol * Make any necessary updates to `pyproject.toml`. * Make any necessary updates to `README.md`. * Ensure that you have **pre-commit Hooks** setup to ensure that `clang-format` and `cppcheck` are run against the code for every commit you make. +* Check for style violations in C/C++ code using `clang-format` by running `gmake lint`. +* Check for style vilotations in Python code using `ruff` by running `ruff check`. +* Format C/C++ code using `clang-format` by running `gmake format`. +* Format Python code using `ruff` by running `ruff format`. * Run `cppcheck` static code analysis by running `gmake check`. -* Check for style violations using `clang-format` by running `gmake lint`. -* Format the CBXP code using `clang-format` by running `gmake format`. ## Found a bug? diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..754ac11 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,410 @@ +def python_versions +def python_executables_and_wheels_map + +pipeline { + agent { + node { + label 'zOS_Ambitus' + } + } + + parameters { + // Note: Each Python version listed must be installed on the + // build agent and must be added to '$PATH' and '$LIBPATH'. + string ( + name: "pythonVersions", + defaultValue: "", + description: ( + "(Required Always) Comma separated list of Python versions to build " + + "wheels for (i.e., Use '12,13' for Python 3.12 and Python 3.13)." + ) + ) + booleanParam( + name: "createRelease", + defaultValue: false, + description: "Toggle whether or not to create a release from this revision." + ) + string( + name: "releaseTag", + defaultValue: "", + description: ( + "(Required When Creating Releases) This will be " + + "the git tag and version number of the release." + ) + ) + string( + name: "releaseTitle", + defaultValue: "", + description: ( + "(Required When Creating Releases) This will be " + + "the title of the release." + ) + ) + string( + name: "gitHubMilestoneLink", + defaultValue: "", + description: ( + "(Required When Creating Releases) This is the GitHub " + + "Milestone URL that coresponds to the release." + ) + ) + booleanParam( + name: "preRelease", + defaultValue: true, + description: "Toggle whether or not this is a pre-release." + ) + } + + options { + ansiColor('css') + } + + stages { + stage('Parameter Validation') { + steps { + script { + if (params.pythonVersions == "") { + error("'pythonVersions' is a required parameter.") + } + if (params.createRelease) { + if (params.releaseTag == "") { + error("'releaseTag' is a required parameter when creating a release.") + } + if (params.releaseTitle == "") { + error("'releaseTitle' is a required parameter when creating a release.") + } + if (params.gitHubMilestoneLink == "") { + error("'gitHubMilestoneLink' is a required parameter when creating a release.") + } + } + } + } + } + stage('Prepare') { + steps { + clean_python_environment() + sh "cmake ." + } + } + stage('Lint') { + steps { + echo "Linting with clang-format ..." + sh "gmake lint" + } + } + stage('Cppcheck') { + steps { + echo "Running cppcheck ..." + sh "gmake check" + } + } + stage('Create Python Distribution Metadata') { + steps { + script { + python_versions = params.pythonVersions.split(",") + python_executables_and_wheels_map = ( + create_python_executables_and_wheels_map(python_versions) + ) + } + } + } + stage('Install & Function Test') { + steps { + script { + // Python distribution + for (python in python_executables_and_wheels_map.keySet()) { + def wheel = python_executables_and_wheels_map[python]["wheelDefault"] + def tar = python_executables_and_wheels_map[python]["tarPublish"] + + echo "Building '${wheel}' and '${tar}' ..." + sh """ + ${python} -m pip install build>=1.3.0 + ${python} -m build + """ + + echo "Install testing '${wheel}' ..." + sh "${python} -m pip install ./dist/${wheel}" + + echo "Function testing '${wheel}' ..." + sh "${python} tests/test.py" + + clean_python_environment() + + echo "Install testing '${tar}' ..." + sh "${python} -m pip install ./dist/${tar}" + + echo "Function testing '${tar} ..." + sh "${python} tests/test.py" + + clean_python_environment() + clean_git_repo() + } + } + // Shell distribution + def cbxp_version = get_cbxp_version() + def pax = "cbxp-${cbxp_version}.pax.Z" + echo "Building '${pax}' ..." + sh """ + cmake . + gmake package + """ + + echo "Install test '${pax}' ..." + sh """ + mkdir install-test + cd install-test + pax -rf ../dist/${pax} + ls install-test/cbxp + """ + + echo "'Function testing './dist/cbxp' ..." + sh "./tests/test.sh" + + clean_git_repo() + } + } + stage('Publish') { + when { + expression { params.createRelease == true } + } + steps { + publish( + python_executables_and_wheels_map, + params.releaseTitle, + params.releaseTag, + env.BRANCH_NAME, + params.gitHubMilestoneLink, + params.preRelease + ) + } + } + } + post { + always { + echo "Cleaning up workspace ..." + cleanWs() + clean_python_environment() + } + } +} + +def create_python_executables_and_wheels_map(python_versions) { + def os = sh( + returnStdout: true, + script: "uname" + ).trim().replace("/", "").toLowerCase() + def zos_release = sh( + returnStdout: true, + script: "uname -r" + ).trim().replace(".", "_") + def processor = sh( + returnStdout: true, + script: "uname -m" + ).trim() + def cbxp_version = get_cbxp_version() + + python_executables_and_wheels_map = [:] + + for (python_version in python_versions) { + python_executables_and_wheels_map["python3.${python_version}"] = [ + "wheelDefault": ( + "cbxp-${cbxp_version}-cp3${python_version}-cp3${python_version}-${os}_${zos_release}_${processor}.whl" + ), + "wheelPublish": "cbxp-${cbxp_version}-cp3${python_version}-none-any.whl", + "tarPublish": "cbxp-${cbxp_version}.tar.gz" + ] + } + + return python_executables_and_wheels_map +} + +def get_cbxp_version() { + return sh( + returnStdout: true, + script: "cat pyproject.toml | grep version | cut -d'=' -f2 | cut -d'\"' -f2" + ).trim() +} + +def clean_python_environment() { + echo "Cleaning Python environment ..." + + sh """ + rm -rf ~/.cache + rm -rf ~/.local + """ +} + +def clean_git_repo() { + echo "Cleaning repo ..." + sh "git clean -fdx" +} + +def publish( + python_executables_and_wheels_map, + release_title + release_tag, + git_branch, + milestone, + pre_release +) { + if (pre_release == true) { + pre_release = "true" + } + else { + pre_release = "false" + } + withCredentials( + [ + usernamePassword( + credentialsId: 'ambitus-github-access-token', + usernameVariable: 'github_user', + passwordVariable: 'github_access_token' + ) + ] + ) { + + // Creating GitHub releases: + // https://docs.github.com/en/rest/releases/releases?apiVersion=2022-11-28#create-a-release + // Uploading release assets: + // https://docs.github.com/en/rest/releases/assets?apiVersion=2022-11-28#upload-a-release-asset + + // Use single quotes for credentials since it is the most secure + // method for interpolating secrets according to the Jenkins docs: + // https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#string-interpolation + + echo "Creating '${release_title}' GitHub release ..." + + def description = build_description(python_executables_and_wheels_map, release_tag, milestone) + + def release_id = sh( + returnStdout: true, + script: ( + 'curl -f -v -L ' + + '-X POST ' + + '-H "Accept: application/vnd.github+json" ' + + '-H "Authorization: Bearer ${github_access_token}" ' + + '-H "X-GitHub-Api-Version: 2022-11-28" ' + + "https://api.github.com/repos/ambitus/cbxp/releases " + + "-d '{" + + " \"tag_name\": \"${release_tag}\"," + + " \"target_commitish\": \"${git_branch}\"," + + " \"name\": \"${release_title}\"," + + " \"body\": \"${description}\"," + + " \"draft\": false," + + " \"prerelease\": ${pre_release}," + + " \"generate_release_notes\":false" + + "}' | grep '\"id\": ' | head -n1 | cut -d':' -f2 | cut -d',' -f1" + ) + ).trim() + + def checksums_file = "SHASUMS256.txt.asc" + + sh """ + touch ./dist/${checksums_file} + chtag -t -c ISO8859-1 ./dist/${checksums_file} + """ + + def tar_publish + def tar_built = false + + clean_git_repo() + + // Build and publish Python packages + for (python in python_executables_and_wheels_map.keySet()) { + def wheel_default = python_executables_and_wheels_map[python]["wheelDefault"] + def wheel_publish = python_executables_and_wheels_map[python]["wheelPublish"] + + echo "Building '${wheel_default}' ..." + + sh """ + ${python} -m pip install build>=1.2.2 + ${python} -m build -w + mv ./dist/${wheel_default} ./dist/${wheel_publish} + """ + + if (tar_built == false) { + tar_publish = python_executables_and_wheels_map[python]["tarPublish"] + echo "Building '${tar_publish}' ..." + sh "${python} -m build -s" + tar_built = true + } + + echo "Uploading '${wheel_default}' as '${wheel_publish}' to '${release_title}' GitHub release ..." + upload_asset(release_id, wheel_publish) + + echo "Adding sha256 checksum for '${wheel_publish}' to ${checksums_file}..." + sh "cd dist && sha256sum -t ${wheel_publish} >> ${checksums_file}" + } + + echo "Uploading '${tar_publish}' to '${release_title}' GitHub release ..." + upload_asset(release_id, tar_publish) + + echo "Adding sha256 checksum for '${tar_publish}' to ${checksums_file}..." + sh "cd dist && sha256sum -t ${tar_publish} >> ${checksums_file}" + + // Build and publish Shell distribution + def cbxp_version = get_cbxp_version() + def pax = "cbxp-${cbxp_version}.pax.Z" + echo "Building '${pax}' ..." + sh """ + cmake . + gmake package + """ + + echo "Uploading '${pax}' to '${release_title}' GitHub release ..." + upload_asset(release_id, pax) + + echo "Adding sha256 checksum for '${pax}' to ${checksums_file}..." + sh "cd dist && sha256sum -t ${pax} >> ${checksums_file}" + + echo "Uploading '${checksums_file}' to '${release_title}' GitHub release ..." + upload_asset(release_id, checksums_file) + } +} + +def upload_asset(release_id, release_asset) { + sh( + 'curl -f -v -L ' + + '-X POST ' + + '-H "Accept: application/vnd.github+json" ' + + '-H "Authorization: Bearer ${github_access_token}" ' + + '-H "X-GitHub-Api-Version: 2022-11-28" ' + + '-H "Content-Type: application/octet-stream" ' + + "\"https://uploads.github.com/repos/ambitus/cbxp/releases/${release_id}/assets?name=${release_asset}\" " + + "--data-binary \"@dist/${release_asset}\"" + ) +} + +def build_description(python_executables_and_wheels_map, release_tag, milestone) { + def description = ( + "Release Notes: ${milestone}\\n \\n \\n" + + "## Python Interface Installation" + ) + + for (python in python_executables_and_wheels_map.keySet()) { + def wheel = python_executables_and_wheels_map[python]["wheelPublish"] + def python_executable = python + def python_label = python.replace("python", "Python ") + description += ( + "Install From **${python_label} Wheel Distribution** *(pre-built)*:\\n" + + "```\\ncurl -O -L https://github.com/ambitus/cbxp/releases/download/${release_tag}/${wheel} " + + "&& ${python_executable} -m pip install ${wheel}\\n```\\n" + ) + } + + def python = python_executables_and_wheels_map.keySet()[-1] + def tar = python_executables_and_wheels_map[python]["tarPublish"] + def cbxp_version = get_cbxp_version() + def pax = "cbxp-${cbxp_version}.pax.Z" + description += ( + "Install From **Source Distribution** *(build on install)*:\\n" + + "> :warning: _Requires z/OS Open XL C/C++ 2.1 compiler._\\n" + + "```\\ncurl -O -L https://github.com/ambitus/cbxp/releases/download/${release_tag}/${tar} " + + "&& python3 -m pip install ${tar}\\n```\\n" + + "## Shell Interface Installation" + + "```\\ncurl -O -L https://github.com/ambitus/cbxp/releases/download/${release_tag}/${pax} " + + "&& pax -rf ${pax}\\n```\\n" + ) + + return description +} diff --git a/README.md b/README.md index 82e14af..da8a1c2 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ +[![clang-format](https://github.com/ambitus/cbxp/actions/workflows/clang-format.yml/badge.svg)](https://github.com/ambitus/cbxp/actions/workflows/clang-format.yml) +[![cppcheck](https://github.com/ambitus/cbxp/actions/workflows/cppcheck.yml/badge.svg)](https://github.com/ambitus/cbxp/actions/workflows/cppcheck.yml) +[![ruff](https://github.com/ambitus/cbxp/actions/workflows/ruff.yml/badge.svg)](https://github.com/ambitus/cbxp/actions/workflows/ruff.yml) [![Version](https://img.shields.io/pypi/v/cbxp?label=alpha)](https://pypi.org/project/cbxp/#history) [![Python Versions](https://img.shields.io/pypi/pyversions/cbxp)](https://pypi.org/project/cbxp/) [![Downloads](https://img.shields.io/pypi/dm/cbxp)](https://pypistats.org/packages/cbxp) diff --git a/pyproject.toml b/pyproject.toml index e1a81c4..08210f7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,10 @@ [build-system] -requires = ["setuptools >= 80.9.0"] -build-backend = "setuptools.build_meta" + requires = ["setuptools >= 80.9.0"] + build-backend = "setuptools.build_meta" [project] name="cbxp" - version="0.0.2" + version="0.0.3" requires-python = ">= 3.12" authors = [ { name = "Leonard J. Carcaramo Jr", email = "lcarcaramo@ibm.com" }, @@ -50,3 +50,23 @@ build-backend = "setuptools.build_meta" [tool.setuptools.package-data] cbxp = ["LICENSE", "NOTICES"] + +[tool.ruff.lint] + # Ruff by default is not very aggressive, only enforcing a few rulesets like E and F. + # To ensure well organized code a bunch more rulesets have been enabled + select = [ + "ERA", # Checks for commented out code + "E", + "F", + "B", + "EM", # Error messages and exceptions + "SIM", # Comes with suggestions on simplifying things + "N", # Checks if code conforms to the PEP8 naming conventions + "PLE", + "UP", + "TRY", # Best practices for try-except + "FLY", # Checks for string joins + "I", # Comes with suggestions on organizing imports + "COM", # Checks for missing commas and unnecessary + "A", + ] diff --git a/python/cbxp/_C.pyi b/python/cbxp/_C.pyi index d82dd77..303a994 100644 --- a/python/cbxp/_C.pyi +++ b/python/cbxp/_C.pyi @@ -1 +1,3 @@ -def call_cbxp(control_block: str, includes_string: str, debug: bool = False) -> dict: ... +def call_cbxp( # noqa: N999 + control_block: str, includes_string: str, debug: bool = False, +) -> dict: ... diff --git a/python/cbxp/__init__.py b/python/cbxp/__init__.py index 99af136..448e3f8 100644 --- a/python/cbxp/__init__.py +++ b/python/cbxp/__init__.py @@ -1,2 +1,2 @@ -from .cbxp import cbxp as cbxp from .cbxp import CBXPError as CBXPError +from .cbxp import cbxp as cbxp diff --git a/python/cbxp/cbxp.py b/python/cbxp/cbxp.py index bd37b4b..49e35e7 100644 --- a/python/cbxp/cbxp.py +++ b/python/cbxp/cbxp.py @@ -3,14 +3,18 @@ from cbxp._C import call_cbxp + class CBXPErrorCode(Enum): """An enum of error and return codes from the cbxp interface""" + COMMA_IN_INCLUDE = -1 BAD_CONTROL_BLOCK = 1 BAD_INCLUDE = 2 + class CBXPError(Exception): """A class of errors for return codes from the cbxp interface""" + def __init__(self, return_code: int, control_block_name: str): self.rc = return_code match self.rc: @@ -24,16 +28,18 @@ def __init__(self, return_code: int, control_block_name: str): message = "an unknown error occurred" super().__init__(message) - + def cbxp( - control_block: str, - includes: list[str] = [], - debug: bool = False + control_block: str, + includes: list[str] = None, + debug: bool = False, ) -> dict: + if includes is None: + includes = [] for include in includes: if "," in include: raise CBXPError(CBXPErrorCode.COMMA_IN_INCLUDE.value, control_block) response = call_cbxp(control_block.lower(), ",".join(includes).lower(), debug=debug) - if response['return_code']: - raise CBXPError(response['return_code'], control_block) - return json.loads(response['result_json']) + if response["return_code"]: + raise CBXPError(response["return_code"], control_block) + return json.loads(response["result_json"]) diff --git a/setup.py b/setup.py index 5d5588f..4d6059b 100644 --- a/setup.py +++ b/setup.py @@ -27,7 +27,7 @@ def main(): + [ "cbxp", "externals", - "/usr/include/zos" + "/usr/include/zos", ] ), extra_link_args=[ @@ -36,8 +36,8 @@ def main(): ], extra_compile_args=[ "-fzos-le-char-mode=ascii", - "-Wno-trigraphs" - ] + "-Wno-trigraphs", + ], ), ], "cmdclass": {"build_ext": build_ext}, diff --git a/tests/test.py b/tests/test.py index ac541ed..bc9e494 100644 --- a/tests/test.py +++ b/tests/test.py @@ -1,8 +1,9 @@ import unittest -from cbxp import cbxp, CBXPError -class TestCBXP(unittest.TestCase): +from cbxp import CBXPError, cbxp + +class TestCBXP(unittest.TestCase): # ============================================================================ # Basic Usage # ============================================================================ @@ -27,7 +28,7 @@ def test_cbxp_can_extract_ascb(self): self.assertIs(type(cbdata), list) for entry in cbdata: self.assertIs(type(entry), dict) - + # ============================================================================ # Include Patterns # ============================================================================ @@ -79,7 +80,7 @@ def test_cbxp_can_extract_the_cvt_and_include_the_asvt_ascb(self): for entry in cbdata["cvtasvt"]["asvtenty"]: self.assertIs(type(entry), dict) - def test_cbxp_include_can_extract_cvt_and_include_pattern_ecvt_and_asvt(self): + def test_cbxp_include_can_extract_cvt_and_include_ecvt_and_asvt(self): cbdata = cbxp("cvt", includes=["ecvt", "asvt"]) self.assertIs(type(cbdata), dict) self.assertIs(type(cbdata["cvtecvt"]), dict) @@ -88,7 +89,9 @@ def test_cbxp_include_can_extract_cvt_and_include_pattern_ecvt_and_asvt(self): for entry in cbdata["cvtasvt"]["asvtenty"]: self.assertIs(type(entry), str) - def test_cbxp_include_can_extract_psa_and_include_pattern_ecvt_asvt_and_cvt_asvt_ascb(self): + def test_cbxp_include_can_extract_psa_and_include_ecvt_asvt_and_cvt_asvt_ascb( + self, + ): cbdata = cbxp("psa", includes=["cvt.ecvt", "cvt.asvt.ascb"]) self.assertIs(type(cbdata), dict) self.assertIs(type(cbdata["flccvt"]), dict) @@ -97,7 +100,7 @@ def test_cbxp_include_can_extract_psa_and_include_pattern_ecvt_asvt_and_cvt_asvt self.assertIs(type(cbdata["flccvt"]["cvtasvt"]["asvtenty"]), list) for entry in cbdata["flccvt"]["cvtasvt"]["asvtenty"]: self.assertIs(type(entry), dict) - + def test_cbxp_can_extract_psa_and_include_cvt_recursive_wildcard(self): cbdata = cbxp("psa", includes=["cvt.**"]) self.assertIs(type(cbdata), dict) @@ -107,7 +110,7 @@ def test_cbxp_can_extract_psa_and_include_cvt_recursive_wildcard(self): self.assertIs(type(cbdata["flccvt"]["cvtasvt"]["asvtenty"]), list) for entry in cbdata["flccvt"]["cvtasvt"]["asvtenty"]: self.assertIs(type(entry), dict) - + def test_cbxp_can_extract_psa_and_include_cvt_wildcard(self): cbdata = cbxp("psa", includes=["cvt.*"]) self.assertIs(type(cbdata), dict) @@ -117,7 +120,7 @@ def test_cbxp_can_extract_psa_and_include_cvt_wildcard(self): self.assertIs(type(cbdata["flccvt"]["cvtasvt"]["asvtenty"]), list) for entry in cbdata["flccvt"]["cvtasvt"]["asvtenty"]: self.assertIs(type(entry), str) - + def test_cbxp_can_extract_cvt_and_include_wildcard_and_asvt_wildcard(self): cbdata = cbxp("cvt", includes=["*", "asvt.*"]) self.assertIs(type(cbdata), dict) @@ -140,49 +143,57 @@ def test_cbxp_can_run_in_debug_mode(self): def test_cbxp_raises_cbxp_error_when_unknown_control_block_is_provided(self): with self.assertRaises(CBXPError) as e: cbxp("unknown") - self.assertEqual("Unknown control block 'unknown' was specified.", str(e.exception)) + self.assertEqual( + "Unknown control block 'unknown' was specified.", str(e.exception), + ) # ============================================================================ # Errors: Bad Include Patterns # ============================================================================ - def test_cbxp_raises_cbxp_error_if_asvt_ascb_is_included_when_extracting_the_psa(self): + def test_cbxp_raises_cbxp_error_if_asvt_ascb_is_included_with_the_psa( + self, + ): with self.assertRaises(CBXPError) as e: cbxp("psa", includes=["asvt.ascb"]) self.assertEqual("A bad include pattern was provided", str(e.exception)) - def test_cbxp_raises_cbxp_error_if_ascb_is_included_when_extracting_the_psa(self): + def test_cbxp_raises_cbxp_error_if_ascb_is_included_with_the_psa(self): with self.assertRaises(CBXPError) as e: cbxp("psa", includes=["ascb"]) self.assertEqual("A bad include pattern was provided", str(e.exception)) - def test_cbxp_raises_cbxp_error_if_ecvt_is_included_when_extracting_the_ascb(self): + def test_cbxp_raises_cbxp_error_if_ecvt_is_included_with_ascb(self): with self.assertRaises(CBXPError) as e: cbxp("ascb", includes=["ecvt"]) self.assertEqual("A bad include pattern was provided", str(e.exception)) - - def test_cbxp_raises_cbxp_error_if_ect_ecvt_and_cvt_ascb_is_included_when_extracting_the_psa(self): + + def test_cbxp_raises_cbxp_error_if_ect_ecvt_and_cvt_ascb_is_included_with_the_psa( + self, + ): with self.assertRaises(CBXPError) as e: - cbdata = cbxp("psa", includes=["cvt.ecvt", "cvt.ascb"]) + cbxp("psa", includes=["cvt.ecvt", "cvt.ascb"]) self.assertEqual("A bad include pattern was provided", str(e.exception)) - def test_cbxp_raises_cbxp_error_if_ecvt_and_cvt_asvt_ascb_is_included_when_extracting_the_psa(self): + def test_cbxp_raises_cbxp_error_if_ecvt_and_cvt_asvt_ascb_is_included_with_the_psa( + self, + ): with self.assertRaises(CBXPError) as e: - cbdata = cbxp("psa", includes=["ecvt", "cvt.asvt.ascb"]) + cbxp("psa", includes=["ecvt", "cvt.asvt.ascb"]) self.assertEqual("A bad include pattern was provided", str(e.exception)) - def test_cbxp_raises_cbxp_error_if_cvt_is_included_when_extracting_the_cvt(self): + def test_cbxp_raises_cbxp_error_if_cvt_is_included_with_the_cvt(self): with self.assertRaises(CBXPError) as e: - cbdata = cbxp("cvt", includes=["cvt"]) + cbxp("cvt", includes=["cvt"]) self.assertEqual("A bad include pattern was provided", str(e.exception)) def test_cbxp_raises_cbxp_error_when_pattern_cannot_contain_comma_1(self): with self.assertRaises(CBXPError) as e: - cbdata = cbxp("cvt", includes=["asvt,ascb"]) + cbxp("cvt", includes=["asvt,ascb"]) self.assertEqual("Include patterns cannot contain commas", str(e.exception)) def test_cbxp_raises_cbxp_error_when_pattern_cannot_contain_comma_2(self): with self.assertRaises(CBXPError) as e: - cbdata = cbxp("cvt", includes=["asvt,as"]) + cbxp("cvt", includes=["asvt,as"]) self.assertEqual("Include patterns cannot contain commas", str(e.exception)) From d32698e1a1d2208d37d29e98269ada2ded2e6ad7 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Fri, 5 Dec 2025 09:52:36 -0500 Subject: [PATCH 02/20] Debug clang-format workflow Signed-off-by: Leonard Carcaramo --- .github/workflows/clang-format.yml | 5 ++++- Jenkinsfile | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index 8ea30ce..76745ac 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -8,8 +8,11 @@ jobs: steps: - uses: actions/checkout@v4 - name: Install clang-format - run: sudo apt install -y cmake clang-format + run: sudo apt install -y cmake clang-format-19 - name: clang-format + # Create symbolic link to clang-format-19 so that + # 'clang-format' can be used to run 'clang-format-19'. run: | + ln -s clang-format $(which clang-format-19) cmake . make lint diff --git a/Jenkinsfile b/Jenkinsfile index 754ac11..3b43fed 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -154,7 +154,7 @@ pipeline { mkdir install-test cd install-test pax -rf ../dist/${pax} - ls install-test/cbxp + ls -alT install-test/cbxp """ echo "'Function testing './dist/cbxp' ..." From 2c69efb00ac14eb8dc74a3467ebb866c977e8b03 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Fri, 5 Dec 2025 09:56:19 -0500 Subject: [PATCH 03/20] Fix symbolic link. Signed-off-by: Leonard Carcaramo --- .github/workflows/clang-format.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index 76745ac..89bff52 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -13,6 +13,6 @@ jobs: # Create symbolic link to clang-format-19 so that # 'clang-format' can be used to run 'clang-format-19'. run: | - ln -s clang-format $(which clang-format-19) + ln -s $(which clang-format-19) clang-format cmake . make lint From 24b6236df146c2da3358c562d40c0a37b1310317 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Fri, 5 Dec 2025 10:03:55 -0500 Subject: [PATCH 04/20] Use clang-format-20 Signed-off-by: Leonard Carcaramo --- .github/workflows/clang-format.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index 89bff52..28fda10 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -8,11 +8,11 @@ jobs: steps: - uses: actions/checkout@v4 - name: Install clang-format - run: sudo apt install -y cmake clang-format-19 + run: sudo apt install -y cmake clang-format-20 - name: clang-format - # Create symbolic link to clang-format-19 so that - # 'clang-format' can be used to run 'clang-format-19'. + # Create symbolic link to clang-format-20 so that + # 'clang-format' can be used to run 'clang-format-20'. run: | - ln -s $(which clang-format-19) clang-format + ln -s $(which clang-format-20) clang-format cmake . make lint From a78f7ac34ecaa039794d7c70e6eb5ef915dc65c4 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Fri, 5 Dec 2025 10:09:02 -0500 Subject: [PATCH 05/20] Try adding clang-format-19 to PATH. Signed-off-by: Leonard Carcaramo --- .github/workflows/clang-format.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index 28fda10..dab77c7 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -8,11 +8,13 @@ jobs: steps: - uses: actions/checkout@v4 - name: Install clang-format - run: sudo apt install -y cmake clang-format-20 + run: sudo apt install -y cmake clang-format-19 - name: clang-format - # Create symbolic link to clang-format-20 so that - # 'clang-format' can be used to run 'clang-format-20'. + # Create symbolic link to clang-format-19 and + # add it to PATH so that 'clang-format' can + # be used to run 'clang-format-19'. run: | - ln -s $(which clang-format-20) clang-format + ln -s $(which clang-format-19) clang-format + export PATH=$PWD:$PATH cmake . make lint From c8142920f7b7f285d8884f2931be2d3b63ec80b7 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Fri, 5 Dec 2025 10:12:21 -0500 Subject: [PATCH 06/20] Add temporary format error. Signed-off-by: Leonard Carcaramo --- cbxp/main.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cbxp/main.cpp b/cbxp/main.cpp index fabb910..cfc57df 100644 --- a/cbxp/main.cpp +++ b/cbxp/main.cpp @@ -35,8 +35,7 @@ int main(int argc, const char* argv[]) { if (argc == 2) { if (std::strcmp(argv[1], "-v") == 0 || - std::strcmp(argv[1], "--version") == 0) { - std::cout << "CBXP " << VERSION << std::endl; + std::strcmp(argv[1], "--version") == 0) { std::cout << "CBXP " << VERSION << std::endl; return 0; } From 98af098b6ac88330592c03ca0d9031b1e6cfa22f Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Fri, 5 Dec 2025 10:16:47 -0500 Subject: [PATCH 07/20] Fix temporary format error. Signed-off-by: Leonard Carcaramo --- cbxp/main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cbxp/main.cpp b/cbxp/main.cpp index cfc57df..fabb910 100644 --- a/cbxp/main.cpp +++ b/cbxp/main.cpp @@ -35,7 +35,8 @@ int main(int argc, const char* argv[]) { if (argc == 2) { if (std::strcmp(argv[1], "-v") == 0 || - std::strcmp(argv[1], "--version") == 0) { std::cout << "CBXP " << VERSION << std::endl; + std::strcmp(argv[1], "--version") == 0) { + std::cout << "CBXP " << VERSION << std::endl; return 0; } From bf7e5af08c050fb29d0993055996d0368ca6fe7c Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Wed, 10 Dec 2025 09:21:02 -0500 Subject: [PATCH 08/20] Fix syntax error. Signed-off-by: Leonard Carcaramo --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 3b43fed..b488e8d 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -241,7 +241,7 @@ def clean_git_repo() { def publish( python_executables_and_wheels_map, - release_title + release_title, release_tag, git_branch, milestone, From c2a92759d61139b8b3610df9faaa43c25bd77e88 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Wed, 10 Dec 2025 09:30:09 -0500 Subject: [PATCH 09/20] Fix syntax error. Signed-off-by: Leonard Carcaramo --- Jenkinsfile | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index b488e8d..168e7b6 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -139,28 +139,28 @@ pipeline { clean_python_environment() clean_git_repo() } + // Shell distribution + def cbxp_version = get_cbxp_version() + def pax = "cbxp-${cbxp_version}.pax.Z" + echo "Building '${pax}' ..." + sh """ + cmake . + gmake package + """ + + echo "Install test '${pax}' ..." + sh """ + mkdir install-test + cd install-test + pax -rf ../dist/${pax} + ls -alT install-test/cbxp + """ + + echo "'Function testing './dist/cbxp' ..." + sh "./tests/test.sh" + + clean_git_repo() } - // Shell distribution - def cbxp_version = get_cbxp_version() - def pax = "cbxp-${cbxp_version}.pax.Z" - echo "Building '${pax}' ..." - sh """ - cmake . - gmake package - """ - - echo "Install test '${pax}' ..." - sh """ - mkdir install-test - cd install-test - pax -rf ../dist/${pax} - ls -alT install-test/cbxp - """ - - echo "'Function testing './dist/cbxp' ..." - sh "./tests/test.sh" - - clean_git_repo() } } stage('Publish') { From fd610de6dc58ff03db658691ca0f17e4abf11960 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Wed, 10 Dec 2025 10:54:58 -0500 Subject: [PATCH 10/20] Update version number. Signed-off-by: Leonard Carcaramo --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f27e724..c0a7e6c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ endif() set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "./dist") -project(CBXP VERSION 0.0.2 +project(CBXP VERSION 0.0.3 DESCRIPTION "A unified and standardized interface for extracting z/OS control block data." LANGUAGES C CXX) From 554262350572d43b648b4bf0c850495134603709 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Wed, 10 Dec 2025 12:16:09 -0500 Subject: [PATCH 11/20] Debug shell install test. Signed-off-by: Leonard Carcaramo --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 168e7b6..96a92b1 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -153,7 +153,7 @@ pipeline { mkdir install-test cd install-test pax -rf ../dist/${pax} - ls -alT install-test/cbxp + ls -alT cbxp-${cbxp_version} """ echo "'Function testing './dist/cbxp' ..." From bb6152d3012cbc07c356d123ec5203793ee19e37 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Thu, 11 Dec 2025 12:27:48 -0500 Subject: [PATCH 12/20] Debug publish stage. Signed-off-by: Leonard Carcaramo --- Jenkinsfile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 96a92b1..4f85e83 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -297,9 +297,11 @@ def publish( ) ).trim() - def checksums_file = "SHASUMS256.txt.asc" + clean_git_repo() + def checksums_file = "SHASUMS256.txt.asc" sh """ + mkdir ./dist touch ./dist/${checksums_file} chtag -t -c ISO8859-1 ./dist/${checksums_file} """ @@ -307,8 +309,6 @@ def publish( def tar_publish def tar_built = false - clean_git_repo() - // Build and publish Python packages for (python in python_executables_and_wheels_map.keySet()) { def wheel_default = python_executables_and_wheels_map[python]["wheelDefault"] @@ -377,7 +377,7 @@ def upload_asset(release_id, release_asset) { def build_description(python_executables_and_wheels_map, release_tag, milestone) { def description = ( - "Release Notes: ${milestone}\\n \\n \\n" + "Release Notes: ${milestone}\\n" + "## Python Interface Installation" ) @@ -401,7 +401,7 @@ def build_description(python_executables_and_wheels_map, release_tag, milestone) + "> :warning: _Requires z/OS Open XL C/C++ 2.1 compiler._\\n" + "```\\ncurl -O -L https://github.com/ambitus/cbxp/releases/download/${release_tag}/${tar} " + "&& python3 -m pip install ${tar}\\n```\\n" - + "## Shell Interface Installation" + + "## Shell Interface Installation\\n" + "```\\ncurl -O -L https://github.com/ambitus/cbxp/releases/download/${release_tag}/${pax} " + "&& pax -rf ${pax}\\n```\\n" ) From 2068bb76f2bab16403bb51b7452f3a51039603ef Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Tue, 16 Dec 2025 13:16:47 -0500 Subject: [PATCH 13/20] Ruff and cmake test target fixes. Signed-off-by: Leonard Carcaramo --- CMakeLists.txt | 2 +- python/cbxp/_C.pyi | 6 ++++-- tests/test.py | 25 +++++++++++++++---------- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b44eb9f..3d92f7f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -160,5 +160,5 @@ add_custom_target( add_custom_target( test COMMAND "./tests/test.sh" - DEPENDS cbxp + DEPENDS libcbxp cbxp ) diff --git a/python/cbxp/_C.pyi b/python/cbxp/_C.pyi index 303a994..7ab645e 100644 --- a/python/cbxp/_C.pyi +++ b/python/cbxp/_C.pyi @@ -1,3 +1,5 @@ -def call_cbxp( # noqa: N999 - control_block: str, includes_string: str, debug: bool = False, +def call_cbxp( # noqa: N999 + control_block: str, + includes_string: str, + debug: bool = False, ) -> dict: ... diff --git a/tests/test.py b/tests/test.py index adbd8e7..7d3351a 100644 --- a/tests/test.py +++ b/tests/test.py @@ -28,13 +28,13 @@ def test_cbxp_can_extract_ascb(self): self.assertIs(type(cbdata), list) for entry in cbdata: self.assertIs(type(entry), dict) - + def test_cbxp_can_extract_assb(self): cbdata = cbxp("assb") self.assertIs(type(cbdata), list) for entry in cbdata: self.assertIs(type(entry), dict) - + # ============================================================================ # Include Patterns # ============================================================================ @@ -62,7 +62,7 @@ def test_cbxp_can_extract_the_asvt_and_include_the_ascb(self): self.assertIs(type(cbdata["asvtenty"]), list) for entry in cbdata["asvtenty"]: self.assertIs(type(entry), dict) - + def test_cbxp_can_extract_the_ascb_and_include_the_assb(self): cbdata = cbxp("ascb", includes=["assb"]) self.assertIs(type(cbdata), list) @@ -84,7 +84,7 @@ def test_cbxp_can_extract_the_psa_and_include_the_cvt_ecvt_ascb(self): self.assertIs(type(cbdata["flccvt"]["cvtasvt"]["asvtenty"]), list) for entry in cbdata["flccvt"]["cvtasvt"]["asvtenty"]: self.assertIs(type(entry), dict) - + def test_cbxp_can_extract_the_cvt_and_include_the_asvt_ascb(self): cbdata = cbxp("cvt", includes=["asvt.ascb"]) self.assertIs(type(cbdata), dict) @@ -113,8 +113,10 @@ def test_cbxp_include_can_extract_psa_and_include_ecvt_asvt_and_cvt_asvt_ascb( self.assertIs(type(cbdata["flccvt"]["cvtasvt"]["asvtenty"]), list) for entry in cbdata["flccvt"]["cvtasvt"]["asvtenty"]: self.assertIs(type(entry), dict) - - def test_cbxp_include_can_extract_psa_and_include_ecvt_asvt_and_cvt_asvt_ascb_assb(self): + + def test_cbxp_include_can_extract_psa_and_include_ecvt_asvt_and_cvt_asvt_ascb_assb( + self, + ): cbdata = cbxp("psa", includes=["cvt.ecvt", "cvt.asvt.ascb.assb"]) self.assertIs(type(cbdata), dict) self.assertIs(type(cbdata["flccvt"]), dict) @@ -145,7 +147,7 @@ def test_cbxp_can_extract_psa_and_include_cvt_wildcard(self): self.assertIs(type(cbdata["flccvt"]["cvtasvt"]["asvtenty"]), list) for entry in cbdata["flccvt"]["cvtasvt"]["asvtenty"]: self.assertIs(type(entry), str) - + def test_cbxp_can_extract_cvt_and_include_wildcard_and_asvt_wildcard(self): cbdata = cbxp("cvt", includes=["*", "asvt.*"]) self.assertIs(type(cbdata), dict) @@ -154,8 +156,10 @@ def test_cbxp_can_extract_cvt_and_include_wildcard_and_asvt_wildcard(self): self.assertIs(type(cbdata["cvtasvt"]["asvtenty"]), list) for entry in cbdata["cvtasvt"]["asvtenty"]: self.assertIs(type(entry), dict) - - def test_cbxp_can_extract_cvt_and_include_wildcard_and_asvt_recursive_wildcard(self): + + def test_cbxp_can_extract_cvt_and_include_wildcard_and_asvt_recursive_wildcard( + self, + ): cbdata = cbxp("cvt", includes=["*", "asvt.**"]) self.assertIs(type(cbdata), dict) self.assertIs(type(cbdata["cvtecvt"]), dict) @@ -179,7 +183,8 @@ def test_cbxp_raises_cbxp_error_when_unknown_control_block_is_provided(self): with self.assertRaises(CBXPError) as e: cbxp("unknown") self.assertEqual( - "Unknown control block 'unknown' was specified.", str(e.exception), + "Unknown control block 'unknown' was specified.", + str(e.exception), ) # ============================================================================ From 3df48226c07eb92ca46211023ee28245c34cc379 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Tue, 16 Dec 2025 13:38:50 -0500 Subject: [PATCH 14/20] Show full directory structure in CLI/library install test. Signed-off-by: Leonard Carcaramo --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 4f85e83..b56c92d 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -153,7 +153,7 @@ pipeline { mkdir install-test cd install-test pax -rf ../dist/${pax} - ls -alT cbxp-${cbxp_version} + ls -alT cbxp-${cbxp_version}/* """ echo "'Function testing './dist/cbxp' ..." From f322369f1c07acfa216c81cb85341cf624c42b3f Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Wed, 17 Dec 2025 07:06:30 -0500 Subject: [PATCH 15/20] Add ruff pre-commit hook. Signed-off-by: Leonard Carcaramo --- .pre-commit-config.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 57d5113..2fec720 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,3 +14,7 @@ repos: pass_filenames: false always_run: true verbose: true + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.14.9 + hooks: + - id: ruff-format From bb65ce90a313f2146b70aa6a9ccf91ea54b5e402 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Wed, 17 Dec 2025 07:24:50 -0500 Subject: [PATCH 16/20] Update contribution guidelines. Signed-off-by: Leonard Carcaramo --- CONTRIBUTING.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fea64f9..3eb089a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -108,9 +108,9 @@ CBXP is tested using automated functional tests. Test cases for new functionalit ## Style Guidelines -:bulb: _`clang-format` can be setup to run automatically using the [pre-commit Hooks](#pre-commit-hooks)._ +:bulb: _`clang-format` and `ruff` can be setup to run automatically using the [pre-commit Hooks](#pre-commit-hooks)._ -The use of the `clang-format` code formatter is required. All Python code also must pass `ruff` style checks. +All C/C++ code must be formatted using `clang-format`, and all Python code must be formatted using `ruff`. The following C/C++ code style conventions should be followed: * Varible names should use snake case *(i.e., `my_variable`)*. @@ -145,11 +145,11 @@ When contributing to CBXP, make sure to complete all applicable tasks in the fol * Make any necessary updates to `pyproject.toml`. * Make any necessary updates to `README.md`. -* Ensure that you have **pre-commit Hooks** setup to ensure that `clang-format` and `cppcheck` are run against the code for every commit you make. -* Check for style violations in C/C++ code using `clang-format` by running `gmake lint`. -* Check for style vilotations in Python code using `ruff` by running `ruff check`. -* Format C/C++ code using `clang-format` by running `gmake format`. -* Format Python code using `ruff` by running `ruff format`. +* Ensure that you have **pre-commit Hooks** setup to ensure that `clang-format`, `cppcheck`, and `ruff` are run against the code for every commit you make. +* Check for style violations in C/C++ code by running `gmake lint`. +* Check for style vilotations in Python code by running `ruff check`. +* Format C/C++ code by running `gmake format`. +* Format Python code by running `ruff format`. * Run `cppcheck` static code analysis by running `gmake check`. ## Found a bug? From 42615a8af742f2f04741884f12e1e6218b3f2206 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Wed, 17 Dec 2025 07:31:04 -0500 Subject: [PATCH 17/20] Update pre-commit Hooks section in the contribution guidelines. Signed-off-by: Leonard Carcaramo --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3eb089a..1f66144 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -48,7 +48,7 @@ There are many ways to contribute to the project. You can write code, work on th If you want to write code, a good way to get started is by looking at the issues section of this repository. Look for the **Good First Issue** tag. Good First Issues are great as a first contribution. ### pre-commit Hooks -To ensure `clang-format` and `cppcheck` are always run against your code on **every commit**, set up the **pre-commit hooks**. +To ensure `clang-format`, `cppcheck`, and `ruff` are always run against your code on **every commit**, set up the **pre-commit hooks**. * Install [`pre-commit`](https://pre-commit.com/). * Setup **pre-commit Hooks**: From abd8ec29b7ab73282ee517fb6bf6eb14e98e5b4f Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Wed, 17 Dec 2025 07:42:44 -0500 Subject: [PATCH 18/20] Fix typo. Signed-off-by: Leonard Carcaramo --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index b56c92d..f74ae37 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -378,7 +378,7 @@ def upload_asset(release_id, release_asset) { def build_description(python_executables_and_wheels_map, release_tag, milestone) { def description = ( "Release Notes: ${milestone}\\n" - + "## Python Interface Installation" + + "## Python Interface Installation\\n" ) for (python in python_executables_and_wheels_map.keySet()) { From 8b5eb203161e4b682049122bdfcff56ff282dc3c Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Wed, 17 Dec 2025 07:51:32 -0500 Subject: [PATCH 19/20] Cleanup. Signed-off-by: Leonard Carcaramo --- CONTRIBUTING.md | 4 ++-- Jenkinsfile | 4 ++-- README.md | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1f66144..f622852 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -23,7 +23,7 @@ The following are a set of guidelines to help you contribute. * [Python Interface Testing](#python-interface-testing) - * [Shell Interface Testing](#shell-interface-testing) + * [CLI Interface Testing](#cli-interface-testing) * [Style Guidelines](#style-guidelines) @@ -97,7 +97,7 @@ CBXP is tested using automated functional tests. Test cases for new functionalit python3 ./tests/test.py ``` -#### Shell Interface Testing +#### CLI Interface Testing 1. Add new tests cases to [`tests/test.sh`](tests/test.sh). 2. Run the test suite using `cmake` and `gmake`. diff --git a/Jenkinsfile b/Jenkinsfile index f74ae37..40e58bf 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -342,7 +342,7 @@ def publish( echo "Adding sha256 checksum for '${tar_publish}' to ${checksums_file}..." sh "cd dist && sha256sum -t ${tar_publish} >> ${checksums_file}" - // Build and publish Shell distribution + // Build and publish CLI/Library distribution def cbxp_version = get_cbxp_version() def pax = "cbxp-${cbxp_version}.pax.Z" echo "Building '${pax}' ..." @@ -401,7 +401,7 @@ def build_description(python_executables_and_wheels_map, release_tag, milestone) + "> :warning: _Requires z/OS Open XL C/C++ 2.1 compiler._\\n" + "```\\ncurl -O -L https://github.com/ambitus/cbxp/releases/download/${release_tag}/${tar} " + "&& python3 -m pip install ${tar}\\n```\\n" - + "## Shell Interface Installation\\n" + + "## CLI/Library Installation\\n" + "```\\ncurl -O -L https://github.com/ambitus/cbxp/releases/download/${release_tag}/${pax} " + "&& pax -rf ${pax}\\n```\\n" ) diff --git a/README.md b/README.md index 7efbc66..90a7799 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ All versions of the **IBM Open Enterprise SDK for Python** that are fully suppor ### Interfaces Currently, the following interfaces are provided for CBXP. Additional interfaces can be added in the future if there are use cases for them. * [Python Interface](https://ambitus.github.io/cbxp/interfaces/python) -* [Shell Interface](https://ambitus.github.io/cbxp/interfaces/shell) +* [CLI Interface](https://ambitus.github.io/cbxp/interfaces/shell) ### Supported Control Blocks From 48f8438911456fa70e280f0a27c3a0ca71b045c4 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Wed, 17 Dec 2025 08:20:53 -0500 Subject: [PATCH 20/20] Minor cleanup. Signed-off-by: Leonard Carcaramo --- Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 40e58bf..ac9abd3 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -139,7 +139,7 @@ pipeline { clean_python_environment() clean_git_repo() } - // Shell distribution + // CLI/Library distribution def cbxp_version = get_cbxp_version() def pax = "cbxp-${cbxp_version}.pax.Z" echo "Building '${pax}' ..." @@ -148,7 +148,7 @@ pipeline { gmake package """ - echo "Install test '${pax}' ..." + echo "Install testing '${pax}' ..." sh """ mkdir install-test cd install-test