Files
wehub-resource-sync d5f207424b
e2e Tests / e2e (macos-latest) (push) Waiting to run
Nix CI / check (push) Waiting to run
Python CI / Python bindings (macos-latest) (push) Waiting to run
e2e Tests / e2e (windows-latest) (push) Waiting to run
Python CI / Python bindings (windows-latest) (push) Waiting to run
Build & Publish / Build Neovim aarch64-apple-darwin (push) Waiting to run
Build & Publish / Build Neovim aarch64-pc-windows-msvc (push) Waiting to run
Build & Publish / Build Neovim x86_64-apple-darwin (push) Waiting to run
Build & Publish / Build Neovim x86_64-pc-windows-msvc (push) Waiting to run
Build & Publish / Build C FFI aarch64-apple-darwin (push) Waiting to run
Build & Publish / Build C FFI aarch64-pc-windows-msvc (push) Waiting to run
Build & Publish / Build C FFI x86_64-apple-darwin (push) Waiting to run
Build & Publish / Build C FFI x86_64-pc-windows-msvc (push) Waiting to run
Build & Publish / Build MCP aarch64-apple-darwin (push) Waiting to run
Build & Publish / Build MCP aarch64-pc-windows-msvc (push) Waiting to run
Build & Publish / Build MCP x86_64-apple-darwin (push) Waiting to run
Build & Publish / Build MCP x86_64-pc-windows-msvc (push) Waiting to run
Build & Publish / Build Python wheels aarch64 (macos-latest) (push) Waiting to run
Build & Publish / Build Python wheels x86_64 (macos-latest) (push) Waiting to run
Build & Publish / Build Python wheels x86_64 (windows-latest) (push) Waiting to run
Build & Publish / Release (push) Blocked by required conditions
Build & Publish / Publish Python wheels to PyPI (push) Blocked by required conditions
Build & Publish / Publish Rust crates (push) Blocked by required conditions
Build & Publish / Publish npm packages (push) Blocked by required conditions
Rust CI / Fuzz Tests (windows-latest) (push) Waiting to run
Rust CI / Test (macos-latest) (push) Waiting to run
Rust CI / Test (windows-latest) (push) Waiting to run
Rust CI / Fuzz Tests (macos-latest) (push) Waiting to run
Python CI / Python bindings (ubuntu-latest) (push) Failing after 0s
Build & Publish / Build Neovim aarch64-linux-android (push) Failing after 0s
Build & Publish / Build Neovim aarch64-unknown-linux-gnu (push) Failing after 0s
Build & Publish / Build MCP x86_64-unknown-linux-musl (push) Failing after 1s
Build & Publish / Build Python wheels aarch64 (ubuntu-latest) (push) Failing after 0s
Build & Publish / Build Python wheels x86_64 (ubuntu-latest) (push) Failing after 1s
Build & Publish / Build Python sdist (push) Failing after 1s
Rust CI / Fuzz Tests (ubuntu-latest) (push) Failing after 1s
Rust CI / Build i686-unknown-linux-gnu (push) Failing after 0s
Rust CI / cargo clippy (push) Failing after 1s
e2e Tests / e2e (ubuntu-latest) (push) Failing after 1s
Lua CI / luacheck lint (push) Failing after 1s
Build & Publish / Build Neovim aarch64-unknown-linux-musl (push) Failing after 1s
Build & Publish / Build Neovim x86_64-unknown-linux-gnu (push) Failing after 0s
Build & Publish / Build Neovim x86_64-unknown-linux-musl (push) Failing after 1s
Build & Publish / Build C FFI aarch64-linux-android (push) Failing after 0s
Build & Publish / Build C FFI aarch64-unknown-linux-gnu (push) Failing after 0s
Build & Publish / Build C FFI aarch64-unknown-linux-musl (push) Failing after 1s
Build & Publish / Build C FFI x86_64-unknown-linux-gnu (push) Failing after 0s
Build & Publish / Build C FFI x86_64-unknown-linux-musl (push) Failing after 1s
Build & Publish / Build MCP aarch64-unknown-linux-gnu (push) Failing after 1s
Build & Publish / Build MCP aarch64-unknown-linux-musl (push) Failing after 0s
Build & Publish / Build MCP x86_64-unknown-linux-gnu (push) Failing after 1s
Spelling / Spell Check with Typos (push) Failing after 0s
Rust CI / Test (ubuntu-latest) (push) Failing after 0s
Rust CI / cargo fmt (push) Failing after 0s
Stylua / Check lua files using Stylua (push) Failing after 1s
Lua CI / lua-language-server type check (push) Failing after 12m29s
e2e Tests / e2e (alpine-musl) (push) Successful in 57m31s
chore: import upstream snapshot with attribution
2026-07-13 12:27:16 +08:00

157 lines
5.3 KiB
Lua

local M = {}
local is_windows = (package.config:sub(1, 1) == '\\')
--- Shell-quote a string for safe interpolation into a command.
---@param s string
---@return string
local function shell_quote(s)
if is_windows then return '"' .. s:gsub('"', '\\"') .. '"' end
return "'" .. s:gsub("'", "'\\''") .. "'"
end
--- Run a git command in the given repository and return trimmed stdout.
---@param repo_root string
---@return string|nil output trimmed stdout, or nil on failure
local function git(repo_root, ...)
local parts = { 'git', '-C', shell_quote(repo_root) }
for i = 1, select('#', ...) do
parts[#parts + 1] = shell_quote(select(i, ...))
end
local redirect = is_windows and ' 2>NUL' or ' 2>/dev/null'
local handle = io.popen(table.concat(parts, ' ') .. redirect)
if not handle then return nil end
local output = handle:read('*a')
handle:close()
if not output or output:match('^%s*$') then return nil end
return output:gsub('%s+$', '')
end
function M.current_release_tag(repo_root)
local raw = git(repo_root, 'tag', '--points-at', 'HEAD')
if not raw then return nil end
-- A nightly commit carries both the per-sha tag (e.g. 0.9.2-nightly.abc1234,
-- which owns a permanent release with that commit's binaries) and the rolling
-- `nightly` alias. Prefer the per-sha tag so a pinned install downloads the
-- binary built for its own commit, not whatever `nightly` currently points at.
local stable, nightly_versioned, nightly_alias, dev, other
for tag in raw:gmatch('[^\n]+') do
if tag:match('^v%d') then
stable = tag
elseif tag:match('%-nightly%.') then
nightly_versioned = tag
elseif tag == 'nightly' then
nightly_alias = tag
elseif tag:match('%-dev%.') then
dev = tag
else
other = tag
end
end
return stable or nightly_versioned or dev or other or nightly_alias
end
function M.read_base_version(repo_root)
local cargo_path = repo_root .. '/crates/fff-core/Cargo.toml'
local f = io.open(cargo_path, 'r')
if not f then return nil end
for line in f:lines() do
local ver = line:match('^version%s*=%s*"([^"]+)"')
if ver then
f:close()
return ver
end
end
f:close()
return nil
end
---@class FFFVersionInfo
---@field version string semver version (e.g. "0.4.0" or "0.4.1-nightly.abc1234")
---@field release_tag string permanent GitHub release tag clients download from (per-sha for nightlies)
---@field is_release boolean true for tagged stable releases
---@field npm_tag string "latest"|"nightly"|"dev"
--- Bump the patch component of a semver string.
--- "1.2.3" → "1.2.4"
---@param version string
---@return string|nil bumped version, or nil if parsing fails
local function bump_patch(version)
local major, minor, patch = version:match('^(%d+)%.(%d+)%.(%d+)')
if not major then return nil end
return string.format('%s.%s.%d', major, minor, tonumber(patch) + 1)
end
--- Compute the version for a new release based on git state.
--- Used by CI to determine what tag to create — NOT for downloads.
---
--- For prerelease versions the patch is bumped so that the result is
--- higher than the current Cargo.toml version in semver ordering.
--- This is required for `cargo set-version` / crates.io publishing
--- (0.4.1-nightly.x > 0.4.0, whereas 0.4.0-nightly.x < 0.4.0).
---
--- tagged release (v*) → version from tag, npm_tag = "latest"
--- main branch → {base+1}-nightly.{sha}, npm_tag = "nightly"
--- detached HEAD → {base+1}-nightly.{sha}, npm_tag = "nightly"
--- other branch (PR / feature) → {base+1}-dev.{sha}, npm_tag = "dev"
---
---@param repo_root string absolute path to the repository root
---@return FFFVersionInfo|nil info
---@return string|nil err
function M.resolve(repo_root)
local tag = git(repo_root, 'describe', '--exact-match', '--tags', '--match', 'v*', 'HEAD')
if tag and tag:match('^v%d') then
return {
version = tag:sub(2),
release_tag = tag,
is_release = true,
npm_tag = 'latest',
}
end
local short_sha = git(repo_root, 'rev-parse', '--short', 'HEAD')
if not short_sha then return nil, 'Failed to determine git SHA' end
local base_version = M.read_base_version(repo_root)
if not base_version then return nil, 'Could not read base version from crates/fff-core/Cargo.toml' end
local next_version = bump_patch(base_version)
if not next_version then return nil, 'Could not parse base version: ' .. base_version end
local branch = git(repo_root, 'symbolic-ref', '--short', 'HEAD')
local prerelease_label, npm_tag
if not branch then
prerelease_label = 'nightly'
npm_tag = 'nightly'
elseif branch == 'main' or branch == 'fix/download-version' then
prerelease_label = 'nightly'
npm_tag = 'nightly'
else
prerelease_label = 'dev'
npm_tag = 'dev'
end
local version = string.format('%s-%s.%s', next_version, prerelease_label, short_sha)
-- Each nightly gets its own permanent per-sha release/tag so a pinned or stale
-- install always downloads the binary built for its exact commit. CI also moves
-- the rolling `nightly` tag to HEAD for "give me latest" tooling, but clients
-- never resolve to it when their commit has a per-sha tag.
return {
version = version,
release_tag = version,
is_release = false,
npm_tag = npm_tag,
}
end
return M