mirror of
https://github.com/github/codeql.git
synced 2026-05-16 04:09:27 +02:00
Compare commits
42 Commits
codeql-cli
...
redsun82/j
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
513305b11d | ||
|
|
62c8112388 | ||
|
|
6b266badc6 | ||
|
|
0f28502e68 | ||
|
|
469d09c9af | ||
|
|
9d52a08793 | ||
|
|
db83285c9f | ||
|
|
15e8e4803d | ||
|
|
c67e1230b6 | ||
|
|
f1febac3ec | ||
|
|
4284d66afb | ||
|
|
0e3ee6efd7 | ||
|
|
365b2ebd6d | ||
|
|
f2a6503efe | ||
|
|
7e7afbabcd | ||
|
|
103745b5d2 | ||
|
|
92672836dc | ||
|
|
c51f2f8780 | ||
|
|
c9cda74195 | ||
|
|
bd003c58a8 | ||
|
|
08097157fd | ||
|
|
b8b01ce71c | ||
|
|
7f72f87204 | ||
|
|
aa09288462 | ||
|
|
8ba7efd455 | ||
|
|
bb467d4abf | ||
|
|
d987aa67ec | ||
|
|
e8bcbbd6df | ||
|
|
acc7e3f32d | ||
|
|
c4305151c3 | ||
|
|
fba96c4eae | ||
|
|
cb652f3dc8 | ||
|
|
6e14111337 | ||
|
|
d7d7cf920a | ||
|
|
a4acf0890e | ||
|
|
812fc2349b | ||
|
|
5b9436a95f | ||
|
|
4768ebabee | ||
|
|
9e31fb50c8 | ||
|
|
2dea9da38c | ||
|
|
1202af1c5c | ||
|
|
9c284b1778 |
8
cpp/justfile
Normal file
8
cpp/justfile
Normal file
@@ -0,0 +1,8 @@
|
||||
import '../lib.just'
|
||||
import? '../../cpp-coding-standards.just'
|
||||
|
||||
[group('build')]
|
||||
build: (_build_dist "cpp")
|
||||
|
||||
[group('test')]
|
||||
language-tests *EXTRA_ARGS: (_language_tests EXTRA_ARGS source_dir() 'ql/test' '../../semmlecode-cpp-tests')
|
||||
9
cpp/ql/consistency-queries/badLocations.ql
Normal file
9
cpp/ql/consistency-queries/badLocations.ql
Normal file
@@ -0,0 +1,9 @@
|
||||
import cpp
|
||||
|
||||
// Locations should either be :0:0:0:0 locations (UnknownLocation, or
|
||||
// a whole file), or all 4 fields should be positive.
|
||||
from Location l
|
||||
where
|
||||
[l.getStartLine(), l.getEndLine(), l.getStartColumn(), l.getEndColumn()] != 0 and
|
||||
[l.getStartLine(), l.getEndLine(), l.getStartColumn(), l.getEndColumn()] < 1
|
||||
select l
|
||||
5
cpp/ql/consistency-queries/nullInToString.ql
Normal file
5
cpp/ql/consistency-queries/nullInToString.ql
Normal file
@@ -0,0 +1,5 @@
|
||||
import cpp
|
||||
|
||||
from Element e
|
||||
where e.toString().matches("%(null)%")
|
||||
select e
|
||||
5
cpp/ql/consistency-queries/qlpack.yml
Normal file
5
cpp/ql/consistency-queries/qlpack.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
name: codeql/cpp-consistency-queries
|
||||
groups: [cpp, test, consistency-queries]
|
||||
dependencies:
|
||||
codeql/cpp-all: ${workspace}
|
||||
extractor: cpp
|
||||
10
cpp/ql/consistency-queries/unusedLocations.ql
Normal file
10
cpp/ql/consistency-queries/unusedLocations.ql
Normal file
@@ -0,0 +1,10 @@
|
||||
import cpp
|
||||
|
||||
from Location l
|
||||
where
|
||||
not any(Element e).getLocation() = l and
|
||||
not any(LambdaCapture lc).getLocation() = l and
|
||||
not any(MacroAccess ma).getActualLocation() = l and
|
||||
not any(NamespaceDeclarationEntry nde).getBodyLocation() = l and
|
||||
not any(XmlLocatable xml).getLocation() = l
|
||||
select l
|
||||
@@ -0,0 +1,5 @@
|
||||
import cpp
|
||||
|
||||
from VariableDeclarationEntry i
|
||||
where not exists(i.getType())
|
||||
select i
|
||||
5
cpp/ql/consistency-queries/variablesWithoutTypes.ql
Normal file
5
cpp/ql/consistency-queries/variablesWithoutTypes.ql
Normal file
@@ -0,0 +1,5 @@
|
||||
import cpp
|
||||
|
||||
from Variable i
|
||||
where not exists(i.getType())
|
||||
select i
|
||||
6
cpp/ql/justfile
Normal file
6
cpp/ql/justfile
Normal file
@@ -0,0 +1,6 @@
|
||||
import "../../lib.just"
|
||||
|
||||
[no-cd]
|
||||
format *ARGS=".": (_format_ql ARGS)
|
||||
|
||||
consistency_queries := source_dir() / "consistency-queries"
|
||||
11
cpp/ql/test/justfile
Normal file
11
cpp/ql/test/justfile
Normal file
@@ -0,0 +1,11 @@
|
||||
import "../justfile"
|
||||
|
||||
base_flags := "--include-location-in-star"
|
||||
|
||||
all_checks := default_db_checks + """\
|
||||
--check-undefined-labels \
|
||||
--check-unused-labels \
|
||||
--consistency-queries=""" + consistency_queries
|
||||
|
||||
[no-cd]
|
||||
test *ARGS=".": (_codeql_test "cpp" base_flags all_checks ARGS)
|
||||
3
java/justfile
Normal file
3
java/justfile
Normal file
@@ -0,0 +1,3 @@
|
||||
import '../lib.just'
|
||||
|
||||
build: (_build_dist "java")
|
||||
6
java/ql/justfile
Normal file
6
java/ql/justfile
Normal file
@@ -0,0 +1,6 @@
|
||||
import "../../lib.just"
|
||||
|
||||
[no-cd]
|
||||
format *ARGS=".": (_format_ql ARGS)
|
||||
|
||||
consistency_queries := source_dir() / "consistency-queries"
|
||||
16
java/ql/test/justfile
Normal file
16
java/ql/test/justfile
Normal file
@@ -0,0 +1,16 @@
|
||||
import "../justfile"
|
||||
|
||||
base_flags := """\
|
||||
CODEQL_EXTRACTOR_KOTLIN_DIAGNOSTIC_LIMIT="\\ " \
|
||||
"""
|
||||
|
||||
all_checks := default_db_checks + """\
|
||||
--check-undefined-labels \
|
||||
--check-repeated-labels \
|
||||
--check-redefined-labels \
|
||||
--check-use-before-definition \
|
||||
--consistency-queries=""" + consistency_queries
|
||||
|
||||
[no-cd]
|
||||
test *ARGS=".": (_codeql_test "java" base_flags all_checks ARGS)
|
||||
|
||||
4
justfile
Normal file
4
justfile
Normal file
@@ -0,0 +1,4 @@
|
||||
# see misc/just/README.md for an overview
|
||||
|
||||
import 'lib.just'
|
||||
import 'misc/just/forward.just'
|
||||
5
misc/bazel/justfile
Normal file
5
misc/bazel/justfile
Normal file
@@ -0,0 +1,5 @@
|
||||
import '../just/lib.just'
|
||||
|
||||
[no-cd, positional-arguments, no-exit-message]
|
||||
hello +ARGS:
|
||||
@echo "hello from bzl" "$@"
|
||||
5
misc/codegen/justfile
Normal file
5
misc/codegen/justfile
Normal file
@@ -0,0 +1,5 @@
|
||||
import "../just/lib.just"
|
||||
|
||||
test *ARGS="": (_bazel "test" "@codeql//misc/codegen/...")
|
||||
|
||||
format *ARGS=".": (_format_py ARGS)
|
||||
44
misc/just/README.md
Normal file
44
misc/just/README.md
Normal file
@@ -0,0 +1,44 @@
|
||||
This directory contains an infrastructure for [`just`](https://github.com/casey/just)
|
||||
recipes that can be used throughout this and the internal repository. In particular we
|
||||
have common verbs (`build`, `test`, `format`, `lint`, `generate`) that individual parts
|
||||
of the project can implement, and some common functionality that can be used to that
|
||||
effect.
|
||||
|
||||
# Forwarding
|
||||
|
||||
The core of the functionality is given by forwarding. The idea is that:
|
||||
|
||||
- if you are in the directory where a verb is implemented, you will get that as per
|
||||
standard `just` behaviour (possibly using fallback).
|
||||
- if on the other hand you are beneath it, and you run something like
|
||||
`just test ql/rust/ql/test/{a,b}`, then a forwarder script finds a common justfile
|
||||
implementing the verb for all the positional arguments passed there, and then retries
|
||||
calling `just test` from there. So if `test` is implemented beneath that (in that case,
|
||||
it is in `rust/ql/test`), it uses that recipe.
|
||||
- even if there isn't a recipe that is common to all the positional arguments, the
|
||||
forwarder will still group the arguments in batches using the same recipe. So
|
||||
`just build ql/rust ql/java`, or
|
||||
`just test ql/rust/ql/test/some/language/test ql/rust/ql/integration-test/some/integration/test`
|
||||
will also work, with corresponding recipes run sequentially.
|
||||
|
||||
Another point is how launching QL tests can be tweaked:
|
||||
|
||||
- by default, the corresponding CLI is built from the internal repo (nothing is done if
|
||||
working in `codeql` standalone), and no additional database or consistency checks are
|
||||
made
|
||||
- `--codeql=built` can be passed to skip the build step (if no changes were made to the
|
||||
CLI/extractors). This is consistent with the same pytest option
|
||||
- you can add the additional checks that CI does with `--all-checks` or the `+`
|
||||
abbreviation. These additional checks are configured in justfiles per language, and
|
||||
correspond to all the additional checks that CI adds (but that a dev might not want to
|
||||
run by default).
|
||||
|
||||
Some caveats:
|
||||
|
||||
- passing arguments with spaces generally doesn't work, although setting arguments with
|
||||
spaces in `justfile`s (for the base arguments) is supported using escaping as in `\\`.
|
||||
This is a known limitation of just (see
|
||||
<https://github.com/casey/just/issues/1988>)
|
||||
- when running different recipes for the same verb, non-positional arguments need to be
|
||||
supported by all recipes involved. For example, this will work ok for `--learn` or
|
||||
`--codeql` options in language and integration tests
|
||||
19
misc/just/build.just
Normal file
19
misc/just/build.just
Normal file
@@ -0,0 +1,19 @@
|
||||
# Helper build recipes
|
||||
|
||||
import "defs.just"
|
||||
|
||||
# Build the given language-specific CLI distribution
|
||||
_build_dist LANGUAGE: _require_semmle_code (_maybe_build_dist LANGUAGE)
|
||||
|
||||
# Build the language-specific distribution if we are in an internal repository checkout
|
||||
# Otherwise, do nothing
|
||||
[no-exit-message]
|
||||
_maybe_build_dist LANGUAGE: (_if_in_semmle_code ('cd "$SEMMLE_CODE"; tools/bazel run //language-packs:intree-' + LANGUAGE) '# using codeql from PATH, if any')
|
||||
|
||||
# Call bazel. Uses our official bazel wrapper if we are in an internal repository checkout
|
||||
[no-cd, no-exit-message]
|
||||
_bazel COMMAND *ARGS: (_if_in_semmle_code 'cd "$SEMMLE_CODE"; tools/bazel' 'bazel' COMMAND ARGS)
|
||||
|
||||
# Call sembuild (requires an internal repository checkout)
|
||||
[no-cd, no-exit-message]
|
||||
_sembuild *ARGS: (_run_in_semmle_code "./build" ARGS)
|
||||
159
misc/just/codeql-test-run.ts
Normal file
159
misc/just/codeql-test-run.ts
Normal file
@@ -0,0 +1,159 @@
|
||||
import * as child_process from "child_process";
|
||||
import * as path from "path";
|
||||
import * as os from "os";
|
||||
import * as fs from "fs";
|
||||
|
||||
const vars = {
|
||||
just: process.env["JUST_EXECUTABLE"] || "just",
|
||||
error: process.env["JUST_ERROR"] || "error",
|
||||
cmd_begin: process.env["CMD_BEGIN"] || "",
|
||||
cmd_end: process.env["CMD_END"] || "",
|
||||
semmle_code: process.env["SEMMLE_CODE"],
|
||||
};
|
||||
|
||||
function invoke(
|
||||
invocation: string[],
|
||||
options: { cwd?: string; log_prefix?: string } = {},
|
||||
): number {
|
||||
const log_prefix =
|
||||
options.log_prefix && options.log_prefix !== ""
|
||||
? `${options.log_prefix} `
|
||||
: "";
|
||||
console.log(
|
||||
`${vars.cmd_begin}${log_prefix}${invocation.join(" ")}${vars.cmd_end}`,
|
||||
);
|
||||
try {
|
||||
child_process.execFileSync(invocation[0], invocation.slice(1), {
|
||||
stdio: "inherit",
|
||||
cwd: options.cwd,
|
||||
});
|
||||
} catch (error) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
type Args = {
|
||||
tests: string[];
|
||||
flags: string[];
|
||||
env: string[];
|
||||
codeql: string;
|
||||
all: boolean;
|
||||
};
|
||||
|
||||
const old_console_error = console.error;
|
||||
|
||||
console.error = (message: string) => {
|
||||
old_console_error(vars.error + message);
|
||||
};
|
||||
|
||||
function parseArgs(args: Args, argv: string) {
|
||||
argv.split(/(?<!\\) /)
|
||||
.map((arg) => arg.replace("\\ ", " "))
|
||||
.forEach((arg) => {
|
||||
if (arg.startsWith("--codeql=")) {
|
||||
args.codeql = arg.split("=")[1];
|
||||
} else if (arg === "+" || arg === "--all-checks") {
|
||||
args.all = true;
|
||||
} else if (arg.startsWith("-")) {
|
||||
args.flags.push(arg);
|
||||
} else if (/^[A-Z_][A-Z_0-9]*=.*$/.test(arg)) {
|
||||
args.env.push(arg);
|
||||
} else if (arg !== "") {
|
||||
args.tests.push(arg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function codeqlTestRun(argv: string[]): number {
|
||||
const [language, base_args, all_args, extra_args] = argv;
|
||||
const ram_per_thread = process.platform === "linux" ? 3000 : 2048;
|
||||
const cpus = os.cpus().length;
|
||||
let args: Args = {
|
||||
tests: [],
|
||||
flags: [`--ram=${ram_per_thread * cpus}`, `-j${cpus}`],
|
||||
env: [],
|
||||
codeql: vars.semmle_code ? "build" : "host",
|
||||
all: false,
|
||||
};
|
||||
parseArgs(args, base_args);
|
||||
parseArgs(args, extra_args);
|
||||
if (args.all) {
|
||||
parseArgs(args, all_args);
|
||||
}
|
||||
if (
|
||||
!vars.semmle_code &&
|
||||
(args.codeql === "build" || args.codeql === "built")
|
||||
) {
|
||||
console.error(
|
||||
"Using `--codeql=build` or `--codeql=built` requires working with the internal repository",
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
if (args.tests.length === 0) {
|
||||
args.tests.push(".");
|
||||
}
|
||||
if (args.codeql === "build") {
|
||||
if (
|
||||
invoke([vars.just, language, "build"], {
|
||||
cwd: vars.semmle_code,
|
||||
}) !== 0
|
||||
) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (args.codeql !== "host") {
|
||||
// disable the default implicit config file, but keep an explicit one
|
||||
// this is the same behavior wrt to `--codeql` as the integration test runner
|
||||
process.env["CODEQL_CONFIG_FILE"] ||= ".";
|
||||
}
|
||||
// Set and unset environment variables
|
||||
args.env.forEach((envVar) => {
|
||||
const [key, value] = envVar.split("=", 2);
|
||||
if (key) {
|
||||
if (value === undefined) {
|
||||
delete process.env[key];
|
||||
} else {
|
||||
process.env[key] = value;
|
||||
}
|
||||
} else {
|
||||
console.error(`Invalid environment variable assignment: ${envVar}`);
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
let codeql;
|
||||
function check_codeql() {
|
||||
if (!fs.existsSync(codeql)) {
|
||||
console.error(`CodeQL executable not found: ${codeql}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
if (args.codeql === "built" || args.codeql === "build") {
|
||||
codeql = path.join(
|
||||
vars.semmle_code!,
|
||||
"target",
|
||||
"intree",
|
||||
`codeql-${language}`,
|
||||
"codeql",
|
||||
);
|
||||
check_codeql();
|
||||
} else if (args.codeql === "host") {
|
||||
codeql = "codeql";
|
||||
} else {
|
||||
codeql = args.codeql;
|
||||
check_codeql();
|
||||
}
|
||||
if (fs.lstatSync(codeql).isDirectory()) {
|
||||
codeql = path.join(codeql, "codeql");
|
||||
if (process.platform === "win32") {
|
||||
codeql += ".exe";
|
||||
}
|
||||
check_codeql();
|
||||
}
|
||||
|
||||
return invoke([codeql, "test", "run", ...args.flags, "--", ...args.tests], {
|
||||
log_prefix: args.env.join(" "),
|
||||
});
|
||||
}
|
||||
|
||||
process.exit(codeqlTestRun(process.argv.slice(2)));
|
||||
58
misc/just/defs.just
Normal file
58
misc/just/defs.just
Normal file
@@ -0,0 +1,58 @@
|
||||
import? '../../../semmle-code.just' # internal repo just file, if present
|
||||
import 'semmle-code-stub.just'
|
||||
|
||||
set fallback
|
||||
set allow-duplicate-recipes
|
||||
set allow-duplicate-variables
|
||||
set unstable
|
||||
|
||||
export PATH_SEP := if os() == "windows" { ";" } else { ":" }
|
||||
export JUST_EXECUTABLE := just_executable()
|
||||
|
||||
error := style("error") + "error" + NORMAL + ": "
|
||||
cmd_sep := "\n#--------------------------------------------------------\n"
|
||||
export CMD_BEGIN := style("command") + cmd_sep
|
||||
export CMD_END := cmd_sep + NORMAL
|
||||
export JUST_ERROR := error
|
||||
|
||||
tsx := "npx tsx@4.19.0"
|
||||
|
||||
default_db_checks := """\
|
||||
--check-databases \
|
||||
--check-diff-informed \
|
||||
--fail-on-trap-errors \
|
||||
"""
|
||||
|
||||
[no-exit-message]
|
||||
@_require_semmle_code:
|
||||
{{ if SEMMLE_CODE == "" { '''
|
||||
echo "''' + error + ''' running this recipe requires doing so from an internal repository checkout" >&2
|
||||
exit 1
|
||||
''' } else { "" } }}
|
||||
|
||||
[no-cd]
|
||||
_run +ARGS:
|
||||
{{ cmd_sep }}{{ ARGS }}{{ cmd_sep }}
|
||||
|
||||
[no-cd]
|
||||
_run_in DIR +ARGS:
|
||||
{{ cmd_sep }}cd "{{ DIR }}"; {{ ARGS }}{{ cmd_sep }}
|
||||
|
||||
[no-cd]
|
||||
_run_in_semmle_code +ARGS: _require_semmle_code (_run_in "$SEMMLE_CODE" ARGS)
|
||||
|
||||
[no-cd, positional-arguments, no-exit-message]
|
||||
@_just +ARGS:
|
||||
echo "-> just $@"
|
||||
"{{ JUST_EXECUTABLE }}" "$@"
|
||||
|
||||
[no-cd, positional-arguments]
|
||||
@_if_not_on_ci_just +ARGS:
|
||||
if [ "${GITHUB_ACTIONS:-}" != "true" ]; then \
|
||||
echo "-> just $@"; \
|
||||
"$JUST_EXECUTABLE" "$@"; \
|
||||
fi
|
||||
|
||||
[no-cd, no-exit-message]
|
||||
_if_in_semmle_code THEN ELSE *ARGS:
|
||||
{{ cmd_sep }}{{ if SEMMLE_CODE != "" { THEN } else { ELSE } }} {{ ARGS }}{{ cmd_sep }}
|
||||
20
misc/just/format.just
Normal file
20
misc/just/format.just
Normal file
@@ -0,0 +1,20 @@
|
||||
import "build.just"
|
||||
|
||||
[no-cd, no-exit-message]
|
||||
_format_ql +ARGS: (_maybe_build_dist "nolang") (
|
||||
_if_in_semmle_code
|
||||
'"$SEMMLE_CODE/target/intree/codeql-nolang/codeql"'
|
||||
'codeql'
|
||||
("query format --in-place -v $(find " + ARGS + " -type f -name '*.ql' -or -name '*.qll')")
|
||||
)
|
||||
|
||||
[no-cd, no-exit-message]
|
||||
_format_py *ARGS=".": (_if_in_semmle_code "uv run black" "black" ARGS)
|
||||
|
||||
[no-cd, no-exit-message]
|
||||
_format_cpp *ARGS=".": (
|
||||
_if_in_semmle_code
|
||||
"uv run clang-format"
|
||||
"clang-format"
|
||||
"-i --verbose $(find " + ARGS + " -type f -name '*.h' -or -name '*.cpp')"
|
||||
)
|
||||
131
misc/just/forward-command.ts
Normal file
131
misc/just/forward-command.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
import * as child_process from "child_process";
|
||||
import * as path from "path";
|
||||
import * as fs from "fs";
|
||||
|
||||
const vars = {
|
||||
just: process.env["JUST_EXECUTABLE"] || "just",
|
||||
error: process.env["JUST_ERROR"] || "",
|
||||
};
|
||||
|
||||
console.debug = (...args: any[]) => {}; // comment out to debug script
|
||||
const old_console_error = console.error;
|
||||
console.error = (message: string) => {
|
||||
old_console_error(vars.error + message);
|
||||
};
|
||||
|
||||
function checkJustCommand(
|
||||
justfile: string,
|
||||
command: string,
|
||||
postitionalArgs: string[],
|
||||
): boolean {
|
||||
if (!fs.existsSync(justfile)) {
|
||||
return false;
|
||||
}
|
||||
let { cwd, args } = getJustContext(justfile, command, [], postitionalArgs);
|
||||
console.debug(
|
||||
`Checking: ${cwd ? `cd ${cwd}; ` : ""}just ${args.join(", ")}`,
|
||||
);
|
||||
const res = child_process.spawnSync(vars.just, ["--dry-run", ...args], {
|
||||
stdio: ["ignore", "ignore", "pipe"],
|
||||
encoding: "utf8",
|
||||
cwd,
|
||||
});
|
||||
console.debug("result:", res);
|
||||
// avoid having the forwarder find itself
|
||||
return (
|
||||
res.status === 0 &&
|
||||
!res.stderr.includes(`forward-command.ts" ${command} "$@"`)
|
||||
);
|
||||
}
|
||||
|
||||
function findJustfile(command: string, arg: string): string | undefined {
|
||||
for (let p = arg; ; p = path.dirname(p)) {
|
||||
const candidate = path.join(p, "justfile");
|
||||
if (checkJustCommand(candidate, command, [arg])) {
|
||||
return candidate;
|
||||
}
|
||||
if (p === "/" || p === ".") {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function forwardCommand(args: string[]): number {
|
||||
if (args.length == 0) {
|
||||
console.error("No command provided");
|
||||
return 1;
|
||||
}
|
||||
return forward(args[0], args.slice(1));
|
||||
}
|
||||
|
||||
function forward(cmd: string, args: string[]): number {
|
||||
// non-positional arguments are flags, + (used by language tests) or environment variable settings
|
||||
const is_non_positional = /^(-.*|\+|[A-Z_][A-Z_0-9]*=.*)$/;
|
||||
const flags = args.filter((arg) => is_non_positional.test(arg));
|
||||
const positionalArgs = args.filter((arg) => !is_non_positional.test(arg));
|
||||
let justfiles: Map<string, string[]> = new Map();
|
||||
for (const arg of positionalArgs.length > 0 ? positionalArgs : ["."]) {
|
||||
const justfile = findJustfile(cmd, arg);
|
||||
if (!justfile) {
|
||||
console.error(`No justfile found for ${cmd} on ${arg}`);
|
||||
return 1;
|
||||
}
|
||||
justfiles.set(justfile, [...(justfiles.get(justfile) || []), arg]);
|
||||
}
|
||||
const invocations = Array.from(justfiles.entries()).map(
|
||||
([justfile, positionalArgs]) => {
|
||||
const { cwd, args } = getJustContext(
|
||||
justfile,
|
||||
cmd,
|
||||
flags,
|
||||
positionalArgs,
|
||||
);
|
||||
console.log(`-> ${cwd ? `cd ${cwd}; ` : ""}just ${args.join(" ")}`);
|
||||
return { cwd, args };
|
||||
},
|
||||
);
|
||||
for (const { cwd, args } of invocations) {
|
||||
if (invokeJust(cwd, args) !== 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function getJustContext(
|
||||
justfile: string,
|
||||
cmd: string,
|
||||
flags: string[],
|
||||
positionalArgs: string[],
|
||||
): { args: string[]; cwd?: string } {
|
||||
if (
|
||||
positionalArgs.length === 1 &&
|
||||
justfile == path.join(positionalArgs[0], "justfile")
|
||||
) {
|
||||
// If there's only one positional argument and it matches the justfile path, suppress arguments
|
||||
// so for example `just build ql/rust` becomes `just build` in the `ql/rust` directory
|
||||
return {
|
||||
cwd: positionalArgs[0],
|
||||
args: [cmd, ...flags],
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
cwd: undefined,
|
||||
args: ["--justfile", justfile, cmd, ...flags, ...positionalArgs],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function invokeJust(cwd: string | undefined, args: string[]): number {
|
||||
try {
|
||||
child_process.execFileSync(vars.just, args, {
|
||||
stdio: "inherit",
|
||||
cwd,
|
||||
});
|
||||
} catch (error) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
process.exit(forwardCommand(process.argv.slice(2)));
|
||||
38
misc/just/forward.just
Normal file
38
misc/just/forward.just
Normal file
@@ -0,0 +1,38 @@
|
||||
# Common verbs
|
||||
# See README.md in this directory for an overview.
|
||||
|
||||
import "lib.just"
|
||||
|
||||
|
||||
# copy&paste necessary for each command until proper forwarding of multiple args is implemented
|
||||
# see https://github.com/casey/just/issues/1988
|
||||
|
||||
_forward := tsx + ' "' + source_dir() + '/forward-command.ts"'
|
||||
|
||||
alias t := test
|
||||
alias b := build
|
||||
alias g := generate
|
||||
alias gen := generate
|
||||
alias f := format
|
||||
alias l := lint
|
||||
|
||||
[no-cd, positional-arguments, no-exit-message]
|
||||
@test *ARGS:
|
||||
{{ _forward }} test "$@"
|
||||
|
||||
|
||||
[no-cd, positional-arguments, no-exit-message]
|
||||
@build *ARGS:
|
||||
{{ _forward }} build "$@"
|
||||
|
||||
[no-cd, positional-arguments, no-exit-message]
|
||||
@generate *ARGS:
|
||||
{{ _forward }} generate "$@"
|
||||
|
||||
[no-cd, positional-arguments, no-exit-message]
|
||||
@lint *ARGS:
|
||||
{{ _forward }} lint "$@"
|
||||
|
||||
[no-cd, positional-arguments, no-exit-message]
|
||||
@format *ARGS:
|
||||
{{ _forward }} format "$@"
|
||||
2
misc/just/justfile
Normal file
2
misc/just/justfile
Normal file
@@ -0,0 +1,2 @@
|
||||
format *ARGS=".":
|
||||
npx prettier --write {{ ARGS }}
|
||||
33
misc/just/language-tests.ts
Normal file
33
misc/just/language-tests.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import * as path from "path";
|
||||
import * as process from "process";
|
||||
import * as child_process from "child_process";
|
||||
|
||||
function languageTests(argv: string[]): number {
|
||||
const [extra_args, dir, ...relativeRoots] = argv;
|
||||
const semmle_code = process.env["SEMMLE_CODE"]!;
|
||||
let roots = relativeRoots.map((root) =>
|
||||
path.relative(semmle_code, path.join(dir, root)),
|
||||
);
|
||||
const invocation = [
|
||||
process.env["JUST_EXECUTABLE"] || "just",
|
||||
"--justfile",
|
||||
path.join(roots[0], "justfile"),
|
||||
"test",
|
||||
"--all-checks",
|
||||
"--codeql=built",
|
||||
...extra_args.split(" "),
|
||||
...roots,
|
||||
];
|
||||
console.log(`-> just ${invocation.slice(1).join(" ")}`);
|
||||
try {
|
||||
child_process.execFileSync(invocation[0], invocation.slice(1), {
|
||||
stdio: "inherit",
|
||||
cwd: semmle_code,
|
||||
});
|
||||
} catch (error) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
process.exit(languageTests(process.argv.slice(2)));
|
||||
47
misc/just/lib.just
Normal file
47
misc/just/lib.just
Normal file
@@ -0,0 +1,47 @@
|
||||
# Helper recipes
|
||||
|
||||
import "build.just"
|
||||
import "format.just"
|
||||
|
||||
# Run language tests. `BASE_FLAGS` are used by default, `ALL_CHECK_FLAGS` are used if
|
||||
# `--all-checks` or `+` is passed along in `EXTRA_ARGS`
|
||||
[no-cd, positional-arguments, no-exit-message]
|
||||
@_codeql_test LANGUAGE BASE_FLAGS ALL_CHECKS_FLAGS EXTRA_ARGS:
|
||||
{{ tsx }} "{{ source_dir() }}/codeql-test-run.ts" "$@"
|
||||
|
||||
# Run all language tests in ROOTS for a language. This is intended to be called by CI
|
||||
[no-cd, positional-arguments, no-exit-message]
|
||||
@_language_tests EXTRA_ARGS SOURCE_DIR +ROOTS: _require_semmle_code
|
||||
{{ tsx }} "{{ source_dir() }}/language-tests.ts" "$@"
|
||||
|
||||
# Run integration tests. Requires an internal repository checkout
|
||||
[no-cd, no-exit-message]
|
||||
_integration_test *ARGS: _require_semmle_code (_run "$SEMMLE_CODE/tools/pytest" ARGS)
|
||||
|
||||
# Generic run command recipe that can be used by other recipes, with nice rendering
|
||||
[no-cd]
|
||||
_run +ARGS:
|
||||
{{ cmd_sep }}{{ ARGS }}{{ cmd_sep }}
|
||||
|
||||
# Run a command in a specific directory
|
||||
[no-cd]
|
||||
_run_in DIR +ARGS:
|
||||
{{ cmd_sep }}cd "{{ DIR }}"; {{ ARGS }}{{ cmd_sep }}
|
||||
|
||||
# Run a command in the internal repository checkout
|
||||
[no-cd]
|
||||
_run_in_semmle_code +ARGS: _require_semmle_code (_run_in "$SEMMLE_CODE" ARGS)
|
||||
|
||||
# Run a just recipe
|
||||
[no-cd, positional-arguments, no-exit-message]
|
||||
@_just +ARGS:
|
||||
echo "-> just $@"
|
||||
"{{ JUST_EXECUTABLE }}" "$@"
|
||||
|
||||
# Run a just recipe, but only if we are not on CI
|
||||
[no-cd, positional-arguments]
|
||||
@_if_not_on_ci_just +ARGS:
|
||||
if [ "${GITHUB_ACTIONS:-}" != "true" ]; then \
|
||||
echo "-> just $@"; \
|
||||
"$JUST_EXECUTABLE" "$@"; \
|
||||
fi
|
||||
1
misc/just/semmle-code-stub.just
Normal file
1
misc/just/semmle-code-stub.just
Normal file
@@ -0,0 +1 @@
|
||||
export SEMMLE_CODE := ""
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
set -eu
|
||||
|
||||
source misc/bazel/runfiles.sh 2>/dev/null || source external/ql+/misc/bazel/runfiles.sh
|
||||
source misc/bazel/runfiles.sh 2>/dev/null || source ../ql+/misc/bazel/runfiles.sh
|
||||
|
||||
ast_generator="$(rlocation "$1")"
|
||||
grammar_file="$(rlocation "$2")"
|
||||
|
||||
14
rust/justfile
Normal file
14
rust/justfile
Normal file
@@ -0,0 +1,14 @@
|
||||
import '../lib.just'
|
||||
|
||||
install: (_bazel "run" "@codeql//rust:install")
|
||||
|
||||
build: (_if_not_on_ci_just "generate" source_dir()) (_build_dist "rust")
|
||||
|
||||
generate: (_bazel "run" "@codeql//rust/codegen")
|
||||
|
||||
lint: (_run_in source_dir() "python3" "lint.py")
|
||||
|
||||
format: (_run_in source_dir() "python3" "lint.py" "--format-only")
|
||||
|
||||
[group('test')]
|
||||
language-tests *EXTRA_ARGS: (_language_tests EXTRA_ARGS source_dir() 'ql/test')
|
||||
52
rust/lint.py
52
rust/lint.py
@@ -4,6 +4,14 @@ import subprocess
|
||||
import pathlib
|
||||
import shutil
|
||||
import sys
|
||||
import argparse
|
||||
|
||||
|
||||
def options():
|
||||
parser = argparse.ArgumentParser(description="lint rust language pack code")
|
||||
parser.add_argument("--format-only", action="store_true", help="Only apply formatting")
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
|
||||
def tool(name):
|
||||
@@ -12,27 +20,35 @@ def tool(name):
|
||||
return ret
|
||||
|
||||
|
||||
this_dir = pathlib.Path(__file__).resolve().parent
|
||||
|
||||
cargo = tool("cargo")
|
||||
bazel = tool("bazel")
|
||||
|
||||
runs = []
|
||||
def main():
|
||||
args = options()
|
||||
this_dir = pathlib.Path(__file__).resolve().parent
|
||||
|
||||
|
||||
def run(tool, args, *, cwd=this_dir):
|
||||
print("+", tool, args)
|
||||
runs.append(subprocess.run([tool] + args.split(), cwd=cwd))
|
||||
cargo = tool("cargo")
|
||||
bazel = tool("bazel")
|
||||
|
||||
runs = []
|
||||
|
||||
|
||||
# make sure bazel-provided sources are put in tree for `cargo` to work with them
|
||||
run(bazel, "run ast-generator:inject-sources")
|
||||
run(cargo, "fmt --all --quiet")
|
||||
def run(tool, args, *, cwd=this_dir):
|
||||
print("+", tool, args)
|
||||
runs.append(subprocess.run([tool] + args.split(), cwd=cwd))
|
||||
|
||||
for manifest in this_dir.rglob("Cargo.toml"):
|
||||
if not manifest.is_relative_to(this_dir / "ql") and not manifest.is_relative_to(this_dir / "integration-tests"):
|
||||
run(cargo,
|
||||
"clippy --fix --allow-dirty --allow-staged --quiet -- -D warnings",
|
||||
cwd=manifest.parent)
|
||||
|
||||
sys.exit(max(r.returncode for r in runs))
|
||||
# make sure bazel-provided sources are put in tree for `cargo` to work with them
|
||||
run(bazel, "run ast-generator:inject-sources")
|
||||
run(cargo, "fmt --all --quiet")
|
||||
|
||||
if not args.format_only:
|
||||
for manifest in this_dir.rglob("Cargo.toml"):
|
||||
if not manifest.is_relative_to(this_dir / "ql") and not manifest.is_relative_to(this_dir / "integration-tests"):
|
||||
run(cargo,
|
||||
"clippy --fix --allow-dirty --allow-staged --quiet -- -D warnings",
|
||||
cwd=manifest.parent)
|
||||
|
||||
return max(r.returncode for r in runs)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
|
||||
10
rust/ql/integration-tests/justfile
Normal file
10
rust/ql/integration-tests/justfile
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
import "../../../lib.just"
|
||||
|
||||
|
||||
[no-cd]
|
||||
test *ARGS=".": (_if_not_on_ci_just "generate" source_dir()) (_integration_test ARGS)
|
||||
|
||||
# TODO in separate PR
|
||||
# [no-cd]
|
||||
# format *ARGS=".": (_format_ql ARGS) (_format_py ARGS)
|
||||
6
rust/ql/justfile
Normal file
6
rust/ql/justfile
Normal file
@@ -0,0 +1,6 @@
|
||||
import "../../lib.just"
|
||||
|
||||
[no-cd]
|
||||
format *ARGS=".": (_format_ql ARGS)
|
||||
|
||||
consistency_queries := source_dir() / "consistency-queries"
|
||||
7
rust/ql/test/justfile
Normal file
7
rust/ql/test/justfile
Normal file
@@ -0,0 +1,7 @@
|
||||
import "../justfile"
|
||||
|
||||
all_checks := default_db_checks + """\
|
||||
--consistency-queries=""" + consistency_queries
|
||||
|
||||
[no-cd]
|
||||
test *ARGS=".": (_codeql_test "rust" "" all_checks ARGS)
|
||||
17
swift/justfile
Normal file
17
swift/justfile
Normal file
@@ -0,0 +1,17 @@
|
||||
import '../lib.just'
|
||||
import "../../ql/swift/ql/justfile"
|
||||
|
||||
install: (_bazel "run" "@codeql//swift:install")
|
||||
|
||||
[group('build')]
|
||||
build: (_build_dist "swift")
|
||||
|
||||
generate: (_bazel "run" "@codeql//swift/codegen")
|
||||
|
||||
format ARGS=".": (_format_cpp ARGS)
|
||||
|
||||
[group('test')]
|
||||
language-tests *EXTRA_ARGS: (_language_tests EXTRA_ARGS source_dir() 'ql/test')
|
||||
|
||||
[group('test')]
|
||||
extra-tests: (_sembuild "target/test/check-queries-swift") (_sembuild "target/test/check-db-upgrades-swift") (_sembuild "target/test/check-db-downgrades-swift")
|
||||
9
swift/ql/integration-tests/justfile
Normal file
9
swift/ql/integration-tests/justfile
Normal file
@@ -0,0 +1,9 @@
|
||||
import "../../../lib.just"
|
||||
|
||||
|
||||
[no-cd]
|
||||
test *ARGS=".": (_just "generate") (_integration_test ARGS)
|
||||
|
||||
# TODO in separate PR
|
||||
# [no-cd]
|
||||
# format *ARGS=".": (_format_ql ARGS) (_format_py ARGS)
|
||||
6
swift/ql/justfile
Normal file
6
swift/ql/justfile
Normal file
@@ -0,0 +1,6 @@
|
||||
import "../../lib.just"
|
||||
|
||||
[no-cd]
|
||||
format *ARGS=".": (_format_ql ARGS)
|
||||
|
||||
consistency_queries := source_dir() / "consistency-queries"
|
||||
11
swift/ql/test/justfile
Normal file
11
swift/ql/test/justfile
Normal file
@@ -0,0 +1,11 @@
|
||||
import "../justfile"
|
||||
|
||||
all_checks := default_db_checks + """\
|
||||
--check-repeated-labels \
|
||||
--check-redefined-labels \
|
||||
--check-use-before-definition \
|
||||
--consistency-queries=""" + consistency_queries
|
||||
|
||||
|
||||
[no-cd]
|
||||
test *ARGS=".": (_codeql_test "swift" "" all_checks ARGS)
|
||||
Reference in New Issue
Block a user