Compare commits

..
11 Commits
Author SHA1 Message Date
Benoit Daloze d697be2f83 Account for Bundler 4
* Fixes https://github.com/ruby/setup-ruby/issues/827
2025-12-05 20:42:13 +01:00
Benoit Daloze 8aeb6ff803 Test Ruby 4.0 previews 2025-11-17 15:27:57 +01:00
ruby-builder-bot 09e84e3b9d Add ruby-4.0.0-preview2 2025-11-17 15:27:57 +01:00
Benoit Daloze d5126b9b35 exec.exec() only accepts strings 2025-10-27 12:32:05 +01:00
Benoit Daloze 274049f8cf Use os.availableParallelism() instead of os.cpus().length
* As https://nodejs.org/api/os.html#oscpus says:
  os.cpus().length should not be used to calculate the amount of parallelism available to an application. Use os.availableParallelism() for this purpose.
2025-10-27 12:32:05 +01:00
Thomas Breland a96ff531da Scale bundler install jobs with CPU count up to 8
The number of jobs should scale with the runner CPU count, up to a
point. The bottleneck becomes network / disk I/O at very large numbers,
and 8 seems like a reasonable maximum based on my experience at this
time.
2025-10-27 12:32:05 +01:00
ruby-builder-bot 4ff6f3611a Update CRuby releases on Windows 2025-10-26 13:11:41 +01:00
ruby-builder-bot 5375105c88 Add ruby-3.3.10 2025-10-26 13:11:10 +01:00
ruby-builder-bot ab177d40ee Update CRuby releases on Windows 2025-10-10 10:24:01 +02:00
ruby-builder-bot 6797dcbb9a Add ruby-3.4.7 2025-10-08 11:26:49 +02:00
Benoit Daloze a16e0e6641 Test on macos-15-intel too
* Fixes https://github.com/ruby/setup-ruby/issues/814
2025-10-03 15:02:50 +02:00
8 changed files with 136 additions and 56 deletions
+6 -2
View File
@@ -17,9 +17,9 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ ubuntu-22.04, ubuntu-24.04, ubuntu-22.04-arm, ubuntu-24.04-arm, macos-13, macos-14, macos-15, windows-2022, windows-2025, windows-11-arm ] os: [ ubuntu-22.04, ubuntu-24.04, ubuntu-22.04-arm, ubuntu-24.04-arm, macos-13, macos-14, macos-15, macos-15-intel, windows-2022, windows-2025, windows-11-arm ]
ruby: [ ruby: [
'1.9', '2.0', '2.1', '2.2', '2.3', '2.4', '2.5', '2.6', '2.7', '3.0', '3.1', '3.2', '3.3', '3.4', ruby-head, '1.9', '2.0', '2.1', '2.2', '2.3', '2.4', '2.5', '2.6', '2.7', '3.0', '3.1', '3.2', '3.3', '3.4', '4.0', ruby-head,
jruby-9.4, jruby, jruby-head, jruby-9.4, jruby, jruby-head,
truffleruby, truffleruby-head, truffleruby, truffleruby-head,
truffleruby+graalvm, truffleruby+graalvm-head truffleruby+graalvm, truffleruby+graalvm-head
@@ -79,6 +79,10 @@ jobs:
- { os: windows-2022, ruby: '1.9' } - { os: windows-2022, ruby: '1.9' }
- { os: windows-2025, ruby: '1.9' } - { os: windows-2025, ruby: '1.9' }
- { os: windows-11-arm, ruby: '1.9' } - { os: windows-11-arm, ruby: '1.9' }
# No preview builds on Windows
- { os: windows-2022, ruby: '4.0' }
- { os: windows-2025, ruby: '4.0' }
- { os: windows-11-arm, ruby: '4.0' }
# TruffleRuby does not support Windows # TruffleRuby does not support Windows
- { os: windows-2022, ruby: truffleruby } - { os: windows-2022, ruby: truffleruby }
- { os: windows-2025, ruby: truffleruby } - { os: windows-2025, ruby: truffleruby }
+1 -1
View File
@@ -15,7 +15,7 @@ This action currently supports these versions of MRI, JRuby and TruffleRuby:
| Interpreter | Versions | | Interpreter | Versions |
| ----------- | -------- | | ----------- | -------- |
| `ruby` | 1.9.3, 2.0.0, 2.1.9, 2.2, all versions from 2.3.0 until 3.5.0-preview1, head, debug, mingw, mswin, ucrt | | `ruby` | 1.9.3, 2.0.0, 2.1.9, 2.2, all versions from 2.3.0 until 4.0.0-preview2, head, debug, mingw, mswin, ucrt |
| `jruby` | 9.1.17.0 - 10.0.2.0, head | | `jruby` | 9.1.17.0 - 10.0.2.0, head |
| `truffleruby` | 19.3.0 - 25.0.0, head | | `truffleruby` | 19.3.0 - 25.0.0, head |
| `truffleruby+graalvm` | 21.2.0 - 25.0.0, head | | `truffleruby+graalvm` | 21.2.0 - 25.0.0, head |
+39 -18
View File
@@ -1,4 +1,5 @@
const fs = require('fs') const fs = require('fs')
const os = require('os')
const path = require('path') const path = require('path')
const core = require('@actions/core') const core = require('@actions/core')
const exec = require('@actions/exec') const exec = require('@actions/exec')
@@ -66,17 +67,15 @@ export async function installBundler(bundlerVersionInput, rubygemsInputSet, lock
} }
} }
const floatVersion = common.floatVersion(rubyVersion)
if (bundlerVersion === 'default') { if (bundlerVersion === 'default') {
if (common.isBundler2dot2Default(engine, rubyVersion)) { if (common.isBundler2dot2PlusDefault(engine, rubyVersion)) {
if (common.windows && engine === 'ruby' && (common.isStableVersion(engine, rubyVersion) || rubyVersion === 'head')) { if (common.windows && engine === 'ruby' && (common.isStableVersion(engine, rubyVersion) || rubyVersion === 'head')) {
// https://github.com/ruby/setup-ruby/issues/371 // https://github.com/ruby/setup-ruby/issues/371
console.log(`Installing latest Bundler for ${engine}-${rubyVersion} on Windows because bin/bundle does not work in bash otherwise`) console.log(`Installing latest Bundler for ${engine}-${rubyVersion} on Windows because bin/bundle does not work in bash otherwise`)
bundlerVersion = 'latest' bundlerVersion = 'latest'
} else { } else {
console.log(`Using Bundler 2 shipped with ${engine}-${rubyVersion}`) console.log(`Using Bundler shipped with ${engine}-${rubyVersion}`)
return '2' return common.isBundler4PlusDefault(engine, rubyVersion) ? '4' : '2'
} }
} else if (common.hasBundlerDefaultGem(engine, rubyVersion)) { } else if (common.hasBundlerDefaultGem(engine, rubyVersion)) {
// Those Rubies have a old Bundler default gem < 2.2 which does not work well for `gem 'foo', github: 'foo/foo'`: // Those Rubies have a old Bundler default gem < 2.2 which does not work well for `gem 'foo', github: 'foo/foo'`:
@@ -89,8 +88,15 @@ export async function installBundler(bundlerVersionInput, rubygemsInputSet, lock
} }
} }
const targetRubyVersion = common.targetRubyVersion(engine, rubyVersion)
if (bundlerVersion === 'latest') { if (bundlerVersion === 'latest') {
bundlerVersion = '2' // Bundler 4 requires Ruby 3.2+
if (targetRubyVersion < 3.2) {
bundlerVersion = '2'
} else {
bundlerVersion = '4'
}
} }
if (isValidBundlerVersion(bundlerVersion)) { if (isValidBundlerVersion(bundlerVersion)) {
@@ -99,24 +105,29 @@ export async function installBundler(bundlerVersionInput, rubygemsInputSet, lock
throw new Error(`Cannot parse bundler input: ${bundlerVersion}`) throw new Error(`Cannot parse bundler input: ${bundlerVersion}`)
} }
// Use Bundler 1 when we know Bundler 2 does not work // Only use Bundler 4 on Ruby 3.2+
if (bundlerVersion.startsWith('2')) { if (common.floatVersion(bundlerVersion) >= 4 && targetRubyVersion < 3.2) {
if (engine === 'ruby' && floatVersion <= 2.2) { console.log('Bundler 4 requires Ruby 3.2+, using Bundler 2 instead on Ruby < 3.2')
console.log('Bundler 2 requires Ruby 2.3+, using Bundler 1 on Ruby <= 2.2') bundlerVersion = '2'
}
// Use Bundler 1 when we know Bundler 2+ does not work
if (common.floatVersion(bundlerVersion) >= 2) {
if (engine === 'ruby' && targetRubyVersion <= 2.2) {
console.log(`Bundler 2+ requires Ruby 2.3+, using Bundler 1 on Ruby <= 2.2`)
bundlerVersion = '1' bundlerVersion = '1'
} else if (engine === 'ruby' && /^2\.3\.[01]/.test(rubyVersion)) { } else if (engine === 'ruby' && /^2\.3\.[01]/.test(rubyVersion)) {
console.log('Ruby 2.3.0 and 2.3.1 have shipped with an old rubygems that only works with Bundler 1') console.log('Ruby 2.3.0 and 2.3.1 have shipped with an old rubygems that only works with Bundler 1')
bundlerVersion = '1' bundlerVersion = '1'
} else if (engine === 'jruby' && rubyVersion.startsWith('9.1')) { // JRuby 9.1 targets Ruby 2.3, treat it the same } else if (engine === 'jruby' && rubyVersion.startsWith('9.1')) { // JRuby 9.1 targets Ruby 2.3, treat it the same
console.log('JRuby 9.1 has a bug with Bundler 2 (https://github.com/ruby/setup-ruby/issues/108), using Bundler 1 instead on JRuby 9.1') console.log('JRuby 9.1 has a bug with Bundler 2+ (https://github.com/ruby/setup-ruby/issues/108), using Bundler 1 instead on JRuby 9.1')
bundlerVersion = '1' bundlerVersion = '1'
} }
} }
const targetRubyVersion = common.targetRubyVersion(engine, rubyVersion)
// Use Bundler 2.3 when we use Ruby 2.3.2 - 2.5 // Use Bundler 2.3 when we use Ruby 2.3.2 - 2.5
// Use Bundler 2.4 when we use Ruby 2.6-2.7 // Use Bundler 2.4 when we use Ruby 2.6-2.7
if (bundlerVersion == '2') { if (bundlerVersion === '2') {
if (targetRubyVersion <= 2.5) { // < 2.3.2 already handled above if (targetRubyVersion <= 2.5) { // < 2.3.2 already handled above
console.log('Ruby 2.3.2 - 2.5 only works with Bundler 2.3') console.log('Ruby 2.3.2 - 2.5 only works with Bundler 2.3')
bundlerVersion = '2.3' bundlerVersion = '2.3'
@@ -136,6 +147,14 @@ export async function installBundler(bundlerVersionInput, rubygemsInputSet, lock
return bundlerVersion return bundlerVersion
} }
function bundlerConfigSetArgs(bundlerVersion, key, value) {
if (bundlerVersion.startsWith('1')) {
return ['config', '--local', key, value]
} else {
return ['config', 'set', '--local', key, value]
}
}
export async function bundleInstall(gemfile, lockFile, platform, engine, rubyVersion, bundlerVersion, cacheVersion) { export async function bundleInstall(gemfile, lockFile, platform, engine, rubyVersion, bundlerVersion, cacheVersion) {
if (gemfile === null) { if (gemfile === null) {
console.log('Could not determine gemfile path, skipping "bundle install" and caching') console.log('Could not determine gemfile path, skipping "bundle install" and caching')
@@ -143,8 +162,8 @@ export async function bundleInstall(gemfile, lockFile, platform, engine, rubyVer
} }
let envOptions = {} let envOptions = {}
if (bundlerVersion.startsWith('1') && common.isBundler2Default(engine, rubyVersion)) { if (bundlerVersion.startsWith('1') && common.isBundler2PlusDefault(engine, rubyVersion)) {
// If Bundler 1 is specified on Rubies which ship with Bundler 2, // If Bundler 1 is specified on Rubies which ship with Bundler 2+,
// we need to specify which Bundler version to use explicitly until the lockfile exists. // we need to specify which Bundler version to use explicitly until the lockfile exists.
console.log(`Setting BUNDLER_VERSION=${bundlerVersion} for "bundle config|lock" commands below to ensure Bundler 1 is used`) console.log(`Setting BUNDLER_VERSION=${bundlerVersion} for "bundle config|lock" commands below to ensure Bundler 1 is used`)
envOptions = { env: { ...process.env, BUNDLER_VERSION: bundlerVersion } } envOptions = { env: { ...process.env, BUNDLER_VERSION: bundlerVersion } }
@@ -155,10 +174,10 @@ export async function bundleInstall(gemfile, lockFile, platform, engine, rubyVer
// An absolute path, so it is reliably under $PWD/vendor/bundle, and not relative to the gemfile's directory // An absolute path, so it is reliably under $PWD/vendor/bundle, and not relative to the gemfile's directory
const bundleCachePath = path.join(process.cwd(), cachePath) const bundleCachePath = path.join(process.cwd(), cachePath)
await exec.exec('bundle', ['config', '--local', 'path', bundleCachePath], envOptions) await exec.exec('bundle', bundlerConfigSetArgs(bundlerVersion, 'path', bundleCachePath), envOptions)
if (fs.existsSync(lockFile)) { if (fs.existsSync(lockFile)) {
await exec.exec('bundle', ['config', '--local', 'deployment', 'true'], envOptions) await exec.exec('bundle', bundlerConfigSetArgs(bundlerVersion, 'deployment', 'true'), envOptions)
} else { } else {
// Generate the lockfile so we can use it to compute the cache key. // Generate the lockfile so we can use it to compute the cache key.
// This will also automatically pick up the latest gem versions compatible with the Gemfile. // This will also automatically pick up the latest gem versions compatible with the Gemfile.
@@ -193,8 +212,10 @@ export async function bundleInstall(gemfile, lockFile, platform, engine, rubyVer
console.log(`Found cache for key: ${cachedKey}`) console.log(`Found cache for key: ${cachedKey}`)
} }
// Number of jobs should scale with runner, up to a point
const jobs = Math.min(os.availableParallelism(), 8)
// Always run 'bundle install' to list the gems // Always run 'bundle install' to list the gems
await exec.exec('bundle', ['install', '--jobs', '4']) await exec.exec('bundle', ['install', '--jobs', `${jobs}`])
// @actions/cache only allows to save for non-existing keys // @actions/cache only allows to save for non-existing keys
if (!common.isExactCacheKeyMatch(key, cachedKey)) { if (!common.isExactCacheKeyMatch(key, cachedKey)) {
+14 -5
View File
@@ -80,7 +80,7 @@ export function isStableVersion(engine, rubyVersion) {
} }
export function hasBundlerDefaultGem(engine, rubyVersion) { export function hasBundlerDefaultGem(engine, rubyVersion) {
return isBundler1Default(engine, rubyVersion) || isBundler2Default(engine, rubyVersion) return isBundler1Default(engine, rubyVersion) || isBundler2PlusDefault(engine, rubyVersion)
} }
export function isBundler1Default(engine, rubyVersion) { export function isBundler1Default(engine, rubyVersion) {
@@ -95,7 +95,7 @@ export function isBundler1Default(engine, rubyVersion) {
} }
} }
export function isBundler2Default(engine, rubyVersion) { export function isBundler2PlusDefault(engine, rubyVersion) {
if (engine === 'ruby') { if (engine === 'ruby') {
return floatVersion(rubyVersion) >= 2.7 return floatVersion(rubyVersion) >= 2.7
} else if (engine.startsWith('truffleruby')) { } else if (engine.startsWith('truffleruby')) {
@@ -107,7 +107,7 @@ export function isBundler2Default(engine, rubyVersion) {
} }
} }
export function isBundler2dot2Default(engine, rubyVersion) { export function isBundler2dot2PlusDefault(engine, rubyVersion) {
if (engine === 'ruby') { if (engine === 'ruby') {
return floatVersion(rubyVersion) >= 3.0 return floatVersion(rubyVersion) >= 3.0
} else if (engine.startsWith('truffleruby')) { } else if (engine.startsWith('truffleruby')) {
@@ -119,6 +119,13 @@ export function isBundler2dot2Default(engine, rubyVersion) {
} }
} }
const UNKNOWN_TARGET_RUBY_VERSION = 9.9
export function isBundler4PlusDefault(engine, rubyVersion) {
const version = targetRubyVersion(engine, rubyVersion)
return version != UNKNOWN_TARGET_RUBY_VERSION && version >= 4.0
}
export function targetRubyVersion(engine, rubyVersion) { export function targetRubyVersion(engine, rubyVersion) {
const version = floatVersion(rubyVersion) const version = floatVersion(rubyVersion)
if (engine === 'ruby') { if (engine === 'ruby') {
@@ -132,6 +139,8 @@ export function targetRubyVersion(engine, rubyVersion) {
return 2.6 return 2.6
} else if (version === 9.4) { } else if (version === 9.4) {
return 3.1 return 3.1
} else if (version === 10.0) {
return 3.4
} }
} else if (engine.startsWith('truffleruby')) { } else if (engine.startsWith('truffleruby')) {
if (version < 21.0) { if (version < 21.0) {
@@ -147,11 +156,11 @@ export function targetRubyVersion(engine, rubyVersion) {
} }
} }
return 9.9 // unknown, assume recent return UNKNOWN_TARGET_RUBY_VERSION // unknown, assume recent
} }
export function floatVersion(rubyVersion) { export function floatVersion(rubyVersion) {
const match = rubyVersion.match(/^\d+\.\d+/) const match = rubyVersion.match(/^\d+(\.\d+|$)/)
if (match) { if (match) {
return parseFloat(match[0]) return parseFloat(match[0])
} else if (isHeadVersion(rubyVersion)) { } else if (isHeadVersion(rubyVersion)) {
Generated Vendored
+59 -28
View File
File diff suppressed because one or more lines are too long
+3 -2
View File
@@ -12,9 +12,10 @@
"3.0.0-preview1", "3.0.0-preview2", "3.0.0-rc1", "3.0.0", "3.0.1", "3.0.2", "3.0.3", "3.0.4", "3.0.5", "3.0.6", "3.0.7", "3.0.0-preview1", "3.0.0-preview2", "3.0.0-rc1", "3.0.0", "3.0.1", "3.0.2", "3.0.3", "3.0.4", "3.0.5", "3.0.6", "3.0.7",
"3.1.0-preview1", "3.1.0", "3.1.1", "3.1.2", "3.1.3", "3.1.4", "3.1.5", "3.1.6", "3.1.7", "3.1.0-preview1", "3.1.0", "3.1.1", "3.1.2", "3.1.3", "3.1.4", "3.1.5", "3.1.6", "3.1.7",
"3.2.0-preview1", "3.2.0-preview2", "3.2.0-preview3", "3.2.0-rc1", "3.2.0", "3.2.1", "3.2.2", "3.2.3", "3.2.4", "3.2.5", "3.2.6", "3.2.7", "3.2.8", "3.2.9", "3.2.0-preview1", "3.2.0-preview2", "3.2.0-preview3", "3.2.0-rc1", "3.2.0", "3.2.1", "3.2.2", "3.2.3", "3.2.4", "3.2.5", "3.2.6", "3.2.7", "3.2.8", "3.2.9",
"3.3.0-preview1", "3.3.0-preview2", "3.3.0-preview3", "3.3.0-rc1", "3.3.0", "3.3.1", "3.3.2", "3.3.3", "3.3.4", "3.3.5", "3.3.6", "3.3.7", "3.3.8", "3.3.9", "3.3.0-preview1", "3.3.0-preview2", "3.3.0-preview3", "3.3.0-rc1", "3.3.0", "3.3.1", "3.3.2", "3.3.3", "3.3.4", "3.3.5", "3.3.6", "3.3.7", "3.3.8", "3.3.9", "3.3.10",
"3.4.0-preview1", "3.4.0-preview2", "3.4.0-rc1", "3.4.0", "3.4.1", "3.4.2", "3.4.3", "3.4.4", "3.4.5", "3.4.6", "3.4.0-preview1", "3.4.0-preview2", "3.4.0-rc1", "3.4.0", "3.4.1", "3.4.2", "3.4.3", "3.4.4", "3.4.5", "3.4.6", "3.4.7",
"3.5.0-preview1", "3.5.0-preview1",
"4.0.0-preview2",
"head", "debug", "asan", "3.4-asan" "head", "debug", "asan", "3.4-asan"
], ],
"jruby": [ "jruby": [
+7
View File
@@ -236,6 +236,9 @@
"3.3.9": { "3.3.9": {
"x64": "https://github.com/ruby/setup-msys2-gcc/releases/latest/download/msys2-ucrt64.7z" "x64": "https://github.com/ruby/setup-msys2-gcc/releases/latest/download/msys2-ucrt64.7z"
}, },
"3.3.10": {
"x64": "https://github.com/ruby/setup-msys2-gcc/releases/latest/download/msys2-ucrt64.7z"
},
"3.4.1": { "3.4.1": {
"arm64": "https://github.com/ruby/setup-msys2-gcc/releases/latest/download/msys2-clangarm64-mingw-w64@r688.7z", "arm64": "https://github.com/ruby/setup-msys2-gcc/releases/latest/download/msys2-clangarm64-mingw-w64@r688.7z",
"x64": "https://github.com/ruby/setup-msys2-gcc/releases/latest/download/msys2-ucrt64-mingw-w64@r688-gcc@14.7z" "x64": "https://github.com/ruby/setup-msys2-gcc/releases/latest/download/msys2-ucrt64-mingw-w64@r688-gcc@14.7z"
@@ -260,6 +263,10 @@
"arm64": "https://github.com/ruby/setup-msys2-gcc/releases/latest/download/msys2-clangarm64.7z", "arm64": "https://github.com/ruby/setup-msys2-gcc/releases/latest/download/msys2-clangarm64.7z",
"x64": "https://github.com/ruby/setup-msys2-gcc/releases/latest/download/msys2-ucrt64.7z" "x64": "https://github.com/ruby/setup-msys2-gcc/releases/latest/download/msys2-ucrt64.7z"
}, },
"3.4.7": {
"arm64": "https://github.com/ruby/setup-msys2-gcc/releases/latest/download/msys2-clangarm64.7z",
"x64": "https://github.com/ruby/setup-msys2-gcc/releases/latest/download/msys2-ucrt64.7z"
},
"head": { "head": {
"arm64": "https://github.com/ruby/setup-msys2-gcc/releases/latest/download/msys2-clangarm64.7z", "arm64": "https://github.com/ruby/setup-msys2-gcc/releases/latest/download/msys2-clangarm64.7z",
"x64": "https://github.com/ruby/setup-msys2-gcc/releases/latest/download/msys2-ucrt64.7z" "x64": "https://github.com/ruby/setup-msys2-gcc/releases/latest/download/msys2-ucrt64.7z"
+7
View File
@@ -236,6 +236,9 @@
"3.3.9": { "3.3.9": {
"x64": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-3.3.9-1/rubyinstaller-3.3.9-1-x64.7z" "x64": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-3.3.9-1/rubyinstaller-3.3.9-1-x64.7z"
}, },
"3.3.10": {
"x64": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-3.3.10-1/rubyinstaller-3.3.10-1-x64.7z"
},
"3.4.1": { "3.4.1": {
"arm64": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-3.4.1-2/rubyinstaller-3.4.1-2-arm.7z", "arm64": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-3.4.1-2/rubyinstaller-3.4.1-2-arm.7z",
"x64": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-3.4.1-2/rubyinstaller-3.4.1-2-x64.7z" "x64": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-3.4.1-2/rubyinstaller-3.4.1-2-x64.7z"
@@ -260,6 +263,10 @@
"arm64": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-3.4.6-1/rubyinstaller-3.4.6-1-arm.7z", "arm64": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-3.4.6-1/rubyinstaller-3.4.6-1-arm.7z",
"x64": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-3.4.6-1/rubyinstaller-3.4.6-1-x64.7z" "x64": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-3.4.6-1/rubyinstaller-3.4.6-1-x64.7z"
}, },
"3.4.7": {
"arm64": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-3.4.7-1/rubyinstaller-3.4.7-1-arm.7z",
"x64": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-3.4.7-1/rubyinstaller-3.4.7-1-x64.7z"
},
"head": { "head": {
"arm64": "https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-head/rubyinstaller-head-arm.7z", "arm64": "https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-head/rubyinstaller-head-arm.7z",
"x64": "https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-head/rubyinstaller-head-x64.7z" "x64": "https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-head/rubyinstaller-head-x64.7z"