Skip to content
Merged
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
208 changes: 208 additions & 0 deletions .github/workflows/send-emails.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
name: Send emails for merged PR

on:
pull_request:
types:
- closed
branches:
- "master"

jobs:
send_patches:
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest

steps:
- name: Checkout repo with full history
uses: actions/checkout@v5
with:
fetch-depth: 100

- name: Install deps (git send-email and jq)
run: |
sudo apt-get update
sudo apt-get install -y jq

## GHA images have a special git package that conflicts with
## git-send-email So this is a workaround to force the installation of
## the conflicting package.
sudo apt-get install -y libauthen-sasl-perl \
libemail-valid-perl \
libio-socket-ssl-perl \
libmailtools-perl perl \
libnet-smtp-ssl-perl

apt-get download git-email
sudo dpkg -i --force-all git-email*deb

- name: Configure git identity
run: |
git config user.name "gccrs gerris bot"
git config user.email "${{ secrets.SMTP_FROM }}"

- name: Export env
env:
GH_EVENT: ${{ toJson(github.event) }}
run: |
echo "$GH_EVENT" > /tmp/gh_event.json

PR_BASE_REF=$(jq -r '.pull_request.base.sha' /tmp/gh_event.json)
echo "PR_BASE_REF=$PR_BASE_REF" >> $GITHUB_ENV

PR_NUMBER=$(jq -r '.pull_request.number' /tmp/gh_event.json)
echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_ENV

PR_TITLE=$(jq -r '.pull_request.title' /tmp/gh_event.json)
echo "PR_TITLE=$PR_TITLE" >> $GITHUB_ENV

PR_URL=$(jq -r '.pull_request.html_url' /tmp/gh_event.json)
echo "PR_URL=$PR_URL" >> $GITHUB_ENV

PR_MERGE_COMMIT=$(jq -r '.pull_request.merge_commit_sha' /tmp/gh_event.json)
echo "PR_MERGE_COMMIT=$PR_MERGE_COMMIT" >> $GITHUB_ENV

PR_TARGET_BRANCH=$(jq -r '.pull_request.base.ref' /tmp/gh_event.json)
echo "PR_TARGET_BRANCH=$PR_TARGET_BRANCH" >> $GITHUB_ENV

PR_LABELS=$(jq -r '[.pull_request.labels[].name] | join(",")' /tmp/gh_event.json)
echo "PR_LABELS=$PR_LABELS" >> $GITHUB_ENV

REPO_SSH=$(jq -r '.repository.ssh_url' /tmp/gh_event.json)
echo "REPO_SSH=$REPO_SSH" >> $GITHUB_ENV

echo "SERIES_DIR=/tmp/series" >> $GITHUB_ENV

- name: Check for label 'no-ml' to skip sending emails
run: |
# Skip if PR has label "no-ml"
if echo "$PR_LABELS" | grep -qiE "(^|,)no-ml(,|$)"; then
echo "Opt-out label present: skipping mailing list."
echo "Opt-out label present: skipping mailing list." > $GITHUB_STEP_SUMMARY
exit 0
fi

- name: Get commit list from PR and skip the internal ones
id: commits
run: |
# Skip commits that touches any of these
patterns=(".github/"
"CODE_OF_CONDUCT.md"
"CONTRIBUTING.md"
"Dockerfile"
"README.md"
"logo.png"
"gcc/rust/gource-gccrs.sh"
"gcc/rust/monthly-diff.py"
)
regex=$(printf '%s\n' "${patterns[@]}" | sed -e 's/[.[\*^$+?(){|\/\\]/\\&/g' | paste -sd'|' -)

rm -f /tmp/commits.txt

git log --format="%H" "$PR_BASE_REF..HEAD" | while read SHA1; do
if grep -q -E "$regex" <(git diff-tree --no-commit-id --name-only -r "$SHA1"); then
echo "Touching something not to be upstreamed, skipping commit $SHA1"
else
echo "$SHA1" >> /tmp/commits.txt
fi
done

COUNT=$(wc -l < /tmp/commits.txt)
echo "COUNT=$COUNT" >> $GITHUB_ENV

- name: Check what to do based on series' size
run: |
MAX=150
if [ "${COUNT}" -gt "$MAX" ]; then
echo "Series has $COUNT commits (> $MAX). Not doing anything" >> $GITHUB_STEP_SUMMARY
exit 0
else if [ "${COUNT}" -eq 1 ]; then
echo "Single commit PR, don't do the cover letter"
echo "DO_COVER=0" >> $GITHUB_ENV
else
echo "Multiple commits ($COUNT) in PR, create a cover letter"
echo "DO_COVER=1" >> $GITHUB_ENV
fi fi

- name: Prepare patch series
run: |
set -euo pipefail

# Create a temporary branch that linearizes the PR commits
git checkout -B ci-mail-patches "$PR_BASE_REF"
# Cherry-pick commits in the exact PR order (no-commit to batch, then commit)
while read sha; do
git cherry-pick "$sha"
done < /tmp/commits.txt

# Build cover letter text
N="${COUNT:-0}"
TITLE="$(printf '[PATCH 0/%d] PR #%s: %s' "$N" "$PR_NUMBER" "$PR_TITLE")"

echo "PR: $PR_URL" > /tmp/description.txt
echo "Merged by: ${{ github.actor }}" >> /tmp/description.txt
echo "Base: $PR_TARGET_BRANCH" >> /tmp/description.txt
echo "" >> /tmp/description.txt
echo "This series was merged into the gccrs repository and is posted here for" >> /tmp/description.txt
echo "upstream visibility and potential drive-by review, as requested by GCC" >> /tmp/description.txt
echo "release managers." >> /tmp/description.txt
echo "" >> /tmp/description.txt
echo " Notes:" >> /tmp/description.txt
echo " - Source branch: $(jq -r '.pull_request.head.label' /tmp/gh_event.json)" >> /tmp/description.txt
echo " - Merge commit: $PR_MERGE_COMMIT" >> /tmp/description.txt
echo " - Commit count: $N" >> /tmp/description.txt
echo "" >> /tmp/description.txt

mkdir /tmp/series

if [ "$DO_COVER" = "1" ]; then
# Generate series + cover letter
git format-patch \
--subject-prefix="gccrs COMMIT" \
--cover-letter \
--description-file=/tmp/description.txt \
--base="$PR_BASE_REF" \
--output-directory /tmp/series \
"$PR_BASE_REF"..HEAD

awk -v CONTENT="$PR_TITLE" '{gsub(/\*\*\* SUBJECT HERE \*\*\*/, CONTENT); print}' /tmp/series/0000-cover-letter.patch > /tmp/temp
mv /tmp/temp /tmp/series/0000-cover-letter.patch
else
# Generate series + cover letter
git format-patch \
--subject-prefix="gccrs COMMIT" \
--no-cover-letter \
--base="$PR_BASE_REF" \
--output-directory /tmp/series \
"$PR_BASE_REF"..HEAD

# for every patch file, insert the github header right after the '---'.
sed '/^---$/ r /tmp/description.txt' -i /tmp/series/*
fi

- name: Send series via git send-email
env:
GIT_SMTP_SERVER: ${{ secrets.SMTP_SERVER }}
GIT_SMTP_ENCRYPTION: tls
GIT_SMTP_SERVER_PORT: ${{ secrets.SMTP_PORT }}
GIT_SMTP_AUTH: "true"
GIT_SMTP_USER: ${{ secrets.SMTP_USERNAME }}
GIT_SMTP_PASSWORD: ${{ secrets.SMTP_PASSWORD }}
FROM: ${{ secrets.SMTP_FROM }}
TO: ${{ secrets.PATCH_TO }}
CC: ${{ secrets.PATCH_CC }}
run: |
set -euo pipefail

git config sendemail.smtpserver "$GIT_SMTP_SERVER"
git config sendemail.smtpserverport "$GIT_SMTP_SERVER_PORT"
git config sendemail.smtpencryption "$GIT_SMTP_ENCRYPTION"
git config sendemail.smtpuser "$GIT_SMTP_USER"
git config sendemail.smtppass "$GIT_SMTP_PASSWORD"
git config sendemail.from "$FROM"
git config sendemail.to "$TO"
if [ -n "${CC:-}" ]; then git config sendemail.cc "$CC"; fi
git config sendemail.thread "true"
git config sendemail.confirm "never"
git config sendemail.annotate "false"

git send-email /tmp/series/*
Loading