CLI tips: create PR for Azure DevOps from CLI

Motivation: Slow and confusing web interface

Azure DevOps, probably one of the worst tools you can get for a your software team, I hated it with passion. The reason that company chooses it over any other software is probably because they can get a decent enough discount when bundled with the M$'s shitty Outlook, Teams, and office suite.
If I could, I would give Azure DevOps's web interface and overall experience a 0 out of 10: it is slow, difficult to navigate, and way behind what you would get from GitHub or GitLab.
Enough for the ranting, in short, I hate Azure DevOps' web interface, therefore, I prefer to use the CLI to interact with it.

Azure CLI: Generic at a cost

Azure DevOps, however bad it is, still provides a command line interface to interact with its API.

As an example, if you want to create a PR through azure DevOps, you can run:
az pr create -s 'source branch' -t 'target branch' --title 'title' --workItem 'ID' --description "description"

I understand that this CLI is intended to be a general audience, so it is meant to be generic, but my issues with this command are:

  1. It is just too difficult to remember all the options without looking at the docs.
  2. Have to type the target, source branch and/or work item manually.

What I want to achieve:

  1. Interactivity: can choose if open in browser and/or draft mode or not
  2. Simple and intuitive: lists all the available branches, and allow selecting one as target and/or source.
  3. Work item linking and transition: Automatically transition the linked work item so it transition from Todo to In progress

Road to the ideal script

To achieve the Interactivity I wanted, I had opted to use a tool called fzf which is a fuzzy finder.

The script below is what I ended up with. It is quite bloated, but does what I look for.

Note before using this script, you need to have:

  1. FZF installed.
  2. Azure CLI authenticated from your command line, meaning you can already create pr in the "dumb" way I mentioned above.
azure-devops-script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#!/bin/bash

LINE="$(printf %"$(tput cols)"s | tr " " "-")" # https://stackoverflow.com/a/42763333/9470346
WORKITEMARG=""


function createPR() {
echo -e "Fetching all git origins..."
git fetch --all --prune

read -rp "
Choose source branch (Y/N): " chooseSource
echo "${LINE}"

if [ "$chooseSource" == "Y" ]; then
sourceBranch=$(git for-each-ref --sort=-committerdate \
--format='%(refname:short) (%(committerdate:relative))' refs/heads \ |
fzf --prompt "Choose a source branch: " --reverse --nth=1 --preview 'git log --oneline --color {1}...{1}~5'\ |
awk '{print $1}')

else
echo -e "Using current branch as source branch"
echo -e "Pushing first..."
sourceBranch=$(git branch --show-current)
git push origin "$sourceBranch" --no-verify
fi

echo "Source Branch:""$sourceBranch"
echo "${LINE}"



targetBranch=$(git for-each-ref --sort=-committerdate \
--format='%(refname:short) (%(committerdate:relative))' refs/heads \ |
fzf --prompt "Choose a target branch: " --reverse --nth=1 --preview 'git log --oneline --color {1}...{1}~5'\ |
awk '{print $1}')
echo "Target Branch:""$targetBranch"
echo "${LINE}"

read -rp "
Add workitem (Y/N): " workItemReq
echo "PR title: ""$workItemReq"
echo "${LINE}"

if [ "$workItemReq" == "Y" ] || [ "$workItemReq" == "y" ]; then
workItem=$(az boards query --id $BOARD_ID --output jsonc|jq -r '.[]|(.id|tostring) + " " + (.fields["System.Title"])'|fzf --prompt "Choose a workItem"|awk '{print $1}')
if [[ -n $workItem ]]; then
## transition selected workitem to in progress
az boards work-item update --id $workItem --state "In Progress"
WORKITEMARG="--work-items $workItem"
fi
fi


read -rp "
Title for your PR: " title
echo "PR title: ""$title"
echo "${LINE}"

read -rp "

Description for your PR: " description
echo "PR description: ""$description"
echo "${LINE}"
if [[ "$description" ]] ; then
DESCRIPTION="-d $description"
fi

read -rp "
Open in browser (Y/N, N): " openBrowser
if [ "$openBrowser" == "Y" ] || [ "$openBrowser" == "y" ]; then
OPEN_BROWSER_ARG="--open"
fi


read -rp "
Is Draft? (Y/N, N): " isDraft
if [ "$isDraft" == "Y" ] || [ "$isDraft" == "y" ]; then
IS_DRAFT_ARG="--draft"
fi

az repos pr create -t "$targetBranch" -s "$sourceBranch" $WORKITEMARG $DESCRIPTION $IS_DRAFT_ARG --title "$title" $OPEN_BROWSER_ARG
}

createPR