diff --git a/README.md b/README.md index 1b08da3a6..02191aac3 100644 --- a/README.md +++ b/README.md @@ -170,7 +170,7 @@ Without a `server`, the social plugin stays idle by design. Tree works without B ## Built on -FlyBot keeps the upstream DS Bot core byte-identical (`ds-bot/`, pinned in `ds-bot.pin.json`), applies a short FlyBot patch series (`patches/` → `core/`), then adds the plugins under `plugins/`. See [#34](https://github.com/ThinkFlowLab/FlyBot/issues/34). The web UI (header, About, settings, update popups) says FlyBot; the npm package and update-check still use the upstream `ds-bot` name and repository. +FlyBot keeps the upstream DS Bot core byte-identical (`ds-bot/`, pinned in `ds-bot.pin.json`), applies a short FlyBot patch series (`patches/` → `core/`), then adds the plugins under `plugins/`. See [#34](https://github.com/ThinkFlowLab/FlyBot/issues/34). The web UI (header, About, settings, update popups) says FlyBot; the npm package keeps the upstream `ds-bot` name (a registry install still checks npm `ds-bot` for updates), while the package's repository, About's links and stars, and the GitHub update check point at ThinkFlowLab/FlyBot. ## More diff --git a/README.zh.md b/README.zh.md index ed44a2f1b..4367d5da2 100644 --- a/README.zh.md +++ b/README.zh.md @@ -164,7 +164,7 @@ export PORT=8787 ## 架构简述 -上游 DS Bot 核心保持字节一致(`ds-bot/`,见 `ds-bot.pin.json`),经 `patches/` 打出 `core/`,插件在 `plugins/`。详见 [#34](https://github.com/ThinkFlowLab/FlyBot/issues/34)。网页界面(顶栏、关于、设置、更新提示)显示 FlyBot;npm 包名和更新检查仍走上游 `ds-bot` 仓库。 +上游 DS Bot 核心保持字节一致(`ds-bot/`,见 `ds-bot.pin.json`),经 `patches/` 打出 `core/`,插件在 `plugins/`。详见 [#34](https://github.com/ThinkFlowLab/FlyBot/issues/34)。网页界面(顶栏、关于、设置、更新提示)显示 FlyBot;npm 包名仍是上游的 `ds-bot`(从 npm 安装时仍查 npm 上的 `ds-bot` 更新),包的仓库地址、关于页的链接和 Star、以及 GitHub 更新检查都指向 ThinkFlowLab/FlyBot。 ## 许可与声明 diff --git a/changelog.d/374-about-behind-branch.fixed.md b/changelog.d/374-about-behind-branch.fixed.md new file mode 100644 index 000000000..66ce69aa9 --- /dev/null +++ b/changelog.d/374-about-behind-branch.fixed.md @@ -0,0 +1 @@ +About FlyBot no longer says "Up to date with main" when main was reset or force-pushed to before the installed commit (it says it could not compare), and the README's "Built on" now says which parts point at ThinkFlowLab/FlyBot and which still use the upstream `ds-bot` name. ([#374](https://github.com/ThinkFlowLab/FlyBot/issues/374)) diff --git a/core/src/host/update.js b/core/src/host/update.js index a6eecb25b..d37ffd09e 100644 --- a/core/src/host/update.js +++ b/core/src/host/update.js @@ -215,7 +215,10 @@ export function install(rt) { if (commit === null || source.branch === undefined || !/^[\w./-]+$/.test(source.branch)) return try { const answer = await fetchJson(`https://api.github.com/repos/${source.owner}/${source.repo}/compare/${commit}...${source.branch}`, { 'user-agent': `${PKG.name}/${PKG.version}` }) - if (Number.isInteger(answer?.ahead_by) && answer.status !== 'diverged') status.behind = answer.ahead_by + // Only a branch that contains the installed commit gives a count. `behind` (the branch was reset or + // force-pushed to before it) and `diverged` mean the commit is no longer on the branch: unknown, never + // "Up to date" (#374 follow-up). + if (Number.isInteger(answer?.ahead_by) && (answer.status === 'ahead' || answer.status === 'identical')) status.behind = answer.ahead_by } catch (error) { rt.warn('ds-bot: comparing with %s failed: %s', source.branch, error?.message ?? error) } diff --git a/core/test/update.test.js b/core/test/update.test.js index c37ebe183..807457ec2 100644 --- a/core/test/update.test.js +++ b/core/test/update.test.js @@ -260,8 +260,9 @@ test('a git install on a branch reports its branch and commit, and how many comm assert.throws(() => rt.updateStart(), /No FlyBot core update/) assert.deepEqual(installs, []) - // Up to date, a branch that moved away from the commit, and an unreachable API: never a made-up number. - for (const [answer, behind] of [[{ status: 'identical', ahead_by: 0 }, 0], [{ status: 'diverged', ahead_by: 3 }, null], [new Error('offline'), null], [{}, null]]) { + // Up to date, a branch that moved away from the commit (diverged, or reset to before it), no status, and an + // unreachable API: never a made-up number. + for (const [answer, behind] of [[{ status: 'identical', ahead_by: 0 }, 0], [{ status: 'diverged', ahead_by: 3 }, null], [{ status: 'behind', ahead_by: 0, behind_by: 2 }, null], [{ ahead_by: 2 }, null], [new Error('offline'), null], [{}, null]]) { const run = start({ source: spec, config: { packagePath: path }, answers: { [compare]: answer } }) assert.equal((await run.rt.updateCheck()).behind, behind) } diff --git a/docs/subsystems/core-host.md b/docs/subsystems/core-host.md index 07d1cdf40..44179b73d 100644 --- a/docs/subsystems/core-host.md +++ b/docs/subsystems/core-host.md @@ -169,7 +169,7 @@ The connector tools are mounted once for the whole DSH profile, so who may use t The About page's facts come from `src/host/update.js` and the core's `package.json`, which now name **ThinkFlowLab/FlyBot** (`repository.url`, `directory: "core"`, `homepage`, `bugs`), not the upstream DS Bot: `repoSlug()` feeds the Star button and its live count (`repo-stars`, hidden when the answer fails), **Source code**, **Release notes** (`/releases`) and the DSH-update check, and `ISSUES_URL` in `diagnostics.js` is `ThinkFlowLab/FlyBot/issues/new` (its `bug.yml` has the `what` and `diagnostics` fields the Feedback page fills). The DSH-update check reads the latest FlyBot release's `core/package.json` for a `dsBot.verifiedDsh` declaration; none is declared today, so no DSH update is offered, which matches the README's pinned DSH version. - **Build of a git install.** `sourceOf` gives a non-version ref as `branch` (`github:ThinkFlowLab/FlyBot#main&path:/core` → `main`). `installedCommit` reads the 40-hex commit that follows (or precedes) the repository name in the running package's **real path** (pnpm names a git dependency's folder after the address and commit it resolved); the profile's lockfile is not read because it can hold several entries of one repository, and no match means no commit is shown, never a guess. The view carries `build: { branch?, commit? }` (commit is the short 7) for git installs and `null` otherwise. This layout is the pnpm convention and has not been checked against a real DSH profile; the pure matcher is tested on its shapes. -- **How far behind.** For a branch install with a known commit, a check makes one unauthenticated `GET /repos///compare/...` and reports `behind` = `ahead_by` (null on a failure, a diverged branch, or a branch name with odd characters). Nothing is ever offered to install for a branch install: updates come from the maintainer reinstalling FlyBot. `config.packagePath` overrides the path read, for tests. +- **How far behind.** For a branch install with a known commit, a check makes one unauthenticated `GET /repos///compare/...` and reports `behind` = `ahead_by` only when the answer's `status` is `ahead` or `identical` (null on a failure, a `diverged` branch, a branch reset or force-pushed to before the commit (`behind`), or a branch name with odd characters), so a commit that is no longer on the branch never reads "Up to date". Nothing is ever offered to install for a branch install: updates come from the maintainer reinstalling FlyBot. `config.packagePath` overrides the path read, for tests. - **Version.** `current` is still the core's own version (`0.1.5-flybot.1`); the page adds `· ` to it. FlyBot's product version (tags such as v0.1.0) is not in the install, so it is not shown. ### Discarded promise `.catch` (#213) diff --git a/patches/ds-bot/0014-flybot-branding.patch b/patches/ds-bot/0014-flybot-branding.patch index 41a75ab7e..9a1a0132e 100644 --- a/patches/ds-bot/0014-flybot-branding.patch +++ b/patches/ds-bot/0014-flybot-branding.patch @@ -481,7 +481,7 @@ diff --git a/src/host/update.js b/src/host/update.js available: status.phase !== 'installed' && target !== null && status.latest !== null && newer(status.latest, status.current), }) -@@ -169,9 +169,27 @@ export function install(rt) { +@@ -169,9 +169,30 @@ export function install(rt) { return { version, spec: `github:${owner}/${repo}#${fragment}` } } @@ -496,7 +496,10 @@ diff --git a/src/host/update.js b/src/host/update.js + if (commit === null || source.branch === undefined || !/^[\w./-]+$/.test(source.branch)) return + try { + const answer = await fetchJson(`https://api.github.com/repos/${source.owner}/${source.repo}/compare/${commit}...${source.branch}`, { 'user-agent': `${PKG.name}/${PKG.version}` }) -+ if (Number.isInteger(answer?.ahead_by) && answer.status !== 'diverged') status.behind = answer.ahead_by ++ // Only a branch that contains the installed commit gives a count. `behind` (the branch was reset or ++ // force-pushed to before it) and `diverged` mean the commit is no longer on the branch: unknown, never ++ // "Up to date" (#374 follow-up). ++ if (Number.isInteger(answer?.ahead_by) && (answer.status === 'ahead' || answer.status === 'identical')) status.behind = answer.ahead_by + } catch (error) { + rt.warn('ds-bot: comparing with %s failed: %s', source.branch, error?.message ?? error) + } @@ -658,7 +661,7 @@ diff --git a/test/update.test.js b/test/update.test.js // Back on the registry with no copy answering: the offer stays cleared. delete answers[latest] setSource(`^${PKG.version}`) -@@ -223,3 +223,62 @@ test('a failed install reports why and can be tried again', async () => { +@@ -223,3 +223,63 @@ test('a failed install reports why and can be tried again', async () => { assert.equal(installs.length, 2) assert.deepEqual(installs[0][1], { registry: 'https://registry.example/' }) }) @@ -696,8 +699,9 @@ diff --git a/test/update.test.js b/test/update.test.js + assert.throws(() => rt.updateStart(), /No FlyBot core update/) + assert.deepEqual(installs, []) + -+ // Up to date, a branch that moved away from the commit, and an unreachable API: never a made-up number. -+ for (const [answer, behind] of [[{ status: 'identical', ahead_by: 0 }, 0], [{ status: 'diverged', ahead_by: 3 }, null], [new Error('offline'), null], [{}, null]]) { ++ // Up to date, a branch that moved away from the commit (diverged, or reset to before it), no status, and an ++ // unreachable API: never a made-up number. ++ for (const [answer, behind] of [[{ status: 'identical', ahead_by: 0 }, 0], [{ status: 'diverged', ahead_by: 3 }, null], [{ status: 'behind', ahead_by: 0, behind_by: 2 }, null], [{ ahead_by: 2 }, null], [new Error('offline'), null], [{}, null]]) { + const run = start({ source: spec, config: { packagePath: path }, answers: { [compare]: answer } }) + assert.equal((await run.rt.updateCheck()).behind, behind) + }