From f2e93170a67b72c8adafc83d4ee1a0d79ac6b126 Mon Sep 17 00:00:00 2001 From: Quentin Castel Date: Tue, 3 Dec 2019 10:34:42 +0000 Subject: [PATCH] init --- .github/workflows/release.yml | 29 ++++++++ .github/workflows/tag.yml | 14 ++++ Dockerfile | 4 ++ README.md | 132 ++++++++++++++++++++++++++++++++++ action.yml | 71 ++++++++++++++++++ backport.sh | 84 ++++++++++++++++++++++ settings.xml | 14 ++++ 7 files changed, 348 insertions(+) create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/tag.yml create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 action.yml create mode 100755 backport.sh create mode 100644 settings.xml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..48703ee --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,29 @@ +on: + push: + # Sequence of patterns matched against refs/tags + tags: + - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 + +name: Create Release + +jobs: + build: + name: Create Release + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@master + - name: Create Release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token + with: + tag_name: ${{ github.ref }} + release_name: Release ${{ github.ref }} + body: | + Changes in this Release + - First Change + - Second Change + draft: false + prerelease: false \ No newline at end of file diff --git a/.github/workflows/tag.yml b/.github/workflows/tag.yml new file mode 100644 index 0000000..ffca624 --- /dev/null +++ b/.github/workflows/tag.yml @@ -0,0 +1,14 @@ +name: Bump version +on: + push: + branches: + - master +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Bump version and push tag + uses: mathieudutour/github-tag-action@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..4386622 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,4 @@ +FROM qcastel/maven-git-gpg:latest + +COPY ./release.sh /usr/local/bin +COPY ./settings.xml /usr/share/maven/conf diff --git a/README.md b/README.md new file mode 100644 index 0000000..01a48de --- /dev/null +++ b/README.md @@ -0,0 +1,132 @@ +# github action backport commits + +The GitHub Action enables you to backport the latest commit of the current branch to other branches. +You can imagine for example putting this github action on master, and automatically backport to your previous release. + +The action won't push directly to your backport branches, instead, it will create a PR. This allows you +to make sure the backport compiles and passes your tests before merging. +The auto-merge of the PR is not covered by this github action. + +# Usage + +## examples + +For back-porting to your branches 'releases-*': + +``` + - name: Backport + uses: qcastel/github-actions-backport@master + with: + backport-branches-regex: "releases*" + + git-release-bot-name: "release-bot" + git-release-bot-email: "release-bot@example.com" + + access-token: ${{ secrets.GITHUB_ACCESS_TOKEN }} +``` + +To add default user reviewers to the PR: + +``` + - name: Backport + uses: qcastel/github-actions-backport@master + with: + backport-branches-regex: "releases*" + + reviewers-users: ['alice', 'bob'] + + git-release-bot-name: "release-bot" + git-release-bot-email: "release-bot@example.com" + + access-token: ${{ secrets.GITHUB_ACCESS_TOKEN }} + +``` + +To add default team reviewers to the PR: + +``` + - name: Backport + uses: qcastel/github-actions-backport@master + with: + backport-branches-regex: "releases*" + + reviewers-teams: ['team-a'] + + git-release-bot-name: "release-bot" + git-release-bot-email: "release-bot@example.com" + + access-token: ${{ secrets.GITHUB_ACCESS_TOKEN }} + +``` + +To setup the bot to sign commits: + +``` + - name: Backport + uses: qcastel/github-actions-backport@master + with: + backport-branches-regex: "releases*" + + reviewers-teams: ['team-a'] + + git-release-bot-name: "release-bot" + git-release-bot-email: "release-bot@example.com" + + gpg-enabled: "true" + gpg-key-id: ${{ secrets.GITHUB_GPG_KEY_ID }} + gpg-key: ${{ secrets.GITHUB_GPG_KEY }} + + access-token: ${{ secrets.GITHUB_ACCESS_TOKEN }} + +``` + + +We welcome contributions! If your usecase is slightly different than us, just suggest a RFE or contribute to this repo directly. + +## Setup the bot gpg key + +Setting up a gpg key for your bot is a good security feature. This way, you can enforce sign commits in your repo, +even for your release bot. + +![Screenshot-2019-11-28-at-20-47-06.png](https://i.postimg.cc/9F6cxpqm/Screenshot-2019-11-28-at-20-47-06.png) + +- Create dedicate github account for your bot and add him into your team for your git repo. +- Create a new GPG key: https://help.github.com/en/github/authenticating-to-github/generating-a-new-gpg-key + +This github action needs the key ID and the key base64 encoded. + +```$xslt + gpg-key-id: ${{ secrets.GITHUB_GPG_KEY_ID }} + gpg-key: ${{ secrets.GITHUB_GPG_KEY }} +``` + +### Get the KID + +You can get the key ID doing the following: + +```$xslt +gpg --list-secret-keys --keyid-format LONG + +sec rsa2048/3EFC3104C0088B08 2019-11-28 [SC] + CBFD9020DAC388A77C68385C3EFC3104C0088B08 +uid [ultimate] bot-openbanking4-dev (it's the bot openbanking4.dev key) +ssb rsa2048/7D1523C9952204C1 2019-11-28 [E] + +``` +The key ID for my bot is 3EFC3104C0088B08. Add this value into your github secret for this repo, under `GITHUB_GPG_KEY_ID` +PS: the key id is not really a secret but we found more elegant to store it there than in plain text in the github action yml + +### Get the GPG private key + +Now we need the raw key and base64 encode +```$xslt +gpg --export-secret-keys --armor 3EFC3104C0088B08 | base64 +``` + +Copy the result and add it in your githup repo secrets under `GITHUB_GPG_KEY`. + +Go the bot account in github and import this GPG key into its profile. + +# License +The Dockerfile and associated scripts and documentation in this project are released under the MIT License. + diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..4bd0824 --- /dev/null +++ b/action.yml @@ -0,0 +1,71 @@ +# action.yml +name: 'Backport commit' +author: https://github.com/qcastel +description: 'Backport your latest commit to other branches' +branding: + color: blue + icon: unlock +inputs: + gpg-enabled: + description: 'Enable gpg signing' + required: false + default: false + gpg-key-id: + description: 'The GPG key ID' + required: false + gpg-key: + description: 'The GPG key' + required: false + + git-release-bot-name: + description: 'The git user name for committing the release' + required: true + git-release-bot-email: + description: 'The git user email for committing the release' + required: true + + access-token: + description: 'Github access token. https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line' + required: true + + backport-branches-regex: + description: 'The regex to match the backport branches. ps: we use grep for that' + required: true + + reviewers-users: + description: 'An array of user logins that will be requested to review the PR' + required: false + reviewers-teams: + description: 'AAn array of team slugs that will be requested to review the PR' + required: false + + pr-body: + description: 'The body to define for the PRs created' + default: "Auto cherry-pick made by release bot. Will auto-merge if build pass" + pr-title: + description: 'The body to define for the PRs created' + default: "Auto cherry-pick made by release bot. Will auto-merge if build pass" + +runs: + using: 'docker' + image: 'Dockerfile' + args: + - backport.sh + env: + GPG_ENABLED: ${{ inputs.gpg-enabled }} + GPG_KEY_ID: ${{ inputs.gpg-key-id }} + GPG_KEY: ${{ inputs.gpg-key }} + + GIT_RELEASE_BOT_NAME: ${{ inputs.git-release-bot-name }} + GIT_RELEASE_BOT_EMAIL: ${{ inputs.git-release-bot-email }} + + GITHUB_ACCESS_TOKEN: ${{ inputs.access-token }} + + BACKPORT_BRANCHES_REGEX: ${{ input.backport-branches-regex}} + + REVIEWERS_USERS: ${{ input.reviewers-users}} + REVIEWERS_TEAMS: ${{ input.reviewers-teams}} + + PR_BODY: ${{ input.pr-body}} + PR_TITLE: ${{ input.pr-title}} + diff --git a/backport.sh b/backport.sh new file mode 100755 index 0000000..3338203 --- /dev/null +++ b/backport.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash +set -e + +# avoid the release loop by checking if the latest commit is a release commit +readonly local last_release_commit_hash=$(git log --author="$GIT_RELEASE_BOT_NAME" --pretty=format:"%H" -1) +echo "Last $GIT_RELEASE_BOT_NAME commit: ${last_release_commit_hash}" +echo "Current commit: ${GITHUB_SHA}" +if [[ "${last_release_commit_hash}" = "${GITHUB_SHA}" ]]; then + echo "Skipping for $GIT_RELEASE_BOT_NAME commit" + exit 0 +fi + +# Making sure we are on top of the branch +echo "Git checkout branch ${GITHUB_REF##*/}" +git checkout ${GITHUB_REF##*/} +echo "Git reset hard to ${GITHUB_SHA}" +git reset --hard ${GITHUB_SHA} + +# This script will do a release of the artifact according to http://maven.apache.org/maven-release/maven-release-plugin/ +echo "Setup git user name to '$GIT_RELEASE_BOT_NAME'" +git config --global user.name "$GIT_RELEASE_BOT_NAME"; +echo "Setup git user email to '$GIT_RELEASE_BOT_EMAIL'" +git config --global user.email "$GIT_RELEASE_BOT_EMAIL"; + +# Setup GPG +echo "GPG_ENABLED '$GPG_ENABLED'" +if [[ $GPG_ENABLED == "true" ]]; then + echo "Enable GPG signing in git config" + git config --global commit.gpgsign true + echo "Using the GPG key ID $GPG_KEY_ID" + git config --global user.signingkey $GPG_KEY_ID + echo "GPG_KEY_ID = $GPG_KEY_ID" + echo "Import the GPG key" + echo "$GPG_KEY" | base64 -d > private.key + gpg --import ./private.key + rm ./private.key +else + echo "GPG signing is not enabled" +fi + +reviewers="" +if [[ -n $REVIEWERS_USERS ]]; then + echo "User reviewers: ${REVIEWERS_USERS}" + reviewers="\"reviewers\": $REVIEWERS_USERS" +else + echo "No user reviewer defined for this github action" +fi + +if [[ -n $REVIEWERS_TEAMS ]]; then + echo "Team reviewers: ${REVIEWERS_TEAMS}" + if [[ -n $REVIEWERS_USERS ]]; then + reviewers="${reviewers}," + fi + reviewers="${reviewers}\"team_reviewers\": $REVIEWERS_TEAMS" +else + echo "No team reviewer defined for this github action" +fi +echo "The reviewers for those PRs: $reviewers" + + +# Cherry pick master in every select branches and create a PR +for branch in $(git branch -r | grep ${BACKPORT_BRANCHES_REGEX} | sed 's/origin\///'); do + git checkout -b auto-${branch} origin/${branch} + git cherry-pick ${GITHUB_SHA} + git push -f origin auto-${branch} + response=$(curl -X POST \ + "https://api.github.com/repos/${GITHUB_REPOSITORY}/pulls?access_token=$GITHUB_ACCESS_TOKEN" \ + -H 'Content-Type: application/json' \ + -H "Authorization: Bearer ${GITHUB_ACCESS_TOKEN}" \ + -d "{ + \"title\": \"${PR_TITLE}\", + \"body\": \"${PR_BODY}\", + \"head\": \"auto-${branch}\", + \"base\": \"${branch}\" + }") + if [[ -z $reviewers ]]; then + pull_request_id=$(echo response | jq .number) + curl -X POST \ + "https://api.github.com/repos/${GITHUB_REPOSITORY}/pulls/${pull_request_id}/requested_reviewers?access_token=$GITHUB_ACCESS_TOKEN" \ + -H 'Content-Type: application/json' \ + -H "Authorization: Bearer ${GITHUB_ACCESS_TOKEN}" \ + -d "{ ${reviewers} }" + fi +done \ No newline at end of file diff --git a/settings.xml b/settings.xml new file mode 100644 index 0000000..ba2b916 --- /dev/null +++ b/settings.xml @@ -0,0 +1,14 @@ + + + + + ${env.MAVEN_REPO_SERVER_ID} + ${env.MAVEN_REPO_SERVER_USERNAME} + + ${env.MAVEN_REPO_SERVER_PASSWORD} + + + \ No newline at end of file