From 1676333c328117bc6848dd3cfa39646069fec16c Mon Sep 17 00:00:00 2001 From: Tannaz Vahidi Date: Mon, 2 Sep 2024 23:05:58 +0200 Subject: [PATCH] lobster-codebeamer supports refs upstream reference (#68) * lobster-codebeamer supports refs upstream reference An optional config file as argument has been added to lobster-codebeamer. This config file should include a list of upstream references and respective cb-fieldNames Resolves https://github.com/bmw-software-engineering/lobster/issues/45 --- CHANGELOG.md | 2 + lobster/tools/codebeamer/codebeamer.py | 89 ++++++++++++++++++++++ packages/lobster-tool-codebeamer/README.md | 27 +++++++ 3 files changed, 118 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index de8ac552..8b17cb36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ ### 0.9.18-dev +* The `lobster-codebeamer` tool now supports `refs` as an upstream reference + * The `lobster-online-report` tool now works with config files located in main- and submodules of a repository. This feature needs `git 1.7.8` or higher. diff --git a/lobster/tools/codebeamer/codebeamer.py b/lobster/tools/codebeamer/codebeamer.py index 3d1e4e5c..57ab9b02 100755 --- a/lobster/tools/codebeamer/codebeamer.py +++ b/lobster/tools/codebeamer/codebeamer.py @@ -41,6 +41,8 @@ import argparse import netrc from urllib.parse import quote +from enum import Enum +import json import requests from lobster.items import Tracing_Tag, Requirement @@ -49,6 +51,26 @@ from lobster.io import lobster_read, lobster_write +class References(Enum): + REFS = "refs" + + +SUPPORTED_REFERENCES = [References.REFS.value] + + +def add_refs_refrences(req, flat_values_list): + # refs + for value in flat_values_list: + if value.get("id"): + ref_id = value.get("id") + req.add_tracing_target(Tracing_Tag("req", str(ref_id))) + + +map_reference_name_to_function = { + References.REFS.value: add_refs_refrences +} + + def query_cb_single(cb_config, url): assert isinstance(cb_config, dict) assert isinstance(url, str) @@ -193,6 +215,30 @@ def to_lobster(cb_config, cb_item): text = None, status = status) + if cb_config.get('references'): + for reference_name, displayed_chosen_names in ( + cb_config['references'].items()): + if reference_name not in map_reference_name_to_function: + continue + + for displayed_name in displayed_chosen_names: + if cb_item.get(displayed_name): + flat_values_list = cb_item.get(displayed_name) if ( + isinstance(cb_item.get(displayed_name), list)) \ + else [cb_item.get(displayed_name)] + else: + flat_values_list = ( + list(value for custom_field + in cb_item["customFields"] + if custom_field["name"] == displayed_name and + custom_field.get("values") + for value in custom_field["values"])) + if not flat_values_list: + continue + + (map_reference_name_to_function[reference_name] + (req, flat_values_list)) + return req @@ -210,6 +256,36 @@ def import_tagged(mh, cb_config, items_to_import): return rv +def ensure_array_of_strings(instance): + if (isinstance(instance, list) and + all(isinstance(item, str) + for item in instance)): + return instance + else: + return [str(instance)] + + +def parse_cb_config(file_name): + assert isinstance(file_name, str) + assert os.path.isfile(file_name) + + with open(file_name, "r", encoding='utf-8') as file: + data = json.loads(file.read()) + + provided_config_keys = set(data.keys()) + supported_references = set(SUPPORTED_REFERENCES) + + if not provided_config_keys.issubset(supported_references): + raise KeyError("The provided references are not supported! " + "supported referenes: '%s'" % + ', '.join(SUPPORTED_REFERENCES)) + + json_config = {} + for key, value in data.items(): + json_config[key] = ensure_array_of_strings(value) + return json_config + + def main(): ap = argparse.ArgumentParser() @@ -217,10 +293,17 @@ def main(): modes.add_argument("--import-tagged", metavar="LOBSTER_FILE", default=None) + modes.add_argument("--import-query", metavar="CB_QUERY_ID", default=None) + ap.add_argument("--config", + help=("name of codebeamer " + "config file, supported references: '%s'" % + ', '.join(SUPPORTED_REFERENCES)), + default=None) + ap.add_argument("--ignore-ssl-errors", action="store_true", default=False, @@ -254,6 +337,12 @@ def main(): "timeout" : options.timeout, } + if options.config: + if os.path.isfile(options.config): + cb_config["references"] = parse_cb_config(options.config) + else: + ap.error("cannot open config file '%s'" % options.config) + if cb_config["root"] is None: ap.error("please set CB_ROOT or use --cb-root") diff --git a/packages/lobster-tool-codebeamer/README.md b/packages/lobster-tool-codebeamer/README.md index d5eb22fb..9c4b729c 100644 --- a/packages/lobster-tool-codebeamer/README.md +++ b/packages/lobster-tool-codebeamer/README.md @@ -13,6 +13,30 @@ requirements management tool * `lobster-codebeamer`: Extrat requirements from codebeamer. +## Configuration +This tool works with an optional config file. In it you can declare which +codebeamer fields should be used as 'refs' reference in the codebeamer file. + +For the 'refs' reference in config file you can write: + +``` +{ +"refs" : "cb-fieldname" +} +``` +or +``` +{ +"refs" : ["cb-fieldname"] +} +``` +or +``` +{ +"refs" : ["cb-fieldname1", "cb-fieldname2"] +} +``` + ## Usage There are two ways you can use this tool: @@ -23,6 +47,9 @@ There are two ways you can use this tool: * Download all requirements generated by a saved codebeamer query (using `--import-query`) +* Configure the 'refs' upstream reference (this argument is optional) +(using `--config`) + ## Limitations The key limitation is item text, which is currently not