├── .github ├── CODEOWNERS └── workflows │ ├── build-node-packages.yml │ ├── codeql-analysis.yml │ ├── create-pr.yml │ ├── get-node-versions.yml │ └── validate-manifest.yml ├── .gitmodules ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SECURITY.md ├── builders ├── build-node.ps1 ├── nix-node-builder.psm1 ├── node-builder.psm1 └── win-node-builder.psm1 ├── config └── node-manifest-config.json ├── installers ├── nix-setup-template.sh └── win-setup-template.ps1 ├── tests ├── Node.Tests.ps1 └── simple-test.js └── versions-manifest.json /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @actions/setup-actions-team 2 | -------------------------------------------------------------------------------- /.github/workflows/build-node-packages.yml: -------------------------------------------------------------------------------- 1 | name: Generate Node.js packages 2 | run-name: Generate Node.js ${{ inputs.VERSION || '18.12.0' }} 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | VERSION: 7 | description: 'Node.js version to build and upload' 8 | required: true 9 | default: '18.12.0' 10 | PUBLISH_RELEASES: 11 | description: 'Whether to publish releases' 12 | required: true 13 | type: boolean 14 | default: false 15 | pull_request: 16 | paths-ignore: 17 | - 'versions-manifest.json' 18 | - 'LICENSE' 19 | - '**.md' 20 | branches: 21 | - 'main' 22 | 23 | jobs: 24 | node: 25 | name: Node 26 | uses: actions/versions-package-tools/.github/workflows/build-tool-packages.yml@main 27 | with: 28 | tool-name: "node" 29 | tool-version: ${{ inputs.VERSION || '18.12.0' }} 30 | publish-release: ${{ inputs.PUBLISH_RELEASES || false }} 31 | secrets: inherit -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: CodeQL analysis 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | schedule: 9 | - cron: '0 3 * * 0' 10 | 11 | jobs: 12 | call-codeQL-analysis: 13 | name: CodeQL analysis 14 | uses: actions/reusable-workflows/.github/workflows/codeql-analysis.yml@main -------------------------------------------------------------------------------- /.github/workflows/create-pr.yml: -------------------------------------------------------------------------------- 1 | name: Create Pull Request 2 | on: 3 | workflow_dispatch: 4 | 5 | jobs: 6 | create-pr: 7 | uses: actions/versions-package-tools/.github/workflows/create-pr-to-update-manifest.yml@main 8 | with: 9 | tool-name: "node" 10 | secrets: inherit 11 | -------------------------------------------------------------------------------- /.github/workflows/get-node-versions.yml: -------------------------------------------------------------------------------- 1 | name: Get Node versions 2 | on: 3 | schedule: 4 | - cron: '0 3,15 * * *' 5 | workflow_dispatch: 6 | 7 | jobs: 8 | get-new-node-versions: 9 | uses: actions/versions-package-tools/.github/workflows/get-new-tool-versions.yml@main 10 | with: 11 | tool-name: "Node" 12 | image-url: "https://nodejs.org/static/images/logo-hexagon-card.png" 13 | secrets: inherit -------------------------------------------------------------------------------- /.github/workflows/validate-manifest.yml: -------------------------------------------------------------------------------- 1 | name: Validate manifest 2 | on: 3 | # The GITHUB_TOKEN secret is used to create a PR 4 | # The pull_request event will not be triggered by it 5 | # That's one of the reasons we need the schedule to validate the versions-manifest.json file 6 | schedule: 7 | - cron: '0 8,20 * * *' 8 | workflow_dispatch: 9 | pull_request: 10 | branches: 11 | - main 12 | paths: 13 | - 'versions-manifest.json' 14 | 15 | jobs: 16 | manifest: 17 | uses: actions/versions-package-tools/.github/workflows/validate-manifest.yml@main 18 | with: 19 | tool-name: "Node" 20 | image-url: "https://nodejs.org/static/images/logo-hexagon-card.png" 21 | secrets: inherit -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "helpers"] 2 | path = helpers 3 | url = https://github.com/actions/versions-package-tools 4 | branch = main 5 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to make participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies within all project spaces, and it also applies when 49 | an individual is representing the project or its community in public spaces. 50 | Examples of representing a project or community include using an official 51 | project e-mail address, posting via an official social media account, or acting 52 | as an appointed representative at an online or offline event. Representation of 53 | a project may be further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at opensource@github.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing 2 | 3 | [fork]: https://github.com/actions/node-versions/fork 4 | [pr]: https://github.com/actions/node-versions/compare 5 | [code-of-conduct]: CODE_OF_CONDUCT.md 6 | 7 | Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great. 8 | 9 | Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [MIT](LICENSE.md). 10 | 11 | Please note that this project is released with a [Contributor Code of Conduct][code-of-conduct]. By participating in this project you agree to abide by its terms. 12 | 13 | ## Submitting a pull request 14 | 15 | 1. [Fork][fork] and clone the repository 16 | 1. Create a new branch: `git checkout -b my-branch-name` 17 | 1. Make your changes 18 | 1. Push to your fork and [submit a pull request][pr] 19 | 1. Make sure that checks in your pull request are green 20 | 21 | Here are a few things you can do that will increase the likelihood of your pull request being accepted: 22 | 23 | - Please include a summary of the change and which issue is fixed. Also include relevant motivation and context. 24 | - Follow the style guide for [PowerShell](https://github.com/PoshCode/PowerShellPracticeAndStyle). 25 | - Write [good commit messages](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). 26 | 27 | ## Code structure 28 | 29 | ### Directory structure 30 | ``` 31 | 32 | ├── .github/ 33 | | └──workflows/ 34 | ├── builders/ 35 | ├── helpers/ 36 | ├── installers/ 37 | └── tests/ 38 | └──sources/ 39 | ``` 40 | - `.github/workflows` - contains repository workflow files. 41 | - `builders` - contains Node.js builder classes and functions. 42 | - `helpers` - contains global helper classes and functions. 43 | - `installers` - contains installation script templates. 44 | - `tests` - contains test scripts. Required tests sources are located in `sources` subfolder. 45 | 46 | ## Resources 47 | 48 | - [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/) 49 | - [Using Pull Requests](https://help.github.com/articles/about-pull-requests/) 50 | - [GitHub Help](https://help.github.com) 51 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 GitHub 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Node.js for Actions 2 | This repository contains the code and scripts that we use to prepare Node.js packages used in [runner-images](https://github.com/actions/runner-images) and accessible through the [setup-node](https://github.com/actions/setup-node) Action. 3 | The file [versions-manifest.json](./versions-manifest.json) contains the list of available and released versions. 4 | 5 | > Caution: this is prepared for and only permitted for use by actions `runner-images` and `setup-node` action. 6 | 7 | **Status**: Currently under development and in use for beta and preview actions. This repo is undergoing rapid changes. 8 | 9 | Latest of LTS versions will be installed on the [runner-images](https://github.com/actions/runner-images) images. Other versions will be pulled JIT using the [`setup-node`](https://github.com/actions/setup-node) action. 10 | 11 | ## Adding new versions 12 | We are trying to prepare packages for new versions of Node.js as soon as they are released. Please open an issue in [actions/runner-images](https://github.com/actions/runner-images) if any versions are missing. 13 | 14 | ## Support Notification Policy 15 | Beginning **approximately six months prior** to the removal of a Node.js version from the [versions-manifest.json](https://github.com/actions/node-versions/blob/main/versions-manifest.json) file, a pinned issue will be created in the [setup-node](https://github.com/actions/setup-node) repository. This pinned issue will provide important details about the upcoming end of support, including the specific date, as well as any other notes, relevant updates or alternatives. We encourage users to regularly check pinned issues for updates on tool versions they are using for maximum transparency, security, performance and overall compatibility with their projects. 16 | 17 | ## Contribution 18 | Contributions are welcome! See [Contributor's Guide](./CONTRIBUTING.md) for more details about contribution process and code structure 19 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | If you discover a security issue in this repo, please submit it through the [GitHub Security Bug Bounty](https://hackerone.com/github) 2 | 3 | Thanks for helping make GitHub Actions safe for everyone. 4 | -------------------------------------------------------------------------------- /builders/build-node.ps1: -------------------------------------------------------------------------------- 1 | using module "./win-node-builder.psm1" 2 | using module "./nix-node-builder.psm1" 3 | 4 | <# 5 | .SYNOPSIS 6 | Generate Node.js artifact. 7 | 8 | .DESCRIPTION 9 | Main script that creates instance of NodeBuilder and builds of Node.js using specified parameters. 10 | 11 | .PARAMETER Version 12 | Required parameter. The version with which Node.js will be built. 13 | 14 | .PARAMETER Architecture 15 | Optional parameter. The architecture with which Node.js will be built. Using x64 by default. 16 | 17 | .PARAMETER Platform 18 | Required parameter. The platform for which Node.js will be built. 19 | 20 | #> 21 | 22 | param( 23 | [Parameter (Mandatory=$true)][Version] $Version, 24 | [Parameter (Mandatory=$true)][string] $Platform, 25 | [string] $Architecture = "x64" 26 | ) 27 | 28 | Import-Module (Join-Path $PSScriptRoot "../helpers" | Join-Path -ChildPath "nix-helpers.psm1") -DisableNameChecking 29 | Import-Module (Join-Path $PSScriptRoot "../helpers" | Join-Path -ChildPath "win-helpers.psm1") -DisableNameChecking 30 | 31 | function Get-NodeBuilder { 32 | <# 33 | .SYNOPSIS 34 | Wrapper for class constructor to simplify importing NodeBuilder. 35 | 36 | .DESCRIPTION 37 | Create instance of NodeBuilder with specified parameters. 38 | 39 | .PARAMETER Version 40 | The version with which Node.js will be built. 41 | 42 | .PARAMETER Platform 43 | The platform for which Node.js will be built. 44 | 45 | .PARAMETER Architecture 46 | The architecture with which Node.js will be built. 47 | 48 | #> 49 | 50 | param ( 51 | [version] $Version, 52 | [string] $Architecture, 53 | [string] $Platform 54 | ) 55 | 56 | $Platform = $Platform.ToLower() 57 | if ($Platform -match 'win32') { 58 | $builder = [WinNodeBuilder]::New($Version, $Platform, $Architecture) 59 | } elseif (($Platform -match 'linux') -or ($Platform -match 'darwin')) { 60 | $builder = [NixNodeBuilder]::New($Version, $Platform, $Architecture) 61 | } else { 62 | Write-Host "##vso[task.logissue type=error;] Invalid platform: $Platform" 63 | exit 1 64 | } 65 | 66 | return $builder 67 | } 68 | 69 | ### Create Node.js builder instance, and build artifact 70 | $Builder = Get-NodeBuilder -Version $Version -Platform $Platform -Architecture $Architecture 71 | $Builder.Build() 72 | -------------------------------------------------------------------------------- /builders/nix-node-builder.psm1: -------------------------------------------------------------------------------- 1 | using module "./node-builder.psm1" 2 | 3 | class NixNodeBuilder : NodeBuilder { 4 | <# 5 | .SYNOPSIS 6 | Ubuntu Node.js builder class. 7 | 8 | .DESCRIPTION 9 | Contains methods that required to build Ubuntu Node.js artifact from sources. Inherited from base NixNodeBuilder. 10 | 11 | .PARAMETER platform 12 | The full name of platform for which Node.js should be built. 13 | 14 | .PARAMETER version 15 | The version of Node.js that should be built. 16 | 17 | #> 18 | 19 | [string] $InstallationTemplateName 20 | [string] $InstallationScriptName 21 | [string] $OutputArtifactName 22 | 23 | NixNodeBuilder( 24 | [version] $version, 25 | [string] $platform, 26 | [string] $architecture 27 | ) : Base($version, $platform, $architecture) { 28 | $this.InstallationTemplateName = "nix-setup-template.sh" 29 | $this.InstallationScriptName = "setup.sh" 30 | $this.OutputArtifactName = "node-$Version-$Platform-$Architecture.tar.gz" 31 | } 32 | 33 | [uri] GetBinariesUri() { 34 | <# 35 | .SYNOPSIS 36 | Get base Node.js URI and return complete URI for Node.js installation executable. 37 | #> 38 | 39 | $base = $this.GetBaseUri() 40 | return "${base}/v$($this.Version)/node-v$($this.Version)-$($this.Platform)-$($this.Architecture).tar.gz" 41 | } 42 | 43 | [void] ExtractBinaries($archivePath) { 44 | Extract-TarArchive -ArchivePath $archivePath -OutputDirectory $this.WorkFolderLocation 45 | } 46 | 47 | [void] CreateInstallationScript() { 48 | <# 49 | .SYNOPSIS 50 | Create Node.js artifact installation script based on template specified in InstallationTemplateName property. 51 | #> 52 | 53 | $installationScriptLocation = New-Item -Path $this.WorkFolderLocation -Name $this.InstallationScriptName -ItemType File 54 | $installationTemplateLocation = Join-Path -Path $this.InstallationTemplatesLocation -ChildPath $this.InstallationTemplateName 55 | 56 | $installationTemplateContent = Get-Content -Path $installationTemplateLocation -Raw 57 | $installationTemplateContent = $installationTemplateContent -f $this.Version.ToString(3), $this.Architecture 58 | $installationTemplateContent | Out-File -FilePath $installationScriptLocation 59 | 60 | Write-Debug "Done; Installation script location: $installationScriptLocation)" 61 | } 62 | 63 | [void] ArchiveArtifact() { 64 | $OutputPath = Join-Path $this.ArtifactFolderLocation $this.OutputArtifactName 65 | Create-TarArchive -SourceFolder $this.WorkFolderLocation -ArchivePath $OutputPath 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /builders/node-builder.psm1: -------------------------------------------------------------------------------- 1 | class NodeBuilder { 2 | <# 3 | .SYNOPSIS 4 | Base Node.js builder class. 5 | 6 | .DESCRIPTION 7 | Base Node.js builder class that contains general builder methods. 8 | 9 | .PARAMETER Version 10 | The version of Node.js that should be built. 11 | 12 | .PARAMETER Platform 13 | The platform of Node.js that should be built. 14 | 15 | .PARAMETER Architecture 16 | The architecture with which Node.js should be built. 17 | 18 | .PARAMETER TempFolderLocation 19 | The location of temporary files that will be used during Node.js package generation. 20 | 21 | .PARAMETER WorkFolderLocation 22 | The location of installation files. 23 | 24 | .PARAMETER ArtifactFolderLocation 25 | The location of generated Node.js artifact. 26 | 27 | .PARAMETER InstallationTemplatesLocation 28 | The location of installation script template. Using "installers" folder from current repository. 29 | 30 | #> 31 | 32 | [version] $Version 33 | [string] $Platform 34 | [string] $Architecture 35 | [string] $TempFolderLocation 36 | [string] $WorkFolderLocation 37 | [string] $ArtifactFolderLocation 38 | [string] $InstallationTemplatesLocation 39 | 40 | NodeBuilder ([version] $version, [string] $platform, [string] $architecture) { 41 | $this.Version = $version 42 | $this.Platform = $platform 43 | $this.Architecture = $architecture 44 | 45 | $this.TempFolderLocation = [IO.Path]::GetTempPath() 46 | $this.WorkFolderLocation = Join-Path $env:RUNNER_TEMP "binaries" 47 | $this.ArtifactFolderLocation = Join-Path $env:RUNNER_TEMP "artifact" 48 | 49 | $this.InstallationTemplatesLocation = Join-Path -Path $PSScriptRoot -ChildPath "../installers" 50 | } 51 | 52 | [uri] GetBaseUri() { 53 | <# 54 | .SYNOPSIS 55 | Return base URI for Node.js binaries. 56 | #> 57 | 58 | return "https://nodejs.org/download/release" 59 | } 60 | 61 | [string] Download() { 62 | <# 63 | .SYNOPSIS 64 | Download Node.js binaries into artifact location. 65 | #> 66 | 67 | $binariesUri = $this.GetBinariesUri() 68 | $targetFilename = [IO.Path]::GetFileName($binariesUri) 69 | $targetFilepath = Join-Path -Path $this.TempFolderLocation -ChildPath $targetFilename 70 | 71 | Write-Debug "Download binaries from $binariesUri to $targetFilepath" 72 | try { 73 | (New-Object System.Net.WebClient).DownloadFile($binariesUri, $targetFilepath) 74 | } catch { 75 | Write-Host "Error during downloading file from '$binariesUri'" 76 | exit 1 77 | } 78 | 79 | Write-Debug "Done; Binaries location: $targetFilepath" 80 | return $targetFilepath 81 | } 82 | 83 | [void] Build() { 84 | <# 85 | .SYNOPSIS 86 | Generates Node.js artifact from downloaded binaries. 87 | #> 88 | 89 | Write-Host "Create WorkFolderLocation and ArtifactFolderLocation folders" 90 | New-Item -Path $this.WorkFolderLocation -ItemType "directory" 91 | New-Item -Path $this.ArtifactFolderLocation -ItemType "directory" 92 | 93 | Write-Host "Download Node.js $($this.Version) [$($this.Architecture)] executable..." 94 | $binariesArchivePath = $this.Download() 95 | 96 | Write-Host "Unpack binaries to target directory" 97 | $this.ExtractBinaries($binariesArchivePath) 98 | 99 | Write-Host "Create installation script..." 100 | $this.CreateInstallationScript() 101 | 102 | Write-Host "Archive artifact" 103 | $this.ArchiveArtifact() 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /builders/win-node-builder.psm1: -------------------------------------------------------------------------------- 1 | using module "./node-builder.psm1" 2 | 3 | class WinNodeBuilder : NodeBuilder { 4 | <# 5 | .SYNOPSIS 6 | Ubuntu Node.js builder class. 7 | 8 | .DESCRIPTION 9 | Contains methods that required to build Ubuntu Node.js artifact from sources. Inherited from base NixNodeBuilder. 10 | 11 | .PARAMETER platform 12 | The full name of platform for which Node.js should be built. 13 | 14 | .PARAMETER version 15 | The version of Node.js that should be built. 16 | 17 | #> 18 | 19 | [string] $InstallationTemplateName 20 | [string] $InstallationScriptName 21 | [string] $OutputArtifactName 22 | 23 | WinNodeBuilder( 24 | [version] $version, 25 | [string] $platform, 26 | [string] $architecture 27 | ) : Base($version, $platform, $architecture) { 28 | $this.InstallationTemplateName = "win-setup-template.ps1" 29 | $this.InstallationScriptName = "setup.ps1" 30 | $this.OutputArtifactName = "node-$Version-$Platform-$Architecture.7z" 31 | } 32 | 33 | [uri] GetBinariesUri() { 34 | <# 35 | .SYNOPSIS 36 | Get base Node.js URI and return complete URI for Node.js installation executable. 37 | #> 38 | 39 | $base = $this.GetBaseUri() 40 | return "${base}/v$($this.Version)/node-v$($this.Version)-win-$($this.Architecture).7z" 41 | } 42 | 43 | [void] ExtractBinaries($archivePath) { 44 | $extractTargetDirectory = Join-Path $this.TempFolderLocation "tempExtract" 45 | Extract-SevenZipArchive -ArchivePath $archivePath -OutputDirectory $extractTargetDirectory 46 | $nodeOutputPath = Get-Item $extractTargetDirectory\* | Select-Object -First 1 -ExpandProperty Fullname 47 | Move-Item -Path $nodeOutputPath\* -Destination $this.WorkFolderLocation 48 | } 49 | 50 | [void] CreateInstallationScript() { 51 | <# 52 | .SYNOPSIS 53 | Create Node.js artifact installation script based on specified template. 54 | #> 55 | 56 | $installationScriptLocation = New-Item -Path $this.WorkFolderLocation -Name $this.InstallationScriptName -ItemType File 57 | $installationTemplateLocation = Join-Path -Path $this.InstallationTemplatesLocation -ChildPath $this.InstallationTemplateName 58 | $installationTemplateContent = Get-Content -Path $installationTemplateLocation -Raw 59 | 60 | $variablesToReplace = @{ 61 | "{{__VERSION__}}" = $this.Version; 62 | "{{__ARCHITECTURE__}}" = $this.Architecture; 63 | } 64 | 65 | $variablesToReplace.keys | ForEach-Object { $installationTemplateContent = $installationTemplateContent.Replace($_, $variablesToReplace[$_]) } 66 | $installationTemplateContent | Out-File -FilePath $installationScriptLocation 67 | Write-Debug "Done; Installation script location: $installationScriptLocation)" 68 | } 69 | 70 | [void] ArchiveArtifact() { 71 | $OutputPath = Join-Path $this.ArtifactFolderLocation $this.OutputArtifactName 72 | Create-SevenZipArchive -SourceFolder $this.WorkFolderLocation -ArchivePath $OutputPath -ArchiveType "7z" 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /config/node-manifest-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "regex": "node-\\d+\\.\\d+\\.\\d+-(\\w+)-((x|arm)\\d+)", 3 | "groups": { 4 | "arch": 2, 5 | "platform": 1 6 | }, 7 | "lts_rule_expression": "(Invoke-RestMethod 'https://raw.githubusercontent.com/nodejs/Release/main/schedule.json').PSObject.Properties | Where-Object { $_.Value.codename } | ForEach-Object { @{ Name = $_.Name.TrimStart('v'); Value = $_.Value.codename } }" 8 | } -------------------------------------------------------------------------------- /installers/nix-setup-template.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | 3 | NODE_VERSION={0} 4 | ARCH={1} 5 | 6 | NODE_TOOLCACHE_PATH=$AGENT_TOOLSDIRECTORY/node 7 | NODE_TOOLCACHE_VERSION_PATH=$NODE_TOOLCACHE_PATH/$NODE_VERSION 8 | NODE_TOOLCACHE_VERSION_ARCH_PATH=$NODE_TOOLCACHE_VERSION_PATH/$ARCH 9 | 10 | echo "Check if Node.js hostedtoolcache folder exist..." 11 | if [ ! -d $NODE_TOOLCACHE_PATH ]; then 12 | mkdir -p $NODE_TOOLCACHE_PATH 13 | fi 14 | 15 | echo "Delete Node.js $NODE_VERSION if installed" 16 | rm -rf $NODE_TOOLCACHE_VERSION_PATH 17 | 18 | echo "Create Node.js $NODE_VERSION folder" 19 | mkdir -p $NODE_TOOLCACHE_VERSION_ARCH_PATH 20 | 21 | echo "Copy Node.js binaries to hostedtoolcache folder" 22 | cp -R ./* $NODE_TOOLCACHE_VERSION_ARCH_PATH 23 | rm $NODE_TOOLCACHE_VERSION_ARCH_PATH/setup.sh 24 | 25 | echo "Create complete file" 26 | touch $NODE_TOOLCACHE_VERSION_PATH/$ARCH.complete 27 | -------------------------------------------------------------------------------- /installers/win-setup-template.ps1: -------------------------------------------------------------------------------- 1 | $ErrorActionPreference = "Stop" 2 | 3 | [Version]$Version = "{{__VERSION__}}" 4 | [string]$Architecture = "{{__ARCHITECTURE__}}" 5 | 6 | $ToolcacheRoot = $env:AGENT_TOOLSDIRECTORY 7 | if ([string]::IsNullOrEmpty($ToolcacheRoot)) { 8 | # GitHub images don't have `AGENT_TOOLSDIRECTORY` variable 9 | $ToolcacheRoot = $env:RUNNER_TOOL_CACHE 10 | } 11 | $NodeToolcachePath = Join-Path -Path $ToolcacheRoot -ChildPath "node" 12 | $NodeToolcacheVersionPath = Join-Path -Path $NodeToolcachePath -ChildPath $Version.ToString() 13 | $NodeToolcacheArchitecturePath = Join-Path $NodeToolcacheVersionPath $Architecture 14 | 15 | Write-Host "Check if Node.js hostedtoolcache folder exist..." 16 | if (-not (Test-Path $NodeToolcachePath)) { 17 | New-Item -ItemType Directory -Path $NodeToolcachePath | Out-Null 18 | } 19 | 20 | Write-Host "Delete Node.js $Version if installed" 21 | if (Test-Path $NodeToolcacheVersionPath) { 22 | Remove-Item $NodeToolcachePath -Recurse -Force | Out-Null 23 | } 24 | 25 | Write-Host "Create Node.js $Version folder" 26 | if (-not (Test-Path $NodeToolcacheArchitecturePath)) { 27 | New-Item -ItemType Directory -Path $NodeToolcacheArchitecturePath | Out-Null 28 | } 29 | 30 | Write-Host "Copy Node.js binaries to hostedtoolcache folder" 31 | Copy-Item -Path * -Destination $NodeToolcacheArchitecturePath -Recurse 32 | Remove-Item $NodeToolcacheArchitecturePath\setup.ps1 -Force | Out-Null 33 | 34 | Write-Host "Create complete file" 35 | New-Item -ItemType File -Path $NodeToolcacheVersionPath -Name "$Architecture.complete" | Out-Null -------------------------------------------------------------------------------- /tests/Node.Tests.ps1: -------------------------------------------------------------------------------- 1 | Import-Module (Join-Path $PSScriptRoot "../helpers/pester-extensions.psm1") 2 | 3 | 4 | 5 | Describe "Node.js" { 6 | 7 | BeforeAll { 8 | function Get-UseNodeLogs { 9 | # GitHub Windows images don't have `HOME` variable 10 | $homeDir = $env:HOME ?? $env:HOMEDRIVE 11 | $logsFolderPath = Join-Path -Path $homeDir -ChildPath "runners/*/_diag/pages" -Resolve 12 | 13 | $useNodeLogFile = Get-ChildItem -Path $logsFolderPath | Where-Object { 14 | $logContent = Get-Content $_.Fullname -Raw 15 | return $logContent -match "setup-node@v" 16 | } | Select-Object -First 1 17 | return $useNodeLogFile.Fullname 18 | } 19 | } 20 | 21 | It "is available" { 22 | "node --version" | Should -ReturnZeroExitCode 23 | } 24 | 25 | It "version is correct" { 26 | $versionOutput = Invoke-Expression "node --version" 27 | $versionOutput | Should -Match $env:VERSION 28 | } 29 | 30 | It "is used from tool-cache" { 31 | $nodePath = (Get-Command "node").Path 32 | $nodePath | Should -Not -BeNullOrEmpty 33 | 34 | # GitHub Windows images don't have `AGENT_TOOLSDIRECTORY` variable 35 | $toolcacheDir = $env:AGENT_TOOLSDIRECTORY ?? $env:RUNNER_TOOL_CACHE 36 | $expectedPath = Join-Path -Path $toolcacheDir -ChildPath "node" 37 | $nodePath.startsWith($expectedPath) | Should -BeTrue -Because "'$nodePath' is not started with '$expectedPath'" 38 | } 39 | 40 | It "cached version is used without downloading" { 41 | 42 | if ($env:RUNNER_TYPE -eq "self-hosted") { 43 | # Get the installed version of Node.js 44 | $nodeVersion = Invoke-Expression "node --version" 45 | # Check if Node.js is installed 46 | $nodeVersion | Should -Not -BeNullOrEmpty 47 | # Check if the installed version of Node.js is the expected version 48 | $nodeVersion | Should -Match $env:VERSION 49 | }else { 50 | # Analyze output of previous steps to check if Node.js was consumed from cache or downloaded 51 | $useNodeLogFile = Get-UseNodeLogs 52 | $useNodeLogFile | Should -Exist 53 | $useNodeLogContent = Get-Content $useNodeLogFile -Raw 54 | $useNodeLogContent | Should -Match "Found in cache" 55 | } 56 | } 57 | 58 | It "Run simple code" { 59 | "node ./simple-test.js" | Should -ReturnZeroExitCode 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /tests/simple-test.js: -------------------------------------------------------------------------------- 1 | function fibonacci(num){ 2 | var a = 1, b = 0, temp; 3 | 4 | while (num >= 0){ 5 | temp = a; 6 | a = a + b; 7 | b = temp; 8 | num--; 9 | } 10 | 11 | return b; 12 | } 13 | 14 | console.log(fibonacci(7)); 15 | console.log(fibonacci(23)); --------------------------------------------------------------------------------