mirror of
https://github.com/mattermost/mattermost-mobile.git
synced 2026-11-05 18:38:54 +00:00
Based on the later commits (after the earlier experimentation and reversions), the meaningful end state of the PR is: **Summary:** Improve E2E CI reliability, performance, and security by introducing robust build caching with safe fingerprinting and cache isolation, duration-based test sharding with graceful fallbacks, more reliable E2E impact detection and status handling, stronger cancellation/concurrency behavior, multiple iOS Detox stability fixes, and hardening GitHub Actions to avoid executing PR-authored code. Also includes CI fixes for iOS builds and a temporary Android E2E test skip for a known regression. --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Mattermost Build <build@mattermost.com>
168 lines
7.4 KiB
YAML
168 lines
7.4 KiB
YAML
# yaml-language-server: $schema=https://json.schemastore.org/github-action.json
|
|
name: Publish E2E/Override commit statuses
|
|
description: >-
|
|
Unblock the required e2e-test/* commit statuses for a SHA so a PR carrying
|
|
E2E/Override (or one that skipped E2E entirely) can merge under required
|
|
checks.
|
|
|
|
Only touches contexts that are actually blocking — pending, failing, or with
|
|
no status yet. A context that is genuinely green keeps its own result and
|
|
description, so the checks list still shows what really passed instead of
|
|
reporting every platform as overridden.
|
|
|
|
A failing context keeps its real pass/fail counts and gains an "- e2e
|
|
overridden" suffix, so the check reads "522 passed, 1 failed, 81 skipped -
|
|
e2e overridden" rather than hiding what failed.
|
|
|
|
Covers all three override paths: E2E never dispatched, E2E already failed
|
|
(statuses are keyed by SHA, so this overwrites the failures), and E2E still
|
|
running. In-flight runs are never cancelled — their finalize step re-checks
|
|
the label (.github/actions/e2e-override-label) so a late result cannot re-red
|
|
a check the maintainer deliberately bypassed.
|
|
|
|
inputs:
|
|
commit_sha:
|
|
description: Commit SHA to post statuses on (the PR head SHA)
|
|
required: true
|
|
state:
|
|
description: >-
|
|
Commit status state (success | pending). Use pending to re-block the PR
|
|
when E2E/Override is removed, so the waiver does not linger on the SHA.
|
|
pending only resets contexts this action previously overrode.
|
|
required: false
|
|
default: success
|
|
description:
|
|
description: >-
|
|
Commit status description for contexts that were pending or had no status.
|
|
A failing context keeps its own description plus an override suffix.
|
|
required: false
|
|
default: e2e overridden
|
|
target_url:
|
|
description: Link shown on the check
|
|
required: false
|
|
default: ''
|
|
|
|
runs:
|
|
using: composite
|
|
steps:
|
|
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
|
env:
|
|
COMMIT_SHA: ${{ inputs.commit_sha }}
|
|
STATE: ${{ inputs.state }}
|
|
DESCRIPTION: ${{ inputs.description }}
|
|
TARGET_URL: ${{ inputs.target_url }}
|
|
with:
|
|
script: |
|
|
const owner = context.repo.owner;
|
|
const repo = context.repo.repo;
|
|
const sha = process.env.COMMIT_SHA;
|
|
const state = process.env.STATE || 'success';
|
|
const description = (process.env.DESCRIPTION || '').substring(0, 140);
|
|
const targetUrl = process.env.TARGET_URL?.trim();
|
|
|
|
if (!sha) {
|
|
throw new Error('e2e-override-status: commit_sha is required');
|
|
}
|
|
|
|
// Relative requires resolve against the workspace, so the repo must be
|
|
// checked out before this action runs.
|
|
const {E2E_STATUS_CONTEXTS} = require('./detox/utils/build-tsio-job-config.js');
|
|
|
|
// Present in every success description this action writes, so the
|
|
// pending path can reset exactly the contexts it overrode and never a
|
|
// platform that passed on its own merits.
|
|
const OVERRIDE_MARKER = 'e2e overridden';
|
|
|
|
// getCombinedStatusForRef caps statuses at 100 per page. This repo only
|
|
// has 5 required contexts today, but other tooling can post legacy
|
|
// statuses on the same SHA — paginate so a busy commit can't silently
|
|
// hide one of the 5 required contexts past page 1.
|
|
const statuses = [];
|
|
for (let page = 1; ; page++) {
|
|
const {data: combined} = await github.rest.repos.getCombinedStatusForRef({
|
|
owner, repo, ref: sha, per_page: 100, page,
|
|
});
|
|
statuses.push(...combined.statuses);
|
|
if (combined.statuses.length < 100) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Only the latest status per context matters — this is current state,
|
|
// not history.
|
|
const latestByContext = new Map(
|
|
statuses.map((status) => [status.context, status]),
|
|
);
|
|
|
|
const failures = [];
|
|
let touched = 0;
|
|
for (const statusContext of E2E_STATUS_CONTEXTS) {
|
|
const latest = latestByContext.get(statusContext);
|
|
const latestDescription = latest?.description || '';
|
|
let statusDescription;
|
|
let statusTargetUrl;
|
|
|
|
if (state === 'pending') {
|
|
// Undo only what this action did. A context that never carried the
|
|
// override — including one that failed on its own after a later
|
|
// push — keeps its real result.
|
|
if (!latestDescription.includes(OVERRIDE_MARKER)) {
|
|
continue;
|
|
}
|
|
statusDescription = description;
|
|
statusTargetUrl = targetUrl;
|
|
} else if (latest?.state === 'success') {
|
|
// Nothing to unblock: either genuinely green — leave the real result
|
|
// and its counts alone — or already overridden, in which case
|
|
// re-posting would only replace a description carrying the real
|
|
// counts with a bare one.
|
|
continue;
|
|
} else if (latest?.state === 'failure' || latest?.state === 'error') {
|
|
// Keep the real counts so the check still says what failed.
|
|
// Reserve room for the suffix before truncating the base: TSIO
|
|
// descriptions are already capped at 140 (decideStatus in
|
|
// tsio-report-status.js), and truncating after concatenation could
|
|
// cut the marker off a long one, leaving the pending path unable to
|
|
// recognise this context as overridden.
|
|
const suffix = ` - ${OVERRIDE_MARKER}`;
|
|
const base = latestDescription.substring(0, Math.max(0, 140 - suffix.length));
|
|
statusDescription = `${base}${suffix}`.substring(0, 140);
|
|
// Keep the link to the real report — that is what a reviewer needs
|
|
// to judge whether the bypass was reasonable, not this action's run.
|
|
statusTargetUrl = latest.target_url || targetUrl;
|
|
} else {
|
|
// Pending, or no status at all (E2E never dispatched / new SHA).
|
|
statusDescription = description;
|
|
statusTargetUrl = targetUrl;
|
|
}
|
|
|
|
touched++;
|
|
try {
|
|
await github.rest.repos.createCommitStatus({
|
|
owner,
|
|
repo,
|
|
sha,
|
|
state,
|
|
context: statusContext,
|
|
description: statusDescription,
|
|
...(statusTargetUrl ? {target_url: statusTargetUrl} : {}),
|
|
});
|
|
core.info(`Published ${state} for ${statusContext} on ${sha}`);
|
|
} catch (err) {
|
|
core.warning(`createCommitStatus ${statusContext} on ${sha}: ${err.message}`);
|
|
failures.push(`${statusContext}: ${err.message}`);
|
|
}
|
|
}
|
|
|
|
if (touched === 0) {
|
|
core.info(
|
|
state === 'pending' ?
|
|
`No e2e-test/* contexts carry the override marker for ${sha} — nothing to reset.` :
|
|
`All required e2e-test/* contexts already pass on their own for ${sha} — nothing to override.`,
|
|
);
|
|
}
|
|
|
|
if (failures.length > 0) {
|
|
throw new Error(`Failed to publish ${failures.length} E2E/Override ${state} status(es): ${failures.join('; ')}`);
|
|
}
|