Skip to content

Audit cask flight step conversions #268

Audit cask flight step conversions

Audit cask flight step conversions #268

Workflow file for this run

name: Close incomplete pull requests
on:
# `pull_request_target` has a write token, so this workflow must only ever run trusted
# base-branch code and must never checkout or execute pull request head code.
pull_request_target:
types:
- opened
- edited
- reopened
permissions: {}
defaults:
run:
shell: bash -euo pipefail {0}
concurrency:
group: "incomplete-pr-${{ github.event.pull_request.number }}"
cancel-in-progress: true
jobs:
manage:
# Restrict this write-token workflow to Homebrew/brew. The first step also
# fails if a repository checkout has occurred.
if: >-
github.repository == 'Homebrew/brew' &&
github.event.pull_request.user.login != 'BrewTestBot' &&
github.event.pull_request.user.login != 'dependabot[bot]'
runs-on: ubuntu-latest
permissions:
# Read the trusted base-branch pull request template through the API; write only
# the issue comment and pull request state needed here.
contents: read
issues: write
pull-requests: write
env:
GH_TOKEN: ${{ github.token }}
INCOMPLETE_TEMPLATE_COMMENT_MARKER: "<!-- incomplete-pr-template -->"
PR_NUMBER: ${{ github.event.pull_request.number }}
PR_TEMPLATE_URL: ${{ github.server_url }}/${{ github.repository }}/blob/main/.github/PULL_REQUEST_TEMPLATE.md
steps:
- name: Verify no checkout
run: |
if git -C "${GITHUB_WORKSPACE:?}" rev-parse --is-inside-work-tree &>/dev/null
then
echo "Refusing to run after a repository checkout in ${GITHUB_WORKSPACE}." >&2
exit 1
fi
- name: Write pull request body
# Do not add a checkout here. `pull_request_target` has a write token, so this
# step must only use inline trusted code and API responses from `main`.
env:
# Bind PR-controlled strings as environment variables instead of interpolating
# them into shell code.
PR_BODY: ${{ github.event.pull_request.body }}
run: |
# This workflow intentionally uses `pull_request_target` so it can close and
# reopen forked pull requests. Keep this self-contained and never execute
# pull request code from this step.
mkdir -p "${RUNNER_TEMP:?}/incomplete-prs"
printf "%s" "${PR_BODY}" >"${RUNNER_TEMP}/incomplete-prs/pr-body"
- name: Fetch pull request template
run: |
gh api "repos/${GITHUB_REPOSITORY:?}/contents/.github/PULL_REQUEST_TEMPLATE.md?ref=main" \
--jq ".content" |
base64 --decode >"${RUNNER_TEMP:?}/incomplete-prs/template"
- name: Check pull request template
id: template
run: |
complete_template="$(
ruby - \
"${RUNNER_TEMP}/incomplete-prs/pr-body" \
"${RUNNER_TEMP}/incomplete-prs/template" <<'RUBY'
CHECKBOX_MARKER = /\A- \[[ xX]\] /
CHECKED_CHECKBOX_MARKER = /\A- \[[xX]\] /
HTML_COMMENT_LINE = /\A<!--.*-->\z/
MARKDOWN_HORIZONTAL_LINE = /\A-+\z/
NORMALISED_CHECKBOX_MARKER = '- [ ] '
REQUIRED_TEMPLATE_PERCENTAGE = 75
PERCENTAGE_SCALE = 100
def lines(path)
File.read(path, mode: 'rb')
.encode('UTF-8', invalid: :replace, undef: :replace)
.lines(chomp: true)
end
def normalise_lines(path)
lines(path).each_with_object([]) do |line, normalised_lines|
line = line.strip.sub(CHECKBOX_MARKER, NORMALISED_CHECKBOX_MARKER)
# Ignore blank lines.
next if line.empty?
# Ignore --- markdown horizontal lines.
next if line.match?(MARKDOWN_HORIZONTAL_LINE)
# Ignore <!-- HTML comments -->
next if line.match?(HTML_COMMENT_LINE)
normalised_lines << line
end.uniq
end
pr_body_path = ARGV.fetch(0)
template_path = ARGV.fetch(1)
pr_lines = normalise_lines(pr_body_path)
template_lines = normalise_lines(template_path)
matching_template_lines = template_lines.count { |line| pr_lines.include?(line) }
scaled_matching_percentage = matching_template_lines * PERCENTAGE_SCALE
scaled_required_percentage = template_lines.count * REQUIRED_TEMPLATE_PERCENTAGE
preserves_template = scaled_matching_percentage >= scaled_required_percentage
has_checked_checkbox = lines(pr_body_path).any? { |line| line.match?(CHECKED_CHECKBOX_MARKER) }
has_non_template_content = (pr_lines - template_lines).any?
puts preserves_template && (has_checked_checkbox || has_non_template_content)
RUBY
)"
case "${complete_template}" in
true | false) ;;
*)
echo "Unexpected template completion result: ${complete_template}" >&2
exit 1
;;
esac
echo "complete_template=${complete_template}" >>"${GITHUB_OUTPUT:?}"
- name: Find incomplete template comment
id: comments
if: >-
(github.event.pull_request.state == 'closed' &&
steps.template.outputs.complete_template == 'true') ||
(github.event.pull_request.state != 'closed' &&
steps.template.outputs.complete_template == 'false')
run: |
comment_ids="$(
gh api --paginate "repos/${GITHUB_REPOSITORY:?}/issues/${PR_NUMBER:?}/comments" \
--jq ".[] | select(.user.login == \"github-actions[bot]\" and (.body | contains(\"${INCOMPLETE_TEMPLATE_COMMENT_MARKER:?}\"))) | .id"
)"
if [[ -n "${comment_ids}" ]]
then
echo "has_incomplete_template_comment=true" >>"${GITHUB_OUTPUT:?}"
else
echo "has_incomplete_template_comment=false" >>"${GITHUB_OUTPUT:?}"
fi
- name: Find pull request closer
id: closer
if: >-
github.event.pull_request.state == 'closed' &&
steps.template.outputs.complete_template == 'true'
run: |
closed_by="$(gh api "repos/${GITHUB_REPOSITORY:?}/issues/${PR_NUMBER:?}" --jq ".closed_by.login // \"\"")"
echo "closed_by=${closed_by}" >>"${GITHUB_OUTPUT:?}"
- name: Reopen completed pull request
if: >-
github.event.pull_request.state == 'closed' &&
steps.template.outputs.complete_template == 'true' &&
steps.closer.outputs.closed_by == 'github-actions[bot]' &&
steps.comments.outputs.has_incomplete_template_comment == 'true'
run: |
gh api --method PATCH "repos/${GITHUB_REPOSITORY:?}/pulls/${PR_NUMBER:?}" \
-f state=open
- name: Comment on incomplete pull request
if: >-
github.event.pull_request.state != 'closed' &&
steps.template.outputs.complete_template == 'false' &&
steps.comments.outputs.has_incomplete_template_comment != 'true'
run: |
gh api --method POST "repos/${GITHUB_REPOSITORY:?}/issues/${PR_NUMBER:?}/comments" \
--raw-field body="$(
cat <<COMMENT
${INCOMPLETE_TEMPLATE_COMMENT_MARKER}
Thanks for your pull request. This has been closed because it appears to use an incomplete or outdated pull request template.
Please edit the pull request body to fill in the current [pull request template](${PR_TEMPLATE_URL:?}). This workflow will reopen the pull request automatically once the template is complete.
COMMENT
)"
- name: Close incomplete pull request
if: >-
github.event.pull_request.state != 'closed' &&
steps.template.outputs.complete_template == 'false'
run: |
gh api --method PATCH "repos/${GITHUB_REPOSITORY:?}/pulls/${PR_NUMBER:?}" \
-f state=closed