├── .github ├── dependabot.yml └── workflows │ └── cron.yml ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── snapcraft.yaml └── snapcraft.yaml.sh /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: 'github-actions' 4 | directory: '/' 5 | schedule: 6 | interval: 'daily' 7 | commit-message: 8 | prefix: 'chore' 9 | include: 'scope' 10 | -------------------------------------------------------------------------------- /.github/workflows/cron.yml: -------------------------------------------------------------------------------- 1 | name: Snap Cron 2 | 3 | permissions: 4 | contents: write 5 | 6 | on: 7 | workflow_dispatch: 8 | push: 9 | schedule: 10 | - cron: '*/15 * * * *' 11 | 12 | jobs: 13 | check: 14 | strategy: 15 | fail-fast: false 16 | matrix: 17 | track: [main, 23, 22, 20, 18] 18 | name: Check branch 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - name: Checkout code 23 | uses: actions/checkout@v4 24 | with: 25 | ref: node${{ matrix.track }} 26 | fetch-depth: 0 27 | if: ${{ matrix.track != 'main' }} 28 | 29 | - name: Checkout code 30 | uses: actions/checkout@v4 31 | with: 32 | fetch-depth: 0 33 | if: ${{ matrix.track == 'main' }} 34 | 35 | - name: Init git config 36 | run: | 37 | git config user.name "GitHub Actions" 38 | git config user.email noreply@github.com 39 | git remote add launchpad git+ssh://openjs@git.launchpad.net/node-snap 40 | mkdir ~/.ssh/ 41 | chmod 700 ~/.ssh 42 | echo "Host git.launchpad.net" > ~/.ssh/config 43 | echo " User openjs" >> ~/.ssh/config 44 | echo " IdentityFile ~/.ssh/launchpad_rsa" >> ~/.ssh/config 45 | echo -e "${{ secrets.LAUNCHPAD_RSA }}" > ~/.ssh/launchpad_rsa 46 | chmod 600 ~/.ssh/launchpad_rsa 47 | # In ephemeral environments like GitHub Action runners, relying on TOFU isn't providing any security 48 | # so require the key obtained by `ssh-keyscan` to match the expected hash from https://help.launchpad.net/SSHFingerprints 49 | ssh-keyscan git.launchpad.net >> ~/.ssh/known_hosts 50 | ssh-keygen -qlF git.launchpad.net | grep -xF 'git.launchpad.net RSA SHA256:UNOzlP66WpDuEo34Wgs8mewypV0UzqHLsIFoqwe8dYo' 51 | 52 | - name: Sync Release 53 | run: ./snapcraft.yaml.sh -r${{ matrix.track }} -gnode${{ matrix.track }} 54 | if: ${{ matrix.track != 'main' }} 55 | 56 | - name: Sync Edge 57 | run: ./snapcraft.yaml.sh -gmain 58 | if: ${{ matrix.track == 'main' }} 59 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | The Node.js Code of Conduct, which applies to this project, can be found at 4 | https://github.com/nodejs/admin/blob/main/CODE_OF_CONDUCT.md. 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Rod Vagg 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Node.js Snap for https://snapcraft.io/ 2 | 3 | [![Get it from the Snap Store](https://snapcraft.io/static/images/badges/en/snap-store-white.svg)](https://snapcraft.io/node) 4 | 5 | [Snaps](https://snapcraft.io/about) are: 6 | 7 | > app packages for desktop, cloud and IoT that are easy to install, secure, cross‐platform and dependency‐free. Snaps are discoverable and installable from the Snap Store, the app store for Linux with an audience of millions. 8 | 9 | The Snap managed from this repository is available as `node` from the Snap store and contains the Node.js runtime, along with the two most widely-used package managers, [npm](https://www.npmjs.com/) and [Yarn](https://yarnpkg.com). They are automatically built and pushed for each supported release line and nightly versions straight from the `master` branch. Once initially installed, new versions of Node.js for the release line you've chosen are automatically updated to your computer within hours of their release on [nodejs.org](https://nodejs.org/). 10 | 11 | * [Installation](#installation) 12 | * [Switching release lines](#switching-release-lines) 13 | * [Nightly ("edge") versions](#nightly-edge-versions) 14 | * [How publishing happens](#how-publishing-happens) 15 | * [Snap configuration](#snap-configuration) 16 | * [Watching for releases](#watching-for-releases) 17 | * [Building Snaps](#building-snaps) 18 | * [Adding new release lines](#adding-new-release-lines) 19 | * [Removing old release lines](#removing-old-release-lines) 20 | * [Default release line](#default-release-line) 21 | 22 | ## Installation 23 | 24 | The `snap` command ships with Ubuntu and is available to be installed in most popular Linux distributions. If you do not have it installed, follow the instructions on Snapcraft to install [_snapd_](https://docs.snapcraft.io/core/install). 25 | 26 | Snaps are delivered via "channels". For Node.js, the channel names are the major-version number of Node.js. So select a supported Node.js version and install with: 27 | 28 | ``` 29 | sudo snap install node --classic --channel=14 30 | ``` 31 | 32 | Substituting `14` for the major version you want to install. Both LTS and Current versions of Node.js are available. 33 | 34 | Once installed, the `node`, `npm` and `yarn` commands are available for use and will remain updated for the channel you selected. 35 | 36 | The `--classic` argument is required here as Node.js needs full access to your system in order to be useful, therefore it needs Snap's "classic confinement". By default, Snaps are much more restricted in their ability to access your disk and network and must request special access from you where they need it. 37 | 38 | ### Switching release lines 39 | 40 | You can use the `refresh` command to switch to a new channel at any time: 41 | 42 | ``` 43 | sudo snap refresh node --channel=15 44 | ``` 45 | 46 | Once switched, snapd will update Node.js for the new channel you have selected. 47 | 48 | ### Nightly ("edge") versions 49 | 50 | The `master` branch from the Node.js [git repository](https://github.com/nodejs/node) are pushed to the Snap store nightly and are available from the `edge` channel. 51 | 52 | ``` 53 | sudo snap install node --classic --channel=edge 54 | ``` 55 | 56 | ## How publishing happens 57 | 58 | The pipeline from releases to the Snap store is complicated and involves many moving pieces. This repository serves as the connection between [nodejs.org/download/](https://nodejs.org/download/), where releases are published, and the Canonical Snap toolchain that builds the snaps ([Launchpad](https://launchpad.net)) and publishes them ([Snapcraft](https://snapcraft.io)). 59 | 60 | ### Snap configuration 61 | 62 | This repository contains a master script [snapcraft.yaml.sh](./snapcraft.yaml.sh), and a Snap build definition file that it creates, [snapcraft.yaml](./snapcraft.yaml). **snapcraft.yaml should never be edited manually**, it is the product of the script. 63 | 64 | This repository contains a branch for each track/channel published to the Snap store. The `master` branch represents the "edge" channel, while the `nodeXX` branches represent the major release lines (e.g. `node14` for Node.js 14.x.x). These release lines are published to the "stable" channel on a track named after the release line. e.g. Node.js 14.x.x releases are published as `14/stable`. 65 | 66 | Each branch, contains both a snapcraft.yaml.sh script and a snapcraft.yaml definition file. These are different between releases as compile requirements change. 67 | 68 | **Changes to the build definition should be made in the snapcraft.yaml.sh script for the relevant branch.** For changes to "edge" (nightly / master) releases, change the snapcraft.yaml.sh script on the `master` branch. For changes to the "14/stable" releases, change the snapcraft.yaml.sh on the `node14` branch. All changes should be made via Pull Request targeting the appropriate branch. 69 | 70 | ### Watching for releases 71 | 72 | This repository uses GitHub Actions on a timer (cron) schedule. See [.github/workflows/cron.yml](./.github/workflows/cron.yml). The Action configuration is set to run for the `master` branch and for each major release line that is currently being published to the Snap store using a matrix configuration. 73 | 74 | Upon run, for each branch, this repository is cloned and the snapcraft.yaml.sh script is run with arguments that tell it what to do. `-rXX` is supplied to specify the release line (e.g. `-r14`, this is omitted for "edge" releases) and `-gnode14` is supplied to specify the Git branch to operate on (more on this below). 75 | 76 | The snapcraft.yaml.sh script will fetch the relevant releases list, either https://nodejs.org/download/release/index.tab for regular releases, or https://nodejs.org/download/nightly/index.tab for "edge" releases. The latest release for the given release line (or latest nightly release) is then used to build the snapcraft.yaml Snap definition file. 77 | 78 | In most cases, building a new snapcraft.yaml file will result in the same file already in this repository. But when there is a new release for that release line, the file will differ. When it differs it is committed and pushed back to this repository on the appropriate branch. 79 | 80 | When changes are made, the commit is _also_ pushed to Launchpad to build the Snap. 81 | 82 | ### Building Snaps 83 | 84 | A mirror of this repository is maintained on Canonical's [Launchpad](https://launchpad.net) at . Launchpad has integration with the [Snap store](https://snapcraft.io) and has builders for many different platforms that can build Snap packages with minimal additional configuration. 85 | 86 | When changes are made to the snapcraft.yaml file for each branch on this repository, the changes are also pushed to https://code.launchpad.net/node-snap for the same branch. 87 | 88 | For each branch we are releasing to the Snap store, we have a Snap build configuration set up in Launchpad (the setup is a manual process for an authorized user at the beginning of each release line). Changes to the branch result in new Snap package builds from the snapcraft.yaml definition file. Once successfully built, the packages are pushed to the Snap store for the relevant track/channel. 89 | 90 | ### Adding new release lines 91 | 92 | The process for adding new release lines when the Node.js Release team begin one is a multi-step process, some of these steps can be contributed to this repository by anybody via Pull Request: 93 | 94 | 1. Request a new Track for the "node" Snap in the Snapcraft forum in the ["Store requests" section](https://forum.snapcraft.io/c/store-requests). The track should be the major release line number (e.g. `14`). The "node" Snap has fast-track approval and is usually authorized within 24 hours by the administrators. This step needs to be performed in order to upload to a new track. An example of this for `14` can be seen here: https://forum.snapcraft.io/t/track-request-for-node-14-fast-track-please/16842/3 95 | 2. Create a new branch in this repository, named `nodeXX` where `XX` is the release line number. 96 | 3. Edit [snapcraft.yaml.sh](./snapcraft.yaml.sh) _if_ required for system configuration required to build the new version. In most cases this is not necessary and the `master` version can be copied. Where the compiler minimums change, the equivalent changes may need to be made in the script. 97 | 4. Edit [.github/workflows/cron.yml](./.github/workflows/cron.yml) to add the new release line to the matrix. 98 | 5. Start a build (manually, or wait for the GitHub Action to trigger by cron), which will update the snapcraft.yaml file for that branch correctly _and_ push the new branch to https://code.launchpad.net/node-snap where it can be further configured. 99 | 6. Navigate to https://code.launchpad.net/node-snap and into the new branch and click on "Create snap package". 100 | - The "name" should be the same as the branch 101 | - The "series" should be inferred from snapcraft.yaml 102 | - The "processors" should be _at least_: armhf, arm64, amd64, i386, ppc64el, s390x 103 | - "Automatically build when branch changes" should be ticked. 104 | - "Automatically upload to store" should be ticked 105 | - "Registered store package name" should be "node" 106 | - "Risk" should be "stable" (this is "edge" for nightly builds) 107 | - "Track" should be the major release line 108 | - Clicking "Create snap package" should create the workflow and authenticate the publishing with the Snap store (this is a simple multi-step authorization process). 109 | 7. Manually request new builds for the Snap from the Snap configuration page in Launchpad ("Request builds"). 110 | 111 | Note that at the time of writing, Snap store authorization for Launchpad has an expiry of 2 years. This can cause Snaps to fail to upload and may not result in a warning. This can be a problem for LTS lines. 112 | 113 | #### Removing old release lines 114 | 115 | When release lines stop seeing new releases, they can be removed from [.github/workflows/cron.yml](./.github/workflows/cron.yml). This stops the entire pipeline from running (although changes to the relevant branch will not even occur without new releases on nodejs.org). The Snap configuration in Launchpad can also be removed but this is not strictly necessary. 116 | 117 | ### Default release line 118 | 119 | Snaps can have a "default" track. This default determines which track is installed if the user doesn't set one (e.g. with `sudo snap install node`). It is up to the Snap author to set this default and update it as appropriate. Users don't follow the default track, it only determines the starting track at time of install. Changing default in the Snap store doesn't impact existing users, only new installs 120 | 121 | The Node.js Snap should have its "default" set to the most recent LTS. This can be done in the Releases page by a Node.js Snap administrator: https://snapcraft.io/node/releases and should be done as soon as a release line enters **Active LTS** as per the [Release Schedule](https://github.com/nodejs/release#release-schedule). 122 | 123 | This is a manual procedure and may require reminders posted to this repository from the community. 124 | -------------------------------------------------------------------------------- /snapcraft.yaml: -------------------------------------------------------------------------------- 1 | name: node 2 | version: '25.0.0-nightly2025060860155daf' 3 | summary: Node.js 4 | description: | 5 | A JavaScript runtime built on Chrome's V8 JavaScript engine. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient. Node.js' package ecosystem, npm, is the largest ecosystem of open source libraries in the world. https://nodejs.org/ 6 | 7 | grade: stable 8 | confinement: classic 9 | base: core22 10 | 11 | apps: 12 | node: 13 | command: bin/node 14 | npm: 15 | command: bin/npm 16 | npx: 17 | command: bin/npx 18 | yarn: 19 | command: bin/yarn.js 20 | yarnpkg: 21 | command: bin/yarn.js 22 | 23 | parts: 24 | node: 25 | plugin: make 26 | source-type: tar 27 | source: https://nodejs.org/download/nightly/v25.0.0-nightly2025060860155daf8d/node-v25.0.0-nightly2025060860155daf8d.tar.gz 28 | build-packages: 29 | # Ensure these and the build environment below match the minimum GCC and G++ versions for this Node release. 30 | # https://github.com/nodejs/node/blob/main/BUILDING.md#building-nodejs-on-supported-platforms 31 | - gcc-12 32 | - g++-12 33 | - python3-distutils 34 | build-environment: 35 | - CC: gcc-12 36 | - CXX: g++-12 37 | - LINK: g++-12 38 | - V: "" 39 | make-parameters: 40 | - V= 41 | override-build: | 42 | ./configure --verbose --prefix=/ --release-urlbase=https://nodejs.org/download/nightly/ --tag=nightly2025060860155daf8d 43 | craftctl default 44 | mkdir -p $CRAFT_PART_INSTALL/etc 45 | echo "prefix = /usr/local" >> $CRAFT_PART_INSTALL/etc/npmrc 46 | yarn: 47 | source-type: tar 48 | source: https://yarnpkg.com/latest.tar.gz 49 | plugin: dump 50 | # Yarn has a problem with lifecycle scripts when used inside snap, they don't complete properly, with exit code !=0. 51 | # Replacing the spinner with proper stdio appears to fix it. 52 | override-build: | 53 | craftctl default 54 | chmod -R g-s $CRAFT_PART_INSTALL 55 | sed -i "s/var stdio = spinner ? undefined : 'inherit';/var stdio = 'inherit';/" $CRAFT_PART_INSTALL/lib/cli.js 56 | -------------------------------------------------------------------------------- /snapcraft.yaml.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euxo pipefail 4 | 5 | __dirname="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 6 | UPDATE_GIT=no 7 | 8 | while getopts "r:g:" opt; do 9 | case $opt in 10 | r) 11 | echo "Updating for latest $OPTARG release" >&2 12 | # release 13 | NODE_VERSION="$(curl -sL --show-error --fail https://nodejs.org/download/release/index.tab | awk 'BEGIN { found = 0 } /^v'"$OPTARG"'\..*[^a-z0-9]src[^a-z0-9]/ && !found { found = 1; print substr($1, 2) }')" 14 | NODE_DISTTYPE="release" 15 | NODE_TAG="" 16 | ;; 17 | g) 18 | echo "Pushing to git $OPTARG" >&2 19 | UPDATE_GIT=yes 20 | GIT_BRANCH=$OPTARG 21 | REMOTE_BRANCH=$GIT_BRANCH 22 | if [ "X${GIT_BRANCH}" = "Xmain" ]; then 23 | REMOTE_BRANCH=master 24 | fi 25 | ;; 26 | \?) 27 | echo "Invalid option: -$OPTARG" >&2 28 | exit 29 | esac 30 | done 31 | 32 | # not a release? 33 | if [ -z ${NODE_DISTTYPE+x} ]; then 34 | # nightly 35 | NODE_VERSION="$(curl -sL --show-error --fail https://nodejs.org/download/nightly/index.tab | awk 'BEGIN { found = 0 } /^v[1-9].*[^a-z0-9]src[^a-z0-9]/ && !found { found = 1; print substr($1, 2) }')" 36 | NODE_DISTTYPE="nightly" 37 | NODE_TAG="$(echo "$NODE_VERSION" | sed -E 's/^[^-]+-//')" 38 | fi 39 | 40 | echo "NODE_VERSION=$NODE_VERSION" 41 | echo "NODE_DISTTYPE=$NODE_DISTTYPE" 42 | echo "NODE_TAG=$NODE_TAG" 43 | 44 | if [ "X${UPDATE_GIT}" = "Xyes" ]; then 45 | git clean -fdx 46 | git reset HEAD --hard 47 | git fetch origin 48 | git checkout "origin/$GIT_BRANCH" --force 49 | git branch -D "$GIT_BRANCH" || true 50 | git checkout -b "$GIT_BRANCH" 51 | fi 52 | 53 | # Write snapcraft.yaml for this config 54 | 55 | cat > "${__dirname}/snapcraft.yaml" << EOF 56 | name: node 57 | version: '${NODE_VERSION:0:30}' 58 | summary: Node.js 59 | description: | 60 | A JavaScript runtime built on Chrome's V8 JavaScript engine. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient. Node.js' package ecosystem, npm, is the largest ecosystem of open source libraries in the world. https://nodejs.org/ 61 | 62 | grade: stable 63 | confinement: classic 64 | base: core22 65 | 66 | apps: 67 | node: 68 | command: bin/node 69 | npm: 70 | command: bin/npm 71 | npx: 72 | command: bin/npx 73 | yarn: 74 | command: bin/yarn.js 75 | yarnpkg: 76 | command: bin/yarn.js 77 | 78 | parts: 79 | node: 80 | plugin: make 81 | source-type: tar 82 | source: https://nodejs.org/download/${NODE_DISTTYPE}/v${NODE_VERSION}/node-v${NODE_VERSION}.tar.gz 83 | build-packages: 84 | # Ensure these and the build environment below match the minimum GCC and G++ versions for this Node release. 85 | # https://github.com/nodejs/node/blob/main/BUILDING.md#building-nodejs-on-supported-platforms 86 | - gcc-12 87 | - g++-12 88 | - python3-distutils 89 | build-environment: 90 | - CC: gcc-12 91 | - CXX: g++-12 92 | - LINK: g++-12 93 | - V: "" 94 | make-parameters: 95 | - V= 96 | override-build: | 97 | ./configure --verbose --prefix=/ --release-urlbase=https://nodejs.org/download/${NODE_DISTTYPE}/ --tag=${NODE_TAG} 98 | craftctl default 99 | mkdir -p \$CRAFT_PART_INSTALL/etc 100 | echo "prefix = /usr/local" >> \$CRAFT_PART_INSTALL/etc/npmrc 101 | yarn: 102 | source-type: tar 103 | source: https://yarnpkg.com/latest.tar.gz 104 | plugin: dump 105 | # Yarn has a problem with lifecycle scripts when used inside snap, they don't complete properly, with exit code !=0. 106 | # Replacing the spinner with proper stdio appears to fix it. 107 | override-build: | 108 | craftctl default 109 | chmod -R g-s \$CRAFT_PART_INSTALL 110 | sed -i "s/var stdio = spinner ? undefined : 'inherit';/var stdio = 'inherit';/" \$CRAFT_PART_INSTALL/lib/cli.js 111 | EOF 112 | 113 | if [ "X${UPDATE_GIT}" = "Xyes" ] && [ -n "$(git status --porcelain "$__dirname")" ]; then 114 | echo "Updating git repo and pushing ..." 115 | git commit "$__dirname" -m "snap: (auto) updated to ${NODE_VERSION}" 116 | git push origin "$GIT_BRANCH" 117 | git push launchpad "$GIT_BRANCH:$REMOTE_BRANCH" 118 | fi 119 | --------------------------------------------------------------------------------