Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions crates/launcher-common/src/template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,51 @@ mod tests {
);
}

/// The emitted licence is the app's `[project].license`, once per header.
///
/// The template used to carry a literal MPL-2.0 header — twice — and never
/// read `app_license`, so realigning an AGPL repo's launcher silently
/// relicensed it (game-server-admin, 2026-09-30). A non-default licence is
/// the only input that tells "reads the config" from "happens to match".
#[test]
fn rendered_licence_is_the_projects_and_appears_once_per_header() {
let mut cfg = sample_config();
cfg.project.license = Some("AGPL-3.0-or-later".into());
let std_ = LauncherStandard::baked().expect("baked standard should parse");
let out = render(&cfg, &std_, None).expect("template should render");

let spdx: Vec<&str> = out
.lines()
.filter(|l| l.contains("SPDX-License-Identifier"))
.collect();
assert_eq!(
spdx,
[
"# SPDX-License-Identifier: AGPL-3.0-or-later",
"# ;; SPDX-License-Identifier: AGPL-3.0-or-later",
],
"exactly one script header and one deed header, both the project's licence"
);
assert_eq!(
out.lines().nth(1),
Some("# SPDX-License-Identifier: AGPL-3.0-or-later"),
"the licence header must sit directly under the shebang"
);
}

/// With no `[project].license` the launcher keeps its historical MPL-2.0.
#[test]
fn rendered_licence_defaults_to_mpl_when_the_project_sets_none() {
let cfg = sample_config();
assert_eq!(cfg.project.license, None);
let std_ = LauncherStandard::baked().expect("baked standard should parse");
let out = render(&cfg, &std_, None).expect("template should render");
assert_eq!(
out.lines().nth(1),
Some("# SPDX-License-Identifier: MPL-2.0")
);
}

/// The port has exactly one spelling in the generated script (#49 AC3).
///
/// `APP_PORT` used to be emitted into every `server-url` launcher and read
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: MPL-2.0
# SPDX-License-Identifier: MPL-2.0
# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
#
# @launcher-deed begin
Expand Down
11 changes: 8 additions & 3 deletions templates/launcher.sh.tera
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: MPL-2.0
{# NOTE: the shebang MUST be the literal first line of this template.
It previously sat below this comment block, and every launcher the
generator emitted began with a blank line -- shellcheck SC2148, and a
Expand All @@ -23,12 +22,18 @@

All three shapes emit the same --integ / --disinteg / --help cross-platform
surface so desktop integration stays uniform across the estate.

The emitted script's licence is the APP's (`[project].license`, default
MPL-2.0), not this template's. It used to be a literal MPL-2.0 -- emitted
twice -- so realigning a launcher in an AGPL repo silently relicensed it
(game-server-admin, 2026-09-30). The tag name is a Tera string so that a
licence scanner reading THIS file sees only the template's own header above.
-#}
# SPDX-License-Identifier: MPL-2.0
# {{ "SPDX-License-Identifier" }}: {{ app_license }}
# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
#
# @launcher-deed begin
# ;; SPDX-License-Identifier: MPL-2.0
# ;; {{ "SPDX-License-Identifier" }}: {{ app_license }}
# (praxis-deed
# :schema-version "1.0.0"
# :canonical-name "{{ app_name | deedstr }}-launcher"
Expand Down
Loading