Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add new pre-commit hook: validate ibm_catalog.json inputs #1080

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions module-assets/.pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,12 @@ repos:
language: python
files: "tests/go.mod"
pass_filenames: false
- id: validate_ibm_catalog_json
name: Validate ibm_catalog.json file
description: Validate if input variables in ibm_catalog.json file are in sync with DA inputs
entry: python3 ci/validateIbmCatalogJson.py
language: python
pass_filenames: false
# helm lint
- repo: https://github.com/gruntwork-io/pre-commit
rev: v0.1.24
Expand Down
97 changes: 97 additions & 0 deletions module-assets/ci/validateIbmCatalogJson.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import json
import os
import sys
from pathlib import Path
from subprocess import PIPE, Popen

IBM_CATALOG_FILE = "ibm_catalog.json"
DA_FOLDER = "solutions"
Copy link
Member

@ocofaigh ocofaigh Dec 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not all DAs will be in a solutions folder (for example landing zone in in patterns folder and WatsonX SaaS DA is in root level). The working directory of the DA will be in the ibm_catalog.json. And if its not, it means it defaults to the root directory of the repo.



# get inputs for solution defined in ibm_catalog.json file
def check_ibm_catalog_file(da_name):
inputs = []
with open(IBM_CATALOG_FILE) as f:
ibm_catalog = json.load(f)
if ibm_catalog and "products" in ibm_catalog and ibm_catalog["products"]:
Copy link
Member

@ocofaigh ocofaigh Dec 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you make sure we only do this for "product_kind": "solution", ? Since we also have module types, and they should be excluded from this check

for product in ibm_catalog["products"]:
if "flavors" in product and product["flavors"]:
for flavor in product["flavors"]:
if (
"working_directory" in flavor
and "configuration" in flavor
and flavor["working_directory"]
and flavor["working_directory"] == f"{DA_FOLDER}/{da_name}"
and flavor["configuration"]
):
inputs = [x["key"] for x in flavor["configuration"]]
return inputs


# get inputs for solution defined in solutions folder
def get_inputs(da_name):
inputs = []
da_path = f"{os.getcwd()}/{DA_FOLDER}/{da_name}"
command = f"terraform-docs --show inputs json {da_path}"
proc = Popen(command, stdout=PIPE, stderr=PIPE, shell=True)
output, error = proc.communicate()

# hard fail if error occurs
if proc.returncode != 0:
print(f"Error getting inputs: {proc.communicate()[1]}")
sys.exit(proc.returncode)

json_object = json.loads(output)
inputs = [x["name"] for x in json_object["inputs"]]
return inputs


# return inputs that are defined as solution (DA) input but are missing in ibm_catalog.json file
def check_inputs_missing(da_inputs, catalog_inputs):
inputs_not_in_catalog = []
for da_input in da_inputs:
if da_input not in catalog_inputs:
inputs_not_in_catalog.append(da_input)
return inputs_not_in_catalog


# return inputs that are not defined as solution (DA) input but are added in ibm_catalog.json file
def check_inputs_extra(da_inputs, catalog_inputs):
inputs_not_in_da = []
for catalog_input in catalog_inputs:
if catalog_input not in da_inputs:
inputs_not_in_da.append(catalog_input)
return inputs_not_in_da


# check solution inputs
def check_da(da_names):
for da_name in da_names:
da_inputs = get_inputs(da_name)
catalog_inputs = check_ibm_catalog_file(da_name)
inputs_not_in_catalog = check_inputs_missing(da_inputs, catalog_inputs)
inputs_not_in_da = check_inputs_extra(da_inputs, catalog_inputs)

if len(inputs_not_in_catalog) > 0 or len(inputs_not_in_da):
print(
f"For solution '{da_name}' the following inputs should be defined in ibm_catalog.json: {inputs_not_in_catalog}"
)
print(
f"For solution '{da_name}' the following inputs should not be defined in ibm_catalog.json: {inputs_not_in_da}"
)
sys.exit(1)


# get solutions
def get_da_names():
da_names = ""
path = Path(DA_FOLDER)
da_names = os.listdir(path)
return da_names


if __name__ == "__main__":

if os.path.isdir(DA_FOLDER) and os.path.isfile(IBM_CATALOG_FILE):
da_names = get_da_names()
check_da(da_names)
Loading