Skip to content
Merged
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
3 changes: 2 additions & 1 deletion .github/release-health.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
"unreleased_grace_hours": 4,
"tag_without_release_grace_hours": 1,
"pypi_lag_grace_minutes": 30,
"remediation": "gh workflow run release.yml --repo OpenAdaptAI/openadapt-flow --ref main -f operation=semantic-release"
"unreleased_remediation": "gh workflow run release.yml --repo OpenAdaptAI/openadapt-flow --ref main -f operation=semantic-release",
"pypi_remediation": "gh workflow run release.yml --repo OpenAdaptAI/openadapt-flow --ref main -f operation=publish-existing-ref -f ref={tag}"
}
]
}
43 changes: 32 additions & 11 deletions .github/workflows/release-health.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ name: Release health
# `failure`.
#
# Three triggers, one script:
# schedule -- the actual detector. Bounds "how long can a releasable fix
# sit unnoticed" to ~7h instead of "until someone looks".
# schedule -- the backstop detector. Bounds "how long can a releasable
# fix sit unnoticed" without spending eight runner starts a
# day on a deliberately human-authorized release lane.
# workflow_run -- fires when a release run COMPLETES NON-SUCCESSFULLY, which
# includes `cancelled` and `skipped`. `if: failure()` steps
# inside a release workflow cannot see either, and a run
Expand All @@ -34,10 +35,10 @@ name: Release health

on:
schedule:
# Every 3 hours. One stdlib step, no dependency install, no cache, so this
# costs seconds a day rather than a matrix. With the 4h grace window below,
# a releasable commit is surfaced within ~7h at worst.
- cron: '53 */3 * * *'
# Twice daily. Failed/cancelled/skipped release runs still trigger the check
# immediately through workflow_run below; this schedule only finds work for
# which nobody started a release at all.
- cron: '53 5,17 * * *'
workflow_dispatch:
workflow_run:
workflows: ["Release and PyPI Publish"]
Expand Down Expand Up @@ -80,6 +81,7 @@ jobs:
github.event.workflow_run.conclusion != 'success')
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
issues: write
steps:
Expand All @@ -93,10 +95,24 @@ jobs:
id: evaluate
env:
GITHUB_TOKEN: ${{ github.token }}
RELEASE_RUN_FAILED: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.conclusion != 'success' && 'true' || 'false' }}
FAILED_RELEASE_RUN_ID: ${{ github.event.workflow_run.id }}
FAILED_RELEASE_HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
FAILED_RELEASE_HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
run: |
set -euo pipefail
extra_args=()
if [ "${RELEASE_RUN_FAILED}" = "true" ]; then
extra_args+=(
--failed-release-run-id "${FAILED_RELEASE_RUN_ID}"
--failed-release-head-sha "${FAILED_RELEASE_HEAD_SHA}"
--failed-release-head-branch "${FAILED_RELEASE_HEAD_BRANCH}"
)
fi
python scripts/check_release_health.py \
--markdown release-health.md \
--github-output "${GITHUB_OUTPUT}" \
"${extra_args[@]}" \
--run-url "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"

# One issue per repository, rewritten in place. A new issue every day is
Expand All @@ -111,10 +127,15 @@ jobs:
set -euo pipefail
# Match on a colon-free prefix and compare the full title in jq: a
# colon inside a GitHub search phrase is parsed as a qualifier.
EXISTING=$(gh issue list --repo "${GITHUB_REPOSITORY}" --state open \
--search "in:title \"Release health\"" --json number,title \
--jq '[.[] | select(.title == env.TITLE)][0].number // empty')
EXISTING_JSON=$(gh issue list --repo "${GITHUB_REPOSITORY}" --state all \
--limit 1000 --json number,title,state \
--jq '[.[] | select(.title == env.TITLE)][0] // {}')
EXISTING=$(jq -r '.number // empty' <<< "${EXISTING_JSON}")
EXISTING_STATE=$(jq -r '.state // empty' <<< "${EXISTING_JSON}")
if [ -n "${EXISTING}" ]; then
if [ "${EXISTING_STATE}" = "CLOSED" ]; then
gh issue reopen "${EXISTING}" --repo "${GITHUB_REPOSITORY}"
fi
gh issue edit "${EXISTING}" --repo "${GITHUB_REPOSITORY}" \
--body-file release-health.md
echo "Updated issue #${EXISTING}."
Expand All @@ -124,7 +145,7 @@ jobs:
fi

- name: Close the issue once every gap is closed
if: steps.evaluate.outputs.alert != 'true'
if: steps.evaluate.outputs.clear == 'true'
env:
GH_TOKEN: ${{ github.token }}
TITLE: "Release health - unreleased work or an incomplete publish"
Expand All @@ -133,7 +154,7 @@ jobs:
# Match on a colon-free prefix and compare the full title in jq: a
# colon inside a GitHub search phrase is parsed as a qualifier.
EXISTING=$(gh issue list --repo "${GITHUB_REPOSITORY}" --state open \
--search "in:title \"Release health\"" --json number,title \
--limit 1000 --json number,title \
--jq '[.[] | select(.title == env.TITLE)][0].number // empty')
if [ -n "${EXISTING}" ]; then
gh issue close "${EXISTING}" --repo "${GITHUB_REPOSITORY}" \
Expand Down
4 changes: 2 additions & 2 deletions public-artifacts.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
},
{
"path": ".github/release-health.json",
"sha256": "890cf7eb9449cef31cb52cf74346e48618697e6831ccb7f82ccedfb9bb73d7df"
"sha256": "f8d5d90650c26a5e5d44051639eff6fae32878170ba76259c5d5447ede8302ac"
},
{
"path": ".github/workflows/canvas-nodom-ladder.yml",
Expand Down Expand Up @@ -109,7 +109,7 @@
},
{
"path": ".github/workflows/release-health.yml",
"sha256": "67c301d999f17407717ac56f629d567f4eed524f74a51f6b0865905686a646ea"
"sha256": "36bbd52aeafa67f83512de6af5d0a608f20885d0c7826abe4e6fe3b772eb2b39"
},
{
"path": ".github/workflows/release.yml",
Expand Down
Loading