@homeflare/config 0.11.1 → 0.12.0

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homeflare/config",
3
- "version": "0.11.1",
3
+ "version": "0.12.0",
4
4
  "description": "Shared tsconfig, oxlint, oxfmt, and non-npm release helpers for HomeFlare projects.",
5
5
  "license": "MIT",
6
6
  "author": "Timothy Schneider",
@@ -1,36 +1,29 @@
1
1
  /**
2
- * `.github/dependabot.yml`, rendered — and the one group that carries kit releases.
2
+ * `.github/dependabot.yml`, rendered.
3
3
  *
4
4
  * ★ MEASURED BEFORE IT WAS RENDERED (2026-09-22): 1 of 14 repositories had a Dependabot
5
5
  * config. Twelve took no dependency or Action updates at all, and nothing said so.
6
6
  *
7
- * ★ THE `homeflare` GROUP IS HOW A KIT RELEASE REACHES A CONSUMER (Tim, 2026-09-23:
8
- * "Dependabot, grouped", checked daily, merged on green). Measured the same day, the
9
- * leg nobody automated had drifted: proxmox and mini pinned `@homeflare/alchemy` 0.13.0
10
- * while the kit had published 0.19.1. `automerge.ts` renders the workflow that arms
11
- * auto-merge on this group's pull request and on nothing else.
7
+ * ⛔ `@homeflare/*` IS IGNORED HERE, NOT GROUPED (retired 2026-09-23, kit auto-bumper
8
+ * design, Tim). A `homeflare` group and a rendered `dependabot-automerge.yml`
9
+ * used to carry kit releases into a consumer; both are gone. `homeflare-bumper` does
10
+ * that job now, over `workflow_dispatch` from this repo's own release, with a schedule
11
+ * backstop — a Dependabot bump running at the same time would open a SECOND, competing
12
+ * pull request for the same version bump. The `ignore` entry below is what stops that:
13
+ * Dependabot never proposes `@homeflare/*` at all, so there is only ever one bump PR.
12
14
  *
13
15
  * Every Dependabot claim below was read from GitHub's docs or dependabot-core's source on
14
16
  * 2026-09-22 (dependabot-core v0.397.0); `docs/repo-shape-dependabot.md` has the citations.
15
17
  */
16
18
  import type { RepoShape } from './shape.ts';
17
19
 
18
- /**
19
- * The group's identifier. ⛔ IT IS ALSO HALF OF A BRANCH NAME the auto-merge workflow
20
- * matches — dependabot-core names a group's branch `dependabot/bun/<group>-<10 hex>`
21
- * (branch_namer/dependency_group_strategy.rb) — so it is exported, not retyped there.
22
- * Dependabot requires an identifier that starts and ends with a letter.
23
- */
24
- export const HOMEFLARE_GROUP = 'homeflare';
25
-
26
20
  /** The first-party scope. Every package the kit publishes is under it. */
27
21
  export const HOMEFLARE_PATTERN = '@homeflare/*';
28
22
 
29
23
  /**
30
- * ★ SEVEN DAYS FOR THIRD-PARTY VERSIONS. The bun block has to run daily for the kit's sake
31
- * (see below), so the weekly pace the estate had for everything else is kept by age
32
- * instead of by calendar: a third-party release is proposed once it is a week old. That
33
- * is also the supply-chain half — a compromised release is usually yanked within days.
24
+ * ★ SEVEN DAYS. A third-party release is proposed once it is a week old rather than on
25
+ * Dependabot's undocumented-but-real 3-day default — that is also the supply-chain
26
+ * half, since a compromised release is usually yanked within days.
34
27
  */
35
28
  export const THIRD_PARTY_COOLDOWN_DAYS = 7;
36
29
 
@@ -65,41 +58,33 @@ version: 2
65
58
 
66
59
  updates:
67
60
  # ── The toolchain (bun.lock) ────────────────────────────────────────────────
68
- # ⚠️ BLOCKED UPSTREAM, 2026-09-22: bun 1.4 writes bun.lock \`lockfileVersion\` 2 and
69
- # Dependabot's updater bundles bun 1.3.14, which reads up to 1, so this block fails in
70
- # every estate repository with "Unsupported bun.lock 'lockfileVersion' 2". The fix is
61
+ # ⚠️ STILL BLOCKED UPSTREAM, 2026-09-22 — unrelated to the ignore below. bun 1.4 writes
62
+ # bun.lock \`lockfileVersion\` 2 and Dependabot's updater bundles bun 1.3.14, which reads
63
+ # up to 1, so this whole block fails in every estate repository with "Unsupported
64
+ # bun.lock 'lockfileVersion' 2" before it reads a single manifest. The fix is
71
65
  # dependabot/dependabot-core pull request 16071. The github-actions block is unaffected.
72
- # ⛔ ONE BUN BLOCK, SO ONE SCHEDULE. Dependabot refuses two blocks for one ecosystem and
73
- # target branch whose directories overlap, so the \`homeflare\` group cannot be daily
74
- # while the rest stays weekly. The block is daily; \`cooldown\` slows the rest.
75
66
  - package-ecosystem: bun
76
67
  directories:
77
68
  ${bunDirs.map((dir) => ` - ${dir}`).join('\n')}
78
69
  schedule:
79
- # ⚠️ Dependabot's \`daily\` is Monday to Friday; a weekend kit release lands on Monday.
80
- interval: daily
70
+ interval: weekly
71
+ day: monday
81
72
  time: '09:00'
82
73
  timezone: America/New_York
83
- # ⛔ THE EXCLUDE IS NOT OPTIONAL. Dependabot applies a 3-day cooldown to every version
84
- # update even when this key is absent, so without it a kit release would wait three
85
- # days before its bump opened — and "daily" would quietly mean "three days late".
86
74
  cooldown:
87
75
  default-days: ${THIRD_PARTY_COOLDOWN_DAYS}
88
- exclude: ['${HOMEFLARE_PATTERN}']
76
+ # ⛔ NEVER PROPOSED HERE. \`homeflare-bumper\` opens the one pull request that bumps
77
+ # \`@homeflare/*\` (kit auto-bumper design, Tim 2026-09-23) — a Dependabot
78
+ # update for the same package would race it and, on the weeks they disagree, leave
79
+ # two open pull requests fighting over the same \`package.json\` line.
80
+ ignore:
81
+ - dependency-name: '${HOMEFLARE_PATTERN}'
89
82
  open-pull-requests-limit: 5
90
83
  commit-message:
91
84
  prefix: 'chore'
92
85
  include: scope
93
86
  labels: [dependencies]
94
87
  groups:
95
- # ★ FIRST, AND EVERY UPDATE TYPE. A kit release is one set of packages built to work
96
- # together, so they move as one pull request; \`bun run check\` is what reads it, and
97
- # .github/workflows/dependabot-automerge.yml merges it when that is green.
98
- # ⚠️ A release that changes what @homeflare/config renders fails the drift test here
99
- # by design; \`bun run repo-shape:refresh\` on the branch is the one-command fix.
100
- ${HOMEFLARE_GROUP}:
101
- patterns: ['${HOMEFLARE_PATTERN}']
102
-
103
88
  # oxfmt and oxlint move together and only affect style. Minor and patch bumps are
104
89
  # noise unless they fail CI, which is what CI is for.
105
90
  lint-and-format:
@@ -20,7 +20,6 @@
20
20
  * test lives in `packages/alchemy/tests/repo-shape-policy.test.ts`, which is the one
21
21
  * place that imports both.
22
22
  */
23
- import { renderAutomerge } from './automerge.ts';
24
23
  import { renderCi } from './ci.ts';
25
24
  import { renderActionlintConfig, renderChangesetConfig } from './companions.ts';
26
25
  import { renderDependabot } from './dependabot.ts';
@@ -68,7 +67,6 @@ export function renderRepoShape(shape: RepoShape): RenderedRepo {
68
67
  '.changeset/config.json': renderChangesetConfig(shape),
69
68
  '.github/dependabot.yml': renderDependabot(shape),
70
69
  '.github/workflows/ci.yml': renderCi(shape),
71
- '.github/workflows/dependabot-automerge.yml': renderAutomerge(shape),
72
70
  '.github/workflows/security.yml': renderSecurity(shape),
73
71
  };
74
72
 
@@ -87,6 +85,5 @@ export const RENDERED_PATHS: readonly RenderedPath[] = [
87
85
  '.github/actionlint.yaml',
88
86
  '.github/dependabot.yml',
89
87
  '.github/workflows/ci.yml',
90
- '.github/workflows/dependabot-automerge.yml',
91
88
  '.github/workflows/security.yml',
92
89
  ];
@@ -86,7 +86,6 @@ export type RenderedPath =
86
86
  | '.github/actionlint.yaml'
87
87
  | '.github/dependabot.yml'
88
88
  | '.github/workflows/ci.yml'
89
- | '.github/workflows/dependabot-automerge.yml'
90
89
  | '.github/workflows/security.yml';
91
90
 
92
91
  export interface RepoShapeException {
package/src/repo-shape.ts CHANGED
@@ -17,8 +17,7 @@
17
17
  * That one file gives the repository:
18
18
  *
19
19
  * · its FILES — `bun run repo-shape:refresh` writes ci.yml, security.yml,
20
- * dependabot-automerge.yml, actionlint.yaml, dependabot.yml and
21
- * the changeset config;
20
+ * actionlint.yaml, dependabot.yml and the changeset config;
22
21
  * · its DRIFT GATE — a `bun:test` calling `driftInRepoShape` fails on a hand edit;
23
22
  * · its SETTINGS — `renderRepoShape(shape).policy` is the options object
24
23
  * `@homeflare/alchemy`'s `declareRepoPolicy` takes, so the ruleset
@@ -34,11 +33,9 @@
34
33
  * including the ones with no Alchemy stack, so it belongs to the package they all
35
34
  * already have — and it takes no dependency on Alchemy or Effect to get there.
36
35
  */
37
- export { GROUP_BRANCH, GROUP_BRANCH_PREFIX, renderAutomerge } from './repo-shape/automerge.ts';
38
36
  export { renderCi, ACTIONLINT_VERSION, BUN_VERSION } from './repo-shape/ci.ts';
39
37
  export { renderActionlintConfig, renderChangesetConfig } from './repo-shape/companions.ts';
40
38
  export {
41
- HOMEFLARE_GROUP,
42
39
  HOMEFLARE_PATTERN,
43
40
  renderDependabot,
44
41
  THIRD_PARTY_COOLDOWN_DAYS,
@@ -1,17 +0,0 @@
1
- import type { RepoShape } from './shape.ts';
2
- /**
3
- * The branch prefix a job-level `if:` can test with `startsWith`. GitHub's expression
4
- * language has no regex, so this is the cheap filter that keeps every other pull request
5
- * from taking a runner slot; `GROUP_BRANCH` is the exact test inside the step.
6
- */
7
- export declare const GROUP_BRANCH_PREFIX: string;
8
- /**
9
- * ⛔ EXACT, AND FAILS CLOSED. A solo update of `@homeflare/config` is
10
- * `dependabot/bun/homeflare/config-0.9.0` and a package named `homeflare-x` would be
11
- * `dependabot/bun/homeflare-x-1.2.3`; neither matches. If Dependabot ever changes its
12
- * format, the symptom is a bump that waits for a person — never one merged by mistake.
13
- */
14
- export declare const GROUP_BRANCH: string;
15
- /** The whole `dependabot-automerge.yml` for a shape. */
16
- export declare function renderAutomerge(shape: RepoShape): string;
17
- //# sourceMappingURL=automerge.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"automerge.d.ts","sourceRoot":"","sources":["../../src/repo-shape/automerge.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAI5C;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAA6C,CAAC;AAEhF;;;;;GAKG;AACH,eAAO,MAAM,YAAY,EAAE,MAA+C,CAAC;AA0D3E,wDAAwD;AACxD,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAyCxD"}
@@ -1,144 +0,0 @@
1
- /**
2
- * `.github/workflows/dependabot-automerge.yml`, rendered.
3
- *
4
- * ★ THE OTHER HALF OF THE `homeflare` GROUP. Dependabot opens the bump; this arms GitHub's
5
- * own auto-merge on it; the branch ruleset's required checks (`ci`, `secret scan`)
6
- * decide whether it ever merges. Nothing here merges anything itself, and a merge
7
- * deploys nothing — every stack in the estate is deployed by hand.
8
- *
9
- * ⛔ `gh pr merge --auto` IS NOT ALWAYS "ARM". When the pull request is already CLEAN,
10
- * UNSTABLE or HAS_HOOKS it merges AT ONCE instead (cli/cli `pkg/cmd/pr/merge/merge.go`,
11
- * `isImmediatelyMergeable`, read at v2.101.0 — the version the mini's job image ships).
12
- * UNSTABLE is "mergeable, with a non-passing status", which is every pull request on a
13
- * branch whose rules require no check: before `check` has run, and even after it failed.
14
- * So the step reads the base branch's active rules first and refuses — a red check, never
15
- * a merge — when none requires a status check. Measured 2026-09-22: homeflare-builds (its
16
- * ruleset not deployed yet) and homeflare-desktop have none.
17
- *
18
- * ⛔ FIRST-PARTY ONLY: A `run:` STEP AND THE GitHub CLI, NO `uses:` AT ALL. GitHub's own
19
- * example ("Automating Dependabot with GitHub Actions") identifies the update with
20
- * `dependabot/fetch-metadata`, which the same page marks as "not certified by GitHub".
21
- * The group is identified by the branch Dependabot gives it instead, whose format is
22
- * dependabot-core's (`branch_namer/dependency_group_strategy.rb`, read at v0.397.0):
23
- * `<prefix>/<package manager>/<directory>/<group>-<10 hex MD5 digest>`, with the root
24
- * directory collapsing to nothing.
25
- */
26
- import { HOMEFLARE_GROUP } from './dependabot.ts';
27
- import type { RepoShape } from './shape.ts';
28
- import { runsOn } from './shape.ts';
29
- import { renderSteps } from './yaml.ts';
30
-
31
- /**
32
- * The branch prefix a job-level `if:` can test with `startsWith`. GitHub's expression
33
- * language has no regex, so this is the cheap filter that keeps every other pull request
34
- * from taking a runner slot; `GROUP_BRANCH` is the exact test inside the step.
35
- */
36
- export const GROUP_BRANCH_PREFIX: string = `dependabot/bun/${HOMEFLARE_GROUP}-`;
37
-
38
- /**
39
- * ⛔ EXACT, AND FAILS CLOSED. A solo update of `@homeflare/config` is
40
- * `dependabot/bun/homeflare/config-0.9.0` and a package named `homeflare-x` would be
41
- * `dependabot/bun/homeflare-x-1.2.3`; neither matches. If Dependabot ever changes its
42
- * format, the symptom is a bump that waits for a person — never one merged by mistake.
43
- */
44
- export const GROUP_BRANCH: string = `^${GROUP_BRANCH_PREFIX}[0-9a-f]{10}$`;
45
-
46
- const HEADER = `# Arms auto-merge on Dependabot's @homeflare/* group, and on nothing else.
47
- #
48
- # 🤖 RENDERED BY @homeflare/config — DO NOT EDIT THIS FILE BY HAND.
49
- # Its input is this repository's \`repo-shape.ts\`; refresh with \`bun run repo-shape:refresh\`.
50
- #
51
- # ★ HOW A KIT RELEASE ARRIVES: the \`${HOMEFLARE_GROUP}\` group in .github/dependabot.yml opens one
52
- # pull request; this arms GitHub's auto-merge on it; the ruleset's required checks decide.
53
- # Nothing here merges anything itself, and merging deploys nothing.
54
- # ⛔ NO THIRD-PARTY ACTION. GitHub's own example uses dependabot/fetch-metadata, which its
55
- # docs mark "not certified by GitHub"; the group is recognised by its branch name instead.
56
- # ⛔ NO REQUIRED CHECK ON THE BASE BRANCH, NO ARMING: there \`gh pr merge --auto\` would merge
57
- # at once, unchecked. The job fails instead, so the pull request waits for a person.
58
- # ⚠️ A RENDERER CHANGE STILL NEEDS A PERSON. When a kit release changes what @homeflare/config
59
- # renders, the bump fails \`check\` (the drift test) and never goes green. Run
60
- # \`bun run repo-shape:refresh\` on Dependabot's branch and push. ⛔ This workflow does not do
61
- # it for you: a push made with GITHUB_TOKEN starts no workflow run, so a refreshed commit
62
- # would never get the required checks and the pull request would wait forever.
63
- `;
64
-
65
- const TRIGGER = `name: dependabot auto-merge
66
-
67
- on:
68
- pull_request:
69
-
70
- # ⛔ NOTHING AT THE TOP; the one job asks for exactly what \`gh pr merge --auto\` needs.
71
- permissions: {}
72
-
73
- concurrency:
74
- group: automerge-\${{ github.ref }}
75
- cancel-in-progress: true
76
- `;
77
-
78
- const JOB_NOTE = ` # ⛔ BOTH LOGINS, NOT EITHER. \`user.login\` is who opened the pull request; \`github.actor\` is
79
- # who started this run. A person pushing to Dependabot's branch changes the actor, so
80
- # their commit never arms anything; only Dependabot's own rebases do.`;
81
-
82
- const PERMISSIONS_NOTE = ` # ★ WHAT GitHub'S OWN EXAMPLE GRANTS FOR THIS STEP, AND NO MORE. A run Dependabot starts gets
83
- # a read-only GITHUB_TOKEN unless the workflow raises it ("Troubleshooting Dependabot on
84
- # GitHub Actions" → "Changing GITHUB_TOKEN permissions").`;
85
-
86
- const ARM = `set -euo pipefail
87
- if [[ ! "$HEAD_REF" =~ ${GROUP_BRANCH} ]]; then
88
- echo "::notice::$HEAD_REF is not the ${HOMEFLARE_GROUP} group's branch; auto-merge not armed"
89
- exit 0
90
- fi
91
- # ⛔ gh merges a CLEAN or UNSTABLE pull request at once rather than arming it. Only a branch
92
- # rule that requires a status check keeps it BLOCKED until the checks have passed.
93
- required=$(gh api "repos/$GITHUB_REPOSITORY/rules/branches/$BASE_REF" \\
94
- --jq '[.[] | select(.type == "required_status_checks")] | length')
95
- if [ "$required" = 0 ]; then
96
- echo "::error::$BASE_REF requires no status check, so gh would merge at once; auto-merge not armed"
97
- exit 1
98
- fi
99
- # ★ --squash: the house repositories allow squash merges only (declareRepoPolicy).
100
- gh pr merge --auto --squash "$PR_URL"`;
101
-
102
- /** The whole `dependabot-automerge.yml` for a shape. */
103
- export function renderAutomerge(shape: RepoShape): string {
104
- // ⚠️ GitHub ACTIONS EXPRESSIONS, NOT TEMPLATE LITERALS: the runner interpolates `${{ … }}`
105
- // at job time, so they must reach the file verbatim (see security.ts for the same note).
106
- // oxlint-disable-next-line no-template-curly-in-string
107
- const headRef = '${{ github.head_ref }}';
108
- // oxlint-disable-next-line no-template-curly-in-string
109
- const baseRef = '${{ github.base_ref }}';
110
- // oxlint-disable-next-line no-template-curly-in-string
111
- const prUrl = '${{ github.event.pull_request.html_url }}';
112
- // oxlint-disable-next-line no-template-curly-in-string
113
- const token = '${{ secrets.GITHUB_TOKEN }}';
114
- const condition = [
115
- "github.event.pull_request.user.login == 'dependabot[bot]'",
116
- "github.actor == 'dependabot[bot]'",
117
- `startsWith(github.head_ref, '${GROUP_BRANCH_PREFIX}')`,
118
- ].join(' && ');
119
-
120
- return `${HEADER}
121
- ${TRIGGER}
122
- jobs:
123
- ${JOB_NOTE}
124
- arm:
125
- name: arm auto-merge
126
- if: ${condition}
127
- runs-on: ${runsOn(shape.runner)}
128
- ${PERMISSIONS_NOTE}
129
- permissions:
130
- contents: write
131
- pull-requests: write
132
- steps:
133
- ${renderSteps(
134
- [
135
- {
136
- env: { BASE_REF: baseRef, GH_TOKEN: token, HEAD_REF: headRef, PR_URL: prUrl },
137
- name: 'Arm auto-merge on the homeflare group',
138
- run: ARM,
139
- },
140
- ],
141
- 3,
142
- )}
143
- `;
144
- }