diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index a55ccc0..0000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,50 +0,0 @@ -version: 2.1 - -orbs: - cfa: continuousauth/npm@2.1.1 - node: electronjs/node@2.3.1 - -workflows: - test_and_release: - # Run the test jobs first, then the release only when all the test jobs are successful - jobs: - - node/test: - name: test-<< matrix.executor >>-<< matrix.node-version >> - override-ci-command: yarn install --frozen-lockfile --ignore-engines - pre-steps: - - when: - condition: - and: - - equal: [ node/macos, << matrix.executor >> ] - - equal: [ '14.16', << matrix.node-version >> ] - steps: - - node/install-rosetta - - when: - condition: - equal: [ node/linux, << matrix.executor >> ] - steps: - - run: - name: Install Linux Dependencies - command: | - sudo apt-get update && sudo apt-get install --no-install-recommends -y libasound2 libgtk-3-0 libnss3 libxss1 libxtst6 xvfb libgbm-dev - matrix: - alias: test - parameters: - executor: - - node/linux - - node/macos - - node/windows - node-version: - - '20.9' - - '18.17' - - '16.20' - # Stay below 14.17.0 or nvm tries to download arm64 artifacts which don't exist - - '14.16' - - cfa/release: - requires: - - test - filters: - branches: - only: - - main - context: cfa-release diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..1bc2491 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,35 @@ +name: Release + +on: + push: + branches: + - main + +jobs: + test: + uses: ./.github/workflows/test.yml + + release: + name: Release + runs-on: ubuntu-latest + needs: test + environment: npm + permissions: + id-token: write # for CFA and npm provenance + steps: + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + - name: Setup Node.js + uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 + with: + node-version: 20.x + cache: 'yarn' + - name: Install + run: yarn install --frozen-lockfile + - uses: continuousauth/action@732eeb237ac0a0b330a7247f744ddc57898ff9c4 # v1.0.4 + with: + project-id: ${{ secrets.CFA_PROJECT_ID }} + secret: ${{ secrets.CFA_SECRET }} + npm-token: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..a83a1fa --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,51 @@ +name: Test + +on: + pull_request: + branches: + - main + schedule: + - cron: '0 22 * * 3' + workflow_call: + +permissions: + contents: read + +jobs: + test: + name: Test + strategy: + matrix: + node-version: + - '20.10' + - '18.18' + - '16.20' + - '14.16' + os: + - macos-latest + - ubuntu-22.04 + - windows-latest + runs-on: "${{ matrix.os }}" + steps: + - name: Install Rosetta + if: ${{ matrix.os == 'macos-latest' && matrix.node-version == '14.16' }} + run: /usr/sbin/softwareupdate --install-rosetta --agree-to-license + - name: Install Linux Dependencies + if: ${{ matrix.os == 'ubuntu-22.04' }} + run: sudo apt-get update && sudo apt-get install --no-install-recommends -y libasound2 libgtk-3-0 libnss3 libxss1 libxtst6 xvfb libgbm-dev + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: Setup Node.js + uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 + with: + node-version: "${{ matrix.node-version }}" + cache: 'yarn' + architecture: ${{ matrix.os == 'macos-latest' && matrix.node-version == '14.16' && 'x64' || env.RUNNER_ARCH }} + - name: Install (Node.js v16+) + if : ${{ matrix.node-version != '14.16' }} + run: yarn install --frozen-lockfile + - name: Install (Node.js < v16) + if : ${{ matrix.node-version == '14.16' }} + run: yarn install --frozen-lockfile --ignore-engines + - name: Test + run: yarn test diff --git a/README.md b/README.md index 6d6c02a..421cdfa 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # @electron/asar - Electron Archive -[![CircleCI build status](https://circleci.com/gh/electron/asar/tree/main.svg?style=shield)](https://circleci.com/gh/electron/asar/tree/main) +[![Test](https://github.com/electron/asar/actions/workflows/test.yml/badge.svg)](https://github.com/electron/asar/actions/workflows/test.yml) [![npm version](http://img.shields.io/npm/v/@electron/asar.svg)](https://npmjs.org/package/@electron/asar) Asar is a simple extensive archive format, it works like `tar` that concatenates diff --git a/package.json b/package.json index 3ca3ad5..559a56d 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,9 @@ "bugs": { "url": "https://github.com/electron/asar/issues" }, + "publishConfig": { + "provenance": true + }, "scripts": { "build": "tsc", "mocha": "xvfb-maybe electron-mocha --reporter spec && mocha --reporter spec", diff --git a/test/api-spec.js b/test/api-spec.js index b34476a..0b7097a 100644 --- a/test/api-spec.js +++ b/test/api-spec.js @@ -9,7 +9,7 @@ const rimraf = require('rimraf'); const asar = require('..'); const compDirs = require('./util/compareDirectories'); const compFileLists = require('./util/compareFileLists'); -const compFiles = require('./util/compareFiles'); +const { compFiles, isSymbolicLinkSync } = require('./util/compareFiles'); const transform = require('./util/transformStream'); async function assertPackageListEquals(actualList, expectedFilename) { @@ -107,38 +107,47 @@ describe('api', function () { asar.extractAll('test/input/extractthis-unpack-dir.asar', 'tmp/extractthis-unpack-dir-api/'); return compDirs('tmp/extractthis-unpack-dir-api/', 'test/expected/extractthis'); }); - it('should extract an archive with symlink', async () => { - await asar.createPackageWithOptions( - 'test/input/packthis-with-symlink/', - 'tmp/packthis-with-symlink.asar', - { dot: false }, - ); - asar.extractAll('tmp/packthis-with-symlink.asar', 'tmp/packthis-with-symlink/'); - return compFiles( - 'tmp/packthis-with-symlink/real.txt', - 'test/input/packthis-with-symlink/real.txt', - ); - }); - it('should extract an archive with symlink having the same prefix', async () => { - await asar.createPackageWithOptions( - 'test/input/packthis-with-symlink-same-prefix/', - 'tmp/packthis-with-symlink-same-prefix.asar', - { dot: false }, - ); - asar.extractAll( - 'tmp/packthis-with-symlink-same-prefix.asar', - 'tmp/packthis-with-symlink-same-prefix/', - ); - return compFiles( - 'tmp/packthis-with-symlink-same-prefix/real.txt', - 'test/input/packthis-with-symlink-same-prefix/real.txt', - ); - }); - it('should not extract an archive with a bad symlink', async () => { - assert.throws(() => { - asar.extractAll('test/input/bad-symlink.asar', 'tmp/bad-symlink/'); + + // We don't extract symlinks on Windows, so skip these tests + if (os.platform() !== 'win32') { + it('should extract an archive with symlink', async () => { + assert.strictEqual(isSymbolicLinkSync('test/input/packthis-with-symlink/real.txt'), true); + await asar.createPackageWithOptions( + 'test/input/packthis-with-symlink/', + 'tmp/packthis-with-symlink.asar', + { dot: false }, + ); + asar.extractAll('tmp/packthis-with-symlink.asar', 'tmp/packthis-with-symlink/'); + return compFiles( + 'tmp/packthis-with-symlink/real.txt', + 'test/input/packthis-with-symlink/real.txt', + ); }); - }); + it('should extract an archive with symlink having the same prefix', async () => { + assert.strictEqual( + isSymbolicLinkSync('test/input/packthis-with-symlink-same-prefix/real.txt'), + true, + ); + await asar.createPackageWithOptions( + 'test/input/packthis-with-symlink-same-prefix/', + 'tmp/packthis-with-symlink-same-prefix.asar', + { dot: false }, + ); + asar.extractAll( + 'tmp/packthis-with-symlink-same-prefix.asar', + 'tmp/packthis-with-symlink-same-prefix/', + ); + return compFiles( + 'tmp/packthis-with-symlink-same-prefix/real.txt', + 'test/input/packthis-with-symlink-same-prefix/real.txt', + ); + }); + it('should not extract an archive with a bad symlink', async () => { + assert.throws(() => { + asar.extractAll('test/input/bad-symlink.asar', 'tmp/bad-symlink/'); + }); + }); + } it('should handle multibyte characters in paths', async () => { await asar.createPackageWithOptions( 'test/input/packthis-unicode-path/', diff --git a/test/cli-spec.js b/test/cli-spec.js index 296f27b..076647c 100644 --- a/test/cli-spec.js +++ b/test/cli-spec.js @@ -10,7 +10,7 @@ const rimraf = require('rimraf'); const compDirs = require('./util/compareDirectories'); const compFileLists = require('./util/compareFileLists'); -const compFiles = require('./util/compareFiles'); +const { compFiles } = require('./util/compareFiles'); const createSymlinkApp = require('./util/createSymlinkApp'); const exec = promisify(childProcess.exec); diff --git a/test/util/compareFiles.js b/test/util/compareFiles.js index 82bfb2d..57840ce 100644 --- a/test/util/compareFiles.js +++ b/test/util/compareFiles.js @@ -3,7 +3,7 @@ const assert = require('assert'); const fs = require('../../lib/wrapped-fs').default; -module.exports = async function (actualFilePath, expectedFilePath) { +async function compFiles(actualFilePath, expectedFilePath) { if (process.env.ELECTRON_ASAR_SPEC_UPDATE) { await fs.writeFile(expectedFilePath, await fs.readFile(actualFilePath)); } @@ -26,9 +26,11 @@ module.exports = async function (actualFilePath, expectedFilePath) { ]; assert.strictEqual(actualSymlinkPointer, expectedSymlinkPointer); } -}; +} function isSymbolicLinkSync(path) { const stats = fs.lstatSync(path); return stats.isSymbolicLink(); } + +module.exports = { compFiles, isSymbolicLinkSync };