Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow revision pinning for rockcraft #19

Merged
merged 2 commits into from
Jan 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,12 @@ jobs:
run: npm test
- name: Try to package code
run: npm run pack

run-rockcraft-pack-action:
strategy:
matrix:
os: [ubuntu-22.04, ubuntu-20.04]
revision: ['1206', '']
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
Expand All @@ -40,6 +41,13 @@ jobs:
with:
path: tests
verbosity: debug
revision: ${{ matrix.revision }}
- name: Assert revision number
if: matrix.revision != ''
run: |
set -ex
installed_rev="$(snap info rockcraft | tail -1 | awk '{print $(NF-2)}')"
[ "$installed_rev" == "(${{ matrix.revision }})" ]
- name: Upload ROCK
uses: actions/upload-artifact@v3
with:
Expand Down
24 changes: 15 additions & 9 deletions dist/rockcraft-pack-action/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4133,7 +4133,7 @@ var external_fs_ = __nccwpck_require__(147);
var external_path_ = __nccwpck_require__(17);
// EXTERNAL MODULE: external "os"
var external_os_ = __nccwpck_require__(37);
;// CONCATENATED MODULE: ./src/tools.ts
;// CONCATENATED MODULE: ./lib/tools.js
// -*- mode: javascript; js-indent-level: 2 -*-


Expand Down Expand Up @@ -4219,20 +4219,20 @@ async function ensureLXD() {
await exec.exec('sudo', ['lxd', 'init', '--auto']);
await ensureLXDNetwork();
}
async function ensureRockcraft(channel) {
async function ensureRockcraft(channel, revision) {
const haveRockcraft = await haveExecutable('/snap/bin/rockcraft');
core.info('Installing Rockcraft...');
await exec.exec('sudo', [
'snap',
haveRockcraft ? 'refresh' : 'install',
'--channel',
channel,
revision.length > 0 ? '--revision' : '--channel',
cjdcordeiro marked this conversation as resolved.
Show resolved Hide resolved
revision.length > 0 ? revision : channel,
'--classic',
'rockcraft'
]);
}

;// CONCATENATED MODULE: ./src/rockcraft-pack.ts
;// CONCATENATED MODULE: ./lib/rockcraft-pack.js
// -*- mode: javascript; js-indent-level: 2 -*-


Expand All @@ -4244,6 +4244,7 @@ class RockcraftBuilder {
constructor(options) {
this.projectRoot = expandHome(options.projectRoot);
this.rockcraftChannel = options.rockcraftChannel;
this.rockcraftRevision = options.rockcraftRevision;
if (allowedVerbosity.includes(options.rockcraftPackVerbosity)) {
this.rockcraftPackVerbosity = options.rockcraftPackVerbosity;
}
Expand All @@ -4256,7 +4257,7 @@ class RockcraftBuilder {
core.startGroup('Installing Rockcraft plus dependencies');
await ensureSnapd();
await ensureLXD();
await ensureRockcraft(this.rockcraftChannel);
await ensureRockcraft(this.rockcraftChannel, this.rockcraftRevision);
core.endGroup();
let rockcraft = 'rockcraft pack';
let rockcraftPackArgs = '';
Expand Down Expand Up @@ -4286,20 +4287,25 @@ class RockcraftBuilder {
}
}

;// CONCATENATED MODULE: ./src/rockcraft-pack-action.ts
;// CONCATENATED MODULE: ./lib/rockcraft-pack-action.js
// -*- mode: javascript; js-indent-level: 2 -*-


async function run() {
try {
const projectRoot = core.getInput('path');
core.info(`Building ROCK in "${projectRoot}"...`);
const rockcraftChannel = core.getInput('rockcraft-channel') || 'edge';
const rockcraftRevision = core.getInput('revision');
const rockcraftChannel = core.getInput('rockcraft-channel') || 'stable';
sergiusens marked this conversation as resolved.
Show resolved Hide resolved
if (rockcraftRevision.length < 1) {
core.warning(`Rockcraft revision not provided. Installing from ${rockcraftChannel}`);
}
const rockcraftPackVerbosity = core.getInput('verbosity');
const builder = new RockcraftBuilder({
projectRoot,
rockcraftChannel,
rockcraftPackVerbosity
rockcraftPackVerbosity,
rockcraftRevision
});
await builder.pack();
const rock = await builder.outputRock();
Expand Down
6 changes: 3 additions & 3 deletions lib/tools.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,14 @@ export async function ensureLXD() {
await exec.exec('sudo', ['lxd', 'init', '--auto']);
await ensureLXDNetwork();
}
export async function ensureRockcraft(channel) {
export async function ensureRockcraft(channel, revision) {
const haveRockcraft = await haveExecutable('/snap/bin/rockcraft');
core.info('Installing Rockcraft...');
await exec.exec('sudo', [
'snap',
haveRockcraft ? 'refresh' : 'install',
'--channel',
channel,
revision.length > 0 ? '--revision' : '--channel',
revision.length > 0 ? revision : channel,
'--classic',
'rockcraft'
]);
Expand Down
6 changes: 6 additions & 0 deletions rockcraft-pack/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ inputs:

The default is 'trace'.
default: 'trace'
revision:
description: >
Pin the snap revision to install.

If not provided, it defaults to whatever revision is in latest/stable.
sergiusens marked this conversation as resolved.
Show resolved Hide resolved
default: ''
outputs:
rock:
description: 'The file name of the resulting ROCK.'
Expand Down
9 changes: 8 additions & 1 deletion src/rockcraft-pack-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,20 @@ async function run(): Promise<void> {
try {
const projectRoot = core.getInput('path')
core.info(`Building ROCK in "${projectRoot}"...`)
const rockcraftRevision = core.getInput('revision')
const rockcraftChannel = core.getInput('rockcraft-channel') || 'stable'
if (rockcraftRevision.length < 1) {
core.warning(
`Rockcraft revision not provided. Installing from ${rockcraftChannel}`
)
}
const rockcraftPackVerbosity = core.getInput('verbosity')

const builder = new RockcraftBuilder({
projectRoot,
rockcraftChannel,
rockcraftPackVerbosity
rockcraftPackVerbosity,
rockcraftRevision
})
await builder.pack()
const rock = await builder.outputRock()
Expand Down
5 changes: 4 additions & 1 deletion src/rockcraft-pack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,19 @@ interface RockcraftBuilderOptions {
projectRoot: string
rockcraftChannel: string
rockcraftPackVerbosity: string
rockcraftRevision: string
}

export class RockcraftBuilder {
projectRoot: string
rockcraftChannel: string
rockcraftPackVerbosity: string
rockcraftRevision: string

constructor(options: RockcraftBuilderOptions) {
this.projectRoot = tools.expandHome(options.projectRoot)
this.rockcraftChannel = options.rockcraftChannel
this.rockcraftRevision = options.rockcraftRevision
if (allowedVerbosity.includes(options.rockcraftPackVerbosity)) {
this.rockcraftPackVerbosity = options.rockcraftPackVerbosity
} else {
Expand All @@ -36,7 +39,7 @@ export class RockcraftBuilder {
core.startGroup('Installing Rockcraft plus dependencies')
await tools.ensureSnapd()
await tools.ensureLXD()
await tools.ensureRockcraft(this.rockcraftChannel)
await tools.ensureRockcraft(this.rockcraftChannel, this.rockcraftRevision)
core.endGroup()

let rockcraft = 'rockcraft pack'
Expand Down
9 changes: 6 additions & 3 deletions src/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,17 @@ export async function ensureLXD(): Promise<void> {
await ensureLXDNetwork()
}

export async function ensureRockcraft(channel: string): Promise<void> {
export async function ensureRockcraft(
channel: string,
revision: string
): Promise<void> {
const haveRockcraft = await haveExecutable('/snap/bin/rockcraft')
core.info('Installing Rockcraft...')
await exec.exec('sudo', [
'snap',
haveRockcraft ? 'refresh' : 'install',
'--channel',
channel,
revision.length > 0 ? '--revision' : '--channel',
revision.length > 0 ? revision : channel,
'--classic',
'rockcraft'
])
Expand Down
57 changes: 48 additions & 9 deletions tests/rockcraft-pack.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ test('RockcraftBuilder expands tilde in project root', () => {
let builder = new build.RockcraftBuilder({
projectRoot: '~',
rockcraftChannel: 'edge',
rockcraftPackVerbosity: 'trace'
rockcraftPackVerbosity: 'trace',
rockcraftRevision: '1'
})
expect(builder.projectRoot).toBe(os.homedir())

builder = new build.RockcraftBuilder({
projectRoot: '~/foo/bar',
rockcraftChannel: 'stable',
rockcraftPackVerbosity: 'trace'
rockcraftPackVerbosity: 'trace',
rockcraftRevision: '1'
})
expect(builder.projectRoot).toBe(path.join(os.homedir(), 'foo/bar'))
})
Expand Down Expand Up @@ -50,7 +52,8 @@ test('RockcraftBuilder.pack runs a ROCK build', async () => {
const builder = new build.RockcraftBuilder({
projectRoot: projectDir,
rockcraftChannel: 'stable',
rockcraftPackVerbosity: 'debug'
rockcraftPackVerbosity: 'debug',
rockcraftRevision: '1'
})
await builder.pack()

Expand Down Expand Up @@ -89,11 +92,43 @@ test('RockcraftBuilder.build can set the Rockcraft channel', async () => {
const builder = new build.RockcraftBuilder({
projectRoot: '.',
rockcraftChannel: 'test-channel',
rockcraftPackVerbosity: 'trace'
rockcraftPackVerbosity: 'trace',
rockcraftRevision: ''
})
await builder.pack()

expect(ensureRockcraft).toHaveBeenCalledWith('test-channel')
expect(ensureRockcraft).toHaveBeenCalledWith('test-channel', '')
})

test('RockcraftBuilder.build can set the Rockcraft revision', async () => {
expect.assertions(1)

const ensureSnapd = jest
.spyOn(tools, 'ensureSnapd')
.mockImplementation(async (): Promise<void> => {})
const ensureLXD = jest
.spyOn(tools, 'ensureLXD')
.mockImplementation(async (): Promise<void> => {})
const ensureRockcraft = jest
.spyOn(tools, 'ensureRockcraft')
.mockImplementation(async (channel): Promise<void> => {})
const execMock = jest
.spyOn(exec, 'exec')
.mockImplementation(
async (program: string, args?: string[]): Promise<number> => {
return 0
}
)

const builder = new build.RockcraftBuilder({
projectRoot: '.',
rockcraftChannel: 'channel',
rockcraftPackVerbosity: 'trace',
rockcraftRevision: '123'
})
await builder.pack()

expect(ensureRockcraft).toHaveBeenCalledWith('channel', '123')
})

test('RockcraftBuilder.build can pass known verbosity', async () => {
Expand All @@ -119,7 +154,8 @@ test('RockcraftBuilder.build can pass known verbosity', async () => {
const builder = new build.RockcraftBuilder({
projectRoot: '.',
rockcraftChannel: 'stable',
rockcraftPackVerbosity: 'trace'
rockcraftPackVerbosity: 'trace',
rockcraftRevision: '1'
})
await builder.pack()

Expand All @@ -133,7 +169,8 @@ test('RockcraftBuilder.build can pass known verbosity', async () => {
new build.RockcraftBuilder({
projectRoot: '.',
rockcraftChannel: 'stable',
rockcraftPackVerbosity: 'fake-verbosity'
rockcraftPackVerbosity: 'fake-verbosity',
rockcraftRevision: '1'
})
}
expect(badBuilder).toThrowError()
Expand All @@ -146,7 +183,8 @@ test('RockcraftBuilder.outputRock fails if there are no ROCKs', async () => {
const builder = new build.RockcraftBuilder({
projectRoot: projectDir,
rockcraftChannel: 'stable',
rockcraftPackVerbosity: 'trace'
rockcraftPackVerbosity: 'trace',
rockcraftRevision: '1'
})

const readdir = jest
Expand All @@ -168,7 +206,8 @@ test('RockcraftBuilder.outputRock returns the first ROCK', async () => {
const builder = new build.RockcraftBuilder({
projectRoot: projectDir,
rockcraftChannel: 'stable',
rockcraftPackVerbosity: 'trace'
rockcraftPackVerbosity: 'trace',
rockcraftRevision: '1'
})

const readdir = jest
Expand Down
20 changes: 16 additions & 4 deletions tests/tools.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,8 +254,8 @@ test('ensureLXD still calls "lxd init" if LXD is installed', async () => {
expect(execMock).toHaveBeenNthCalledWith(4, 'sudo', ['lxd', 'init', '--auto'])
})

test('ensureSnapcraft installs Snapcraft if needed', async () => {
expect.assertions(2)
test('ensureRockcraft installs Rockcraft if needed', async () => {
expect.assertions(4)

const accessMock = jest
.spyOn(fs.promises, 'access')
Expand All @@ -275,7 +275,7 @@ test('ensureSnapcraft installs Snapcraft if needed', async () => {
}
)

await tools.ensureRockcraft('edge')
await tools.ensureRockcraft('edge', '')

expect(accessMock).toHaveBeenCalled()
expect(execMock).toHaveBeenNthCalledWith(1, 'sudo', [
Expand All @@ -286,6 +286,18 @@ test('ensureSnapcraft installs Snapcraft if needed', async () => {
'--classic',
'rockcraft'
])

await tools.ensureRockcraft('stable', '1234')

expect(accessMock).toHaveBeenCalled()
expect(execMock).toHaveBeenNthCalledWith(2, 'sudo', [
'snap',
'install',
'--revision',
'1234',
'--classic',
'rockcraft'
])
})

test('ensureRockcraft refreshes if Rockcraft is installed', async () => {
Expand All @@ -309,7 +321,7 @@ test('ensureRockcraft refreshes if Rockcraft is installed', async () => {
}
)

await tools.ensureRockcraft('edge')
await tools.ensureRockcraft('edge', '')

expect(accessMock).toHaveBeenCalled()
expect(execMock).toHaveBeenNthCalledWith(1, 'sudo', [
Expand Down
Loading