Compare commits

...

42 Commits

Author SHA1 Message Date
Paolo Tranquilli
513305b11d C++: Add conditional import for coding-standards recipe
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-02 12:39:37 +02:00
Paolo Tranquilli
62c8112388 C++: Port to new just-based language test definition
Add justfiles for C++ following the pattern of other ported languages
(go, rust, swift). Move consistency queries from semmle-code's
semmlecode-cpp-consistency-queries/ to ql/cpp/ql/consistency-queries/.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-02 12:24:24 +02:00
Paolo Tranquilli
6b266badc6 Merge remote-tracking branch 'origin/main' into redsun82/just2-cpp 2026-04-02 12:23:22 +02:00
Paolo Tranquilli
0f28502e68 Merge branch 'main' into redsun82/just2 2025-11-14 12:28:00 +01:00
Paolo Tranquilli
469d09c9af Merge branch 'main' into redsun82/just2 2025-08-14 15:05:44 +02:00
Paolo Tranquilli
9d52a08793 Just: add some docs in source 2025-08-12 10:00:17 +02:00
Paolo Tranquilli
db83285c9f Merge branch 'main' into redsun82/just2 2025-08-12 09:59:46 +02:00
Paolo Tranquilli
15e8e4803d Just: run prettier on .ts files 2025-08-12 09:46:27 +02:00
Paolo Tranquilli
c67e1230b6 Just: add README.md 2025-08-12 09:46:00 +02:00
Paolo Tranquilli
f1febac3ec Merge branch 'main' into redsun82/just2 2025-08-11 14:06:16 +02:00
Paolo Tranquilli
4284d66afb Merge branch 'main' into redsun82/just2 2025-07-18 15:27:26 +02:00
Paolo Tranquilli
0e3ee6efd7 Just: reorganize code and revamp formatting 2025-07-18 15:27:12 +02:00
Paolo Tranquilli
365b2ebd6d Merge branch 'main' into redsun82/just2 2025-07-18 14:26:56 +02:00
Paolo Tranquilli
f2a6503efe Just: use bazel directly for dist building 2025-07-18 14:26:48 +02:00
Paolo Tranquilli
7e7afbabcd Merge branch 'main' into redsun82/just2 2025-07-17 16:57:44 +02:00
Paolo Tranquilli
103745b5d2 Just: group just invocations in forwarder and improve logging 2025-07-10 10:34:35 +02:00
Paolo Tranquilli
92672836dc Merge branch 'main' into redsun82/just2 2025-07-10 10:17:03 +02:00
Paolo Tranquilli
c51f2f8780 Merge branch 'main' into redsun82/just2 2025-07-09 14:50:41 +02:00
Paolo Tranquilli
c9cda74195 Just: allow mixing different verb implementations
This allows to mix different verb implementations in a single
invocation, for example:
```
just build ql/rust ql/java
just test ql/rust/ql/test/some/test ql/rust/ql/integrartion-test/some other
```
If a common justfile recipe is found, it is used for all arguments in
one go. If on the other hand no common justfile recipe is found, each
argument is processed separately in sequence.

This does require that any flags passed are compatible with all recipes
involved (like is the case for `--learn` or `--codeql=built` for
language and integration tests).
2025-07-09 14:47:38 +02:00
Paolo Tranquilli
bd003c58a8 Just: add _if_not_on_ci_just helper, and add generation prerequisites 2025-07-08 17:22:27 +02:00
Paolo Tranquilli
08097157fd Merge branch 'main' into redsun82/just2 2025-07-08 16:01:41 +02:00
Paolo Tranquilli
b8b01ce71c Just: rename _build to _build_dist 2025-07-08 15:53:51 +02:00
Paolo Tranquilli
7f72f87204 Just: fix just rust format and similar 2025-07-08 15:50:37 +02:00
Paolo Tranquilli
aa09288462 Just: introduce aliases 2025-07-08 15:49:23 +02:00
Paolo Tranquilli
8ba7efd455 Just: fix mono-argument case for argumentless recipes 2025-07-08 15:41:18 +02:00
Paolo Tranquilli
bb467d4abf Just: fix CI build for rust 2025-07-08 15:40:35 +02:00
Paolo Tranquilli
d987aa67ec Merge branch 'main' into redsun82/just2 2025-07-08 14:06:30 +02:00
Paolo Tranquilli
e8bcbbd6df Just: add language-tests.ts helper 2025-07-08 14:06:14 +02:00
Paolo Tranquilli
acc7e3f32d Just: add generate prerequisite to rust ql tests 2025-07-08 10:52:37 +02:00
Paolo Tranquilli
c4305151c3 Just: simplify forwarder using --justfile 2025-07-08 10:52:15 +02:00
Paolo Tranquilli
fba96c4eae Just: add root lib.just 2025-07-07 17:39:59 +02:00
Paolo Tranquilli
cb652f3dc8 Just: add format to just directory 2025-07-07 17:37:19 +02:00
Paolo Tranquilli
6e14111337 Just: use --all-checks and --codeql special flags, and relativize flags in forwarder 2025-07-07 17:35:06 +02:00
Paolo Tranquilli
d7d7cf920a Just: format ts files 2025-07-07 15:52:53 +02:00
Paolo Tranquilli
a4acf0890e Just: fix ram option for codeql test run 2025-07-07 15:52:20 +02:00
Paolo Tranquilli
812fc2349b Merge branch 'main' into redsun82/just2 2025-07-07 15:50:09 +02:00
Paolo Tranquilli
5b9436a95f Just: fix swift tests 2025-07-04 17:27:43 +02:00
Paolo Tranquilli
4768ebabee Merge branch 'main' into redsun82/just2 2025-07-04 17:22:17 +02:00
Paolo Tranquilli
9e31fb50c8 Just: fix and add windows 2025-07-04 16:07:31 +02:00
Paolo Tranquilli
2dea9da38c Just: add codegen 2025-07-04 13:45:45 +02:00
Paolo Tranquilli
1202af1c5c Just: fix for windows 2025-07-04 13:45:10 +02:00
Paolo Tranquilli
9c284b1778 Just: introduce scaffolding for common verbs, and apply to rust 2025-07-04 12:32:14 +02:00
37 changed files with 771 additions and 19 deletions

8
cpp/justfile Normal file
View 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')

View 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

View File

@@ -0,0 +1,5 @@
import cpp
from Element e
where e.toString().matches("%(null)%")
select e

View File

@@ -0,0 +1,5 @@
name: codeql/cpp-consistency-queries
groups: [cpp, test, consistency-queries]
dependencies:
codeql/cpp-all: ${workspace}
extractor: cpp

View 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

View File

@@ -0,0 +1,5 @@
import cpp
from VariableDeclarationEntry i
where not exists(i.getType())
select i

View File

@@ -0,0 +1,5 @@
import cpp
from Variable i
where not exists(i.getType())
select i

6
cpp/ql/justfile Normal file
View 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
View 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
View File

@@ -0,0 +1,3 @@
import '../lib.just'
build: (_build_dist "java")

6
java/ql/justfile Normal file
View 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
View 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
View File

@@ -0,0 +1,4 @@
# see misc/just/README.md for an overview
import 'lib.just'
import 'misc/just/forward.just'

1
lib.just Normal file
View File

@@ -0,0 +1 @@
import "misc/just/lib.just"

5
misc/bazel/justfile Normal file
View 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
View 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
View 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
View 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)

View 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
View 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
View 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')"
)

View 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
View 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
View File

@@ -0,0 +1,2 @@
format *ARGS=".":
npx prettier --write {{ ARGS }}

View 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
View 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

View File

@@ -0,0 +1 @@
export SEMMLE_CODE := ""

View File

@@ -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
View 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')

View File

@@ -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())

View 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
View 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
View 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
View 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")

View 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
View 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
View 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)