@devdogsuga/backstage 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4462,107 +4462,107 @@ async function resolveAppId(org, appSlug) {
4462
4462
  }
4463
4463
  //#endregion
4464
4464
  //#region src/github/rulesets/desired.ts
4465
- /**
4466
- * Canonical fixed-ruleset name -> earlier name(s) this reconciler recognizes
4467
- * as the SAME slot, so the first run renames rather than creating a
4468
- * duplicate that leaves the old one live and unmanaged.
4469
- *
4470
- * Only `main` has a legacy alias today (`main-protection`, live on GitHub as
4471
- * of 2026-09-24). `production`, `~ALL` and `team/**` have no live ruleset to
4472
- * rename — they are created fresh. The tag ruleset keeps its live name,
4473
- * `tag-protection`, unchanged; nothing about its shape is wrong today, so
4474
- * there is no rename to make.
4475
- */
4476
- const LEGACY_NAME_ALIASES = { main: ["main-protection"] };
4477
- /** Ruleset names this reconciler deletes outright — nothing in the desired set replaces them. */
4478
- const DELETE_RULESET_NAMES = ["comp-branches"];
4479
- /**
4480
- * A live ruleset name this reconciler must NEVER touch: one `teamSync.ts`
4481
- * created and owns (`team/<slug>`, an exact-ref ruleset), as opposed to the
4482
- * `team/**` wildcard-creation ruleset this module itself manages.
4483
- *
4484
- * `teamRulesetName()` in DevDogsUGA's `rulesets.ts` builds these as
4485
- * `team/${slug}`, and slugs never contain `/`, so a live name is a per-team
4486
- * ruleset iff it starts with `team/` and is not the literal `team/**` this
4487
- * reconciler owns.
4488
- */
4465
+ /** Earlier live names which occupy the same managed slot. */
4466
+ const LEGACY_NAME_ALIASES = { "main-reviews": ["main", "main-protection"] };
4467
+ /** Obsolete fixed rulesets removed after the production-branch cutover. */
4468
+ const DELETE_RULESET_NAMES = ["comp-branches", "production"];
4489
4469
  function isPerTeamRulesetName(name) {
4490
4470
  return name.startsWith("team/") && name !== "team/**";
4491
4471
  }
4472
+ const main$1 = { ref_name: {
4473
+ include: ["refs/heads/main"],
4474
+ exclude: []
4475
+ } };
4476
+ const always = (actor_id) => ({
4477
+ actor_id,
4478
+ actor_type: "Team",
4479
+ bypass_mode: "always"
4480
+ });
4492
4481
  /**
4493
- * The five fixed rulesets, built from resolved actor ids.
4482
+ * Fixed DevDogsUGA rulesets.
4494
4483
  *
4495
- * Pure — no network, no `gh` — so `desired.test.ts` can assert the shape
4496
- * without mocking anything, and `commands.ts` calls this only after
4497
- * resolving `RulesetActors` from the live org.
4484
+ * The main policy is deliberately split. A bypass actor bypasses every rule
4485
+ * in one ruleset, so combining immutable history, PR reviews, updates and CI
4486
+ * would make a direct-push exception an accidental force-push exception too.
4498
4487
  */
4499
4488
  function buildDesiredRulesets(actors) {
4500
4489
  return [
4501
4490
  {
4502
- name: "main",
4491
+ name: "main-integrity",
4503
4492
  target: "branch",
4504
4493
  enforcement: "active",
4505
- conditions: { ref_name: {
4506
- include: ["refs/heads/main"],
4507
- exclude: []
4508
- } },
4509
- bypass_actors: [{
4510
- actor_id: actors.devopsTeamId,
4511
- actor_type: "Team",
4512
- bypass_mode: "always"
4513
- }],
4514
- rules: [
4515
- { type: "deletion" },
4516
- { type: "non_fast_forward" },
4494
+ conditions: main$1,
4495
+ bypass_actors: [],
4496
+ rules: [{ type: "deletion" }, { type: "non_fast_forward" }]
4497
+ },
4498
+ {
4499
+ name: "main-updates",
4500
+ target: "branch",
4501
+ enforcement: "active",
4502
+ conditions: main$1,
4503
+ bypass_actors: [
4517
4504
  {
4518
- type: "update",
4519
- parameters: { update_allows_fetch_and_merge: false }
4505
+ actor_id: actors.reviewersTeamId,
4506
+ actor_type: "Team",
4507
+ bypass_mode: "pull_request"
4520
4508
  },
4521
- {
4522
- type: "pull_request",
4523
- parameters: {
4524
- allowed_merge_methods: ["squash"],
4525
- dismiss_stale_reviews_on_push: false,
4526
- require_code_owner_review: false,
4527
- require_last_push_approval: false,
4528
- required_approving_review_count: 0,
4529
- required_review_thread_resolution: false
4530
- }
4509
+ always(actors.devopsTeamId),
4510
+ always(actors.adminsTeamId)
4511
+ ],
4512
+ rules: [{
4513
+ type: "update",
4514
+ parameters: { update_allows_fetch_and_merge: false }
4515
+ }]
4516
+ },
4517
+ {
4518
+ name: "main-reviews",
4519
+ target: "branch",
4520
+ enforcement: "active",
4521
+ conditions: main$1,
4522
+ bypass_actors: [always(actors.devopsTeamId), always(actors.adminsTeamId)],
4523
+ rules: [{
4524
+ type: "pull_request",
4525
+ parameters: {
4526
+ allowed_merge_methods: ["squash"],
4527
+ dismiss_stale_reviews_on_push: false,
4528
+ require_code_owner_review: true,
4529
+ require_last_push_approval: true,
4530
+ required_approving_review_count: 1,
4531
+ required_review_thread_resolution: true
4531
4532
  }
4532
- ]
4533
+ }]
4533
4534
  },
4534
4535
  {
4535
- name: "production",
4536
+ name: "main-ci",
4536
4537
  target: "branch",
4537
4538
  enforcement: "active",
4538
- conditions: { ref_name: {
4539
- include: ["refs/heads/production"],
4540
- exclude: []
4541
- } },
4542
- bypass_actors: [{
4543
- actor_id: actors.devopsTeamId,
4544
- actor_type: "Team",
4545
- bypass_mode: "pull_request"
4546
- }],
4547
- rules: [
4548
- { type: "deletion" },
4549
- { type: "non_fast_forward" },
4550
- {
4551
- type: "update",
4552
- parameters: { update_allows_fetch_and_merge: false }
4553
- },
4554
- {
4555
- type: "pull_request",
4556
- parameters: {
4557
- allowed_merge_methods: ["merge"],
4558
- dismiss_stale_reviews_on_push: false,
4559
- require_code_owner_review: true,
4560
- require_last_push_approval: false,
4561
- required_approving_review_count: 1,
4562
- required_review_thread_resolution: false
4563
- }
4539
+ conditions: main$1,
4540
+ bypass_actors: [always(actors.devopsTeamId), always(actors.adminsTeamId)],
4541
+ rules: [{
4542
+ type: "required_status_checks",
4543
+ parameters: {
4544
+ do_not_enforce_on_create: false,
4545
+ strict_required_status_checks_policy: false,
4546
+ required_status_checks: [
4547
+ {
4548
+ context: "validate",
4549
+ integration_id: 15368
4550
+ },
4551
+ {
4552
+ context: "database",
4553
+ integration_id: 15368
4554
+ },
4555
+ {
4556
+ context: "format",
4557
+ integration_id: 15368
4558
+ },
4559
+ {
4560
+ context: "flutter",
4561
+ integration_id: 15368
4562
+ }
4563
+ ]
4564
4564
  }
4565
- ]
4565
+ }]
4566
4566
  },
4567
4567
  {
4568
4568
  name: "~ALL",
@@ -4570,17 +4570,17 @@ function buildDesiredRulesets(actors) {
4570
4570
  enforcement: "active",
4571
4571
  conditions: { ref_name: {
4572
4572
  include: ["~ALL"],
4573
- exclude: ["refs/heads/team/**"]
4573
+ exclude: ["refs/heads/main", "refs/heads/team/**"]
4574
4574
  } },
4575
- bypass_actors: [{
4576
- actor_id: actors.devopsTeamId,
4577
- actor_type: "Team",
4578
- bypass_mode: "always"
4579
- }, ...actors.renovateAppId !== void 0 ? [{
4580
- actor_id: actors.renovateAppId,
4581
- actor_type: "Integration",
4582
- bypass_mode: "always"
4583
- }] : []],
4575
+ bypass_actors: [
4576
+ always(actors.devopsTeamId),
4577
+ always(actors.adminsTeamId),
4578
+ ...actors.renovateAppId === void 0 ? [] : [{
4579
+ actor_id: actors.renovateAppId,
4580
+ actor_type: "Integration",
4581
+ bypass_mode: "always"
4582
+ }]
4583
+ ],
4584
4584
  rules: [
4585
4585
  {
4586
4586
  type: "update",
@@ -4599,15 +4599,15 @@ function buildDesiredRulesets(actors) {
4599
4599
  include: ["refs/heads/team/**"],
4600
4600
  exclude: []
4601
4601
  } },
4602
- bypass_actors: [{
4603
- actor_id: actors.appId,
4604
- actor_type: "Integration",
4605
- bypass_mode: "always"
4606
- }, {
4607
- actor_id: actors.devopsTeamId,
4608
- actor_type: "Team",
4609
- bypass_mode: "always"
4610
- }],
4602
+ bypass_actors: [
4603
+ {
4604
+ actor_id: actors.appId,
4605
+ actor_type: "Integration",
4606
+ bypass_mode: "always"
4607
+ },
4608
+ always(actors.devopsTeamId),
4609
+ always(actors.adminsTeamId)
4610
+ ],
4611
4611
  rules: [
4612
4612
  { type: "creation" },
4613
4613
  { type: "deletion" },
@@ -4622,15 +4622,7 @@ function buildDesiredRulesets(actors) {
4622
4622
  include: ["refs/tags/**"],
4623
4623
  exclude: []
4624
4624
  } },
4625
- bypass_actors: [{
4626
- actor_id: actors.adminsTeamId,
4627
- actor_type: "Team",
4628
- bypass_mode: "always"
4629
- }, {
4630
- actor_id: actors.devopsTeamId,
4631
- actor_type: "Team",
4632
- bypass_mode: "always"
4633
- }],
4625
+ bypass_actors: [always(actors.adminsTeamId), always(actors.devopsTeamId)],
4634
4626
  rules: [
4635
4627
  { type: "creation" },
4636
4628
  { type: "update" },
@@ -4702,6 +4694,17 @@ function canonicalizeRule(rule) {
4702
4694
  }
4703
4695
  };
4704
4696
  }
4697
+ if (rule.type === "required_status_checks") return {
4698
+ type: "required_status_checks",
4699
+ parameters: {
4700
+ do_not_enforce_on_create: rule.parameters.do_not_enforce_on_create,
4701
+ strict_required_status_checks_policy: rule.parameters.strict_required_status_checks_policy,
4702
+ required_status_checks: [...rule.parameters.required_status_checks].sort((a, b) => a.context.localeCompare(b.context)).map((check) => ({
4703
+ context: check.context,
4704
+ integration_id: check.integration_id
4705
+ }))
4706
+ }
4707
+ };
4705
4708
  return { type: rule.type };
4706
4709
  }
4707
4710
  function sortRules(rules) {
@@ -4824,6 +4827,7 @@ const DEFAULT_REPO$1 = "DevDogsUGA";
4824
4827
  const DEFAULT_APP_SLUG = "devdogs-platform";
4825
4828
  const DEFAULT_DEVOPS_SLUG = "devops";
4826
4829
  const DEFAULT_ADMINS_SLUG = "admins";
4830
+ const DEFAULT_REVIEWERS_SLUG = "reviewers";
4827
4831
  /** TASK-299 — installed separately from the platform App; may not exist yet. */
4828
4832
  const DEFAULT_RENOVATE_SLUG = "renovate";
4829
4833
  function parseOptions$1(argv) {
@@ -4903,11 +4907,13 @@ async function runGithubRulesets(argv) {
4903
4907
  };
4904
4908
  let devopsTeamId;
4905
4909
  let adminsTeamId;
4910
+ let reviewersTeamId;
4906
4911
  let appId;
4907
4912
  try {
4908
- [devopsTeamId, adminsTeamId, appId] = await Promise.all([
4913
+ [devopsTeamId, adminsTeamId, reviewersTeamId, appId] = await Promise.all([
4909
4914
  resolveTeamId(opts.org, DEFAULT_DEVOPS_SLUG),
4910
4915
  resolveTeamId(opts.org, DEFAULT_ADMINS_SLUG),
4916
+ resolveTeamId(opts.org, DEFAULT_REVIEWERS_SLUG),
4911
4917
  resolveAppId(opts.org, opts.appSlug)
4912
4918
  ]);
4913
4919
  } catch (err) {
@@ -4923,6 +4929,7 @@ async function runGithubRulesets(argv) {
4923
4929
  const actors = {
4924
4930
  devopsTeamId,
4925
4931
  adminsTeamId,
4932
+ reviewersTeamId,
4926
4933
  appId,
4927
4934
  renovateAppId
4928
4935
  };
package/dist/launch.js CHANGED
@@ -320,7 +320,7 @@ async function launchWith(argv, options) {
320
320
  */
321
321
  async function launch(argv) {
322
322
  await launchWith(argv, { dispatch: async (args) => {
323
- const { main } = await import("./cli-YLCe3Zrx.js");
323
+ const { main } = await import("./cli-ZF4QgJro.js");
324
324
  await main(args);
325
325
  } });
326
326
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devdogsuga/backstage",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Officer and production CLI for DevDogsUGA: deploys, env sync with Bitwarden and GitHub, the migration planner role, club graphics and QR codes, GitHub rulesets and settings, and the newsletter. Ships built JS; run it anywhere with `pnpm dlx @devdogsuga/backstage` (no checkout needed to start; commands that read a checkout say so).",
@@ -41,9 +41,9 @@
41
41
  "typescript": "^6.0.3",
42
42
  "zod": "4.4.3",
43
43
  "@devdogsuga/brand": "0.1.5",
44
- "@devdogsuga/newsletter": "0.1.8",
44
+ "@devdogsuga/events": "0.1.5",
45
45
  "@devdogsuga/telemetry": "0.1.3",
46
- "@devdogsuga/events": "0.1.5"
46
+ "@devdogsuga/newsletter": "0.1.9"
47
47
  },
48
48
  "peerDependencies": {
49
49
  "@devdogsuga/db": "*",
@@ -66,8 +66,8 @@
66
66
  "vitest": "^4.1.11",
67
67
  "@devdogsuga/cli-core": "0.0.0",
68
68
  "@devdogsuga/config": "0.1.2",
69
- "@devdogsuga/db": "0.1.2",
70
- "@devdogsuga/env": "0.1.4"
69
+ "@devdogsuga/db": "0.1.3",
70
+ "@devdogsuga/env": "0.1.5"
71
71
  },
72
72
  "scripts": {
73
73
  "build": "tsdown && node scripts/write-build-info.mjs && node ../../scripts/check-bundle-imports.mjs",