(List (Com {[LIT_CHARS set]} {[LIT_CHARS -o]} {[LIT_CHARS errexit]} ) (Com {[LIT_CHARS set]} {[LIT_CHARS -o]} {[LIT_CHARS nounset]} ) (Com {[LIT_CHARS set]} {[LIT_CHARS -o]} {[LIT_CHARS pipefail]} ) (= scope= flags=0 words=[{[LIT_CHARS -r]}] bindings=[('KUBE_ROOT', {[DQ [ComSub (Com {[LIT_CHARS dirname]} {[DQ [VarSub BASH_SOURCE]]})][LIT_CHARS /..]]})]) (Com {[LIT_CHARS cd]} {[DQ [VarSub KUBE_ROOT]]} ) (= scope= flags=0 words=[{[LIT_CHARS -r]}] bindings=[('STARTINGBRANCH', {[ComSub (Com {[LIT_CHARS git]} {[LIT_CHARS symbolic-ref]} {[LIT_CHARS --short]} {[LIT_CHARS HEAD]})]})]) (= scope= flags=0 words=[{[LIT_CHARS -r]}] bindings=[('REBASEMAGIC', {[DQ [VarSub KUBE_ROOT][LIT_CHARS /.git/rebase-apply]]})]) (= scope= flags=0 words=[] bindings=[('DRY_RUN', {[VarSub DRY_RUN test_op=VS_TEST_COLON_HYPHEN {[DQ ]}]})]) (= scope= flags=0 words=[] bindings=[('UPSTREAM_REMOTE', {[VarSub UPSTREAM_REMOTE test_op=VS_TEST_COLON_HYPHEN {[LIT_CHARS upstream]}]})]) (= scope= flags=0 words=[] bindings=[('FORK_REMOTE', {[VarSub FORK_REMOTE test_op=VS_TEST_COLON_HYPHEN {[LIT_CHARS origin]}]})]) (If (DBracket {B1 UNARY_STRING_z {[VarSub GITHUB_USER test_op=VS_TEST_COLON_HYPHEN {}]}}) (List (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS "Please export GITHUB_USER= (or GH organization, if that's where your fork lives)"]]} ) (Com {[LIT_CHARS exit]} {[LIT_CHARS 1]} ) ) ) (If (Pipeline! (Com {[LIT_CHARS which]} {[LIT_CHARS hub]} < (FilenameRedirectNode filename={[LIT_CHARS /dev/null]} "> 1), > ) ) (List (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS "Can't find 'hub' tool in PATH, please install from https://github.com/github/hub"]]} ) (Com {[LIT_CHARS exit]} {[LIT_CHARS 1]} ) ) ) (If (DBracket {B2 BINARY_INT_LT {[DQ [VarSub #]]} {[LIT_CHARS 2]}}) (List (Com {[LIT_CHARS echo]} {[DQ [VarSub 0][LIT_CHARS " ...: cherry pick one or more onto and leave instructions for proposing pull request"]]} ) (Com {[LIT_CHARS echo]} ) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS " Checks out and handles the cherry-pick of (possibly multiple) for you."]]} ) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS " Examples:"]]} ) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS " "][VarSub 0][LIT_CHARS " upstream/release-3.14 12345 # Cherry-picks PR 12345 onto upstream/release-3.14 and proposes that as a PR."]]} ) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS " "][VarSub 0][LIT_CHARS " upstream/release-3.14 12345 56789 # Cherry-picks PR 12345, then 56789 and proposes the combination as a single PR."]]} ) (Com {[LIT_CHARS echo]} ) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS " Set the DRY_RUN environment var to skip git push and creating PR."]]} ) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS " This is useful for creating patches to a release branch without making a PR."]]} ) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS " When DRY_RUN is set the script will leave you in a branch containing the commits you cherry-picked."]]} ) (Com {[LIT_CHARS echo]} ) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS " Set UPSTREAM_REMOTE (default: upstream) and FORK_REMOTE (default: origin)"]]} ) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS " To override the default remote names to what you have locally."]]} ) (Com {[LIT_CHARS exit]} {[LIT_CHARS 2]} ) ) ) (If (AndOr OP_AND_IF (= scope= flags=0 words=[] bindings=[('git_status', {[ComSub (Com redirects=[(FilenameRedirectNode filename={[LIT_CHARS /dev/null]} "> 2)]{[LIT_CHARS git]} {[LIT_CHARS status]} {[LIT_CHARS --porcelain]} {[LIT_CHARS --untracked] [LIT_DBRACKET_LIKE "="] [LIT_CHARS no]})]})]) (DBracket {B1 UNARY_STRING_n {[DQ [VarSub git_status]]}}) ) (List (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS "!!! Dirty tree. Clean up and try again."]]} ) (Com {[LIT_CHARS exit]} {[LIT_CHARS 1]} ) ) ) (If (DBracket {B1 UNARY_FILE_e {[DQ [VarSub REBASEMAGIC]]}}) (List (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS "!!! 'git rebase' or 'git am' in progress. Clean up and try again."]]} ) (Com {[LIT_CHARS exit]} {[LIT_CHARS 1]} ) ) ) (= scope= flags=0 words=[{[LIT_CHARS -r]}] bindings=[('BRANCH', {[DQ [VarSub 1]]})]) (Com {[LIT_CHARS shift]} {[LIT_CHARS 1]} ) (= scope= flags=0 words=[{[LIT_CHARS -r]}] bindings=[('PULLS', {[Array {[DQ [VarSub @]]}]})]) (FunctionDef join [] (List (= scope= flags=0 words=[] bindings=[('IFS', {[DQ [VarSub 1]]})]) (Com {[LIT_CHARS shift]} ) (Com {[LIT_CHARS echo]} {[DQ [VarSub *]]} ) ) ) (= scope= flags=0 words=[{[LIT_CHARS -r]}] bindings=[('PULLDASH', {[ComSub (Com {[LIT_CHARS join]} {[LIT_CHARS -]} {[DQ [VarSub PULLS bracket_op=(Index {A Atom NODE_ARITH_WORD {AS_OP_AT "@"}}) transform_ops=[PatSub {} {[LIT_POUND "#"]} do_suffix]]]})]})]) (= scope= flags=0 words=[{[LIT_CHARS -r]}] bindings=[('PULLSUBJ', {[ComSub (Com {[LIT_CHARS join]} {[DQ [LIT_CHARS " "]]} {[DQ [VarSub PULLS bracket_op=(Index {A Atom NODE_ARITH_WORD {AS_OP_AT "@"}}) transform_ops=[PatSub {} {[LIT_POUND "#"]} do_suffix]]]})]})]) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS "+++ Updating remotes..."]]} ) (Com {[LIT_CHARS git]} {[LIT_CHARS remote]} {[LIT_CHARS update]} {[DQ [VarSub UPSTREAM_REMOTE]]} {[DQ [VarSub FORK_REMOTE]]} ) (If (Pipeline! (Com {[LIT_CHARS git]} {[LIT_CHARS log]} {[LIT_CHARS -n1]} {[LIT_CHARS --format] [LIT_DBRACKET_LIKE "="] [LIT_OTHER "%"] [LIT_CHARS H]} {[DQ [VarSub BRANCH]]} < (FilenameRedirectNode filename={[LIT_CHARS /dev/null]} "> 1), (DescriptorRedirectNode target={[LIT_CHARS 1]} &"> 2), > ) ) (List (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS "!!! '"][VarSub BRANCH][LIT_CHARS "' not found. The second argument should be something like "][VarSub UPSTREAM_REMOTE][LIT_CHARS /release-0.21.]]} ) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS " (In particular, it needs to be a valid, existing remote branch that I can 'git checkout'.)"]]} ) (Com {[LIT_CHARS exit]} {[LIT_CHARS 1]} ) ) ) (= scope= flags=0 words=[{[LIT_CHARS -r]}] bindings=[('NEWBRANCHREQ', {[DQ [LIT_CHARS automated-cherry-pick-of-][VarSub PULLDASH]]})]) (= scope= flags=0 words=[{[LIT_CHARS -r]}] bindings=[('NEWBRANCH', {[DQ [ComSub (Pipeline (Com {[LIT_CHARS echo]} {[DQ [VarSub NEWBRANCHREQ][LIT_CHARS -][VarSub BRANCH]]}) (Com {[LIT_CHARS sed]} {[SQ ]}) )]]})]) (= scope= flags=0 words=[{[LIT_CHARS -r]}] bindings=[('NEWBRANCHUNIQ', {[DQ [VarSub NEWBRANCH][LIT_CHARS -][ComSub (Com {[LIT_CHARS date]} {[LIT_OTHER "+"] [LIT_OTHER "%"] [LIT_CHARS s]})]]})]) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS "+++ Creating local branch "][VarSub NEWBRANCHUNIQ]]} ) (= scope= flags=0 words=[] bindings=[('cleanbranch', {[DQ ]})]) (= scope= flags=0 words=[] bindings=[('prtext', {[DQ ]})]) (= scope= flags=0 words=[] bindings=[('gitamcleanup', {[LIT_CHARS false]})]) (FunctionDef return_to_kansas [] (List (If (DBracket {B2 BINARY_STRING_EQUAL {[DQ [VarSub gitamcleanup]]} {[DQ [LIT_CHARS true]]}}) (List (Com {[LIT_CHARS echo]} ) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS "+++ Aborting in-progress git am."]]} ) (AndOr OP_OR_IF (Com {[LIT_CHARS git]} {[LIT_CHARS am]} {[LIT_CHARS --abort]} < (FilenameRedirectNode filename={[LIT_CHARS /dev/null]} "> 1), (DescriptorRedirectNode target={[LIT_CHARS 1]} &"> 2), > ) (Com {[LIT_CHARS true]} ) ) ) ) (If (DBracket {B1 UNARY_STRING_z {[DQ [VarSub DRY_RUN]]}}) (List (Com {[LIT_CHARS echo]} ) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS "+++ Returning you to the "][VarSub STARTINGBRANCH][LIT_CHARS " branch and cleaning up."]]} ) (AndOr OP_OR_IF (Com {[LIT_CHARS git]} {[LIT_CHARS checkout]} {[LIT_CHARS -f]} {[DQ [VarSub STARTINGBRANCH]]} < (FilenameRedirectNode filename={[LIT_CHARS /dev/null]} "> 1), (DescriptorRedirectNode target={[LIT_CHARS 1]} &"> 2), > ) (Com {[LIT_CHARS true]} ) ) (If (DBracket {B1 UNARY_STRING_n {[DQ [VarSub cleanbranch]]}}) (AndOr OP_OR_IF (Com {[LIT_CHARS git]} {[LIT_CHARS branch]} {[LIT_CHARS -D]} {[DQ [VarSub cleanbranch]]} < (FilenameRedirectNode filename={[LIT_CHARS /dev/null]} "> 1), (DescriptorRedirectNode target={[LIT_CHARS 1]} &"> 2), > ) (Com {[LIT_CHARS true]} ) ) ) (If (DBracket {B1 UNARY_STRING_n {[DQ [VarSub prtext]]}}) (Com {[LIT_CHARS rm]} {[DQ [VarSub prtext]]} ) ) ) ) ) ) (Com {[LIT_CHARS trap]} {[LIT_CHARS return_to_kansas]} {[LIT_CHARS EXIT]} ) (= scope= flags=0 words=[] bindings=[('SUBJECTS', {[Array ]})]) (FunctionDef make-a-pr [] (List (= scope= flags=0 words=[] bindings=[('rel', {[DQ [ComSub (Com {[LIT_CHARS basename]} {[DQ [VarSub BRANCH]]})]]})]) (Com {[LIT_CHARS echo]} ) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS "+++ Creating a pull request on GitHub at "][VarSub GITHUB_USER][LIT_CHARS ":"][VarSub NEWBRANCH]]} ) (= scope= flags=0 words=[] bindings=[('prtext', {[DQ [ComSub (Com {[LIT_CHARS mktemp]} {[LIT_CHARS -t]} {[LIT_CHARS prtext.XXXX]})]]})]) (Com {[LIT_CHARS cat]} < (FilenameRedirectNode filename={[DQ [VarSub prtext]]} "> 1), (HereDocRedirectNode here_end='EOF' do_expansion=True body_word={[DQ [LIT_CHARS "Automated cherry pick of "][VarSub PULLSUBJ][LIT_CHARS "\n"][LIT_CHARS "\n"][LIT_CHARS "Cherry pick of "][VarSub PULLSUBJ][LIT_CHARS " on "][VarSub rel][LIT_CHARS ".\n"][LIT_CHARS "\n"][ComSub (Com {[LIT_CHARS printf]} {[SQ ]} {[DQ [VarSub SUBJECTS bracket_op=(Index {A Atom NODE_ARITH_WORD {AS_OP_AT "@"}})]]})][LIT_CHARS "\n"]]} 0), > ) (Com {[LIT_CHARS hub]} {[LIT_CHARS pull-request]} {[LIT_CHARS -F]} {[DQ [VarSub prtext]]} {[LIT_CHARS -h]} {[DQ [VarSub GITHUB_USER][LIT_CHARS ":"][VarSub NEWBRANCH]]} {[LIT_CHARS -b]} {[DQ [LIT_CHARS "kubernetes:"][VarSub rel]]} ) ) ) (Com {[LIT_CHARS git]} {[LIT_CHARS checkout]} {[LIT_CHARS -b]} {[DQ [VarSub NEWBRANCHUNIQ]]} {[DQ [VarSub BRANCH]]} ) (= scope= flags=0 words=[] bindings=[('cleanbranch', {[DQ [VarSub NEWBRANCHUNIQ]]})]) (= scope= flags=0 words=[] bindings=[('gitamcleanup', {[LIT_CHARS true]})]) (For pull [{[DQ [VarSub PULLS bracket_op=(Index {A Atom NODE_ARITH_WORD {AS_OP_AT "@"}})]]}]) (List (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS "+++ Downloading patch to /tmp/"][VarSub pull][LIT_CHARS ".patch (in case you need to do this again)"]]} ) (Com {[LIT_CHARS curl]} {[LIT_CHARS -o]} {[DQ [LIT_CHARS /tmp/][VarSub pull][LIT_CHARS .patch]]} {[LIT_CHARS -sSL]} {[DQ [LIT_CHARS "http://pr.k8s.io/"][VarSub pull][LIT_CHARS .patch]]} ) (Com {[LIT_CHARS echo]} ) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS "+++ About to attempt cherry pick of PR. To reattempt:"]]} ) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS " "][LIT_OTHER "$"][LIT_CHARS " git am -3 /tmp/"][VarSub pull][LIT_CHARS .patch]]} ) (Com {[LIT_CHARS echo]} ) (AndOr OP_OR_IF (Com {[LIT_CHARS git]} {[LIT_CHARS am]} {[LIT_CHARS -3]} {[DQ [LIT_CHARS /tmp/][VarSub pull][LIT_CHARS .patch]]} ) (List (= scope= flags=0 words=[] bindings=[('conflicts', {[LIT_CHARS false]})]) (While (AndOr OP_AND_IF (= scope= flags=0 words=[] bindings=[('unmerged', {[ComSub (Pipeline (Com {[LIT_CHARS git]} {[LIT_CHARS status]} {[LIT_CHARS --porcelain]}) (Com {[LIT_CHARS grep]} {[LIT_OTHER "^"] [LIT_CHARS U]}) )]})]) (AndOr OP_OR_IF (DBracket {B1 UNARY_STRING_n {[VarSub unmerged]}}) (DBracket {B1 UNARY_FILE_e {[DQ [VarSub REBASEMAGIC]]}}) ) ) (List (= scope= flags=0 words=[] bindings=[('conflicts', {[LIT_CHARS true]})]) (Com {[LIT_CHARS echo]} ) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS "+++ Conflicts detected:"]]} ) (Com {[LIT_CHARS echo]} ) (AndOr OP_OR_IF (Subshell (Pipeline (Com {[LIT_CHARS git]} {[LIT_CHARS status]} {[LIT_CHARS --porcelain]} ) (Com {[LIT_CHARS grep]} {[LIT_OTHER "^"] [LIT_CHARS U]} ) ) ) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS "!!! None. Did you git am --continue?"]]} ) ) (Com {[LIT_CHARS echo]} ) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS "+++ Please resolve the conflicts in another window (and remember to 'git add / git am --continue')"]]} ) (Com {[LIT_CHARS read]} {[LIT_CHARS -p]} {[DQ [LIT_CHARS "+++ Proceed (anything but 'y' aborts the cherry-pick)? [y/n] "]]} {[LIT_CHARS -r]} ) (Com {[LIT_CHARS echo]} ) (If (Pipeline! (DBracket {B2 BINARY_STRING_TILDE_EQUAL {[DQ [VarSub REPLY]]} {[LIT_OTHER "^"] [LIT_DBRACKET_LIKE "["] [LIT_CHARS yY] [LIT_DBRACKET_LIKE "]"] [LIT_OTHER "$"]}}) ) (List (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS Aborting.]]} < (DescriptorRedirectNode target={[LIT_CHARS 2]} &"> 1), > ) (Com {[LIT_CHARS exit]} {[LIT_CHARS 1]} ) ) ) ) ) (If (DBracket {B2 BINARY_STRING_NOT_EQUAL {[DQ [VarSub conflicts]]} {[DQ [LIT_CHARS true]]}}) (List (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS "!!! git am failed, likely because of an in-progress 'git am' or 'git rebase'"]]} ) (Com {[LIT_CHARS exit]} {[LIT_CHARS 1]} ) ) ) ) ) (= scope= flags=0 words=[] bindings=[('subject', {[ComSub (Pipeline (Com {[LIT_CHARS grep]} {[LIT_CHARS -m]} {[LIT_CHARS 1]} {[DQ [LIT_CHARS "^Subject"]]} {[DQ [LIT_CHARS /tmp/][VarSub pull][LIT_CHARS .patch]]}) (Com {[LIT_CHARS sed]} {[LIT_CHARS -e]} {[SQ ]}) (Com {[LIT_CHARS sed]} {[SQ ]}) )]})]) (= scope= flags=0 words=[] bindings=[('SUBJECTS+', {[Array {[DQ [LIT_CHARS "#"][VarSub pull][LIT_CHARS ": "][VarSub subject]]}]})]) ) ) (= scope= flags=0 words=[] bindings=[('gitamcleanup', {[LIT_CHARS false]})]) (If (DBracket {B1 UNARY_STRING_n {[DQ [VarSub DRY_RUN]]}}) (List (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS "!!! Skipping git push and PR creation because you set DRY_RUN."]]} ) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS "To return to the branch you were in when you invoked this script:"]]} ) (Com {[LIT_CHARS echo]} ) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS " git checkout "][VarSub STARTINGBRANCH]]} ) (Com {[LIT_CHARS echo]} ) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS "To delete this branch:"]]} ) (Com {[LIT_CHARS echo]} ) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS " git branch -D "][VarSub NEWBRANCHUNIQ]]} ) (Com {[LIT_CHARS exit]} {[LIT_CHARS 0]} ) ) ) (If (Pipeline (Com {[LIT_CHARS git]} {[LIT_CHARS remote]} {[LIT_CHARS -v]} ) (Com {[LIT_CHARS grep]} {[LIT_OTHER "^"] [VarSub FORK_REMOTE]} ) (Com {[LIT_CHARS grep]} {[LIT_CHARS kubernetes/kubernetes.git]} ) ) (List (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS "!!! You have "][VarSub FORK_REMOTE][LIT_CHARS " configured as your kubernetes/kubernetes.git"]]} ) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS "This isn't normal. Leaving you with push instructions:"]]} ) (Com {[LIT_CHARS echo]} ) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS "+++ First manually push the branch this script created:"]]} ) (Com {[LIT_CHARS echo]} ) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS " git push REMOTE "][VarSub NEWBRANCHUNIQ][LIT_CHARS ":"][VarSub NEWBRANCH]]} ) (Com {[LIT_CHARS echo]} ) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS "where REMOTE is your personal fork (maybe "][VarSub UPSTREAM_REMOTE][LIT_CHARS "? Consider swapping those.)."]]} ) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS "OR consider setting UPSTREAM_REMOTE and FORK_REMOTE to different values."]]} ) (Com {[LIT_CHARS echo]} ) (Com {[LIT_CHARS make-a-pr]} ) (= scope= flags=0 words=[] bindings=[('cleanbranch', {[DQ ]})]) (Com {[LIT_CHARS exit]} {[LIT_CHARS 0]} ) ) ) (Com {[LIT_CHARS echo]} ) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS "+++ I'm about to do the following to push to GitHub (and I'm assuming "][VarSub FORK_REMOTE][LIT_CHARS " is your personal fork):"]]} ) (Com {[LIT_CHARS echo]} ) (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS " git push "][VarSub FORK_REMOTE][LIT_CHARS " "][VarSub NEWBRANCHUNIQ][LIT_CHARS ":"][VarSub NEWBRANCH]]} ) (Com {[LIT_CHARS echo]} ) (Com {[LIT_CHARS read]} {[LIT_CHARS -p]} {[DQ [LIT_CHARS "+++ Proceed (anything but 'y' aborts the cherry-pick)? [y/n] "]]} {[LIT_CHARS -r]} ) (If (Pipeline! (DBracket {B2 BINARY_STRING_TILDE_EQUAL {[DQ [VarSub REPLY]]} {[LIT_OTHER "^"] [LIT_DBRACKET_LIKE "["] [LIT_CHARS yY] [LIT_DBRACKET_LIKE "]"] [LIT_OTHER "$"]}}) ) (List (Com {[LIT_CHARS echo]} {[DQ [LIT_CHARS Aborting.]]} < (DescriptorRedirectNode target={[LIT_CHARS 2]} &"> 1), > ) (Com {[LIT_CHARS exit]} {[LIT_CHARS 1]} ) ) ) (Com {[LIT_CHARS git]} {[LIT_CHARS push]} {[DQ [VarSub FORK_REMOTE]]} {[LIT_CHARS -f]} {[DQ [VarSub NEWBRANCHUNIQ][LIT_CHARS ":"][VarSub NEWBRANCH]]} ) (Com {[LIT_CHARS make-a-pr]} ) )