Skip to content

Commit 210af1f

Browse files
committed
feat(images): always-on boot-screen label with PR + short-sha@branch
The boot-screen footer now renders a single build-identity label on EVERY build, not just CI PR previews (the previous gating meant a local `make installer/iso` got the stock theme and showed nothing): with a PR: Coder Box - PR #55: <title> (d02f0ac@my-branch) without a PR: Coder Box - d02f0ac@my-branch - New coderBox.branch option, injected by the Makefile (GIT_BRANCH, preferring CODER_BOX_BRANCH so CI can pass github.head_ref past the detached-HEAD checkout). Branch "HEAD"/unknown is dropped from the stamp. - New coderBox.bootLabel assembles "<short-sha>@<branch>" (conventional form; keeps a -dirty suffix) plus the optional PR prefix. - base/iso.nix always builds the custom theme from bootLabel (shrunk menu box + footer), so the label is visible locally and testable without a PR env.
1 parent 547d855 commit 210af1f

4 files changed

Lines changed: 105 additions & 39 deletions

File tree

‎.github/workflows/test.yml‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,12 @@ jobs:
156156
# keep their plain names.
157157
CODER_BOX_PR_TITLE: ${{ github.event.pull_request.title }}
158158
CODER_BOX_PR_NUMBER: ${{ github.event.pull_request.number }}
159+
# Branch name for the boot-screen label's "<short-sha>@<branch>" stamp. A
160+
# PR checkout is a detached HEAD (so the Makefile's `git rev-parse
161+
# --abbrev-ref HEAD` would say "HEAD"); github.head_ref is the real source
162+
# branch on pull_request events and empty otherwise (the Makefile then
163+
# falls back to the local branch name).
164+
CODER_BOX_BRANCH: ${{ github.head_ref }}
159165
strategy:
160166
fail-fast: false
161167
matrix:

‎Makefile‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,13 @@ NIX_OUTPUT_FLAGS ?=
8686
# checkout (the module then falls back to self.rev / "unknown").
8787
GIT_REV := $(shell git rev-parse HEAD 2>/dev/null)$(shell git diff-index --quiet HEAD -- 2>/dev/null || echo -dirty)
8888

89+
# Git branch injected into images alongside the rev, for the boot-screen label's
90+
# "<short-sha>@<branch>" stamp (coderBox.branch). Prefer an explicit
91+
# CODER_BOX_BRANCH (CI sets it from github.head_ref, since a PR checkout is a
92+
# detached HEAD where `rev-parse --abbrev-ref HEAD` would just say "HEAD"); fall
93+
# back to the local branch name. Empty/"HEAD" is dropped from the label.
94+
GIT_BRANCH := $(or $(CODER_BOX_BRANCH),$(shell git rev-parse --abbrev-ref HEAD 2>/dev/null))
95+
8996
# Optional PR title + number woven into the image's pretty version name
9097
# (boot-menu label + ISO file name) via coderBox.prTitle / coderBox.prNumber.
9198
# Not injected through the Nix expression (an arbitrary title would need
@@ -134,7 +141,7 @@ iso_comp_field = $(if $(ISO_COMPRESSION),isoImage.squashfsCompression = "$(ISO_C
134141
# $(1) = host (nixosConfigurations.<host>)
135142
# $(2) = arch token (empty = builder's native arch)
136143
# $(3) = extra module fields (nix attrset body, may be empty)
137-
box_cfg = let f = builtins.getFlake (toString ./.); in (f.nixosConfigurations.$(1).extendModules { modules = [ { nixpkgs.hostPlatform = "$(if $(2),$(call norm_arch,$(2)),$${builtins.currentSystem})"; coderBox.rev = "$(GIT_REV)"; $(3) } ]; }).config.system.build
144+
box_cfg = let f = builtins.getFlake (toString ./.); in (f.nixosConfigurations.$(1).extendModules { modules = [ { nixpkgs.hostPlatform = "$(if $(2),$(call norm_arch,$(2)),$${builtins.currentSystem})"; coderBox.rev = "$(GIT_REV)"; coderBox.branch = "$(GIT_BRANCH)"; $(3) } ]; }).config.system.build
138145

139146
define box_build
140147
@mkdir -p out

‎nixos/_images/base/iso.nix‎

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -35,64 +35,64 @@
3535
boot.loader.systemd-boot.enable = lib.mkForce false;
3636
boot.loader.efi.canTouchEfiVariables = lib.mkForce false;
3737

38-
# ── Show the PR identity on the boot screen (PR-preview builds only) ──────────
39-
# A PR title can't live in the boot-menu entry: that entry is a single,
40-
# non-wrapping line in a fixed-width GRUB/isolinux menu, so a long title
38+
# ── Show the build identity on the boot screen as a footer label ─────────────
39+
# The boot-menu ENTRY can't carry the build identity: it's a single,
40+
# non-wrapping line in a fixed-width GRUB/isolinux menu, so a long PR title
4141
# overflows and gets clipped (and widening the menu makes it span the whole
42-
# screen). Instead, for a PR-preview build, surface the full "PR #N: <title>"
43-
# as a standalone GRUB *label* — boot-screen chrome, not a selectable entry —
44-
# shown as a footer UNDER the menu.
42+
# screen). Instead, render coderBox.bootLabel — e.g.
43+
# "Coder Box - PR #46: <title> (abc123@branch)", or just
44+
# "Coder Box - abc123@branch" with no PR — as a standalone GRUB *label*
45+
# (boot-screen chrome, not a selectable entry) shown as a footer UNDER the menu.
46+
# The label is ALWAYS present (every build has a commit/branch), so this also
47+
# makes the footer visible on local/non-PR builds, not just CI PR previews.
4548
#
4649
# Key gotcha: the stock theme's boot_menu fills almost the whole height with an
4750
# opaque white pixmap (boot_menu_*.png), and GRUB paints that box OVER any
4851
# label that overlaps it — so a footer placed inside the box is invisible. The
4952
# menu only has a handful of entries, so we shrink boot_menu's height to free
50-
# the lower third of the screen, then place the label there on the plain
53+
# the lower area of the screen, then place the label there on the plain
5154
# background (dark text, good contrast). The menu WIDTH is untouched (still the
5255
# stock 800px), so the menu doesn't blow up horizontally like the earlier
5356
# full-width experiment. EFI/GRUB only; the BIOS/isolinux text menu has no
5457
# theme, so there the identity is available off-menu via /etc/coder-box-pr +
55-
# the installer console banner. Non-PR builds use the stock theme untouched.
58+
# the installer console banner.
5659
#
5760
# substituteInPlace uses --replace-fail so a future nixpkgs theme reflow fails
5861
# the build loudly instead of silently dropping the footer.
5962
isoImage.grubTheme =
6063
let
61-
inherit (config.coderBox) prFull;
64+
inherit (config.coderBox) bootLabel;
6265
# theme.txt wraps the text in double quotes; neutralise quotes/backslashes
6366
# so an arbitrary title can't break the theme parser.
64-
prFullThemeSafe = builtins.replaceStrings [ "\"" "\\" ] [ "'" "" ] prFull;
67+
bootLabelThemeSafe = builtins.replaceStrings [ "\"" "\\" ] [ "'" "" ] bootLabel;
6568
in
66-
if prFull == "" then
67-
pkgs.nixos-grub2-theme
68-
else
69-
pkgs.runCommand "coder-box-grub2-theme-pr" { } ''
70-
cp -r ${pkgs.nixos-grub2-theme} "$out"
71-
chmod -R u+w "$out"
69+
pkgs.runCommand "coder-box-grub2-theme" { } ''
70+
cp -r ${pkgs.nixos-grub2-theme} "$out"
71+
chmod -R u+w "$out"
7272
73-
# 1) Shrink the menu box so its opaque pixmap stops at ~62% of the screen,
74-
# leaving the lower area free for the footer (stock fills to the
75-
# progress bar and would cover it).
76-
substituteInPlace "$out/theme.txt" \
77-
--replace-fail 'height = 100%-3%-100-3%-3%-32-3%' 'height = 62%-100-6%'
73+
# 1) Shrink the menu box so its opaque pixmap stops at ~62% of the screen,
74+
# leaving the lower area free for the footer (stock fills to the
75+
# progress bar and would cover it).
76+
substituteInPlace "$out/theme.txt" \
77+
--replace-fail 'height = 100%-3%-100-3%-3%-32-3%' 'height = 62%-100-6%'
7878
79-
# 2) Footer label in the freed area, centred horizontally, just above the
80-
# timeout progress bar (which lives at ~95%). Quoted heredoc so the
81-
# build shell does no expansion; the PR text is already substituted by
82-
# Nix (and quote/backslash-sanitised).
83-
cat >> "$out/theme.txt" <<'EOF'
79+
# 2) Footer label in the freed area, centred horizontally, above the
80+
# timeout progress bar (which lives at ~95%). Quoted heredoc so the
81+
# build shell does no expansion; the text is already substituted by Nix
82+
# (and quote/backslash-sanitised).
83+
cat >> "$out/theme.txt" <<'EOF'
8484
85-
+ label {
86-
top = 78%
87-
left = 5%
88-
width = 90%
89-
align = "center"
90-
color = "#232627"
91-
font = "DejaVu Regular"
92-
text = "${prFullThemeSafe}"
93-
}
94-
EOF
95-
'';
85+
+ label {
86+
top = 78%
87+
left = 5%
88+
width = 90%
89+
align = "center"
90+
color = "#232627"
91+
font = "DejaVu Regular"
92+
text = "${bootLabelThemeSafe}"
93+
}
94+
EOF
95+
'';
9696

9797
# Tools install.sh expects at runtime, shipped in the base layer so every ISO
9898
# flavour (installer + appliance) has them:

‎nixos/_images/box-turnkey.nix‎

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,12 @@ let
3434
# The PR identity is surfaced off-menu instead: recorded at /etc/coder-box-pr
3535
# and printed by the installer console banner (see prFull / ../installer/iso.nix).
3636
# Empty for tag/main/local builds.
37-
inherit (config.coderBox) prTitle prNumber;
37+
inherit (config.coderBox)
38+
prTitle
39+
prNumber
40+
rev
41+
branch
42+
;
3843

3944
# Flatten newlines so the identity stays a single line in the file / banner.
4045
prTitleClean = builtins.replaceStrings [ "\n" ] [ " " ] prTitle;
@@ -43,6 +48,32 @@ let
4348
# Full PR identity for off-menu surfaces (baked image record + installer
4449
# console banner): "PR #46: <full title>". Empty for non-PR builds.
4550
prFull = lib.optionalString (prTitle != "") "PR${prNumMenu}: ${prTitleClean}";
51+
52+
# Short build revision for the human-facing version stamp (full 40-char hashes
53+
# are unwieldy on the boot screen). Keep the "-dirty" suffix if present.
54+
revShort =
55+
if rev == "unknown" || rev == "" then
56+
"unknown"
57+
else
58+
let
59+
dirty = lib.hasSuffix "-dirty" rev;
60+
bare = lib.removeSuffix "-dirty" rev;
61+
in
62+
builtins.substring 0 12 bare + lib.optionalString dirty "-dirty";
63+
64+
# A detached-HEAD checkout (the default for GitHub Actions' PR builds) reports
65+
# branch "HEAD", which is noise — treat it like an unknown branch and drop it.
66+
branchClean = if branch == "HEAD" || branch == "unknown" then "" else branch;
67+
68+
# Version stamp woven into the boot-screen label, using the conventional
69+
# "<short-sha>@<branch>" form (branch omitted when unknown/detached).
70+
versionStamp = revShort + lib.optionalString (branchClean != "") "@${branchClean}";
71+
72+
# Boot-screen label (the GRUB footer in ../base/iso.nix). ALWAYS present so the
73+
# image's identity is visible on the boot screen regardless of build type:
74+
# with a PR: "Coder Box - PR #46: <title> (<short-sha>@<branch>)"
75+
# without a PR: "Coder Box - <short-sha>@<branch>"
76+
bootLabel = "Coder Box - " + (if prFull != "" then "${prFull} (${versionStamp})" else versionStamp);
4677
in
4778
{
4879
imports = [
@@ -70,6 +101,17 @@ in
70101
description = "Git revision this Coder box image was built from.";
71102
};
72103

104+
# Git branch this image was built from, woven into the boot-screen label as
105+
# "<short-sha>@<branch>". Like coderBox.rev, the Makefile injects it (path
106+
# flakerefs carry no git metadata); CI can also set CODER_BOX_BRANCH for PR
107+
# builds where the checkout is a detached HEAD. Empty/"HEAD" is treated as
108+
# unknown and dropped from the label.
109+
options.coderBox.branch = lib.mkOption {
110+
type = lib.types.str;
111+
default = builtins.getEnv "CODER_BOX_BRANCH";
112+
description = "Git branch this Coder box image was built from (woven into the boot-screen label when known).";
113+
};
114+
73115
# PR title for a pull-request preview build. CI sets it via the
74116
# CODER_BOX_PR_TITLE environment variable (read here under `--impure`, which
75117
# every image build already uses), so an arbitrary title never has to be
@@ -104,6 +146,17 @@ in
104146
description = "Full PR identity (number + untruncated title) for off-menu surfaces (empty for non-PR builds).";
105147
};
106148

149+
# Boot-screen label (the GRUB footer in ../base/iso.nix), e.g.
150+
# "Coder Box - PR #46: <title> (abc123def456@my-branch)" or, without a PR,
151+
# "Coder Box - abc123def456@my-branch". Always non-empty.
152+
options.coderBox.bootLabel = lib.mkOption {
153+
type = lib.types.str;
154+
internal = true;
155+
readOnly = true;
156+
default = bootLabel;
157+
description = "Boot-screen footer label (build identity: PR + short-sha@branch); always present.";
158+
};
159+
107160
config = {
108161

109162
# ── Bake the repo into the image at /etc/nixos-repo ──────────────────────────

0 commit comments

Comments
 (0)