Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .github/workflows/workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,19 @@ jobs:
New-Item -ItemType Directory -Force -Path $pluginDir
New-Item -ItemType Junction -Path "$pluginDir\yarn" -Target $PWD

# Validate version listing
- name: Validate mise ls-remote works
shell: bash
run: |
echo "Listing available yarn versions..."
mise ls-remote yarn | head -20
echo ""
echo "Checking for v1 versions..."
mise ls-remote yarn | grep -E '^1\.' | head -5 || (echo "ERROR: No v1 versions found!" && exit 1)
echo ""
echo "Checking for v2+ versions..."
mise ls-remote yarn | grep -E '^[234]\.' | head -5 || (echo "ERROR: No v2+ versions found!" && exit 1)

# Test Yarn v1 (Classic)
- name: Test Yarn v1 installation
shell: bash
Expand Down
138 changes: 100 additions & 38 deletions hooks/available.lua
Original file line number Diff line number Diff line change
@@ -1,55 +1,117 @@
--- List all available versions
PLUGIN = {}

local function execCommand(cmd)
local handle = io.popen(cmd .. " 2>/dev/null")
if handle then
local result = handle:read("*a")
handle:close()
return result
end
return ""
local function fetch_github_tags(repo_url)
-- Use git ls-remote to get tags
local cmd = 'git ls-remote --refs --tags "' .. repo_url .. '"'

-- Detect Windows
local is_windows = package.config:sub(1,1) == '\\'

-- Redirect stderr appropriately for the platform
if is_windows then
cmd = cmd .. " 2>NUL"
else
cmd = cmd .. " 2>/dev/null"
end

local handle = io.popen(cmd)
if not handle then
return {}
end

local result = handle:read("*a")
handle:close()

-- If result is empty or nil, return empty table
if not result or result == "" then
return {}
end

local tags = {}
for line in result:gmatch("[^\r\n]+") do
-- Extract tag name from refs/tags/...
local tag = line:match("refs/tags/(.+)$")
if tag then
table.insert(tags, tag)
end
end

return tags
end

local function version_compare(a, b)
-- Simple version comparison for sorting
local function parse_version(v)
local parts = {}
for part in string.gmatch(v, "[^%.]+") do
table.insert(parts, tonumber(part) or 0)
end
return parts
end

local a_parts = parse_version(a)
local b_parts = parse_version(b)

for i = 1, math.max(#a_parts, #b_parts) do
local a_val = a_parts[i] or 0
local b_val = b_parts[i] or 0
if a_val ~= b_val then
return a_val > b_val -- Descending order
end
end

return false
end

function PLUGIN:Available(ctx)
local versions = {}

-- Get Yarn Berry versions (v2.x+) FIRST in DESCENDING order
-- When mise reverses the list, these will appear LAST in ASCENDING order
local berry_output = execCommand([[
git ls-remote --refs --tags "https://github.com/yarnpkg/berry.git" |
grep '@yarnpkg/cli' |
sed -E 's|^.+refs/tags/@yarnpkg/cli/||g' |
sort -rV
]])

for version in berry_output:gmatch("[^\n]+") do
if version and version ~= "" then
table.insert(versions, {
version = version
})
-- Get Yarn Berry versions (v2.x+)
local berry_tags = fetch_github_tags("https://github.com/yarnpkg/berry.git")
local berry_versions = {}

for _, tag in ipairs(berry_tags) do
-- Extract version from @yarnpkg/cli/X.X.X format
local version = tag:match("@yarnpkg/cli/(.+)$")
if version then
table.insert(berry_versions, version)
end
end

-- Get Yarn Classic versions (v1.x) SECOND in DESCENDING order
-- When mise reverses the list, these will appear FIRST in ASCENDING order
local classic_output = execCommand([[
git ls-remote --refs --tags "https://github.com/yarnpkg/yarn.git" |
sed -E 's|^.+refs/tags/||g' |
grep -E '^v' |
sed -E 's|^v||g' |
grep -Ev '^0\.' |
sort -rV
]])

for version in classic_output:gmatch("[^\n]+") do
if version and version ~= "" then
table.insert(versions, {
version = version
})
-- Sort Berry versions in descending order
table.sort(berry_versions, version_compare)

-- Add Berry versions to the list
for _, version in ipairs(berry_versions) do
table.insert(versions, {
version = version
})
end

-- Get Yarn Classic versions (v1.x)
local classic_tags = fetch_github_tags("https://github.com/yarnpkg/yarn.git")
local classic_versions = {}

for _, tag in ipairs(classic_tags) do
-- Remove 'v' prefix if present
local version = tag:match("^v(.+)$") or tag
-- Only include 1.x versions (exclude 0.x)
if version:match("^1%.") then
table.insert(classic_versions, version)
end
end

-- Sort Classic versions in descending order
table.sort(classic_versions, version_compare)

-- Add Classic versions to the list
for _, version in ipairs(classic_versions) do
table.insert(versions, {
version = version
})
end

return versions
end

Expand Down
63 changes: 52 additions & 11 deletions hooks/post_install.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@
PLUGIN = {}

local function download_file(url, output_path)
-- Try wget first, then curl
local wget_cmd = "wget -q -O " .. output_path .. " " .. url .. " 2>/dev/null"
local curl_cmd = "curl -sSL -o " .. output_path .. " " .. url .. " 2>/dev/null"
-- Detect Windows
local is_windows = package.config:sub(1,1) == '\\'
local stderr_redirect = is_windows and " 2>NUL" or " 2>/dev/null"

if os.execute(wget_cmd) == 0 then
-- Try curl first (more likely to be available on Windows via Git Bash)
local curl_cmd = "curl -sSL -o " .. output_path .. " " .. url .. stderr_redirect
local wget_cmd = "wget -q -O " .. output_path .. " " .. url .. stderr_redirect

if os.execute(curl_cmd) == 0 then
return true
elseif os.execute(curl_cmd) == 0 then
elseif os.execute(wget_cmd) == 0 then
return true
end
return false
Expand Down Expand Up @@ -44,17 +48,54 @@ function PLUGIN:PostInstall(ctx)
-- Yarn Berry (v2.x+) - download single JS file
local yarn_url = "https://repo.yarnpkg.com/" .. version .. "/packages/yarnpkg-cli/bin/yarn.js"

-- Create bin directory
os.execute("mkdir -p " .. install_path .. "/bin")
-- Detect Windows
local is_windows = package.config:sub(1,1) == '\\'

-- Create bin directory (cross-platform)
local bin_dir = install_path .. "/bin"
if is_windows then
os.execute('mkdir "' .. bin_dir .. '" 2>NUL')
else
os.execute("mkdir -p " .. bin_dir)
end

-- Download yarn.js
local yarn_file = install_path .. "/bin/yarn"
if not download_file(yarn_url, yarn_file) then
local yarn_js_file = bin_dir .. "/yarn.js"
if not download_file(yarn_url, yarn_js_file) then
error("Failed to download Yarn v2+")
end

-- Make executable
os.execute("chmod +x " .. yarn_file)
-- Create wrapper script
if is_windows then
-- Create yarn.cmd wrapper for Windows
local yarn_cmd = bin_dir .. "/yarn.cmd"
local cmd_file = io.open(yarn_cmd, "w")
if cmd_file then
cmd_file:write("@echo off\n")
cmd_file:write('node "%~dp0yarn.js" %*\n')
cmd_file:close()
end

-- Also create yarn without extension for Git Bash
local yarn_sh = bin_dir .. "/yarn"
local sh_file = io.open(yarn_sh, "w")
if sh_file then
sh_file:write("#!/bin/sh\n")
sh_file:write('exec node "$(dirname "$0")/yarn.js" "$@"\n')
sh_file:close()
end
else
-- Create shell wrapper for Unix
local yarn_file = bin_dir .. "/yarn"
local wrapper_file = io.open(yarn_file, "w")
if wrapper_file then
wrapper_file:write("#!/bin/sh\n")
wrapper_file:write('exec node "$(dirname "$0")/yarn.js" "$@"\n')
wrapper_file:close()
end
-- Make executable
os.execute("chmod +x " .. yarn_file)
end
end

return {}
Expand Down
9 changes: 6 additions & 3 deletions hooks/pre_install.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ function PLUGIN:PreInstall(ctx)
-- Yarn Classic (v1.x) - return tarball URL for mise to handle
local archive_url = "https://classic.yarnpkg.com/downloads/" .. version .. "/yarn-v" .. version .. ".tar.gz"

-- Note about GPG verification
if os.getenv("MISE_YARN_SKIP_GPG") == nil then
local gpg_check = io.popen("command -v gpg 2>/dev/null")
-- Note about GPG verification (skip on Windows)
local is_windows = package.config:sub(1,1) == '\\'
if os.getenv("MISE_YARN_SKIP_GPG") == nil and not is_windows then
local stderr_redirect = " 2>/dev/null"

local gpg_check = io.popen("command -v gpg" .. stderr_redirect)
local has_gpg = gpg_check and gpg_check:read("*a"):match("%S")
if gpg_check then gpg_check:close() end

Expand Down
6 changes: 3 additions & 3 deletions metadata.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@

PLUGIN = {
name = "yarn",
author = "vfox-yarn contributors",
author = "mise-plugins",
version = "0.1.0",
description = "Yarn package manager plugin for vfox",
homepage = "https://github.com/version-fox/vfox-yarn",
description = "Yarn package manager plugin for mise",
homepage = "https://github.com/mise-plugins/mise-yarn",
license = "MIT",
notes = [[
This plugin installs Yarn package manager.
Expand Down
Loading