CircleCI-Public / path-filtering-orb

MIT License
24 stars 62 forks source link

Proposal for better error handling in wrong config.yml #28

Closed d-tsuji closed 1 year ago

d-tsuji commented 3 years ago

Describe Request:

JSONDecodeError will be raised if there is a Typo in the config.yml description.

Proper handling of where users are going wrong will improve usability.

Examples:

Sadly, the following sample is a config.yml that typo's true as ture.

version: '2.1'
orbs:
  path-filtering: circleci/path-filtering@0.0.1
workflows:
  generate-config:
    jobs:
      - path-filtering/filter:
          base-revision: main
          config-path: .circleci/continue-config.yml
          mapping: |
            src/.* build-code ture
            doc/.* build-docs true

When CircleCI runs in this case, the following error occurs in Set parameters. Just looking at the error log, the cause is not clear and the user is confused. I was puzzled.

#!/usr/bin/env python3
#!/usr/bin/env python3

import json
import os
import re
import subprocess

output_path = os.environ.get('OUTPUT_PATH')
head = os.environ.get('CIRCLE_SHA1')
base = subprocess.run(
  ['git', 'merge-base', os.environ.get('BASE_REVISION'), head],
  check=True,
  capture_output=True
).stdout.decode('utf-8').strip()

if head == base:
  try:
    # If building on the same branch as BASE_REVISION, we will get the
    # current commit as merge base. In that case try to go back to the
    # first parent, i.e. the last state of this branch before the
    # merge, and use that as the base.
    base = subprocess.run(
      ['git', 'rev-parse', 'HEAD~1'], # FIXME this breaks on the first commit, fallback to something
      check=True,
      capture_output=True
    ).stdout.decode('utf-8').strip()
  except:
    # This can fail if this is the first commit of the repo, so that
    # HEAD~1 actually doesn't resolve. In this case we can compare
    # against this magic SHA below, which is the empty tree. The diff
    # to that is just the first commit as patch.
    base = '4b825dc642cb6eb9a060e54bf8d69288fbee4904'

print('Comparing {}...{}'.format(base, head))
changes = subprocess.run(
  ['git', 'diff', '--name-only', base, head],
  check=True,
  capture_output=True
).stdout.decode('utf-8').splitlines()

mappings = [
  m.split() for m in
  os.environ.get('MAPPING').splitlines()
]

def check_mapping(m):
  if 3 != len(m):
    raise Exception("Invalid mapping")
  path, param, value = m
  regex = re.compile(r'^' + path + r'$')
  for change in changes:
    if regex.match(change):
      return True
  return False

def convert_mapping(m):
  return [m[1], json.loads(m[2])]

mappings = filter(check_mapping, mappings)
mappings = map(convert_mapping, mappings)
mappings = dict(mappings)

with open(output_path, 'w') as fp:
  fp.write(json.dumps(mappings))
Traceback (most recent call last):
  File "<string>", line 61, in <module>
  File "<string>", line 57, in convert_mapping
  File "/home/circleci/.pyenv/versions/3.8.12/lib/python3.8/json/__init__.py", line 357, in loads
    return _default_decoder.decode(s)
  File "/home/circleci/.pyenv/versions/3.8.12/lib/python3.8/json/decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/home/circleci/.pyenv/versions/3.8.12/lib/python3.8/json/decoder.py", line 355, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

Exited with code exit status 1
CircleCI received exit code 1
h42zhu commented 1 year ago

This issue should be fixed by the linked PR.