Skip to content

Commit

Permalink
fix: update snapcraft requirements, fix ci multipass errors (#144)
Browse files Browse the repository at this point in the history
* fix: update snapcraft requirements, fix ci

* ci: fix classic confinement tests
  • Loading branch information
VerteDinde authored Apr 17, 2022
1 parent eb0998b commit 0549fd8
Show file tree
Hide file tree
Showing 14 changed files with 164 additions and 39 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [10.x, 12.x, 14.x, 16.x]
node-version: [12.x, 14.x, 16.x]

steps:
- uses: actions/checkout@v2
Expand Down
41 changes: 34 additions & 7 deletions ci/snapcraft.yaml
Original file line number Diff line number Diff line change
@@ -1,21 +1,48 @@
name: electron-app
name: electronApp
version: '1.0.0'
summary: App summary
description: |
App description
base: core18
base: core20
confinement: strict
grade: devel
confinement: devmode

apps:
electronApp:
extensions: [gnome-3-34]
plugs:
- alsa
- browser-support
- desktop
- desktop-legacy
- gsettings
- home
- network
- opengl
- pulseaudio
- unity7
- wayland
- x11
environment:
DISABLE_WAYLAND: "1"
TMPDIR: $XDG_RUNTIME_DIR

parts:
electron-deps:
plugin: nil
after:
- desktop-gtk3
electronApp:
source: .
plugin: dump
stage-packages:
- libnotify4
- libnss3
- libpcre3
- libuuid1
- libxss1
- libxtst6

electron-launch:
plugin: dump
source: .
override-build: |
snapcraftctl build
chmod +x bin/electron-launch
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
},
"dependencies": {
"@malept/cross-spawn-promise": "^1.0.0",
"debug": "^4.1.1",
"debug": "^4.3.4",
"electron-installer-common": "^0.10.2",
"fs-extra": "^9.0.0",
"js-yaml": "^3.10.0",
Expand Down
File renamed without changes.
7 changes: 4 additions & 3 deletions resources/snapcraft.yaml → resources/classic/snapcraft.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: |
App description
grade: devel
confinement: devmode
confinement: classic

apps:
electronApp:
Expand All @@ -26,12 +26,13 @@ apps:
parts:
electronApp:
source: .
plugin: dump
plugin: nil
stage-packages:
- libnotify4
- libnss3
- libpcre3
- libuuid1
- libxss1
- libxtst6
after:
- desktop-gtk2
- desktop-gtk3
3 changes: 3 additions & 0 deletions resources/desktop-launcher.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh

exec "$@" --executed-from="$(pwd)" --pid=$$
44 changes: 44 additions & 0 deletions resources/strict/snapcraft.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: electronApp
version: '1.0.0'
summary: App summary
description: |
App description
base: core18
confinement: strict
grade: devel

apps:
electronApp:
extensions: [gnome-3-34]
plugs:
- browser-support
- desktop
- desktop-legacy
- gsettings
- home
- network
- unity7
- wayland
- x11
environment:
DISABLE_WAYLAND: "1"
TMPDIR: $XDG_RUNTIME_DIR

parts:
electronApp:
source: .
plugin: dump
stage-packages:
- libnotify4
- libnss3
- libpcre3
- libxss1
- libxtst6

electron-launch:
plugin: dump
source: .
override-build: |
snapcraftctl build
chmod +x bin/electron-launch
23 changes: 16 additions & 7 deletions src/launcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,33 @@ limitations under the License.
const fs = require('fs-extra')
const path = require('path')

function getBrowserSandboxFlag (data) {
if (data.apps) {
const plugs = data.apps[`${data.name}`].plugs
return plugs.includes('browser-sandbox') ? '' : '--no-sandbox'
}
return ''
}

async function copyLauncher (snapDir, config) {
const binDir = path.join(snapDir, 'bin')
let launcherPath = path.resolve(__dirname, '..', 'resources', 'desktop-launcher.sh')
if (config.confinement === 'classic') {
const binDir = path.join(snapDir, 'bin')
const launcherPath = path.resolve(__dirname, '..', 'resources', 'classic-launcher.sh')
await fs.mkdirs(binDir)
await fs.copy(launcherPath, path.join(binDir, 'electron-launch'))
launcherPath = path.resolve(__dirname, '..', 'resources', 'classic', 'classic-launcher.sh')
}
await fs.mkdirs(binDir)
await fs.copy(launcherPath, path.join(binDir, 'electron-launch'))
}

function createDesktopLaunchCommand (data) {
const executableName = data.executableName || data.productName
const executableName = data.executableName || data.productName || data.name

delete data.executableName
delete data.productName

const launcher = data.confinement === 'classic' ? 'bin/electron-launch' : 'desktop-launch'
const sandboxFlag = getBrowserSandboxFlag(data)

return `${launcher} '$SNAP/${data.name}/${executableName}'`
return `bin/electron-launch $SNAP/${data.name}/${executableName} ${sandboxFlag}`
}

module.exports = {
Expand Down
15 changes: 11 additions & 4 deletions src/snapcraft.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,19 @@ class Snapcraft {
const args = [command]
for (const flag in options) {
const value = options[flag]
if (value) {
args.push(`--${flag}=${value}`)
} else {
args.push(`--${flag}`)
if (flag !== 'target-arch') {
if (value) {
args.push(`--${flag}=${value}`)
} else {
args.push(`--${flag}`)
}
}
}
/* istanbul ignore if */
if (debug.enabled) {
args.push('--destructive-mode')
args.push('--debug')
}

if (extraArgs) {
Array.prototype.push.apply(args, extraArgs)
Expand Down
9 changes: 7 additions & 2 deletions src/yaml.js
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,6 @@ class SnapcraftYAML {
}

updateDependencies () {
this.parts.after[0] = common.getGTKDepends(this.electronVersion, DEPENDENCY_MAP)
this.parts['stage-packages'] = this.parts['stage-packages']
.concat(common.getATSPIDepends(this.electronVersion, DEPENDENCY_MAP))
.concat(common.getDRMDepends(this.electronVersion, DEPENDENCY_MAP))
Expand All @@ -210,6 +209,10 @@ class SnapcraftYAML {
.concat(common.getUUIDDepends(this.electronVersion, DEPENDENCY_MAP))
.concat(common.getXcbDri3Depends(this.electronVersion, DEPENDENCY_MAP))

if (this.data.confinement === 'classic') {
this.parts.after[0] = common.getGTKDepends(this.electronVersion, DEPENDENCY_MAP)
}

return this.data
}

Expand Down Expand Up @@ -255,7 +258,9 @@ class SnapcraftYAML {
}

module.exports = async function createYamlFromTemplate (snapDir, packageDir, userSupplied) {
const templateFilename = path.resolve(__dirname, '..', 'resources', 'snapcraft.yaml')
const templateFilename = (userSupplied.confinement && userSupplied.confinement === 'classic')
? path.resolve(__dirname, '..', 'resources', 'classic', 'snapcraft.yaml')
: path.resolve(__dirname, '..', 'resources', 'strict', 'snapcraft.yaml')
delete userSupplied.snapcraft

const yamlData = new SnapcraftYAML()
Expand Down
4 changes: 1 addition & 3 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,7 @@ test('snap name has no letters', t => {
t.throws(() => creator.sanitizeName('0-9'), { message: /needs to have at least one letter/ })
})

// TODO: These are currently failing in CI, due to GH Actions not working with multipass.
// Configure this with a custom Docker image or LXD to get these working in CI again.
if (!process.env.FAST_TESTS_ONLY && !process.env.CI) {
if (!process.env.FAST_TESTS_ONLY) {
test.serial('creates a snap', async t => {
const snapPath = await snap({ src: path.join(__dirname, 'fixtures', 'app-with-asar') })
t.truthy(snapPath, 'snap returns a truthy value')
Expand Down
12 changes: 6 additions & 6 deletions test/launcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,24 @@ require('./_util')

test('desktop-launch command uses productName by default', t => {
const command = launcher.createDesktopLaunchCommand({ name: 'app-name', productName: 'App Name' })
t.true(command.startsWith('desktop-launch'), 'Command uses desktop-launch')
t.true(command.endsWith("/App Name'"), 'Command uses exe-name')
t.true(command.startsWith('bin/electron-launch'), 'Command uses electron-launch')
t.true(command.includes('App Name'), 'Command uses productName')
})

test('desktop-launch command uses executableName if specified', t => {
const command = launcher.createDesktopLaunchCommand({ name: 'app-name', productName: 'App Name', executableName: 'exe-name' })
t.true(command.startsWith('desktop-launch'), 'Command uses desktop-launch')
t.true(command.endsWith("/exe-name'"), 'Command uses exe-name')
t.true(command.startsWith('bin/electron-launch'), 'Command uses electron-launch')
t.true(command.includes('exe-name'), 'Command uses exe-name')
})

test('launcher is classic launcher in classic confinement', t => {
const command = launcher.createDesktopLaunchCommand({ productName: 'App Name', confinement: 'classic' })
t.true(command.startsWith('bin/electron-launch'), 'Command uses electron-launch')
})

test('no custom launcher is copied to bin folder in non-classic confinement', async t => {
test('custom launcher is copied to bin folder in non-classic confinement', async t => {
await launcher.copyLauncher(t.context.tempDir.name, { confinement: 'strict' })
t.false(await fs.pathExists(path.join(t.context.tempDir.name, 'bin', 'electron-launch')), 'launcher does not exist')
t.true(await fs.pathExists(path.join(t.context.tempDir.name, 'bin', 'electron-launch')), 'launcher exists')
})

test('custom launcher is copied to bin folder in classic confinement', async t => {
Expand Down
8 changes: 7 additions & 1 deletion test/snapcraft.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

const debug = require('debug')('electron-installer-snap:snapcraft')
const Snapcraft = require('../src/snapcraft')
const test = require('ava')

Expand All @@ -33,5 +34,10 @@ test('generateArgs flags and options', t => {
const snapcraft = new Snapcraft()
const args = snapcraft.generateArgs('nonexistent', { a: 1, b: null }, ['foo', 'bar'])

t.deepEqual(args, ['nonexistent', '--a=1', '--b', 'foo', 'bar'], 'generated args')
// Note: --destructive-mode and --debug are enabled by default in CI
if (debug.enabled) {
t.deepEqual(args, ['nonexistent', '--a=1', '--b', '--destructive-mode', '--debug', 'foo', 'bar'], 'generated args')
} else {
t.deepEqual(args, ['nonexistent', '--a=1', '--b', 'foo', 'bar'], 'generated args')
}
})
33 changes: 29 additions & 4 deletions test/yaml.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,38 @@ test('custom app config', async t => {
t.true(apps.electronAppName.daemon, 'daemon is set in app')
})

test('Electron < 2 apps use desktop-gtk2', async t => {
const { parts } = await createYaml(t, { name: 'electronAppName' }, '1.8.2')
test('strict confinement should apply by default', async t => {
const snapcraftYaml = await createYaml(t, { name: 'electronAppName' })
t.is(snapcraftYaml.confinement, 'strict')
})

test('custom confinement config (devmode should apply correctly)', async t => {
const snapcraftYaml = await createYaml(t, { name: 'electronAppName', confinement: 'devmode' })
t.is(snapcraftYaml.confinement, 'devmode')
})

test('custom confinement config (strict should apply correctly)', async t => {
const snapcraftYaml = await createYaml(t, { name: 'electronAppName', confinement: 'strict' })
t.is(snapcraftYaml.confinement, 'strict')
})

test('custom confinement config (classic should apply correctly)', async t => {
const snapcraftYaml = await createYaml(t, { name: 'electronAppName', confinement: 'classic' })
t.is(snapcraftYaml.confinement, 'classic')
})

test('use gnome extensions with strict confinement', async t => {
const { apps } = await createYaml(t, { name: 'electronAppName' })
t.deepEqual(apps.electronAppName.extensions, ['gnome-3-34'])
})

test('Electron < 2 classic confinement apps use desktop-gtk2', async t => {
const { parts } = await createYaml(t, { name: 'electronAppName', confinement: 'classic' }, '1.8.2')
t.deepEqual(parts.electronAppName.after, ['desktop-gtk2'])
})

test('Electron 2 apps use desktop-gtk3', async t => {
const { parts } = await createYaml(t, { name: 'electronAppName' }, '2.0.0-beta.1')
test('Electron 2 classic confinement apps use desktop-gtk3', async t => {
const { parts } = await createYaml(t, { name: 'electronAppName', confinement: 'classic' }, '2.0.0-beta.1')
t.deepEqual(parts.electronAppName.after, ['desktop-gtk3'])
})

Expand Down

0 comments on commit 0549fd8

Please sign in to comment.