def test_iterate_commands_no_commands(self): """Test iterate_commands when the yaml has no commands.""" yaml_dict = load(TestHelpers.I_CANT_BELIEVE_THAT_VALIDATES) gen = iterate_commands(yaml_dict) count = 0 for _ in gen: count = count + 1 self.assertEqual(count, 0)
def test_iterate_commands(self): """test iterate_commands.""" yaml_dict = load(TestRulebreaker.RULEBREAKER.format(inject_here="")) gen = iterate_commands(yaml_dict) count = 0 for _ in gen: count = count + 1 self.assertEqual(count, 14)
def no_keyval_inc(yaml: dict) -> List[LintError]: """Prevent usage of keyval.inc.""" def _out_message(context: str) -> LintError: return f"{context} includes keyval.inc, which is not permitted. Do not use keyval.inc." out: List[LintError] = [] for context, command in iterate_commands(yaml): if "command" in command and command["command"] == "keyval.inc": out.append(_out_message(context)) return out
def no_working_dir_on_shell(yaml: dict) -> List[LintError]: """Do not allow working_dir to be set on shell.exec, subprocess.*.""" def _out_message(context: str, cmd: str) -> LintError: return f"{context} is a {cmd} command with a working_dir parameter. Do not set working_dir, instead `cd` into the directory in the shell script." out: List[LintError] = [] for context, command in iterate_commands(yaml): if "command" in command and command["command"] in SHELL_COMMANDS: if "params" in command and "working_dir" in command["params"]: out.append(_out_message(context, command["command"])) return out
def shell_exec_explicit_shell(yaml: dict) -> List[LintError]: """Require explicitly specifying shell in uses of shell.exec.""" def _out_message(context: str) -> LintError: return f"{context} is a shell.exec command without an explicitly declared shell. You almost certainly want to add 'shell: bash' to the parameters list." out: List[LintError] = [] for context, command in iterate_commands(yaml): if "command" in command and command["command"] == "shell.exec": if "params" not in command or "shell" not in command["params"]: out.append(_out_message(context)) return out
def no_shell_exec(yaml: dict) -> List[LintError]: """Do not allow shell.exec. Users should use subprocess.exec instead.""" def _out_message(context: str) -> LintError: return ( f"{context} is a shell.exec command, which is forbidden. " "Extract your shell script out of the YAML and into a .sh file " "in directory 'evergreen', and use subprocess.exec instead.") out: List[LintError] = [] for context, command in iterate_commands(yaml): if "command" in command and command["command"] == "shell.exec": out.append(_out_message(context)) return out
def no_multiline_expansions_update(yaml: dict) -> List[LintError]: """Forbid multi-line values in expansion.updates parameters.""" def _out_message(context: str, idx: int) -> LintError: return (f"{context}, key-value pair {idx} is an expansions.update " "command a multi-line values, which is forbidden. For " "long-form values, prefer expansions.write.") out: List[LintError] = [] for context, command in iterate_commands(yaml): if "command" in command and command["command"] == "expansions.update": if "params" in command and "updates" in command["params"]: for idx, item in enumerate(command["params"]["updates"]): if "value" in item and "\n" in item["value"]: out.append(_out_message(context, idx)) return out
def subprocess_exec_bootstraps_shell(yaml: dict) -> List[LintError]: """Require that subprocess.exec functions that consume evergreen scripts correctly bootstrap the prelude.""" def _out_message(context: str, key: str) -> LintError: return f"{context} is a subprocess.exec command that calls an evergreen shell script without a correctly set environment. You must set 'params.env.{key}' to '${{{key}}}'." def _out_message_binary(context: str) -> LintError: return f"{context} is a subprocess.exec command that calls an evergreen shell script through a binary other than bash, which is unsupported." # we're looking for subprocess exec commands that look like this #- command: subprocess.exec # params: # args: # - "src/evergreen/do_something.sh" # if we find one, we want to ensure that env on params is set to correctly # allow activate_venv to be bootstrapped, and the binary is set to bash out: List[LintError] = [] for context, command in iterate_commands(yaml): if "command" in command and command["command"] != "subprocess.exec": continue if "params" not in command: continue params = command["params"] if "args" not in params or not EVERGREEN_SCRIPT_RE.search( params["args"][0]): continue if "binary" not in params or params["binary"] != "bash": out.append(_out_message_binary(context)) if "env" in params: if "workdir" not in params[ "env"] or params["env"]["workdir"] != "${workdir}": out.append(_out_message(context, "workdir")) if "python" not in params[ "env"] or params["env"]["python"] != "${python}": out.append(_out_message(context, "python")) else: out.append(_out_message(context, "workdir")) out.append(_out_message(context, "python")) return out