Skip to content
Open
Show file tree
Hide file tree
Changes from 7 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
22 changes: 12 additions & 10 deletions packages/cli-build/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,24 +86,26 @@ Usage:
$ percy build:approve [options] <build-id>

Arguments:
build-id Build ID to approve
build-id Build ID to approve

Options:
--username <string> Username for authentication (can also be set via BROWSERSTACK_USERNAME env
var)
--access-key <string> Access key for authentication (can also be set via BROWSERSTACK_ACCESS_KEY
env var)
--username <string> Username for authentication (can also be set via
BROWSERSTACK_USERNAME env var)
--access-key <string> Access key for authentication (can also be set via
BROWSERSTACK_ACCESS_KEY env var)
--pass-if-previously-approved Doesn't exit with an error if there are previous approvals

Global options:
-v, --verbose Log everything
-q, --quiet Log errors only
-s, --silent Log nothing
-l, --labels <string> Associates labels to the build (ex: --labels=dev,prod )
-h, --help Display command help
-v, --verbose Log everything
-q, --quiet Log errors only
-s, --silent Log nothing
-l, --labels <string> Associates labels to the build (ex: --labels=dev,prod )
-h, --help Display command help

Examples:
$ percy build:approve <build-id>
$ percy build:approve <build-id> --username username --access-key **key**
$ percy build:approve <build-id> --pass-if-previously-approved
```

### `percy build:unapprove`
Expand Down
19 changes: 18 additions & 1 deletion packages/cli-build/src/approve.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,15 @@ import { fetchCredentials, reviewCommandConfig } from './utils.js';
*/
export const approve = command('approve', {
description: 'Approve Percy builds',
...reviewCommandConfig
...reviewCommandConfig,
...{
flags: [
...reviewCommandConfig.flags,
{
name: 'pass-if-previously-approved',
description: 'Does not exit with an error if the build has already been approved'
}]
}
}, async ({ flags, args, percy, log, exit }) => {
// Early return if Percy is disabled
if (!percy) {
Expand Down Expand Up @@ -38,6 +46,15 @@ export const approve = command('approve', {
log.info(`Build ${args.buildId} approved successfully!`);
log.info(`Approved by: ${approvedBy.user_name} (${approvedBy.user_email})`);
} catch (error) {
if (
flags.passIfPreviouslyApproved &&
Array.isArray(error?.response?.body?.errors) &&
error.response.body.errors.some(e => e.detail === 'approve action is already performed on this build')
) {
log.info(`Build ${args.buildId} is already approved: skipping approval`);
exit(0);
}

log.error(`Failed to approve build ${args.buildId}`);
log.error(error);

Expand Down
32 changes: 32 additions & 0 deletions packages/cli-build/test/approve.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -309,4 +309,36 @@ describe('percy build:approve', () => {
'[percy] Approved by: temp-username ([email protected])'
]);
});

it('logs an error when build approval fails with 409 Conflict', async () => {
process.env.PERCY_FORCE_PKG_VALUE = JSON.stringify({ name: '@percy/client', version: '1.0.0' });
process.env.BROWSERSTACK_USERNAME = 'env-username';
process.env.BROWSERSTACK_ACCESS_KEY = 'env-access-key';

api.reply('/reviews', (req) => [409, { errors: [{ detail: 'approve action is already performed on this build' }] }]);

await expectAsync(approve(['123'])).toBeRejected();

expect(logger.stderr).toEqual([
'[percy] Failed to approve build 123',
'[percy] Error: approve action is already performed on this build',
'[percy] Error: Failed to approve the build'
]);
});

it('does not error when build is previously approved and --pass-if-previously-approved flag is used', async () => {
process.env.PERCY_FORCE_PKG_VALUE = JSON.stringify({ name: '@percy/client', version: '1.0.0' });
process.env.BROWSERSTACK_USERNAME = 'env-username';
process.env.BROWSERSTACK_ACCESS_KEY = 'env-access-key';

api.reply('/reviews', (req) => [409, { errors: [{ detail: 'approve action is already performed on this build' }] }]);

await expectAsync(approve(['123', '--pass-if-previously-approved'])).toBeResolved();

expect(logger.stderr).toEqual([]);
expect(logger.stdout).toEqual([
'[percy] Approving build 123...',
'[percy] Build 123 is already approved: skipping approval'
]);
});
});