mattermost-mobile-upstream/.github/workflows/e2e-label-manager.yml
yasser khan bcac248ec0
feat(e2e): Integrate TSIO reporting (#9925)
Retire legacy maestro per-platform contexts from cancel-e2e-runs and
document the canonical PR, master, and CMT status context mapping.
Wire Detox + Maestro (PR/main/CMT) into Test System IO with a single
commit status (e2e/mobile; CMT uses e2e/compatibility-matrix-testing)
and groups mobile-pr / mobile-main / cmt-mobile.

Upload shard results with correct framework labels, merge Jest shards
into TSIO Detox shape, stub missing/dead shards as failures, and post
channel summaries after status settles. Matterwick MASTER is treated as
MAIN for mobile-main routing.

Also harden report/fail paths, stage Maestro screenshots per flow for
TSIO galleries, fix a few Detox setup/testID issues, and skip known
platform flakes so the pipeline stays actionable while TSIO lands.
2026-07-23 06:43:28 +00:00

222 lines
8.5 KiB
YAML

# Matterwick triggers E2E only on pull_request:labeled (see matterwick/server/pull_request.go).
# synchronize alone does nothing — on push we must cancel stale runs, remove E2E/Run*,
# and re-add E2E/Run in one job so Matterwick receives a fresh labeled webhook.
#
# 1. refresh-e2e-run-label (synchronize):
# Force-cancel in-flight E2E, then remove + re-add E2E/Run via PAT.
#
# 2. add-e2e-run-label (opened):
# Add E2E/Run unless already present. Skips when E2E/Override is set.
#
# 3. Honor E2E/Override (labeled E2E/Override):
# Removes all E2E/Run* labels and cancels in-progress E2E workflow runs.
#
# 4. Cancel in-progress E2E runs (E2E/Run* unlabeled by a human):
# Skips when mattermost-build (the PAT user) removed the label (refresh strip
# or post-run cleanup) so synchronize refresh does not race Matterwick dispatch.
#
# Fork PR guard (github.event.pull_request.head.repo.full_name == github.repository)
# is applied per-step. Fork PR contexts only get a read-only GITHUB_TOKEN, so
# addLabels / removeLabel / gh-run-cancel would all 403. Mandatory E2E for fork
# PRs is enforced separately.
#
# Base-branch guard: auto E2E/Run refresh only runs for PRs targeting main.
# Stacked PRs (base != main) are skipped so Matterwick is not triggered on every
# intermediate-branch push.
#
name: E2E label manager
on:
pull_request:
types:
- opened
- synchronize
- labeled
- unlabeled
concurrency:
group: e2e-label-manager-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
refresh-e2e-run-label:
if: >-
github.event.action == 'synchronize'
&& github.event.pull_request.base.ref == 'main'
&& github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-24.04
permissions:
actions: write
statuses: write
issues: write
pull-requests: write
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Force-cancel in-flight E2E runs for the previous commit
uses: ./.github/actions/cancel-e2e-runs
with:
head_branch: ${{ github.event.pull_request.head.ref }}
pr_number: ${{ github.event.pull_request.number }}
exclude_head_sha: ${{ github.event.pull_request.head.sha }}
reason: E2E superseded by new commit push
- name: Remove and re-add E2E/Run for Matterwick
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.MATTERMOST_BUILD_GH_TOKEN }}
script: |
const owner = context.repo.owner;
const repo = context.repo.repo;
const prNumber = context.payload.pull_request.number;
const runLabels = ['E2E/Run', 'E2E/Run-iOS', 'E2E/Run-Android'];
const {data: labels} = await github.rest.issues.listLabelsOnIssue({
owner, repo, issue_number: prNumber,
});
const labelNames = labels.map((label) => label.name);
if (labelNames.includes('E2E/Override')) {
core.info(`PR #${prNumber} has E2E/Override — stripping run labels only.`);
for (const label of runLabels) {
if (!labelNames.includes(label)) {
continue;
}
try {
await github.rest.issues.removeLabel({
owner, repo, issue_number: prNumber, name: label,
});
} catch (err) {
if (err.status !== 404) {
throw err;
}
}
}
return;
}
// Remove first so re-adding always emits pull_request:labeled for Matterwick.
for (const label of runLabels) {
try {
await github.rest.issues.removeLabel({
owner, repo, issue_number: prNumber, name: label,
});
core.info(`Removed ${label} from PR #${prNumber} before refresh.`);
} catch (err) {
if (err.status !== 404) {
throw err;
}
}
}
core.info(`PR #${prNumber} synchronize — re-adding E2E/Run (Matterwick labeled hook).`);
await github.rest.issues.addLabels({
owner, repo, issue_number: prNumber,
labels: ['E2E/Run'],
});
add-e2e-run-label:
if: >-
github.event.action == 'opened'
&& github.event.pull_request.base.ref == 'main'
&& github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-24.04
permissions:
issues: write
pull-requests: write
steps:
- name: Add E2E/Run (PAT — emits labeled webhook for Matterwick)
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.MATTERMOST_BUILD_GH_TOKEN }}
script: |
const owner = context.repo.owner;
const repo = context.repo.repo;
const prNumber = context.payload.pull_request.number;
const runLabels = ['E2E/Run', 'E2E/Run-iOS', 'E2E/Run-Android'];
const {data: labels} = await github.rest.issues.listLabelsOnIssue({
owner, repo, issue_number: prNumber,
});
const labelNames = labels.map((label) => label.name);
if (labelNames.includes('E2E/Override')) {
core.info(`PR #${prNumber} has E2E/Override label — skipping E2E/Run.`);
for (const label of runLabels) {
if (!labelNames.includes(label)) {
continue;
}
try {
await github.rest.issues.removeLabel({
owner, repo, issue_number: prNumber, name: label,
});
core.info(`Removed stale ${label} from PR #${prNumber} (E2E/Override active).`);
} catch (err) {
if (err.status !== 404) {
throw err;
}
}
}
return;
}
if (labelNames.includes('E2E/Run')) {
core.info(`PR #${prNumber} already has E2E/Run on open — skipping add.`);
return;
}
core.info(`PR #${prNumber} opened — adding E2E/Run via PAT (Matterwick labeled hook).`);
await github.rest.issues.addLabels({
owner, repo, issue_number: prNumber,
labels: ['E2E/Run'],
});
e2e-label-manager:
runs-on: ubuntu-24.04
permissions:
issues: write
pull-requests: write
actions: write
statuses: write
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
# ── Honor E2E/Override: strip run labels + cancel in-flight E2E ─────────
- name: Honor E2E/Override
if: >-
github.event.action == 'labeled'
&& github.event.label.name == 'E2E/Override'
&& github.event.pull_request.head.repo.full_name == github.repository
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const owner = context.repo.owner;
const repo = context.repo.repo;
const prNumber = context.payload.pull_request.number;
const runLabels = ['E2E/Run', 'E2E/Run-iOS', 'E2E/Run-Android'];
for (const label of runLabels) {
try {
await github.rest.issues.removeLabel({
owner, repo, issue_number: prNumber, name: label,
});
core.info(`Removed ${label} from PR #${prNumber} (E2E/Override applied).`);
} catch (err) {
if (err.status === 404) {
core.info(`${label} was not set on PR #${prNumber}; nothing to remove.`);
continue;
}
throw err;
}
}
- name: Cancel in-progress E2E runs
if: >-
github.event.pull_request.head.repo.full_name == github.repository
&& github.event.action == 'labeled'
&& github.event.label.name == 'E2E/Override'
uses: ./.github/actions/cancel-e2e-runs
with:
head_branch: ${{ github.event.pull_request.head.ref }}
pr_number: ${{ github.event.pull_request.number }}
reason: E2E cancelled (E2E/Override label applied)