Files
rustfs/.github/actions/schedule-failure-issue/action.yml
T
hector 6b2dd06ce6 ci: file scheduled-failure issues in rustfs/backlog (#7847)
Scheduled pipeline failures currently open [scheduled-failure] tracking
issues in rustfs/rustfs itself, adding bot noise to the code repository's
issue tracker. Route that alerting to rustfs/backlog instead.

- schedule-failure-issue gains target-repository (default rustfs/backlog);
  dedupe lookup, comment appends and issue creation target that repository.
- New source-token input (default ${{ github.token }}) reads the failed-job
  list from the reported run; the run still lives in and links to
  rustfs/rustfs. The issue body now carries a '- Repository:' line.
- All consumer workflows pass secrets.BACKLOG_ISSUE_TOKEN; the
  workflow-scoped GITHUB_TOKEN cannot open issues cross-repo. Alert job
  permissions blocks are unchanged.
2026-09-14 21:04:30 +08:00

164 lines
6.5 KiB
YAML

# Copyright 2024 RustFS Team
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
name: "Schedule Failure Issue"
description: >-
Open (or update) a tracking issue when a scheduled workflow run fails or
does not complete normally.
Issues are filed in the target repository (default rustfs/backlog), not
the repository the workflow runs in.
Dedupes by workflow name: if an open issue titled
"[scheduled-failure] <workflow name>" already exists there, the result is
appended as a comment; otherwise a new issue is created. This is the
single alerting mechanism for all scheduled pipelines (backlog#1149 ci-8).
inputs:
github-token:
description: >-
Token with issues:write on the target repository. The workflow-scoped
secrets.GITHUB_TOKEN is scoped to the code repository and cannot open
issues in rustfs/backlog, so pass a PAT / GitHub App token stored as a
repository secret (BACKLOG_ISSUE_TOKEN).
required: true
target-repository:
description: "Repository the failure-tracking issue is filed in."
required: false
default: rustfs/backlog
source-token:
description: >-
Token used to read the failed-job list from the reported run. Defaults
to the workflow's own token, which can read runs of its own repository.
required: false
default: ${{ github.token }}
workflow-name:
description: "Workflow name used for the issue title (the dedupe key)."
required: false
default: ${{ github.workflow }}
label:
description: >-
Label applied when a new issue is created. Must already exist in the
target repository; if applying it fails, the issue is created without a
label. Set to an empty string to skip labeling.
required: false
default: "infrastructure"
source-run-id:
description: "Run ID to report. Defaults to the current workflow run."
required: false
default: ${{ github.run_id }}
source-run-attempt:
description: "Run attempt to report. Defaults to the current attempt."
required: false
default: ${{ github.run_attempt }}
source-event:
description: "Trigger event of the run being reported."
required: false
default: ${{ github.event_name }}
source-ref-name:
description: "Ref name of the run being reported."
required: false
default: ${{ github.ref_name }}
source-sha:
description: "Commit SHA of the run being reported."
required: false
default: ${{ github.sha }}
details-file:
description: "Optional Markdown file appended to the issue body."
required: false
default: ""
runs:
using: "composite"
steps:
- name: Open or update failure-tracking issue
shell: bash
env:
GH_TOKEN: ${{ inputs.github-token }}
SOURCE_TOKEN: ${{ inputs.source-token }}
TARGET_REPOSITORY: ${{ inputs.target-repository }}
WORKFLOW_NAME: ${{ inputs.workflow-name }}
ISSUE_LABEL: ${{ inputs.label }}
SOURCE_RUN_ID: ${{ inputs.source-run-id }}
SOURCE_RUN_ATTEMPT: ${{ inputs.source-run-attempt }}
SOURCE_EVENT: ${{ inputs.source-event }}
SOURCE_REF_NAME: ${{ inputs.source-ref-name }}
SOURCE_SHA: ${{ inputs.source-sha }}
DETAILS_FILE: ${{ inputs.details-file }}
run: |
set -euo pipefail
title="[scheduled-failure] ${WORKFLOW_NAME}"
run_url="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${SOURCE_RUN_ID}"
# Inspect the reported run attempt. It can be the current in-workflow
# failure or a completed run observed by the external watchdog. The
# run lives in the repository running the workflow, so authenticate
# with the source token, not the target-repository token.
failed_jobs="$(GH_TOKEN="${SOURCE_TOKEN}" gh api \
"repos/${GITHUB_REPOSITORY}/actions/runs/${SOURCE_RUN_ID}/attempts/${SOURCE_RUN_ATTEMPT}/jobs" \
--paginate \
--jq '.jobs[]
| select(.conclusion == "failure" or .conclusion == "timed_out" or .conclusion == "cancelled")
| "- `\(.name)` (\(.conclusion))"')"
if [ -z "${failed_jobs}" ]; then
failed_jobs="- (failed job not recorded yet — see the run page)"
fi
details=""
if [ -n "${DETAILS_FILE}" ]; then
if [ -f "${DETAILS_FILE}" ]; then
details="$(cat "${DETAILS_FILE}")"
else
details="Details file was not available: \`${DETAILS_FILE}\`"
fi
fi
body="$(cat <<EOF
Run of **${WORKFLOW_NAME}** did not complete successfully.
- Repository: ${GITHUB_REPOSITORY}
- Run: ${run_url} (attempt ${SOURCE_RUN_ATTEMPT})
- Event: \`${SOURCE_EVENT}\`
- Ref: \`${SOURCE_REF_NAME}\` @ \`${SOURCE_SHA}\`
Non-success jobs:
${failed_jobs}
${details}
EOF
)"
# Dedupe by exact title among OPEN issues in the target repository (a
# closed issue means the earlier breakage was resolved; a new failure
# gets a fresh issue). GitHub search strips the [] characters, so
# search loosely and match the exact title with jq.
existing="$(gh issue list --repo "${TARGET_REPOSITORY}" --state open --limit 100 \
--search "\"scheduled-failure\" in:title" --json number,title \
| jq -r --arg title "${title}" 'map(select(.title == $title)) | (.[0].number // empty)')"
if [ -n "${existing}" ]; then
echo "Appending comment to existing open issue rustfs/backlog#${existing}"
gh issue comment "${existing}" --repo "${TARGET_REPOSITORY}" --body "${body}"
exit 0
fi
echo "Creating new issue in ${TARGET_REPOSITORY}: ${title}"
if [ -n "${ISSUE_LABEL}" ]; then
if gh issue create --repo "${TARGET_REPOSITORY}" \
--title "${title}" --body "${body}" --label "${ISSUE_LABEL}"; then
exit 0
fi
echo "::warning::issue creation with label '${ISSUE_LABEL}' failed (missing label?); retrying without a label"
fi
gh issue create --repo "${TARGET_REPOSITORY}" --title "${title}" --body "${body}"