mirror of
https://github.com/vee1e/gittuf.git
synced 2026-09-02 18:57:10 +00:00
123 lines
4.5 KiB
Python
123 lines
4.5 KiB
Python
#!/usr/bin/env python
|
|
|
|
import os
|
|
import platform
|
|
import re
|
|
import shlex
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import difflib
|
|
import stat
|
|
|
|
REQUIRED_BINARIES = ["git", "gittuf", "ssh-keygen"]
|
|
SNIPPET_PATTERN = r"```bash\n([\s\S]*?)\n```"
|
|
if platform.system() == "Windows":
|
|
EXPECTED_OUTPUT_FILENAME = "tester-expected-win.txt"
|
|
SHELL = "powershell.exe"
|
|
else:
|
|
EXPECTED_OUTPUT_FILENAME = "tester-expected-unix.txt"
|
|
SHELL = "/bin/bash"
|
|
GET_STARTED_FILENAME = "get-started.md"
|
|
|
|
# Validate that we have all the binaries required to run the test commands
|
|
def check_binaries():
|
|
for p in REQUIRED_BINARIES:
|
|
if not shutil.which(p):
|
|
raise Exception(f"required command {p} not found")
|
|
|
|
|
|
# This is required for deleting the directory on Windows
|
|
def remove_readonly(func, path, _):
|
|
"""Clear the readonly attribute and retry the operation."""
|
|
os.chmod(path, stat.S_IWRITE)
|
|
func(path)
|
|
|
|
# Replacements for some bash commands to work in PowerShell
|
|
def powershellify(cmds):
|
|
for i in range(len(cmds)):
|
|
# chaining commands in PowerShell works with ; instead of &&.
|
|
cmds[i] = cmds[i].replace("&&", ";")
|
|
|
|
# mkdir generates output in PowerShell, redirecting that to null
|
|
if "mkdir" in cmds[i]:
|
|
cmds[i] = re.sub(r'(mkdir\s+[a-zA-Z0-9-]+)', r'\1 > $null', cmds[i])
|
|
|
|
# quotes work differently in PowerShell, and the -N "" in the
|
|
# documentation causes ssh-keygen to break down in PowerShell.
|
|
# This can be solved by encapsulating the "" in single quotes like such:
|
|
if "ssh-keygen" in cmds[i]:
|
|
cmds[i] = cmds[i].replace('-N ""', "-N '\"\"'")
|
|
return cmds
|
|
|
|
def test_commands():
|
|
curr_path = os.getcwd()
|
|
docs_path = os.path.join(curr_path, "docs")
|
|
testing_path = os.path.join(docs_path, "testing")
|
|
get_started_file = os.path.realpath(os.path.join(docs_path, GET_STARTED_FILENAME))
|
|
os.chdir(testing_path)
|
|
|
|
# Check for supported platform
|
|
match platform.system():
|
|
case "Linux" | "Darwin" | "Windows":
|
|
expected_output_file = os.path.realpath(os.path.join(testing_path, EXPECTED_OUTPUT_FILENAME))
|
|
case _:
|
|
raise SystemExit("Unknown platform.")
|
|
|
|
# Prepare temporary directory
|
|
tmp_dir = os.path.realpath(tempfile.mkdtemp())
|
|
os.chdir(tmp_dir)
|
|
|
|
try:
|
|
with open(expected_output_file) as fp1, open(get_started_file) as fp2:
|
|
# Read in the get_started.md and expected output files
|
|
expected_output = fp1.read()
|
|
expected_output = re.sub(r'[\r\n]', '', expected_output)
|
|
get_started = fp2.read()
|
|
snippets = re.findall(SNIPPET_PATTERN, get_started)
|
|
|
|
# Prepend the set command to echo commands and exit in case of
|
|
# failure
|
|
if platform.system() == "Windows":
|
|
snippets = powershellify(snippets)
|
|
script = "\nSet-PSDebug -Trace 1\n {}".format("\n".join(snippets))
|
|
else:
|
|
script = "\nset -xe\n{}".format("\n".join(snippets))
|
|
script += "\ngittuf verify-ref main" # Workaround for non-deterministic hashes
|
|
|
|
# Set some environment variables to control commit creation
|
|
cmd_env = os.environ.copy()
|
|
|
|
cmd_env["GIT_AUTHOR_NAME"] = "Jane Doe"
|
|
cmd_env["GIT_AUTHOR_EMAIL"] = "jane.doe@example.com"
|
|
cmd_env["GIT_AUTHOR_DATE"] = "2024-06-03T14:00:00.000Z"
|
|
cmd_env["GIT_COMMITTER_NAME"] = "Jane Doe"
|
|
cmd_env["GIT_COMMITTER_EMAIL"] = "jane.doe@example.com"
|
|
cmd_env["GIT_COMMITTER_DATE"] = "2024-06-03T14:00:00.000Z"
|
|
|
|
# Execute generated script
|
|
proc = subprocess.Popen(
|
|
[SHELL, "-c", script],
|
|
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
|
|
universal_newlines=True, env=cmd_env)
|
|
stdout, _ = proc.communicate()
|
|
stdout = re.sub(r'[\r\n]', '', stdout)
|
|
|
|
# Compare and notify user of result
|
|
if stdout != expected_output:
|
|
difflist = list(difflib.Differ().compare(
|
|
expected_output.splitlines(),
|
|
stdout.splitlines()))
|
|
raise SystemExit("Testing failed due to unexpected output:\n {}".format("\n".join(difflist)))
|
|
else:
|
|
print("Testing completed successfully.")
|
|
|
|
finally:
|
|
# Cleanup
|
|
os.chdir(curr_path)
|
|
shutil.rmtree(tmp_dir, onerror=remove_readonly)
|
|
|
|
if __name__ == "__main__":
|
|
check_binaries()
|
|
test_commands()
|