Skip to content

Commit 537c92a

Browse files
committed
Refactor away from a single big file
1 parent 28c64bc commit 537c92a

File tree

8 files changed

+280
-241
lines changed

8 files changed

+280
-241
lines changed

collectors/BUILD.bazel

Whitespace-only changes.

collectors/basics.bzl

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
"""
2+
Some basic collectors.
3+
"""
4+
5+
6+
def _shell(repository_ctx):
7+
"""Detect the shell."""
8+
9+
return repository_ctx.os.environ.get("SHELL")
10+
11+
def _os(repository_ctx):
12+
return repository_ctx.os.name
13+
14+
15+
def _arch(repository_ctx):
16+
return repository_ctx.os.arch
17+
18+
19+
def register():
20+
return {
21+
"shell": _shell,
22+
"os": _os,
23+
"arch": _arch,
24+
}

collectors/bazel.bzl

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
"""
2+
Some Bazel and repository oriented collectors.
3+
"""
4+
5+
load("@bazel_skylib//lib:paths.bzl", "paths")
6+
7+
8+
def _is_bazelisk(repository_ctx):
9+
"""Detect if the build is using bazelisk; this persists into the repo env state."""
10+
11+
return repository_ctx.os.environ.get("BAZELISK") != None or repository_ctx.os.environ.get("BAZELISK_SKIP_WRAPPER") != None
12+
13+
def _has_tools_bazel(repository_ctx):
14+
"""Detect if the repository has a tools/bazel wrapper script."""
15+
16+
return repository_ctx.path(paths.join(str(repository_ctx.workspace_root), "tools/bazel")).exists
17+
18+
19+
def _has_bazel_prelude(repository_ctx):
20+
"""Detect if the repository has a //tools/build_rules/prelude_bazel."""
21+
22+
return repository_ctx.path(paths.join(str(repository_ctx.workspace_root), "tools/build_rules/prelude_bazel")).exists
23+
24+
25+
def _has_workspace(repository_ctx):
26+
"""Detect if the repository has a WORKSPACE file."""
27+
28+
return repository_ctx.path(paths.join(str(repository_ctx.workspace_root), "WORKSPACE")).exists or repository_ctx.path(paths.join(str(repository_ctx.workspace_root), "WORKSPACE.bazel")).exists
29+
30+
31+
def _has_module(repository_ctx):
32+
"""Detect if the repository has a MODULE.bazel file."""
33+
34+
return repository_ctx.path(paths.join(str(repository_ctx.workspace_root), "MODULE.bazel")).exists
35+
36+
37+
def _bazel_version(repository_ctx):
38+
return native.bazel_version
39+
40+
41+
def _repo_bzlmod(repository_ctx):
42+
return repository_ctx.attr.deps
43+
44+
45+
def register():
46+
return {
47+
"bazelisk": _is_bazelisk,
48+
"has_bazel_tool": _has_tools_bazel,
49+
"has_bazel_prelude": _has_bazel_prelude,
50+
"has_bazel_workspace": _has_workspace,
51+
"has_bazel_module": _has_module,
52+
"bazel_version": _bazel_version,
53+
"deps": _repo_bzlmod,
54+
}

collectors/ci.bzl

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
"""
2+
Collectors designed to inspect the CI environment.
3+
"""
4+
5+
6+
def _is_ci(repository_ctx):
7+
"""Detect if the build is happening in 'CI'. Pretty much all the vendors set this."""
8+
9+
return repository_ctx.os.environ.get("CI") != None
10+
11+
12+
def _build_counter(repository_ctx):
13+
"""Try to get a counter for the build.
14+
15+
This allows estimation of rate of builds.
16+
"""
17+
18+
# Note that on GHA run numbers may be reused and there's a retry count
19+
# subcounter. Since that's the only platform to do so, we're going to just
20+
# pretend it doesn't exist.
21+
for counter_var in [
22+
"BUILDKITE_BUILD_NUMBER", # Buildkite
23+
"GITHUB_RUN_NUMBER", # Github/forgejo/gitea
24+
"CI_PIPELINE_IID", # Gitlab
25+
"CIRCLE_BUILD_NUM", # CircleCI
26+
"DRONE_BUILD_NUMBER", # Drone
27+
"BUILD_NUMBER", # Jenkins
28+
"CI_PIPELINE_NUMBER", # Woodpecker?
29+
"TRAVIS_BUILD_NUMBER", # Travis
30+
]:
31+
counter = repository_ctx.os.environ.get(counter_var)
32+
if counter:
33+
return counter
34+
35+
36+
def _build_runner(repository_ctx):
37+
"""Try to identify the CI/CD runner environment."""
38+
39+
for var, platform in [
40+
("BUILDKITE_BUILD_NUMBER", "buildkite"),
41+
("FORGEJO_TOKEN", "forgejo"), # FIXME: This value is a secret, avoid
42+
("GITEA_ACTIONS", "gitea"),
43+
("GITHUB_RUN_NUMBER", "github-actions"),
44+
("GITLAB_CI", "gitlab"),
45+
("CIRCLE_BUILD_NUM", "circleci"),
46+
("DRONE_BUILD_NUMBER", "drone"),
47+
("BUILD_NUMBER", "jenkins"),
48+
("TRAVIS", "travis")
49+
]:
50+
val = repository_ctx.os.environ.get(var)
51+
if val != None:
52+
return platform
53+
54+
# Set on Woodpecker and in some other environments
55+
return repository_ctx.os.environ.get("CI_SYSTEM_NAME")
56+
57+
58+
def _repo_org(repository_ctx):
59+
"""Try to extract the organization name."""
60+
61+
repo = None
62+
for var in [
63+
"BUILDKITE_ORGANIZATION_SLUG", # Buildkite
64+
"GITHUB_REPOSITORY_OWNER", # GH/Gitea/Forgejo
65+
"CI_PROJECT_NAMESPACE", # GL
66+
"CIRCLE_PROJECT_USERNAME", # Circle
67+
# TODO: Jenkins only has the fetch URL which seems excessively sensitive
68+
"DRONE_REPO_NAMESPACE", # Drone
69+
"CI_REPO_OWNER", # Woodpecker
70+
"TRAVIS_REPO_SLUG", # Travis
71+
]:
72+
repo = repository_ctx.os.environ.get(var)
73+
if repo:
74+
return repo
75+
76+
77+
def register():
78+
return {
79+
"ci": _is_ci,
80+
"counter": _build_counter,
81+
"runner": _build_runner,
82+
"org": _repo_org,
83+
}

collectors/fingerprinting.bzl

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
"""
2+
Machinery for computing anonymous aggregation IDs.
3+
"""
4+
5+
load("@bazel_skylib//lib:paths.bzl", "paths")
6+
load(":utils.bzl", "hash")
7+
8+
9+
def _repo_id(repository_ctx):
10+
"""Try to extract an aggregation ID from the repo context.
11+
12+
Ideally we want to use the first few (usually stable!) lines from a highly
13+
stable file such as the README. This will provide a consistent aggregation
14+
ID regardless of whether a project is checked out locally or remotely.
15+
16+
Note that the repo ID doesn't depend on the org name, since the org name
17+
cannot be determined on workstations but we do want to count CI vs
18+
workstation builds for a single repo consistently.
19+
20+
"""
21+
22+
readme_file = None
23+
for suffix in [
24+
"",
25+
# Github allows the README to be squirreled away, so we may need to
26+
# check subdirs. Assume that gitlab et all allow the same.
27+
"doc",
28+
"docs",
29+
".github",
30+
".gitlab",
31+
".gitea",
32+
".forgejo",
33+
]:
34+
dir = repository_ctx.workspace_root
35+
if suffix:
36+
dir = paths.join(str(dir), suffix)
37+
dir = repository_ctx.path(dir)
38+
if dir.exists and dir.is_dir:
39+
for entry in dir.readdir():
40+
if entry.basename.lower().find("readme") != -1:
41+
readme_file = entry
42+
break
43+
44+
if readme_file:
45+
break
46+
47+
# As a fallback use the top of the MODULE.bazel file
48+
if not readme_file:
49+
readme_file = repository_ctx.path(paths.join(str(repository_ctx.workspace_root), "MODULE.bazel"))
50+
51+
return hash(repository_ctx, "\n".join(repository_ctx.read(readme_file).split("\n")[:4]))
52+
53+
54+
def _repo_user(repository_ctx):
55+
"""Try to extract a fingerprint for the user who initiated the build.
56+
57+
Note that we salt the user IDs with the identified project ID to prevent
58+
correllation.
59+
60+
"""
61+
62+
user = None
63+
for var in [
64+
"BUILDKITE_BUILD_AUTHOR_EMAIL", # Buildkite
65+
"GITHUB_ACTOR", # GH/Gitea/Forgejo
66+
"GITLAB_USER_EMAIL", # GL
67+
"CIRCLE_USERNAME", # Circle
68+
# TODO: Jenkins
69+
"DRONE_COMMIT_AUTHOR", # Drone
70+
"DRONE_COMMIT_AUTHOR_EMAIL", # Drone
71+
"CI_COMMIT_AUTHOR", # Woodpecker
72+
"CI_COMMIT_AUTHOR_EMAIL", # Woodpecker
73+
# TODO: Travis
74+
"LOGNAME", # Generic unix
75+
"USER", # Generic unix
76+
]:
77+
user = repository_ctx.os.environ.get(var)
78+
if user:
79+
break
80+
81+
if user:
82+
return hash(repository_ctx, str(_repo_id(repository_ctx)) + ";" + user)
83+
84+
85+
def register():
86+
return {
87+
"id": _repo_id,
88+
"user": _repo_user,
89+
}

collectors/utils.bzl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
load("//:sha1.bzl", sha1="sha1")
2+
3+
def hash(repository_ctx, data, fn=sha1):
4+
"""Hash, honoring a salt value from the environment."""
5+
6+
salt = repository_ctx.os.environ.get("ASPECT_TOOLS_TELEMETRY_SALT")
7+
if salt:
8+
data = salt + ";" + data
9+
return fn(data)

examples/simple/MODULE.bazel.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)