Add support for ARM builds (#278)

6ab5719 · Favio Manriquez · 2024-06-16 12:19

3 files +290 -6

Files changed

modified dist/index.js
+33 −3
@@ -9160,7 +9160,9 @@ async function main() {
9160 9160
9161 9161 async function installOTP(otpSpec, osVersion) {
9162 9162 const otpVersion = await getOTPVersion(otpSpec, osVersion)
9163 core.startGroup(`Installing Erlang/OTP ${otpVersion} - built on ${osVersion}`)
9163 + core.startGroup(
9164 + `Installing Erlang/OTP ${otpVersion} - built on ${getRunnerOSArchitecture()}/${osVersion}`,
9165 + )
9164 9166 await doWithMirrors({
9165 9167 hexMirrors: hexMirrorsInput(),
9166 9168 actionTitle: `install Erlang/OTP ${otpVersion}`,
@@ -9354,7 +9356,7 @@ async function getOTPVersions(osVersion) {
9354 9356 let otpVersionsListings
9355 9357 let originListing
9356 9358 if (process.platform === 'linux') {
9357 originListing = `/builds/otp/${osVersion}/builds.txt`
9359 + originListing = `/builds/otp/${getRunnerOSArchitecture()}/${osVersion}/builds.txt`
9358 9360 otpVersionsListings = await doWithMirrors({
9359 9361 hexMirrors: hexMirrorsInput(),
9360 9362 actionTitle: `fetch ${originListing}`,
@@ -9605,6 +9607,32 @@ function isKnownBranch(ver) {
9605 9607 return ['main', 'master', 'maint', 'latest'].includes(ver)
9606 9608 }
9607 9609
9610 +function githubARMRunnerArchs() {
9611 + return ['ARM', 'ARM64']
9612 +}
9613 +
9614 +function githubAMDRunnerArchs() {
9615 + return ['X86', 'X64']
9616 +}
9617 +
9618 +function getRunnerOSArchitecture() {
9619 + // These options come from:
9620 + // https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables
9621 + if (githubARMRunnerArchs().includes(process.env.RUNNER_ARCH)) {
9622 + return 'arm64'
9623 + }
9624 +
9625 + if (githubAMDRunnerArchs().includes(process.env.RUNNER_ARCH)) {
9626 + return 'amd64'
9627 + }
9628 +
9629 + throw new Error(
9630 + 'Invalid Github runner architecture, expected one of ' +
9631 + `${githubAMDRunnerArchs().concat(githubARMRunnerArchs()).join(', ')} ` +
9632 + `but got process.env.RUNNER_ARCH = ${process.env.RUNNER_ARCH}`,
9633 + )
9634 +}
9635 +
9608 9636 function getRunnerOSVersion() {
9609 9637 const ImageOSToContainer = {
9610 9638 ubuntu18: 'ubuntu-18.04',
@@ -9843,7 +9871,7 @@ async function install(toolName, opts) {
9843 9871 tool: 'Erlang/OTP',
9844 9872 linux: {
9845 9873 downloadToolURL: () =>
9846 `${hexMirror}/builds/otp/${versionSpec}.tar.gz`,
9874 + `${hexMirror}/builds/otp/${getRunnerOSArchitecture()}/${versionSpec}.tar.gz`,
9847 9875 extract: async (file) => {
9848 9876 const dest = undefined
9849 9877 const flags = ['zx', '--strip-components=1']
@@ -10133,6 +10161,8 @@ module.exports = {
10133 10161 getGleamVersion,
10134 10162 getRebar3Version,
10135 10163 getVersionFromSpec,
10164 + githubAMDRunnerArchs,
10165 + githubARMRunnerArchs,
10136 10166 install,
10137 10167 parseVersionFile,
10138 10168 }
modified src/setup-beam.js
+33 −3
@@ -55,7 +55,9 @@ async function main() {
55 55
56 56 async function installOTP(otpSpec, osVersion) {
57 57 const otpVersion = await getOTPVersion(otpSpec, osVersion)
58 core.startGroup(`Installing Erlang/OTP ${otpVersion} - built on ${osVersion}`)
58 + core.startGroup(
59 + `Installing Erlang/OTP ${otpVersion} - built on ${getRunnerOSArchitecture()}/${osVersion}`,
60 + )
59 61 await doWithMirrors({
60 62 hexMirrors: hexMirrorsInput(),
61 63 actionTitle: `install Erlang/OTP ${otpVersion}`,
@@ -254,7 +256,7 @@ async function getOTPVersions(osVersion) {
254 256 let otpVersionsListings
255 257 let originListing
256 258 if (process.platform === 'linux') {
257 originListing = `/builds/otp/${osVersion}/builds.txt`
259 + originListing = `/builds/otp/${getRunnerOSArchitecture()}/${osVersion}/builds.txt`
258 260 otpVersionsListings = await doWithMirrors({
259 261 hexMirrors: hexMirrorsInput(),
260 262 actionTitle: `fetch ${originListing}`,
@@ -505,6 +507,32 @@ function isKnownBranch(ver) {
505 507 return ['main', 'master', 'maint', 'latest'].includes(ver)
506 508 }
507 509
510 +function githubARMRunnerArchs() {
511 + return ['ARM', 'ARM64']
512 +}
513 +
514 +function githubAMDRunnerArchs() {
515 + return ['X86', 'X64']
516 +}
517 +
518 +function getRunnerOSArchitecture() {
519 + // These options come from:
520 + // https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables
521 + if (githubARMRunnerArchs().includes(process.env.RUNNER_ARCH)) {
522 + return 'arm64'
523 + }
524 +
525 + if (githubAMDRunnerArchs().includes(process.env.RUNNER_ARCH)) {
526 + return 'amd64'
527 + }
528 +
529 + throw new Error(
530 + 'Invalid Github runner architecture, expected one of ' +
531 + `${githubAMDRunnerArchs().concat(githubARMRunnerArchs()).join(', ')} ` +
532 + `but got process.env.RUNNER_ARCH = ${process.env.RUNNER_ARCH}`,
533 + )
534 +}
535 +
508 536 function getRunnerOSVersion() {
509 537 const ImageOSToContainer = {
510 538 ubuntu18: 'ubuntu-18.04',
@@ -743,7 +771,7 @@ async function install(toolName, opts) {
743 771 tool: 'Erlang/OTP',
744 772 linux: {
745 773 downloadToolURL: () =>
746 `${hexMirror}/builds/otp/${versionSpec}.tar.gz`,
774 + `${hexMirror}/builds/otp/${getRunnerOSArchitecture()}/${versionSpec}.tar.gz`,
747 775 extract: async (file) => {
748 776 const dest = undefined
749 777 const flags = ['zx', '--strip-components=1']
@@ -1033,6 +1061,8 @@ module.exports = {
1033 1061 getGleamVersion,
1034 1062 getRebar3Version,
1035 1063 getVersionFromSpec,
1064 + githubAMDRunnerArchs,
1065 + githubARMRunnerArchs,
1036 1066 install,
1037 1067 parseVersionFile,
1038 1068 }
modified test/setup-beam.test.js
+224 −0
@@ -61,8 +61,11 @@ async function all() {
61 61 await testFailInstallElixir()
62 62 await testFailInstallGleam()
63 63 await testFailInstallRebar3()
64 + await testFailGetOTPVersion()
64 65
65 66 await testOTPVersions()
67 + await testLinuxARM64OTPVersions()
68 + await testLinuxAMD64OTPVersions()
66 69 await testElixirVersions()
67 70 await testGleamVersions()
68 71 await testRebar3Versions()
@@ -171,6 +174,9 @@ async function testOTPVersions() {
171 174 )
172 175
173 176 if (process.platform === 'linux') {
177 + const previousRunnerArch = process.env.RUNNER_ARCH
178 + process.env.RUNNER_ARCH = 'X64'
179 +
174 180 before = simulateInput('version-type', 'strict')
175 181 spec = '26'
176 182 osVersion = 'ubuntu-24.04'
@@ -252,6 +258,8 @@ async function testOTPVersions() {
252 258 expected = 'master'
253 259 got = await setupBeam.getOTPVersion(spec, osVersion, hexMirrors)
254 260 assert.deepStrictEqual(got, expected)
261 +
262 + process.env.RUNNER_ARCH = previousRunnerArch
255 263 }
256 264
257 265 if (process.platform === 'win32') {
@@ -277,6 +285,222 @@ async function testOTPVersions() {
277 285 simulateInput('hexpm-mirrors', hexMirrors, { multiline: true })
278 286 }
279 287
288 +async function testLinuxARM64OTPVersions() {
289 + let got
290 + let expected
291 + let spec
292 + let osVersion
293 + let before
294 + const hexMirrors = simulateInput(
295 + 'hexpm-mirrors',
296 + 'https://repo.hex.pm, https://cdn.jsdelivr.net/hex',
297 + { multiline: true },
298 + )
299 +
300 + const arm64Options = setupBeam.githubARMRunnerArchs()
301 + process.env.RUNNER_ARCH =
302 + arm64Options[Math.floor(Math.random() * arm64Options.length)]
303 +
304 + if (process.platform === 'linux') {
305 + before = simulateInput('version-type', 'strict')
306 + spec = '26'
307 + osVersion = 'ubuntu-24.04'
308 + expected = 'maint-26'
309 + got = await setupBeam.getOTPVersion(spec, osVersion, hexMirrors)
310 + assert.deepStrictEqual(got, expected)
311 +
312 + simulateInput('version-type', before)
313 + spec = '27.0'
314 + osVersion = 'ubuntu-24.04'
315 + expected = 'OTP-27.0'
316 + got = await setupBeam.getOTPVersion(spec, osVersion, hexMirrors)
317 + assert.deepStrictEqual(got, expected)
318 +
319 + simulateInput('version-type', before)
320 + spec = '25.3.2.1'
321 + osVersion = 'ubuntu-20.04'
322 + expected = 'OTP-25.3.2.1'
323 + got = await setupBeam.getOTPVersion(spec, osVersion, hexMirrors)
324 + assert.deepStrictEqual(got, expected)
325 + simulateInput('version-type', before)
326 +
327 + spec = '20'
328 + osVersion = 'ubuntu-20.04'
329 + expected = 'OTP-20.3.8.26'
330 + got = await setupBeam.getOTPVersion(spec, osVersion)
331 + assert.deepStrictEqual(got, expected)
332 +
333 + spec = '20.3.8.26'
334 + osVersion = 'ubuntu-20.04'
335 + expected = 'OTP-20.3.8.26'
336 + got = await setupBeam.getOTPVersion(spec, osVersion, hexMirrors)
337 + assert.deepStrictEqual(got, expected)
338 +
339 + spec = '20.x'
340 + osVersion = 'ubuntu-20.04'
341 + expected = 'OTP-20.3.8.26'
342 + got = await setupBeam.getOTPVersion(spec, osVersion)
343 + assert.deepStrictEqual(got, expected)
344 +
345 + spec = '20.0'
346 + osVersion = 'ubuntu-20.04'
347 + expected = 'OTP-20.0.5'
348 + got = await setupBeam.getOTPVersion(spec, osVersion)
349 + assert.deepStrictEqual(got, expected)
350 +
351 + spec = '20.0.x'
352 + osVersion = 'ubuntu-20.04'
353 + expected = 'OTP-20.0.5'
354 + got = await setupBeam.getOTPVersion(spec, osVersion)
355 + assert.deepStrictEqual(got, expected)
356 +
357 + spec = 'maint'
358 + osVersion = 'ubuntu-22.04'
359 + expected = 'maint'
360 + got = await setupBeam.getOTPVersion(spec, osVersion, hexMirrors)
361 + assert.deepStrictEqual(got, expected)
362 +
363 + spec = 'master'
364 + osVersion = 'ubuntu-22.04'
365 + expected = 'master'
366 + got = await setupBeam.getOTPVersion(spec, osVersion, hexMirrors)
367 + assert.deepStrictEqual(got, expected)
368 + }
369 +
370 + simulateInput('hexpm-mirrors', hexMirrors, { multiline: true })
371 +}
372 +
373 +async function testLinuxAMD64OTPVersions() {
374 + let got
375 + let expected
376 + let spec
377 + let osVersion
378 + let before
379 + const hexMirrors = simulateInput(
380 + 'hexpm-mirrors',
381 + 'https://repo.hex.pm, https://cdn.jsdelivr.net/hex',
382 + { multiline: true },
383 + )
384 +
385 + const amd64Options = setupBeam.githubAMDRunnerArchs()
386 + process.env.RUNNER_ARCH =
387 + amd64Options[Math.floor(Math.random() * amd64Options.length)]
388 +
389 + if (process.platform === 'linux') {
390 + before = simulateInput('version-type', 'strict')
391 + spec = '26'
392 + osVersion = 'ubuntu-24.04'
393 + expected = 'maint-26'
394 + got = await setupBeam.getOTPVersion(spec, osVersion, hexMirrors)
395 + assert.deepStrictEqual(got, expected)
396 +
397 + simulateInput('version-type', before)
398 + spec = '27.0'
399 + osVersion = 'ubuntu-24.04'
400 + expected = 'OTP-27.0'
401 + got = await setupBeam.getOTPVersion(spec, osVersion, hexMirrors)
402 + assert.deepStrictEqual(got, expected)
403 +
404 + simulateInput('version-type', before)
405 + spec = '25.3.2.1'
406 + osVersion = 'ubuntu-20.04'
407 + expected = 'OTP-25.3.2.1'
408 + got = await setupBeam.getOTPVersion(spec, osVersion, hexMirrors)
409 + assert.deepStrictEqual(got, expected)
410 +
411 + simulateInput('version-type', before)
412 + spec = '19.3.x'
413 + osVersion = 'ubuntu-16.04'
414 + expected = 'OTP-19.3.6.13'
415 + got = await setupBeam.getOTPVersion(spec, osVersion)
416 + assert.deepStrictEqual(got, expected)
417 +
418 + spec = '^19.3.6'
419 + osVersion = 'ubuntu-16.04'
420 + expected = 'OTP-19.3.6.13'
421 + got = await setupBeam.getOTPVersion(spec, osVersion)
422 + assert.deepStrictEqual(got, expected)
423 +
424 + spec = '^19.3'
425 + osVersion = 'ubuntu-18.04'
426 + expected = 'OTP-19.3.6.13'
427 + got = await setupBeam.getOTPVersion(spec, osVersion)
428 + assert.deepStrictEqual(got, expected)
429 +
430 + spec = '20'
431 + osVersion = 'ubuntu-20.04'
432 + expected = 'OTP-20.3.8.26'
433 + got = await setupBeam.getOTPVersion(spec, osVersion)
434 + assert.deepStrictEqual(got, expected)
435 +
436 + spec = '20.3.8.26'
437 + osVersion = 'ubuntu-20.04'
438 + expected = 'OTP-20.3.8.26'
439 + got = await setupBeam.getOTPVersion(spec, osVersion, hexMirrors)
440 + assert.deepStrictEqual(got, expected)
441 +
442 + spec = '20.x'
443 + osVersion = 'ubuntu-20.04'
444 + expected = 'OTP-20.3.8.26'
445 + got = await setupBeam.getOTPVersion(spec, osVersion)
446 + assert.deepStrictEqual(got, expected)
447 +
448 + spec = '20.0'
449 + osVersion = 'ubuntu-20.04'
450 + expected = 'OTP-20.0.5'
451 + got = await setupBeam.getOTPVersion(spec, osVersion)
452 + assert.deepStrictEqual(got, expected)
453 +
454 + spec = '20.0.x'
455 + osVersion = 'ubuntu-20.04'
456 + expected = 'OTP-20.0.5'
457 + got = await setupBeam.getOTPVersion(spec, osVersion)
458 + assert.deepStrictEqual(got, expected)
459 +
460 + spec = 'maint'
461 + osVersion = 'ubuntu-22.04'
462 + expected = 'maint'
463 + got = await setupBeam.getOTPVersion(spec, osVersion, hexMirrors)
464 + assert.deepStrictEqual(got, expected)
465 +
466 + spec = 'master'
467 + osVersion = 'ubuntu-22.04'
468 + expected = 'master'
469 + got = await setupBeam.getOTPVersion(spec, osVersion, hexMirrors)
470 + assert.deepStrictEqual(got, expected)
471 + }
472 +
473 + simulateInput('hexpm-mirrors', hexMirrors, { multiline: true })
474 +}
475 +
476 +async function testFailGetOTPVersion() {
477 + const hexMirrors = simulateInput(
478 + 'hexpm-mirrors',
479 + 'https://repo.hex.pm, https://cdn.jsdelivr.net/hex',
480 + { multiline: true },
481 + )
482 +
483 + const previousRunnerArch = process.env.RUNNER_ARCH
484 + process.env.RUNNER_ARCH = 'invalid'
485 +
486 + if (process.platform === 'linux') {
487 + const spec = '26'
488 + const osVersion = 'ubuntu-24.04'
489 +
490 + assert.rejects(
491 + async () => {
492 + await setupBeam.getOTPVersion(spec, osVersion, hexMirrors)
493 + },
494 + (err) => {
495 + assert.ok(err instanceof Error)
496 + return true
497 + },
498 + `Fetching OTP Version with invalid Github runner architecture is supposed to fail`,
499 + )
500 + }
501 + process.env.RUNNER_ARCH = previousRunnerArch
502 +}
503 +
280 504 async function testElixirVersions() {
281 505 let got
282 506 let expected

Parents: c54ac46