diff --git a/.github/workflows/README.md b/.github/workflows/README.md
new file mode 100644
index 0000000000..d013edd4bd
--- /dev/null
+++ b/.github/workflows/README.md
@@ -0,0 +1,38 @@
+# Github actions README
+This is an introduction about auto-cherry-pick workflow.
+take 202205 branch for example:
+1. pr_cherrypick_prestep:
+```mermaid
+graph
+Start(Origin PR) --> A{merged?}
+A -- NO --> STOP
+A -- YES --> A1{Approved
for 202205
Branch?}
+A1 -- NO --> STOP
+A1 -- YES --> A2(pr_cherrypick_prestep)
+B(pr_cherrypick_prestep)
+B --> B1{cherry pick
conflict?}
+B1 -- YES --> B2(Add tag:
Cherry Pick Confclit_202205) --> B3(Add comment:
refer author code conflict) --> STOP1(STOP)
+B1 -- NO --> B4(Create New PR) -- success --> B5(New PR add tag:
automerge) --> B6(New PR add comment:
Origin PR link) --> B7(Origin PR add tag:
Created PR to 202205 Branch) --> B8(Origin PR add comment:
New PR link)
+B4 -- fail --> STOP1
+```
+
+2. automerge:
+```mermaid
+graph
+Start(PR azp finished successfully) --> A{author:
mssonicbld?}
+A -- NO --> STOP
+A -- YES --> B{tag:
automerge?} -- YES --> C(Merge PR)
+B -- NO --> STOP
+```
+
+3. pr_cherrypick_poststep:
+```mermaid
+graph
+A(PR is Merged) --> B{tag:
automerge?}
+B -- YES --> B1{author:
mssonicbld?}
+B1 -- YES --> B2{"title starts:
[action] [PR:123]"}
+B2 -- YES --> C(Origin PR remove tag:
Created PR to 202205 Branch) --> D(Origin PR add tag:
Included in 202205 Branch)
+B -- NO --> STOP
+B1 -- NO --> STOP
+B2 -- NO --> STOP
+```
diff --git a/.github/workflows/pr_cherrypick_poststep.yml b/.github/workflows/pr_cherrypick_poststep.yml
new file mode 100644
index 0000000000..1e9e497075
--- /dev/null
+++ b/.github/workflows/pr_cherrypick_poststep.yml
@@ -0,0 +1,49 @@
+name: PostCherryPick
+on:
+ pull_request_target:
+ types:
+ - closed
+ branches:
+ - '20*'
+
+jobs:
+ post_cherry_pick:
+ if: github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'automerge') && github.event.pull_request.head.user.login == 'mssonicbld' && startsWith(github.event.pull_request.title, '[action]')
+ runs-on: ubuntu-latest
+ steps:
+ - name: Debug
+ env:
+ GITHUB_CONTEXT: ${{ toJson(github) }}
+ run: echo $GITHUB_CONTEXT | jq
+ - name: Checkout
+ uses: actions/checkout@v3
+ with:
+ persist-credentials: false
+ - name: Main
+ env:
+ GITHUB_CONTEXT: ${{ toJson(github) }}
+ TOKEN: ${{ secrets.TOKEN }}
+ run: |
+ set -e
+ pr_url=$(echo $GITHUB_CONTEXT | jq -r ".event.pull_request._links.html.href")
+ pr_id=$(echo $GITHUB_CONTEXT | jq -r ".event.number")
+ base_ref=$(echo $GITHUB_CONTEXT | jq -r ".base_ref")
+ echo ${TOKEN} | gh auth login --with-token
+ title=$(echo $GITHUB_CONTEXT | jq -r ".event.pull_request.title")
+ origin_pr_id=$(echo $title | grep -Eo "\[action\] \[PR:[0-9]*\]" | grep -Eo "[0-9]*")
+ origin_pr_url=$(echo $pr_url | sed "s/$pr_id/$origin_pr_id/")
+ echo =============================
+ echo pr_url: $pr_url
+ echo pr_id: $pr_id
+ echo base_ref: $base_ref
+ echo title: $title
+ echo origin_pr_id: $origin_pr_id
+ echo origin_pr_url: $origin_pr_url
+ echo =============================
+ # Add label
+ if [[ "$origin_pr_id" == "" ]];then
+ echo "original PR didn't found."
+ exit 1
+ fi
+ gh pr edit $origin_pr_url --add-label "Included in ${base_ref} Branch"
+ gh pr edit $origin_pr_url --remove-label "Created PR to ${base_ref} Branch,Request for ${base_ref} Branch,Approved for ${base_ref} Branch"
diff --git a/.github/workflows/pr_cherrypick_prestep.yml b/.github/workflows/pr_cherrypick_prestep.yml
new file mode 100644
index 0000000000..3caf3f9408
--- /dev/null
+++ b/.github/workflows/pr_cherrypick_prestep.yml
@@ -0,0 +1,136 @@
+name: PreCherryPick
+on:
+ pull_request_target:
+ types:
+ - labeled
+ - closed
+ branches:
+ - master-test
+
+jobs:
+ pre_cherry_pick:
+ if: github.event.pull_request.merged == true && ( (github.event.action == 'closed' && contains(join(github.event.pull_request.labels.*.name, ','), 'Approved for 20')) || (github.event.action == 'labeled' && startsWith(github.event.label.name, 'Approved for 20')) )
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+ persist-credentials: false
+ - name: Debug
+ env:
+ GITHUB_CONTEXT: ${{ toJson(github) }}
+ run: echo $GITHUB_CONTEXT | jq
+ - name: Main
+ env:
+ GITHUB_CONTEXT: ${{ toJson(github) }}
+ TOKEN: ${{ secrets.TOKEN }}
+ run: |
+ set -e
+
+ sha=$(echo $GITHUB_CONTEXT | jq -r ".event.pull_request.merge_commit_sha")
+ pr_id=$(echo $GITHUB_CONTEXT | jq -r ".event.number")
+ pr_url=$(echo $GITHUB_CONTEXT | jq -r ".event.pull_request._links.html.href")
+ repository=$(echo $GITHUB_CONTEXT | jq -r ".repository")
+ labels=$(echo $GITHUB_CONTEXT | jq -r ".event.pull_request.labels[].name")
+ author=$(echo $GITHUB_CONTEXT | jq -r ".event.pull_request.base.user.login")
+ branches=$(git branch -a --list 'origin/20????' | awk -F/ '{print$3}' | grep -E "202[0-9]{3}")
+ if [[ $(echo $GITHUB_CONTEXT | jq -r ".event.action") == "labeled" ]];then
+ labels=$(echo $GITHUB_CONTEXT | jq -r ".event.label.name")
+ fi
+ title=$(echo $GITHUB_CONTEXT | jq -r ".event.pull_request.title")
+ echo =============================
+ echo SHA: $sha
+ echo PRID: $pr_id
+ echo pr_url: $pr_url
+ echo repository: $repository
+ echo branches: $branches
+ echo labels:
+ echo "$labels"
+ echo ${TOKEN} | gh auth login --with-token
+ echo author: $author
+ echo title: $title
+ echo =============================
+
+ git config user.name mssonicbld
+ git config user.email sonicbld@microsoft.com
+ git config credential.https://github.com.username mssonicbld
+ git remote add mssonicbld https://mssonicbld:${TOKEN}@github.com/mssonicbld/sonic-buildimage
+ git fetch mssonicbld
+ git remote -vv
+
+ cherry_pick(){
+ set -e
+ local create_pr=''
+ while read label
+ do
+ echo label: $label
+ if [[ "$label" == "Approved for $branch Branch" ]];then
+ create_pr=1
+ fi
+ if [[ "$label" == "Created PR to $branch Branch" ]];then
+ echo "already has tag: Created PR to $branch Branch, return"
+ return 0
+ fi
+ if [[ "$label" == "Included in $branch Branch" ]];then
+ echo "already has tag: Included in $branch Branch, return"
+ return 0
+ fi
+ if [[ "$label" == "Cherry Pick Conflict_$branch" ]];then
+ echo "already has tag: Cherry Pick Conflict_$branch, return"
+ return 0
+ fi
+ done <<< "$labels"
+
+ if [[ "$create_pr" != "1" ]];then
+ echo "Didn't find 'Approved for $branch Branch' tag."
+ return 0
+ fi
+ # Begin to cherry-pick PR
+ git cherry-pick --abort 2>/dev/null || true
+ git clean -xdff 2>/dev/null || true
+ git reset HEAD --hard || true
+ git checkout -b $branch --track origin/$branch
+ git status | grep "working tree clean"
+
+ if ! git cherry-pick $sha;then
+ echo 'cherry-pick failed.'
+ git cherry-pick --abort
+ git status | grep "working tree clean"
+ # Add label
+ gh pr edit $pr_url --add-label "Cherry Pick Conflict_$branch"
+ echo 'Add label "Cherry Pick Conflict_$branch" success'
+ gh pr comment $pr_url --body "@${author} PR conflicts with $branch branch"
+ echo 'Add commnet "@${author} PR conflicts with $branch branch"'
+ else
+ # Create PR to release branch
+ git push mssonicbld HEAD:$branch-${pr_id} -f
+ result=$(gh pr create -R ${repository} -H mssonicbld:$branch-${pr_id} -B $branch -t "[action] [PR:$pr_id] $title" -b '' 2>&1)
+ echo $result | grep "already exists" && { echo $result; return 0; }
+ echo $result | grep github.com || { echo $result; return 1; }
+ new_pr_rul=$(echo $result | grep github.com)
+ echo new_pr_rul: $new_pr_rul
+
+ # Add label to old PR
+ gh pr edit $pr_url --add-label "Created PR to $branch Branch"
+ echo Add label Created PR to $branch Branch
+ # Add comment to old PR
+ gh pr comment $pr_url --body "Cherry-pick PR to $branch: ${new_pr_rul}"
+ echo Add comment to old PR
+
+ # Add label to new PR
+ gh pr edit $new_pr_rul --add-label "automerge"
+ echo Add label automerge to new PR
+ # Add comment to new PR
+ gh pr comment $new_pr_rul --body "Original PR: ${pr_url}"
+ echo Add comment to new PR
+ fi
+ }
+
+ for branch in $branches
+ do
+ echo -------------------------------------------
+ echo Begin to parse Branch: $branch
+ cherry_pick
+ done
+