Skip to content

feat(git): allow version policy functions#2152

Open
ramboman wants to merge 2 commits intofolke:mainfrom
ramboman:feat-version-function
Open

feat(git): allow version policy functions#2152
ramboman wants to merge 2 commits intofolke:mainfrom
ramboman:feat-version-function

Conversation

@ramboman
Copy link
Copy Markdown

Description

With this pull request, it is possible to assign a function to the version key in the configuration or in a spec to implement more complex version policies.

Examples of problems it can solve

Example 1

The user want lazy.nvim to respect a cooldown period (e.g.: 21 days) for all packages. It is part of his strategy to mitigate the threat of supply chain attacks. Here is a simple way to achieve this:

Add this function somewhere in the personal configuration files:

function version_policy_commit_cooldown(repo, branch, date)
  local output = vim.fn.system({
    "git",
    string.format([[--git-dir=%s/.git]], repo),
    "rev-list", branch, "-1",
    string.format([[--before=%s]], date) })
  return { branch = branch, commit = vim.split(output, "\n")[1] }
end

Note: Inspired by #2135

Assign to the defaults version key the following version policy function:

...
-- Setup lazy.nvim
require("lazy").setup({
  defaults = {
    version = function(repo, branch)
      return version_policy_commit_cooldown(repo, branch, "21 days ago")
    end
  },
...

Example 2

The user has a more complex version policy for a specific plugin. He wants:

  • To preserve the cooldown period of 21 days
  • To select a package that has a semver version tag with the patch number not 0
  • If there is no version tag with a patch number not 0, choose the newest version tag
  • If there is no version tag, pick the newest commit

Here is a way to achieve this:

Add these functions somewhere in the personal configuration files:

function get_commit_refs_list(repo, branch, before_date, after_date)
  local command = {
    "git",
    string.format([[--git-dir=%s/.git]], repo),
    "log",
    branch,
    "--format=%H\t%(decorate:tag=tag:,separator= ,prefix=,suffix=)",
  }
  if before_date ~= nil then
    table.insert(command, 5, string.format([[--before=%s]], before_date))
  end
  if after_date ~= nil then
    table.insert(command, 5, string.format([[--after=%s]], after_date))
  end
  local stdout = vim.fn.system(command)
  stdout = string.gsub(stdout, '^(.*)%s$', '%1')
  local output = {}
  local refs = {}
  local sections = {}
  for i, line in ipairs(vim.split(stdout, "\n")) do
    refs = {}
    sections = vim.split(line, "\t")
    for j, ref in ipairs(vim.split(sections[2], " ")) do
      refs[j] = ref
    end
    output[i] = { commit = sections[1], refs = refs }
  end
  return output
end

function get_release_commit_tag(commit_refs_list, pattern)
  local tag = nil
  for _, commit_data in ipairs(commit_refs_list) do
    for _, ref in ipairs(commit_data.refs) do
      if string.sub(ref, 1, 4) == "tag:" then
        tag = string.sub(ref, 5, -1)
        if string.match(tag, pattern) then
          return { commit = commit_data.commit, tag = tag }
        end
      end
    end
  end
  return nil
end

Assign to the spec version key the following version policy function:

...
require("lazy").setup({
...
  spec = {
    -- add your plugins here
    {
      "nvim-telescope/telescope.nvim",
      version = function(repo, branch)
        local commit_refs_list = get_commit_refs_list(repo, branch, "21 days ago", nil)
        local commit_tag =
          get_release_commit_tag(commit_refs_list, "^v%d+%.%d+%.[1-9]")
          or get_release_commit_tag(commit_refs_list, "^v%d+")
          or { commit = commit_refs_list[1].commit, tag = nil }
        if commit_tag.tag == nil then
          return { branch = branch, commit = commit_tag.commit }
        end
        return {
          branch = branch,
          version = string.sub(commit_tag.tag, 2, -1),
          tag = commit_tag.tag,
          commit = commit_tag.commit,
        }
      end,
    },
...

Related Issue(s)

Screenshots

@github-actions github-actions Bot added the size/m Medium PR (<50 lines changed) label Apr 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m Medium PR (<50 lines changed)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feature: minimum release age / update cooldown for security Delayed plugin updates as security feature

1 participant