Skip to content

Commit

Permalink
Feat: Enable support to submit single commits
Browse files Browse the repository at this point in the history
Each commit in the pull request are processed individually as a
single commit before submitting to Gerrit repository. This option
allows you to preserve git history.

This requires `inputs.SUBMIT_SINGLE_COMMITS` to be set to 'true'
from the caller.

Remove extra inputs. Gerrit server and port and project has be read
from .gitreview file. Composite actions have a limitation on
the number of the inputs that can be passed to 10.

Update doc example with new feat options.

Signed-off-by: Anil Belur <[email protected]>
  • Loading branch information
askb committed Aug 1, 2024
1 parent 4bdafe2 commit 27f4a30
Show file tree
Hide file tree
Showing 4 changed files with 277 additions and 139 deletions.
7 changes: 2 additions & 5 deletions .github/workflows/call-g2g-composite-action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,8 @@ jobs:
id: gerrit-upload
uses: lfit/github2gerrit@main
with:
USE_PR_AS_COMMIT: false
FETCH_DEPTH: 10
GERRIT_KNOWN_HOSTS: ${{ vars.GERRIT_KNOWN_HOSTS }}
GERRIT_SERVER: ${{ vars.GERRIT_SERVER }}
GERRIT_SERVER_PORT: "29418"
SUBMIT_SINGLE_COMMITS: "true"
USE_PR_AS_COMMIT: "false"
GERRIT_SSH_PRIVKEY_G2G: ${{ secrets.GERRIT_SSH_PRIVKEY_G2G }}
GERRIT_SSH_USER_G2G: ${{ vars.GERRIT_SSH_USER_G2G }}
GERRIT_SSH_USER_G2G_EMAIL: ${{ vars.GERRIT_SSH_USER_G2G_EMAIL }}
Expand Down
146 changes: 114 additions & 32 deletions .github/workflows/github2gerrit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ name: github2gerrit-reusable-workflow
on:
workflow_call:
inputs:
SUBMIT_SINGLE_COMMITS:
description: "Submit one commit at a time to the Gerrit repository"
required: false
default: false
type: boolean
USE_PR_AS_COMMIT:
description: "Use PR body and tittle as commit message"
required: false
Expand Down Expand Up @@ -73,6 +78,14 @@ jobs:
with:
python-version: "3.11"

- name: Validate workflow inputs
if: ${{ (inputs.USE_PR_AS_COMMIT == true) && (inputs.SUBMIT_SINGLE_COMMITS == true) }}
shell: bash
# yamllint disable rule:line-length
run: |
echo "Error: USE_PR_AS_COMMIT and SUBMIT_SINGLE_COMMITS cannot be enabled at the same time"
exit 1
- name: "Install required dependencies: git-review,jq"
shell: bash
run: |
Expand Down Expand Up @@ -212,9 +225,37 @@ jobs:
env:
GH_TOKEN: ${{ github.token }}

- name: Prepare commits to submit one at a time
shell: bash
if: ${{ (env.PR_COMMITS > 0) && (inputs.SUBMIT_SINGLE_COMMITS == true) }}
# yamllint disable rule:line-length
run: |
set -x
commit_shas=$(gh pr view ${{ env.PR_NUMBER }} --json commits --jq '.commits[] | .oid')
git checkout -b tmp_branch ${{ github.event.pull_request.base.sha }}
# Cherry-pick the commits into diff branch and amend to add change-Id
for csha in ${commit_shas}; do
git checkout tmp_branch
git cherry-pick "${csha}"
git commit -s -v --no-edit --amend
change_id="$(git log --format="%(trailers:key=Change-Id,valueonly,separator=%x2C)" -n1)"
if [ -n "${change_id}" ]; then
# Capture the newly created change-Id
echo "$change_id" >> change-Id.txt
else
echo "FAIL: Change-Id not created, exit job!"
exit 1
fi
git checkout ${{ env.GERRIT_BRANCH }}
done
git log -n3
env:
GH_TOKEN: ${{ github.token }}

- name: Squash commits into a single commit
shell: bash
if: ${{ (env.PR_COMMITS > 0) }}
if: ${{ (env.PR_COMMITS > 0) && (inputs.SUBMIT_SINGLE_COMMITS == false) }}
# yamllint disable rule:line-length
run: |
set -x
Expand Down Expand Up @@ -251,7 +292,7 @@ jobs:
git log -n2
- name: Overwrite commit message with PR tittle and body
if: ${{ (github.event_name == 'pull_request_target') && (env.PR_COMMITS > 0) && (inputs.USE_PR_AS_COMMIT == true) }}
if: ${{ (github.event_name == 'pull_request_target') && (env.PR_COMMITS > 0) && (inputs.USE_PR_AS_COMMIT == true) && (inputs.SUBMIT_SINGLE_COMMITS == false) }}
shell: bash
# yamllint disable rule:line-length
run: |
Expand Down Expand Up @@ -285,6 +326,10 @@ jobs:
run: |
set -x
if ${{ inputs.SUBMIT_SINGLE_COMMITS == true }}; then
git checkout tmp_branch
fi
reviewers_emails_list="${{ inputs.REVIEWERS_EMAIL }}"
# If the reviewers email is unset/empty then use a default
reviewers=${reviewers_emails_list:-"${{ inputs.GERRIT_SSH_USER_G2G_EMAIL }}"}
Expand All @@ -293,35 +338,68 @@ jobs:
echo "git review .... inprogress"
git review --yes -t "$topic" --reviewers "$reviewers"
# retrive change-id from the submitted PR
gerrit_change_id=$(git show HEAD --format=%B -s | grep Change-Id: | cut -d " " -f2;)
if [[ "$gerrit_change_id" != '' ]]; then
echo "GERRIT_CHANGE_ID=${gerrit_change_id}" >> "$GITHUB_ENV"
fi
- name: Retrive the Gerrit change number from Change-ID
if: env.GERRIT_CHANGE_ID != ''
- name: Validate Change-ID and retrive the Gerrit change number
id: change_num
shell: bash
# yamllint disable rule:line-length
run: |
set -x
# Query for a pre-existing gerrit review to retrive Change-Id
ssh -v -p 29418 "${{ inputs.GERRIT_SSH_USER_G2G }}@${{ env.GERRIT_SERVER }}" \
gerrit query limit:1 owner:self is:open \
project:"${{ env.PROJECT_REPO_GERRIT }}" \
--current-patch-set --format=JSON \
"${{ env.GERRIT_CHANGE_ID }}" > query_result.txt
if [[ ! -s change-Id.txt ]]; then
# retrive change-id from the submitted PR
gerrit_change_id=$(git show HEAD --format=%B -s | grep Change-Id: | cut -d " " -f2;)
if [[ "$gerrit_change_id" == '' ]]; then
echo "GERRIT_CHANGE_ID: null"; exit 1
fi
echo "$gerrit_change_id" >> change-Id.txt
fi
query_result_url=$(jq -r '.url | select( . != null )' query_result.txt)
query_result_number=$(jq -r '.number | select( . != null )' query_result.txt)
query_result_commit_sha=$(jq -r '.currentPatchSet.revision | select( . != null )' query_result.txt)
if [[ -s change-Id.txt ]]; then
GERRIT_CHANGE_ID_VALUES="$(<change-Id.txt)"
{
echo 'GERRIT_CHANGE_ID<<EOF'
echo "${GERRIT_CHANGE_ID_VALUES}"
echo EOF
} >> "$GITHUB_ENV"
fi
echo "GERRIT_CHANGE_REQUEST_URL=${query_result_url}" >> "$GITHUB_ENV"
echo "GERRIT_CHANGE_REQUEST_NUMBER=${query_result_number}" >> "$GITHUB_ENV"
echo "GERRIT_COMMIT_SHA=${query_result_commit_sha}" >> "$GITHUB_ENV"
while IFS="" read -r cid; do
# Query for a pre-existing gerrit review to retrive Change-Id
ssh -v -n -p 29418 "${{ inputs.GERRIT_SSH_USER_G2G }}@${{ env.GERRIT_SERVER }}" \
"gerrit query limit:1 owner:self is:open" \
"project:${{ env.PROJECT_REPO_GERRIT }}" \
--current-patch-set --format=JSON \
"$cid" > query_result.txt
query_result_url=$(jq -r '.url | select( . != null )' query_result.txt)
query_result_number=$(jq -r '.number | select( . != null )' query_result.txt)
query_result_commit_sha=$(jq -r '.currentPatchSet.revision | select( . != null )' query_result.txt)
echo "${query_result_url}" >> change-url.txt
echo "${query_result_commit_sha}" >> commit-sha.txt
echo "${query_result_number}" >> change-request-number.txt
done < change-Id.txt
GERRIT_CHANGE_REQUEST_URL_VALUES="$(<change-url.txt)"
{
echo 'GERRIT_CHANGE_REQUEST_URL<<EOF'
echo "${GERRIT_CHANGE_REQUEST_URL_VALUES}"
echo EOF
} >> "$GITHUB_ENV"
GERRIT_COMMIT_SHA_VALUES="$(<commit-sha.txt)"
{
echo 'GERRIT_COMMIT_SHA<<EOF'
echo "${GERRIT_COMMIT_SHA_VALUES}"
echo EOF
} >> "$GITHUB_ENV"
GERRIT_CHANGE_REQUEST_NUM_VALUES="$(<change-request-number.txt)"
{
echo 'GERRIT_CHANGE_REQUEST_NUM<<EOF'
echo "${GERRIT_CHANGE_REQUEST_NUM_VALUES}"
echo EOF
} >> "$GITHUB_ENV"
- name: Add source of Github PR URL as a gerrit comment
if: env.GERRIT_CHANGE_ID != ''
Expand All @@ -334,22 +412,26 @@ jobs:
pr_path="${{ github.server_url }}/${{ github.repository }}/pull/${{ env.PR_NUMBER }}"
message="$(printf 'GHPR: %s\nAcition-Run: %s\n' "${pr_path}" "${run_url}")"
# Add a comment on the change was create from Github.
ssh -v -p 29418 "${{ inputs.GERRIT_SSH_USER_G2G }}@${{ env.GERRIT_SERVER }}" \
gerrit review -m "'""${message}""'" \
--branch ${{ env.GERRIT_BRANCH }} --project "${{ env.PROJECT_REPO_GERRIT }}" \
"${{ env.GERRIT_COMMIT_SHA }}"
- name: PR Comment update CR number
if: env.GERRIT_CHANGE_REQUEST_URL != ''
# Add comment backref change request to Github PR and workflow job.
while IFS="" read -r csha; do
ssh -v -n -p 29418 "${{ inputs.GERRIT_SSH_USER_G2G }}@${{ env.GERRIT_SERVER }}" \
gerrit review -m "'""${message}""'" \
--branch ${{ env.GERRIT_BRANCH }} --project "${{ env.PROJECT_REPO_GERRIT }}" \
"$csha"
done < commit-sha.txt
- name: Add comment to refrence the change-request on the pull-request
if: |
hashFiles('commit-sha.txt') != '' ||
(! startsWith(env.GERRIT_CHANGE_REQUEST_URL, ''))
uses: actions/github-script@v7
with:
result-encoding: string
retries: 3
retry-exempt-status-codes: 400,401
script: |
const output = `The pull-request PR-${{ env.PR_NUMBER }} is submitted to Gerrit [${{ inputs.ORGANIZATION }}](https://${{ env.GERRIT_SERVER }})! \n
To follow up on the change visit: [${{ env.GERRIT_CHANGE_REQUEST_NUMBER }}](${{ env.GERRIT_CHANGE_REQUEST_URL }}) \n \n
To follow up on the change visit: \n \n ${{ env.GERRIT_CHANGE_REQUEST_URL }} \n \n
NOTE: The pull-request PR-${{ env.PR_NUMBER }} will be closed, re-opening the pull-request will not update the same commit and may result in duplicate changes on Gerrit.`
github.rest.issues.createComment({
issue_number: context.issue.number,
Expand Down
43 changes: 30 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,41 @@ The action extracts the commits from a GitHub pull-request and submits them to a
The action and workflow are written with bash scripts using well known Git SCM tools, gh, jq and git-review.

1. The action is triggered when a new pull request is created on a GitHub repository configured with the action.
2. Squash all the commits in the pull request into a single commit.
2. One of the below options can be used depending on the workflow followed by the community.

- Squash all the commits in the pull request into a single commit and use consolidate the commit titles and body into a single commit (Default).
- Squash all the commits in the pull request into a single commit and using the pull request title and body as the commit title and body (USE_PR_AS_COMMIT).
- Submit each commit as a separate single commit preserving the git history (SUBMIT_SINGLE_COMMITS).

3. Check for a Change-Id line in the pull request commit message. If it is not present, add the Change-Id to the commit. If the Change-Id is found in any of the commits, it will be reused along with the patch.
4. Create a Gerrit patch with the Change-Id, squashing all PR changes into a single commit.
5. Add a pull-request reference as a comment on the Gerrit change for committers or reviewers to refer to the source of change request.
6. Close the pull request once the Gerrit patch is submitted. A comment is added to the pull request with the URL to the change. Any updates will require the pull request to be reopened. Updates to the pull request are done with a force push, which triggers the workflows to ensure the change is resubmitted.
4. Add the Change-Id (and optionally squash changes into a single commit if required).
5. Add a pull-request and workflow run reference link as a comment on the Gerrit change that was created for committers or reviewers to back reference to the source of change request.
6. Add a comment to the pull request with the URL to the change. Any updates will require the pull request to be reopened and updates to the pull request must be done with a force push, which triggers the workflows to ensure the change is resubmitted.
7. Close the pull request once the Gerrit patch is submitted successfully.

## Features

### Use pull-request a commit message
### Use pull-request as a single squashed commit message

- Commits in a pull request are squashed into a single commit before submitting the change request to Gerrit. This is the default behavior shown in the caller workflow examples.
- Merge commits get filtered out.
- Here `inputs.SUBMIT_SINGLE_COMMITS` is set to 'false' by default.

### Use pull-request body and title in the commit message

- Commits in a pull request are squashed into a single commit before submitting the change request to Gerrit.
- The commit message title and body is extracted from the pull request body and title along with the change-Id and Signed-off-by lines. Commits are still squashed and while only the commit body and title are discarded.
- Requires setting `inputs.USE_PR_AS_COMMIT` to 'true'.
- This option is exclusive with `inputs.SUBMIT_SINGLE_COMMITS` and cannot be used together.

### Use pull-request a commit message
### Submit each commit as a separate single commit

- Set the commit message as pull request body and title along with the change-Id and Signed-off-by lines. Commit message are squashed and the commit body and tittle are discarded.
- Each commit in the pull request are processed individually as a single commit before submitting to Gerrit repository. This option allows you to preserve git history.
- Requires `inputs.SUBMIT_SINGLE_COMMITS` to be set to 'true' in the caller.

## Caveats - Future Improvements

- Commits in a pull request are submitted as independent change requests to Gerrit under the same topic.
- Code review comments on Gerrit will not be updated back on the pull request, requiring developers to follow up on the Gerrit change request URL.
- `inputs.SUBMIT_SINGLE_COMMITS` has not be tested extensively for handling large pull requests.
- Code review comments on Gerrit are not synchronized back to the pull request comment, therefore requires developers to follow up on the Gerrit change request URL. Rework through the recommended changes can be done by reopening the pull request and updating to the commits through a force push.

## Required Inputs

Expand All @@ -44,7 +59,8 @@ The action and workflow are written with bash scripts using well known Git SCM t

## Optional Inputs

- `USE_PR_AS_COMMIT`: Use commit body and tittle from pull-request (Default: false)
- `SUBMIT_SINGLE_COMMITS`: Submit one commit at a time to the Gerrit repository (Default: false)
- `USE_PR_AS_COMMIT`: Use commit body and title from pull-request (Default: false)
- `FETCH_DEPTH`: fetch-depth of the clone repo. (Default: 10)
- `GERRIT_PROJECT`: Gerrit project repository (Default read from .gitreview).
- `GERRIT_SERVER`: Gerrit server FQDN (Default read from .gitreview).
Expand All @@ -55,6 +71,7 @@ The action and workflow are written with bash scripts using well known Git SCM t
## Full Example Usage with Composite Action

Use the composite action as a step in the workflow for further processing.
Example workflow does not enable `SUBMIT_SINGLE_COMMITS` and `USE_PR_AS_COMMIT`

```yaml
---
Expand Down Expand Up @@ -85,10 +102,10 @@ jobs:
id: gerrit-upload
uses: lfit/github2gerrit@main
with:
SUBMIT_SINGLE_COMMITS: "false"
USE_PR_AS_COMMIT: "false"
FETCH_DEPTH: 10
GERRIT_KNOWN_HOSTS: ${{ vars.GERRIT_KNOWN_HOSTS }}
GERRIT_SERVER: ${{ vars.GERRIT_SERVER }}
GERRIT_SERVER_PORT: "29418"
GERRIT_SSH_PRIVKEY_G2G: ${{ secrets.GERRIT_SSH_PRIVKEY_G2G }}
GERRIT_SSH_USER_G2G: ${{ vars.GERRIT_SSH_USER_G2G }}
GERRIT_SSH_USER_G2G_EMAIL: ${{ vars.GERRIT_SSH_USER_G2G_EMAIL }}
Expand Down
Loading

0 comments on commit 27f4a30

Please sign in to comment.