diff --git a/README.md b/README.md index d8a105c..b4ec8ed 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,8 @@ To output both JSON and a Junit formatted xml file use: postman collection run 11111111-11111111-1111-1111-1111-111111111111 -e 11111111-11111111-1111-1111-1111-111111111111 | postman-cli-transformer output.json --junit-out-file junit.xml ``` +Furthermore, the tool will exit with a code of 1 if any of the tests run by the CLI fail. This behavior may be turned off by a flag. + ## Development To contribute to this tool, first checkout the code. Then create a new virtual environment: diff --git a/postman_cli_transformer/cli.py b/postman_cli_transformer/cli.py index ff3db64..2e4594c 100644 --- a/postman_cli_transformer/cli.py +++ b/postman_cli_transformer/cli.py @@ -9,24 +9,34 @@ @click.command() -@click.argument("output", type=click.File("w"), default="-", required=False) +@click.argument("output", type=click.File("w"), required=True) @click.option( + "-junit", "--junit-out-file", required=False, type=click.File("w"), help="File location to output junit xml file from transformed CLI results.", ) +@click.option( + "-bup", + "--bubble-up-exit-code", + default=True, + required=False, + type=click.BOOL, + help="""Defaults to True. Since this tool is used to transform output results from the Postman CLI, + it will exit with an error if the underlying Postman CLI output contains an error. + This will facilitate the failure of the task in a CI/CD pipeline. If you do not want + this behavior and wish the exit code to reflect the exit state of this app, set + this flag to False.""", +) @click.version_option() -def cli(output, junit_out_file): +def cli(output, junit_out_file, bubble_up_exit_code): """This script will take as input the STDOUT from a Postman CLI collection run and transform the output text to a file containing the output data - organized in a JSON format. This JSON data is then - written into a specific file. - - \b - Output to stdout: - postman-cli-transformer + organized in a JSON format. It will also preserve + the CLI standard out and send to STDOUT at the end + of its execution. \b Output to file foo.json: @@ -40,7 +50,7 @@ def cli(output, junit_out_file): stdin_data = sys.stdin.read() - parsed_stdin = parse(stdin_data) + parsed_stdin, errored = parse(stdin_data) if junit_out_file: current_time_of_test_run = datetime.now().isoformat() @@ -51,6 +61,12 @@ def cli(output, junit_out_file): output.write(parsed_stdin) output.flush() + click.echo(stdin_data) + + if bubble_up_exit_code: + if errored: + raise click.exceptions.Exit(1) + def parse(data): raw_lines = [] @@ -60,7 +76,8 @@ def parse(data): processor = Processor(raw_lines) results = processor.parsed + errored = processor.errored json_str = json.dumps(results) - return json_str + return json_str, errored diff --git a/postman_cli_transformer/processor.py b/postman_cli_transformer/processor.py index 8948520..bc31b25 100644 --- a/postman_cli_transformer/processor.py +++ b/postman_cli_transformer/processor.py @@ -21,6 +21,7 @@ def __init__(self, lines_to_process): # Class property definiing self.processing_helper = ProcessingHelper() self.parsed = {"collectionName": "", "folders": []} + self.errored = False self.lines_to_process = lines_to_process # Get header info out of the way @@ -167,6 +168,7 @@ def _process_rest_of_lines(self): self.processing_helper.update_current_line_type( LINE_TYPES.ERROR_HEADER_LINE ) + self.errored = True case LINE_TYPES.ERROR_LINE: self.processing_helper.update_current_line_type( diff --git a/tests/test_data/test_junit_transformer.py b/tests/test_junit_transformer.py similarity index 100% rename from tests/test_data/test_junit_transformer.py rename to tests/test_junit_transformer.py diff --git a/tests/test_processor.py b/tests/test_processor.py index 47bae50..07b1b71 100644 --- a/tests/test_processor.py +++ b/tests/test_processor.py @@ -37,6 +37,7 @@ def test_should_be_able_to_process_folders(): processor = Processor(lines) results = processor.parsed + errored = processor.errored expected_results = { "collectionName": "Pinball Map Collection", @@ -48,6 +49,7 @@ def test_should_be_able_to_process_folders(): } assert json.dumps(results) == json.dumps(expected_results) + assert errored is False def test_should_be_able_to_process_urls(): @@ -73,6 +75,7 @@ def test_should_be_able_to_process_urls(): processor = Processor(lines) results = processor.parsed + errored = processor.errored expected_results = { "collectionName": "Pinball Map Collection", @@ -145,6 +148,7 @@ def test_should_be_able_to_process_urls(): } assert json.dumps(results) == json.dumps(expected_results) + assert errored is False def test_should_be_able_to_process_tests(): @@ -182,6 +186,7 @@ def test_should_be_able_to_process_tests(): processor = Processor(lines) results = processor.parsed + errored = processor.errored expected_results = { "collectionName": "Pinball Map Collection", @@ -353,6 +358,7 @@ def test_should_be_able_to_process_tests(): } assert json.dumps(results) == json.dumps(expected_results) + assert errored is False def test_should_be_able_to_process_root_level_requests(): @@ -400,6 +406,7 @@ def test_should_be_able_to_process_root_level_requests(): processor = Processor(lines) results = processor.parsed + errored = processor.errored expected_results = { "collectionName": "Pinball Map Collection", @@ -624,6 +631,7 @@ def test_should_be_able_to_process_root_level_requests(): } assert json.dumps(results) == json.dumps(expected_results) + assert errored is False def test_should_be_able_to_process_the_summary_table(): @@ -667,6 +675,7 @@ def test_should_be_able_to_process_the_summary_table(): processor = Processor(lines) results = processor.parsed + errored = processor.errored expected_results = { "collectionName": "Deactivate User Accounts", @@ -745,6 +754,7 @@ def test_should_be_able_to_process_the_summary_table(): } assert json.dumps(results) == json.dumps(expected_results) + assert errored is False def test_should_be_able_to_process_error_descriptions(): @@ -810,6 +820,7 @@ def test_should_be_able_to_process_error_descriptions(): processor = Processor(lines) results = processor.parsed + errored = processor.errored expected_results = { "collectionName": "Pinball Map Collection", @@ -963,3 +974,4 @@ def test_should_be_able_to_process_error_descriptions(): } assert json.dumps(results) == json.dumps(expected_results) + assert errored is True