diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6b84dbd..935d04f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -32,7 +32,7 @@ jobs: run-rockcraft-pack-action: strategy: matrix: - os: [ubuntu-24.04, ubuntu-22.04, ubuntu-20.04] + os: [ubuntu-24.04, ubuntu-22.04] revision: ['1206', ''] runs-on: ${{ matrix.os }} steps: diff --git a/dist/rockcraft-pack-action/index.js b/dist/rockcraft-pack-action/index.js index 48279b2..5977ae8 100644 --- a/dist/rockcraft-pack-action/index.js +++ b/dist/rockcraft-pack-action/index.js @@ -20093,10 +20093,12 @@ var RockcraftBuilder = class { rockcraftChannel; rockcraftPackVerbosity; rockcraftRevision; + envFile; constructor(options) { this.projectRoot = expandHome(options.projectRoot); this.rockcraftChannel = options.rockcraftChannel; this.rockcraftRevision = options.rockcraftRevision; + this.envFile = options.envFile; if (allowedVerbosity.includes(options.rockcraftPackVerbosity)) { this.rockcraftPackVerbosity = options.rockcraftPackVerbosity; } else { @@ -20117,13 +20119,14 @@ var RockcraftBuilder = class { rockcraftPackArgs = `${rockcraftPackArgs} --verbosity ${this.rockcraftPackVerbosity}`; } rockcraft = `${rockcraft} ${rockcraftPackArgs.trim()}`; - await exec3.exec( - "sudo", - ["--preserve-env", "--user", shellUser(), ...rockcraft.split(" ")], - { - cwd: this.projectRoot - } - ); + let sourceCmd = ""; + if (this.envFile) { + sourceCmd = `source ${this.envFile} && `; + } + const bashCommand = `${sourceCmd}sudo --preserve-env --user ${shellUser()} ${rockcraft}`; + await exec3.exec("bash", ["-c", bashCommand], { + cwd: this.projectRoot + }); } // This wrapper is for the benefit of the tests, due to the crazy // typing of fs.promises.readdir() @@ -20150,6 +20153,7 @@ async function run() { core3.info(`Building rock in "${projectRoot}"...`); const rockcraftRevision = core3.getInput("revision"); const rockcraftChannel = core3.getInput("rockcraft-channel") || "stable"; + const envFile = core3.getInput("env-file") || ""; if (rockcraftRevision.length < 1) { core3.warning( `Rockcraft revision not provided. Installing from ${rockcraftChannel}` @@ -20160,7 +20164,8 @@ async function run() { projectRoot, rockcraftChannel, rockcraftPackVerbosity, - rockcraftRevision + rockcraftRevision, + envFile }); await builder.pack(); const rock = await builder.outputRock(); diff --git a/rockcraft-pack/action.yml b/rockcraft-pack/action.yml index 6a78c97..4b4dea7 100644 --- a/rockcraft-pack/action.yml +++ b/rockcraft-pack/action.yml @@ -27,6 +27,11 @@ inputs: If not provided, it defaults to whatever revision is in latest/stable. default: '' + env-file: + description: > + The path to the file containing the environment for execution. + + default: '' outputs: rock: description: 'The file name of the resulting rock.' diff --git a/src/rockcraft-pack-action.ts b/src/rockcraft-pack-action.ts index 54b1989..1b36558 100644 --- a/src/rockcraft-pack-action.ts +++ b/src/rockcraft-pack-action.ts @@ -9,6 +9,7 @@ async function run(): Promise { core.info(`Building rock in "${projectRoot}"...`) const rockcraftRevision = core.getInput('revision') const rockcraftChannel = core.getInput('rockcraft-channel') || 'stable' + const envFile = core.getInput('env-file') || '' if (rockcraftRevision.length < 1) { core.warning( `Rockcraft revision not provided. Installing from ${rockcraftChannel}` @@ -20,7 +21,8 @@ async function run(): Promise { projectRoot, rockcraftChannel, rockcraftPackVerbosity, - rockcraftRevision + rockcraftRevision, + envFile }) await builder.pack() const rock = await builder.outputRock() diff --git a/src/rockcraft-pack.ts b/src/rockcraft-pack.ts index 0bc1a96..570ca37 100644 --- a/src/rockcraft-pack.ts +++ b/src/rockcraft-pack.ts @@ -13,6 +13,7 @@ interface RockcraftBuilderOptions { rockcraftChannel: string rockcraftPackVerbosity: string rockcraftRevision: string + envFile: string } export class RockcraftBuilder { @@ -20,11 +21,13 @@ export class RockcraftBuilder { rockcraftChannel: string rockcraftPackVerbosity: string rockcraftRevision: string + envFile: string constructor(options: RockcraftBuilderOptions) { this.projectRoot = tools.expandHome(options.projectRoot) this.rockcraftChannel = options.rockcraftChannel this.rockcraftRevision = options.rockcraftRevision + this.envFile = options.envFile if (allowedVerbosity.includes(options.rockcraftPackVerbosity)) { this.rockcraftPackVerbosity = options.rockcraftPackVerbosity } else { @@ -49,13 +52,17 @@ export class RockcraftBuilder { } rockcraft = `${rockcraft} ${rockcraftPackArgs.trim()}` - await exec.exec( - 'sudo', - ['--preserve-env', '--user', tools.shellUser(), ...rockcraft.split(' ')], - { - cwd: this.projectRoot - } - ) + + // Source environment and run the command + let sourceCmd = '' + if (this.envFile) { + sourceCmd = `source "${this.envFile}" && ` + } + const bashCommand = `${sourceCmd}sudo --preserve-env --user ${tools.shellUser()} ${rockcraft}` + + await exec.exec('bash', ['-c', bashCommand], { + cwd: this.projectRoot + }) } // This wrapper is for the benefit of the tests, due to the crazy diff --git a/tests/rockcraft-pack.test.ts b/tests/rockcraft-pack.test.ts index 5050842..2ddae2b 100644 --- a/tests/rockcraft-pack.test.ts +++ b/tests/rockcraft-pack.test.ts @@ -16,7 +16,8 @@ test('RockcraftBuilder expands tilde in project root', () => { projectRoot: '~', rockcraftChannel: 'edge', rockcraftPackVerbosity: 'trace', - rockcraftRevision: '1' + rockcraftRevision: '1', + envFile: '' }) expect(builder.projectRoot).toBe(os.homedir()) @@ -24,7 +25,8 @@ test('RockcraftBuilder expands tilde in project root', () => { projectRoot: '~/foo/bar', rockcraftChannel: 'stable', rockcraftPackVerbosity: 'trace', - rockcraftRevision: '1' + rockcraftRevision: '1', + envFile: '' }) expect(builder.projectRoot).toBe(path.join(os.homedir(), 'foo/bar')) }) @@ -59,7 +61,8 @@ test('RockcraftBuilder.pack runs a rock build', async () => { projectRoot: projectDir, rockcraftChannel: 'stable', rockcraftPackVerbosity: 'debug', - rockcraftRevision: '1' + rockcraftRevision: '1', + envFile: 'my-env-file' }) await builder.pack() @@ -68,15 +71,12 @@ test('RockcraftBuilder.pack runs a rock build', async () => { expect(ensureRockcraft).toHaveBeenCalled() expect(shellUser).toHaveBeenCalled() expect(execMock).toHaveBeenCalledWith( - 'sudo', + 'bash', [ - '--preserve-env', - '--user', - user, - 'rockcraft', - 'pack', - '--verbosity', - 'debug' + '-c', + 'source "my-env-file" && sudo --preserve-env --user ' + + user + + ' rockcraft pack --verbosity debug' ], { cwd: projectDir @@ -108,7 +108,8 @@ test('RockcraftBuilder.build can set the Rockcraft channel', async () => { projectRoot: '.', rockcraftChannel: 'test-channel', rockcraftPackVerbosity: 'trace', - rockcraftRevision: '' + rockcraftRevision: '', + envFile: '' }) await builder.pack() @@ -139,7 +140,8 @@ test('RockcraftBuilder.build can set the Rockcraft revision', async () => { projectRoot: '.', rockcraftChannel: 'channel', rockcraftPackVerbosity: 'trace', - rockcraftRevision: '123' + rockcraftRevision: '123', + envFile: '' }) await builder.pack() @@ -175,20 +177,16 @@ test('RockcraftBuilder.build can pass known verbosity', async () => { projectRoot: '.', rockcraftChannel: 'stable', rockcraftPackVerbosity: 'trace', - rockcraftRevision: '1' + rockcraftRevision: '1', + envFile: '' }) await builder.pack() expect(execMock).toHaveBeenCalledWith( - 'sudo', + 'bash', [ - '--preserve-env', - '--user', - user, - 'rockcraft', - 'pack', - '--verbosity', - 'trace' + '-c', + 'sudo --preserve-env --user ' + user + ' rockcraft pack --verbosity trace' ], expect.anything() ) @@ -198,7 +196,8 @@ test('RockcraftBuilder.build can pass known verbosity', async () => { projectRoot: '.', rockcraftChannel: 'stable', rockcraftPackVerbosity: 'fake-verbosity', - rockcraftRevision: '1' + rockcraftRevision: '1', + envFile: '' }) } expect(badBuilder).toThrow() @@ -212,7 +211,8 @@ test('RockcraftBuilder.outputRock fails if there are no rocks', async () => { projectRoot: projectDir, rockcraftChannel: 'stable', rockcraftPackVerbosity: 'trace', - rockcraftRevision: '1' + rockcraftRevision: '1', + envFile: '' }) const readdir = jest @@ -233,7 +233,8 @@ test('RockcraftBuilder.outputRock returns the first rock', async () => { projectRoot: projectDir, rockcraftChannel: 'stable', rockcraftPackVerbosity: 'trace', - rockcraftRevision: '1' + rockcraftRevision: '1', + envFile: '' }) const readdir = jest