diff --git a/README.md b/README.md index 3c75930..422eb52 100644 --- a/README.md +++ b/README.md @@ -87,3 +87,29 @@ The `snapcraft-args` parameter can be used to pass additional arguments to Snapcraft. This is primarily intended to allow the use of experimental features by passing `--enable-experimental-*` arguments to Snapcraft. + +### `ua-token` + +The `ua-token` parameter can be used to tell Snapcraft to attach an Ubuntu +Advantage (UA) token inside the build environment. Snapcraft will ensure +the token is detached before exiting, but be warned that it is possible +some failures may prevent detaching (e.g. aborted jobs). + +In order to make the UA token available to the workflow, it should be stored +as a repository secret: + +1. choose the "Settings" tab. +2. choose "Secrets" from the menu on the left. +3. click "Add a new secret". +4. set the name to `UA_TOKEN` (or whatever is referenced in the workflow), + and paste the UA token as the value. + +An example workflow with UA token stored as secret `UA_TOKEN`: + +```yaml +... + - uses: snapcore/action-build@v1 + with: + path: path-to-snapcraft-project + ua-token: ${{ secrets.UA_TOKEN }} +``` diff --git a/__tests__/build.test.ts b/__tests__/build.test.ts index 91b5dcd..f3701d5 100644 --- a/__tests__/build.test.ts +++ b/__tests__/build.test.ts @@ -13,10 +13,10 @@ afterEach(() => { }) test('SnapcraftBuilder expands tilde in project root', () => { - let builder = new build.SnapcraftBuilder('~', true, 'stable', '') + let builder = new build.SnapcraftBuilder('~', true, 'stable', '', '') expect(builder.projectRoot).toBe(os.homedir()) - builder = new build.SnapcraftBuilder('~/foo/bar', true, 'stable', '') + builder = new build.SnapcraftBuilder('~/foo/bar', true, 'stable', '', '') expect(builder.projectRoot).toBe(path.join(os.homedir(), 'foo/bar')) }) @@ -41,7 +41,7 @@ test('SnapcraftBuilder.build runs a snap build', async () => { process.env['GITHUB_RUN_ID'] = '42' const projectDir = 'project-root' - const builder = new build.SnapcraftBuilder(projectDir, true, 'stable', '') + const builder = new build.SnapcraftBuilder(projectDir, true, 'stable', '', '') await builder.build() expect(ensureSnapd).toHaveBeenCalled() @@ -76,7 +76,7 @@ test('SnapcraftBuilder.build can disable build info', async () => { } ) - const builder = new build.SnapcraftBuilder('.', false, 'stable', '') + const builder = new build.SnapcraftBuilder('.', false, 'stable', '', '') await builder.build() expect(execMock).toHaveBeenCalledWith('sg', expect.any(Array), { @@ -106,7 +106,7 @@ test('SnapcraftBuilder.build can set the Snapcraft channel', async () => { } ) - const builder = new build.SnapcraftBuilder('.', false, 'edge', '') + const builder = new build.SnapcraftBuilder('.', false, 'edge', '', '') await builder.build() expect(ensureSnapcraft).toHaveBeenCalledWith('edge') @@ -134,7 +134,8 @@ test('SnapcraftBuilder.build can pass additional arguments', async () => { '.', false, 'stable', - '--foo --bar' + '--foo --bar', + '' ) await builder.build() @@ -145,11 +146,45 @@ test('SnapcraftBuilder.build can pass additional arguments', async () => { ) }) +test('SnapcraftBuilder.build can pass UA token', async () => { + expect.assertions(1) + + const ensureSnapd = jest + .spyOn(tools, 'ensureSnapd') + .mockImplementation(async (): Promise => {}) + const ensureLXD = jest + .spyOn(tools, 'ensureLXD') + .mockImplementation(async (): Promise => {}) + const ensureSnapcraft = jest + .spyOn(tools, 'ensureSnapcraft') + .mockImplementation(async (channel): Promise => {}) + const execMock = jest.spyOn(exec, 'exec').mockImplementation( + async (program: string, args?: string[]): Promise => { + return 0 + } + ) + + const builder = new build.SnapcraftBuilder( + '.', + false, + 'stable', + '', + 'test-ua-token' + ) + await builder.build() + + expect(execMock).toHaveBeenCalledWith( + 'sg', + ['lxd', '-c', 'snapcraft --ua-token test-ua-token'], + expect.anything() + ) +}) + test('SnapcraftBuilder.outputSnap fails if there are no snaps', async () => { expect.assertions(2) const projectDir = 'project-root' - const builder = new build.SnapcraftBuilder(projectDir, true, 'stable', '') + const builder = new build.SnapcraftBuilder(projectDir, true, 'stable', '', '') const readdir = jest .spyOn(builder, '_readdir') @@ -167,7 +202,7 @@ test('SnapcraftBuilder.outputSnap returns the first snap', async () => { expect.assertions(2) const projectDir = 'project-root' - const builder = new build.SnapcraftBuilder(projectDir, true, 'stable', '') + const builder = new build.SnapcraftBuilder(projectDir, true, 'stable', '', '') const readdir = jest .spyOn(builder, '_readdir') diff --git a/action.yml b/action.yml index 9e97d21..c416d0b 100644 --- a/action.yml +++ b/action.yml @@ -36,6 +36,12 @@ inputs: must be turned on via a `--enable-experimental-*` command line argument. This parameter can be used to turn on such features. default: '' + ua-token: + description: > + UA token to attach in build environment. + + Snapcraft will detach the token when no longer required. + default: '' outputs: snap: description: 'The file name of the resulting snap.' diff --git a/dist/index.js b/dist/index.js index e6eab0c..23a5c4c 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1499,11 +1499,12 @@ function expandHome(p) { return p; } class build_SnapcraftBuilder { - constructor(projectRoot, includeBuildInfo, snapcraftChannel, snapcraftArgs) { + constructor(projectRoot, includeBuildInfo, snapcraftChannel, snapcraftArgs, uaToken) { this.projectRoot = expandHome(projectRoot); this.includeBuildInfo = includeBuildInfo; this.snapcraftChannel = snapcraftChannel; this.snapcraftArgs = snapcraftArgs; + this.uaToken = uaToken; } build() { return build_awaiter(this, void 0, void 0, function* () { @@ -1528,6 +1529,9 @@ class build_SnapcraftBuilder { if (this.snapcraftArgs) { snapcraft = `${snapcraft} ${this.snapcraftArgs}`; } + if (this.uaToken) { + snapcraft = `${snapcraft} --ua-token ${this.uaToken}`; + } yield Object(exec.exec)('sg', ['lxd', '-c', snapcraft], { cwd: this.projectRoot, env @@ -1577,7 +1581,8 @@ function run() { Object(core.info)(`Building Snapcraft project in "${path}"...`); const snapcraftChannel = Object(core.getInput)('snapcraft-channel'); const snapcraftArgs = Object(core.getInput)('snapcraft-args'); - const builder = new build_SnapcraftBuilder(path, buildInfo, snapcraftChannel, snapcraftArgs); + const uaToken = Object(core.getInput)('ua-token'); + const builder = new build_SnapcraftBuilder(path, buildInfo, snapcraftChannel, snapcraftArgs, uaToken); yield builder.build(); const snap = yield builder.outputSnap(); Object(core.setOutput)('snap', snap); diff --git a/src/build.ts b/src/build.ts index 3ee9176..782c9a8 100644 --- a/src/build.ts +++ b/src/build.ts @@ -27,17 +27,20 @@ export class SnapcraftBuilder { includeBuildInfo: boolean snapcraftChannel: string snapcraftArgs: string + uaToken: string constructor( projectRoot: string, includeBuildInfo: boolean, snapcraftChannel: string, - snapcraftArgs: string + snapcraftArgs: string, + uaToken: string ) { this.projectRoot = expandHome(projectRoot) this.includeBuildInfo = includeBuildInfo this.snapcraftChannel = snapcraftChannel this.snapcraftArgs = snapcraftArgs + this.uaToken = uaToken } async build(): Promise { @@ -64,6 +67,9 @@ export class SnapcraftBuilder { if (this.snapcraftArgs) { snapcraft = `${snapcraft} ${this.snapcraftArgs}` } + if (this.uaToken) { + snapcraft = `${snapcraft} --ua-token ${this.uaToken}` + } await exec.exec('sg', ['lxd', '-c', snapcraft], { cwd: this.projectRoot, diff --git a/src/main.ts b/src/main.ts index 51797b4..dfc5902 100644 --- a/src/main.ts +++ b/src/main.ts @@ -11,12 +11,14 @@ async function run(): Promise { core.info(`Building Snapcraft project in "${path}"...`) const snapcraftChannel = core.getInput('snapcraft-channel') const snapcraftArgs = core.getInput('snapcraft-args') + const uaToken = core.getInput('ua-token') const builder = new SnapcraftBuilder( path, buildInfo, snapcraftChannel, - snapcraftArgs + snapcraftArgs, + uaToken ) await builder.build() const snap = await builder.outputSnap()