Skip to content
Open
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
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,30 @@ the failing iOS run should have held. Keep the value fixed for a given job:
GitHub matches required checks by name, so a name that changes per commit can
never be required.

## Cancelling superseded runs

Push twice in quick succession and the first run's queued tests are dead
weight. `cancel-previous` cancels them when the newer run is submitted:

```yaml
- uses: devicecloud-dev/device-cloud-for-maestro@v2
with:
api-key: ${{ secrets.DCD_API_KEY }}
app-file: build/app.apk
cancel-previous: true
check-name: Android
```

The previous run is matched on repo + branch (or PR number) + `check-name`, so
set `check-name` per job whenever one commit runs this action more than once —
without it the iOS job would cancel the Android job's queued tests. Runs from
the same workflow run never cancel each other.

Only queued tests are cancelled: anything already running on a device finishes
and reports normally. Cancelled tests are refunded at 75%. The superseded run
exits 0 rather than failing your build, sends no completion email or webhook,
and its GitHub check is closed as skipped so it cannot block a PR.

## Migrating from Maestro Cloud

Replace the `uses` line in your workflow:
Expand Down
3 changes: 3 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ inputs:
async:
description: 'Immediately return (exit code 0) from the command without waiting for the results of the run (useful for saving CI minutes)'
required: false
cancel-previous:
description: 'Cancel the still-queued tests of the previous run of this job on the same branch or PR. Tests already running are left to finish; cancelled tests are refunded at 75%. Set check-name per job when one commit runs this action more than once, since it scopes the group'
required: false
device-locale:
description: 'Locale that will be set to a device, ISO-639-1 code and uppercase ISO-3166-1 code e.g. "de_DE" for Germany'
required: false
Expand Down
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ const run = async (): Promise<void> => {
appBinaryId,
appFilePath,
async,
cancelPrevious,
config,
deviceLocale,
downloadArtifacts,
Expand Down Expand Up @@ -177,6 +178,7 @@ const run = async (): Promise<void> => {
'app-binary-id': appBinaryId,
'app-file': appFilePath,
async,
'cancel-previous': cancelPrevious,
config,
'device-locale': deviceLocale,
'download-artifacts': downloadArtifacts,
Expand Down
6 changes: 6 additions & 0 deletions src/methods/params.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,21 @@ describe('getParameters', () => {
it('maps boolean inputs from the string "true"', async () => {
inputs['async'] = 'true';
inputs['google-play'] = 'true';
inputs['cancel-previous'] = 'true';
inputs['debug'] = 'true';
let params = await getParameters();
expect(params.async).toBe(true);
expect(params.googlePlay).toBe(true);
expect(params.cancelPrevious).toBe(true);
expect(params.debug).toBe(true);

inputs['async'] = 'false';
inputs['cancel-previous'] = '';
params = await getParameters();
expect(params.async).toBe(false);
// Unset means off: the falsy-dropping reducer in index.ts then omits
// the flag entirely, so an opted-out run's command line is unchanged.
expect(params.cancelPrevious).toBe(false);
});

it('normalises empty device inputs to null', async () => {
Expand Down
4 changes: 4 additions & 0 deletions src/methods/params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export type Params = {
androidDevice: string | null;
excludeFlows: string;
googlePlay: boolean;
cancelPrevious: boolean;
iosDevice: string | null;
name?: string;
deviceLocale?: string;
Expand Down Expand Up @@ -187,6 +188,8 @@ export async function getParameters(): Promise<Params> {
const excludeFlows = core.getInput('exclude-flows', { required: false });
const googlePlay =
core.getInput('google-play', { required: false }) === 'true';
const cancelPrevious =
core.getInput('cancel-previous', { required: false }) === 'true';

const deviceLocale = core.getInput('device-locale', { required: false });
const downloadArtifacts = parseDownloadArtifacts(
Expand Down Expand Up @@ -266,6 +269,7 @@ export async function getParameters(): Promise<Params> {
iosDevice,
excludeFlows,
googlePlay,
cancelPrevious,
deviceLocale,
downloadArtifacts,
maestroVersion,
Expand Down