Close stale fleetie-initiated issues. (#45530)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #45700 Not a product change. This PR will allow us to run the workflow manually. After ~2 weeks, if there are no issues, we'll make it automatic. ## Testing - [x] Added/updated automated tests - [x] QA'd all new/changed functionality manually <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added automated workflow to identify and close stale issues created by Fleet team members, with dry-run capability and operation limits. * Added system to build and maintain a deduplicated list of Fleet team member handles from GitHub organization and repository history. * **Tests** * Added comprehensive test suites for stale issue management and handle list generation with mock GitHub API interactions and boundary condition coverage. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/fleetdm/fleet/pull/45530?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
name: Close stale Fleetie-initiated issues
|
||||
|
||||
# Marks open issues authored by current or former Fleeties as stale after 2 years of no activity, then
|
||||
# closes them after 14 more days of inactivity once labeled stale. Activity (any comment or update) bumps
|
||||
# `updated_at` and resets both clocks. Issues with the `bug`, `:product`, or any `customer-*` label are
|
||||
# exempt.
|
||||
#
|
||||
# Why this isn't just `actions/stale`: that action filters by labels, not by author. We can't pre-tag
|
||||
# issues with a "fleetie-initiated" label and hand off to actions/stale either, because adding a label
|
||||
# bumps `updated_at` and resets the staleness clock for the entire backlog. The closest upstream PR is
|
||||
# https://github.com/actions/stale/pull/1181 (`anyOfAuthors` allowlist input). It has been open with no
|
||||
# review since October 2024. When it merges, we should be able to replace this whole flow with a small
|
||||
# `actions/stale` config that passes the handle list from `build-fleetie-handles.js` as `anyOfAuthors`
|
||||
# and delete `stale-fleetie-issues.js` and its tests.
|
||||
|
||||
on:
|
||||
workflow_dispatch: # Manual
|
||||
inputs:
|
||||
dry_run:
|
||||
description: 'If true, log candidates without writing labels, comments, or closing issues.'
|
||||
type: boolean
|
||||
default: true
|
||||
max_operations:
|
||||
description: 'Maximum GitHub API write operations per run. Each modified issue costs 2 writes (comment + label, or comment + close).'
|
||||
type: number
|
||||
default: 400
|
||||
|
||||
concurrency:
|
||||
# Scope by event_name + ref so a pull_request trigger doesn't preempt an in-flight
|
||||
# workflow_dispatch run, and vice versa. Same-event same-ref runs still cancel as expected.
|
||||
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
close-stale-fleetie-issues:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # 4.4.0
|
||||
with:
|
||||
node-version: '24'
|
||||
|
||||
- name: Build Fleetie handle list
|
||||
env:
|
||||
# Fine-scoped PAT with read:org on the fleetdm org. Provisioned by IT; without it the script
|
||||
# falls back to handbook-only sources and emits a warning.
|
||||
READ_ORG_TOKEN: ${{ secrets.FLEET_GITHUB_TOKEN_MEMBERS_READ }}
|
||||
FLEETIE_HANDLES_OUT: ${{ runner.temp }}/fleeties.txt
|
||||
run: node .github/scripts/build-fleetie-handles.js
|
||||
|
||||
- name: Stale and close Fleetie-authored issues
|
||||
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
||||
env:
|
||||
FLEETIE_HANDLES_FILE: ${{ runner.temp }}/fleeties.txt
|
||||
# Force dry-run for every event other than workflow_dispatch.
|
||||
DRY_RUN: ${{ (github.event_name == 'workflow_dispatch' && inputs.dry_run == false) && 'false' || 'true' }}
|
||||
# parseMaxOps in the script applies the 400 default when the value is empty.
|
||||
MAX_OPERATIONS: ${{ inputs.max_operations }}
|
||||
with:
|
||||
script: |
|
||||
const run = require('./.github/scripts/stale-fleetie-issues.js');
|
||||
await run({ github, context, core });
|
||||
@@ -0,0 +1,64 @@
|
||||
name: Test stale Fleetie-issue scripts
|
||||
|
||||
# Runs the unit tests for the stale-Fleetie-issue scripts on PRs that change either script (or its
|
||||
# tests), the closer workflow, or this workflow. Handbook edits are deliberately excluded: the
|
||||
# scripts are resilient to any handle-shaped content the handbook can realistically contain
|
||||
# (denylist, length cap, trailing-hyphen filter, format regex), and the handbook changes often
|
||||
# enough that triggering on it would mostly burn CI minutes with no signal.
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- '.github/scripts/build-fleetie-handles.js'
|
||||
- '.github/scripts/build-fleetie-handles.test.js'
|
||||
- '.github/scripts/stale-fleetie-issues.js'
|
||||
- '.github/scripts/stale-fleetie-issues.test.js'
|
||||
- '.github/workflows/close-stale-fleetie-initiated-issues.yml'
|
||||
- '.github/workflows/test-stale-fleetie-issue-scripts.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/scripts/build-fleetie-handles.js'
|
||||
- '.github/scripts/build-fleetie-handles.test.js'
|
||||
- '.github/scripts/stale-fleetie-issues.js'
|
||||
- '.github/scripts/stale-fleetie-issues.test.js'
|
||||
- '.github/workflows/close-stale-fleetie-initiated-issues.yml'
|
||||
- '.github/workflows/test-stale-fleetie-issue-scripts.yml'
|
||||
workflow_dispatch: # Manual
|
||||
|
||||
# For PRs, github.head_ref groups by source branch. For pushes (e.g. main), head_ref is empty so
|
||||
# we fall back to github.ref so successive pushes to the same branch share a group and
|
||||
# cancellation actually applies.
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # 4.4.0
|
||||
with:
|
||||
node-version: '24'
|
||||
|
||||
- name: Run tests
|
||||
run: node --test .github/scripts/build-fleetie-handles.test.js .github/scripts/stale-fleetie-issues.test.js
|
||||
Reference in New Issue
Block a user