Skip to content
Snippets Groups Projects
Unverified Commit 88afb0c9 authored by Alexander Lesnenko's avatar Alexander Lesnenko Committed by GitHub
Browse files

Improve backports (#21148)

* extract actions

* check metabase membership
parent 37642aaa
No related branches found
No related tags found
No related merge requests found
name: Find squashed commit
description: Finds squashed commit in master by pull request name
inputs:
pull-request-number:
required: true
base-ref:
required: true
outputs:
commit:
value: ${{ steps.find-squashed-commit.outputs.commit }}
description: Found commit SHA
runs:
using: "composite"
steps:
- run: |
git checkout $BASE_REF
git fetch --all
echo "Looking for a commit that contains pull request number $PULL_REQUEST_NUMBER in $BASE_REF"
COMMIT=$(env -i git log $BASE_REF --grep="(#$PULL_REQUEST_NUMBER)" --format="%H")
echo "commit SHA $COMMIT"
echo "::set-output name=commit::$COMMIT"
id: find-squashed-commit
shell: bash
env:
PULL_REQUEST_NUMBER: ${{ inputs.pull-request-number }}
BASE_REF: ${{ inputs.base-ref }}
name: Get latest release branch
outputs:
branch-name:
value: ${{ steps.get-latest-release-branch.outputs.result }}
runs:
using: "composite"
steps:
- uses: actions/github-script@v4
id: get-latest-release-branch
with:
result-encoding: string
script: |
const releaseBranches = await github.git.listMatchingRefs({
owner: context.repo.owner,
repo: context.repo.repo,
ref: "heads/release-x.",
});
const getVersionFromBranch = branch => {
const match = branch.match(/release-x\.(.*?)\.x/);
return match && parseInt(match[1]);
};
const latestReleaseBranch = releaseBranches.data
.filter(branch => getVersionFromBranch(branch.ref) !== null)
.reduce(
(prev, current) =>
getVersionFromBranch(prev.ref) > getVersionFromBranch(current.ref)
? prev
: current,
{ ref: "" },
);
const latestReleaseBranchName = latestReleaseBranch.ref.replace(
/^refs\/heads\//,
"",
);
console.log(`Latest release branch: ${latestReleaseBranchName}`);
return latestReleaseBranchName;
name: Notify Pull Request
inputs:
message:
required: true
include-log:
required: false
default: true
runs:
using: "composite"
steps:
- uses: actions/github-script@v4
id: get-latest-release-branch
with:
result-encoding: string
script: |
const message = "${{ inputs.message }}"
const shouldIncludeLog = ${{ inputs.include-log }}.toString() === "true";
const author = context.payload.sender.login;
let body = `@${author} ${message}`;
if (shouldIncludeLog) {
const { GITHUB_SERVER_URL, GITHUB_REPOSITORY, GITHUB_RUN_ID } = process.env;
const runUrl = `${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}`;
body += ` [[Logs]](${runUrl})`;
}
github.issues.createComment({
issue_number: context.payload.number,
owner: context.repo.owner,
repo: context.repo.repo,
body,
});
# Creates a pull request with the latest release branch as a target with a cherry-picked commit if an associated pull request has `backport` label
name: AutoBackport
name: Auto-backport
on:
push:
branches:
- master
pull_request:
types: [closed, labeled]
jobs:
pr_info:
name: Check if the commit should be backported
create-backport:
if: github.event.pull_request.merged == true && (contains(github.event.pull_request.labels.*.name, 'backport') || github.event.label.name == 'backport')
runs-on: ubuntu-20.04
outputs:
title: ${{ fromJson(steps.collect_pr_info.outputs.result).title }}
number: ${{ fromJson(steps.collect_pr_info.outputs.result).pullRequestNumber }}
author: ${{ fromJson(steps.collect_pr_info.outputs.result).author }}
should_backport: ${{ fromJson(steps.collect_pr_info.outputs.result).hasBackportLabel }}
steps:
- uses: actions/github-script@v4
id: collect_pr_info
- uses: actions/checkout@v2
with:
script: |
const commitMessage = context.payload.commits[0].message;
const pullRequestNumbers = Array.from(commitMessage.matchAll(/\(#(.*?)\)/g))
if (pullRequestNumbers.length === 0) {
return {
author: "",
pullRequestNumber: 0,
title: "",
hasBackportLabel: false
};
}
if (pullRequestNumbers > 1) {
throw "Multiple PRs are associated with this commit";
}
const pullRequestNumber = pullRequestNumbers[0][1];
const { data } = await github.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pullRequestNumber
});
const hasBackportLabel = data.labels.some((label) => label.name === 'backport');
const { title, user } = data
console.log(`PR #${pullRequestNumber}: "${title}" hasBackportLabel=${hasBackportLabel}`)
return {
author: user.login,
pullRequestNumber,
title: data.title,
hasBackportLabel
}
fetch-depth: 0
get_latest_release_branch:
name: Get latest release branch
runs-on: ubuntu-20.04
outputs:
branch_name: ${{ steps.get_branch_name.outputs.result }}
steps:
- uses: actions/github-script@v4
id: get_branch_name
- uses: ./.github/actions/find-squashed-commit
name: Find commit
id: find_commit
with:
result-encoding: string
script: |
const releaseBranches = await github.git.listMatchingRefs({
owner: context.repo.owner,
repo: context.repo.repo,
ref: "heads/release-x.",
});
const getVersionFromBranch = branch => {
const match = branch.match(/release-x\.(.*?)\.x/);
return match && parseInt(match[1])
};
const latestReleaseBranch = releaseBranches.data
.filter(branch => getVersionFromBranch(branch.ref) !== null)
.reduce((prev, current) => getVersionFromBranch(prev.ref) > getVersionFromBranch(current.ref) ? prev : current, { ref: "" });
const latestReleaseBranchName = latestReleaseBranch.ref.replace(/^refs\/heads\//, "");
pull-request-number: ${{ github.event.pull_request.number }}
base-ref: ${{ github.event.pull_request.base.ref }}
console.log(`Latest release branch: ${latestReleaseBranchName}`)
- uses: ./.github/actions/get-latest-release-branch
name: Get latest release branch
id: get_latest_release_branch
return latestReleaseBranchName;
create_backport_pull_request:
runs-on: ubuntu-20.04
name: Create a backport PR with the commit
needs: [pr_info, get_latest_release_branch]
if: ${{ needs.pr_info.outputs.should_backport == 'true' }}
env:
TARGET_BRANCH: ${{ needs.get_latest_release_branch.outputs.branch_name }}
ORIGINAL_PULL_REQUEST_NUMBER: ${{ needs.pr_info.outputs.number }}
ORIGINAL_TITLE: ${{ needs.pr_info.outputs.title }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v3
name: Checkout
with:
fetch-depth: 0
- run: |
- id: create_backport_pull_request
run: |
git config --global user.email "metabase-github-automation@metabase.com"
git config --global user.name "$GITHUB_ACTOR"
BACKPORT_BRANCH="backport-$GITHUB_SHA"
BACKPORT_BRANCH="backport-$COMMIT"
git checkout ${TARGET_BRANCH}
git fetch --all
git checkout -b "${BACKPORT_BRANCH}" origin/"${TARGET_BRANCH}"
git cherry-pick "${GITHUB_SHA}"
git push -u origin "${BACKPORT_BRANCH}"
git checkout -b ${BACKPORT_BRANCH}
git cherry-pick ${COMMIT} || true
CONFLICTS=$(git ls-files -u | wc -l)
if [ "$CONFLICTS" -gt 0 ]; then
echo "Could not cherry pick because of a conflict"
echo "::set-output name=has-conflicts::true"
git cherry-pick --abort
git checkout master
exit 0
fi
git checkout master
git push -u origin ${BACKPORT_BRANCH}
hub pull-request -b "${TARGET_BRANCH}" -h "${BACKPORT_BRANCH}" -l "auto-backported" -a "${GITHUB_ACTOR}" -F- <<<"🤖 backported \"${ORIGINAL_TITLE}\"
#${ORIGINAL_PULL_REQUEST_NUMBER}"
notify_when_failed:
runs-on: ubuntu-20.04
name: Notify about failure
needs: [pr_info, create_backport_pull_request]
if: ${{ failure() }}
steps:
- uses: actions/github-script@v4
env:
TARGET_BRANCH: ${{ steps.get_latest_release_branch.outputs.branch-name }}
ORIGINAL_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
ORIGINAL_TITLE: ${{ github.event.pull_request.title }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COMMIT: ${{ steps.find_commit.outputs.commit }}
- uses: ./.github/actions/notify-pull-request
if: ${{ steps.create_backport_pull_request.outputs.has-conflicts == 'true' }}
with:
script: |
const { GITHUB_SERVER_URL, GITHUB_REPOSITORY, GITHUB_RUN_ID } = process.env;
const runUrl = `${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}`
include-log: false
message: could not create a backport due to conflicts
github.issues.createComment({
issue_number: ${{ needs.pr_info.outputs.number }},
owner: context.repo.owner,
repo: context.repo.repo,
body: `@${{ needs.pr_info.outputs.author }} could not automatically create a backport PR 😩 [[Logs]](${runUrl})`
})
- uses: ./.github/actions/notify-pull-request
if: ${{ failure() }}
with:
include-log: true
message: something went wrong while creating a backport
......@@ -11,7 +11,19 @@ jobs:
if: contains(github.event.comment.body, '@metabase-bot backport')
runs-on: ubuntu-20.04
steps:
- uses: actions/github-script@v6
- id: is_organization_member
uses: JamesSingleton/is-organization-member@1.0.0
with:
organization: metabase
username: ${{ github.event.issue.user.login }}
token: ${{ secrets.GITHUB_TOKEN }}
- run: |
result=${{ steps.is_organization_member.outputs.result }}
if [ $result == false ]; then
echo User ${{ github.event.comment.user.login }} is not a member of Metabase organization
exit 1
fi
- uses: actions/github-script@v4
id: branch_info
with:
script: |
......@@ -116,16 +128,8 @@ jobs:
needs: create_pull_request
if: ${{ failure() }}
steps:
- uses: actions/github-script@v6
- uses: actions/checkout@v2
- uses: ./.github/actions/notify-pull-request
with:
script: |
const { GITHUB_SERVER_URL, GITHUB_REPOSITORY, GITHUB_RUN_ID} = process.env;
const runUrl = `${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}`
const author = context.payload.comment.user.login;
github.issues.createComment({
issue_number: context.payload.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `@${author} could not automatically a backport PR 😩 [[Logs]](${runUrl})`
})
include-log: true
message: something went wrong while creating a backport
......@@ -14,6 +14,18 @@ jobs:
branch_name: ${{ fromJson(steps.fetch_pr.outputs.data).head.ref }}
commit_sha: ${{ fromJson(steps.fetch_pr.outputs.data).head.sha }}
steps:
- id: is_organization_member
uses: JamesSingleton/is-organization-member@1.0.0
with:
organization: metabase
username: ${{ github.event.issue.user.login }}
token: ${{ secrets.GITHUB_TOKEN }}
- run: |
result=${{ steps.is_organization_member.outputs.result }}
if [ $result == false ]; then
echo User ${{ github.event.comment.user.login }} is not a member of Metabase organization
exit 1
fi
- name: Fetch issue
uses: octokit/request-action@v2.x
id: fetch_issue
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment