Skip to content

Commit 8079af7

Browse files
committed
Swift: add autobuild failure diagnostics
1 parent 7323d4e commit 8079af7

File tree

13 files changed

+528
-17
lines changed

13 files changed

+528
-17
lines changed
Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,34 @@
11
"""
2-
recreation of internal `create_database_utils.py` to run the tests locally, with minimal
3-
and swift-specialized functionality
2+
Simplified version of internal `create_database_utils.py` used to run the tests locally, with
3+
minimal and swift-specialized functionality
4+
TODO unify integration testing code across the public and private repositories
45
"""
56
import subprocess
67
import pathlib
78
import sys
9+
import shutil
810

911

10-
def run_codeql_database_create(cmds, lang, keep_trap=True):
12+
def runSuccessfully(cmd):
13+
res = subprocess.run(cmd)
14+
if res.returncode:
15+
print("FAILED", file=sys.stderr)
16+
print(" ", *cmd, f"(exit code {res.returncode})", file=sys.stderr)
17+
sys.exit(res.returncode)
18+
19+
def runUnsuccessfully(cmd):
20+
res = subprocess.run(cmd)
21+
if res.returncode == 0:
22+
print("FAILED", file=sys.stderr)
23+
print(" ", *cmd, f"(exit code 0, expected to fail)", file=sys.stderr)
24+
sys.exit(1)
25+
26+
27+
def run_codeql_database_create(cmds, lang, keep_trap=True, db=None, runFunction=runSuccessfully):
28+
""" db parameter is here solely for compatibility with the internal test runner """
1129
assert lang == 'swift'
1230
codeql_root = pathlib.Path(__file__).parents[2]
31+
shutil.rmtree("db", ignore_errors=True)
1332
cmd = [
1433
"codeql", "database", "create",
1534
"-s", ".", "-l", "swift", "--internal-use-lua-tracing", f"--search-path={codeql_root}", "--no-cleanup",
@@ -19,8 +38,4 @@ def run_codeql_database_create(cmds, lang, keep_trap=True):
1938
for c in cmds:
2039
cmd += ["-c", c]
2140
cmd.append("db")
22-
res = subprocess.run(cmd)
23-
if res.returncode:
24-
print("FAILED", file=sys.stderr)
25-
print(" ", *cmd, file=sys.stderr)
26-
sys.exit(res.returncode)
41+
runFunction(cmd)
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
"""
2+
Simplified POSIX only version of internal `diagnostics_test_utils.py` used to run the tests locally
3+
TODO unify integration testing code across the public and private repositories
4+
"""
5+
6+
import json
7+
import pathlib
8+
import subprocess
9+
import os
10+
import difflib
11+
import sys
12+
13+
14+
def _normalize_actual(test_dir, database_dir):
15+
proc = subprocess.run(['codeql', 'database', 'export-diagnostics', '--format', 'raw', '--', database_dir],
16+
stdout=subprocess.PIPE, universal_newlines=True, check=True, text=True)
17+
data = proc.stdout.replace(str(test_dir.absolute()), "<test-root-directory>")
18+
data = json.loads(data)
19+
data[:] = [e for e in data if not e["source"]["id"].startswith("cli/")]
20+
for e in data:
21+
e.pop("timestamp")
22+
return _normalize_json(data)
23+
24+
25+
def _normalize_expected(test_dir):
26+
with open(test_dir / "diagnostics.expected") as expected:
27+
text = expected.read()
28+
return _normalize_json(_load_concatenated_json(text))
29+
30+
31+
def _load_concatenated_json(text):
32+
text = text.lstrip()
33+
entries = []
34+
decoder = json.JSONDecoder()
35+
while text:
36+
obj, index = decoder.raw_decode(text)
37+
entries.append(obj)
38+
text = text[index:].lstrip()
39+
return entries
40+
41+
42+
def _normalize_json(data):
43+
entries = [json.dumps(e, sort_keys=True, indent=2) for e in data]
44+
entries.sort()
45+
entries.append("")
46+
return "\n".join(entries)
47+
48+
49+
def check_diagnostics(test_dir=".", test_db="db"):
50+
test_dir = pathlib.Path(test_dir)
51+
test_db = pathlib.Path(test_db)
52+
actual = _normalize_actual(test_dir, test_db)
53+
if os.environ.get("CODEQL_INTEGRATION_TEST_LEARN") == "true":
54+
with open(test_dir / "diagnostics.expected", "w") as expected:
55+
expected.write(actual)
56+
return
57+
expected = _normalize_expected(test_dir)
58+
if actual != expected:
59+
with open(test_dir / "diagnostics.actual", "w") as actual_out:
60+
actual_out.write(actual)
61+
actual = actual.splitlines(keepends=True)
62+
expected = expected.splitlines(keepends=True)
63+
print("".join(difflib.unified_diff(actual, expected, fromfile="diagnostics.actual", tofile="diagnostics.expected")), file=sys.stderr)
64+
sys.exit(1)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"helpLinks": [
3+
"https://docs.github.com/en/enterprise-server/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/customizing-code-scanning"
4+
],
5+
"plaintextMessage": "The detected build command failed (tried /usr/bin/xcodebuild build -project <test-root-directory>/hello-failure.xcodeproj -target hello-failure CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO).\n\nSet up a manual build command.",
6+
"severity": "error",
7+
"source": {
8+
"extractorName": "swift",
9+
"id": "swift/autobuilder/build-command-failed",
10+
"name": "Detected build command failed"
11+
},
12+
"visibility": {
13+
"cliSummaryTable": true,
14+
"statusPage": true,
15+
"telemetry": true
16+
}
17+
}

0 commit comments

Comments
 (0)