diff --git a/README.md b/README.md
index 465fd53..fa69f45 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,31 @@
+- [Gong](#gong)
+ - [Build Status](#build-status)
+ - [Summary](#summary)
+ - [Usage](#usage)
+ - [Installation](#installation)
+ - [Currently supported clients](#currently-supported-clients)
+ - [Login](#login)
+ - [Start working on an issue](#start-working-on-an-issue)
+ - [`gong browse`](#gong-browse)
+ - [`gong comment`](#gong-comment)
+ - [Why a pipe?](#why-a-pipe)
+ - [githooks](#githooks)
+ - [`gong prepare-commit-message`](#gong-prepare-commit-message)
+ - [`commit-msg`](#commit-msg)
+ - [Install commit hooks on your repository](#install-commit-hooks-on-your-repository)
+ - [`gong create`](#gong-create)
+ - [Issues/Feedback](#issuesfeedback)
+ - [CHANGELOG](#changelog)
+ - [1.6.0](#160)
+ - [1.4.0](#140)
+ - [1.3.4](#134)
+ - [Upcoming features](#upcoming-features)
+ - [`gong slack`](#gong-slack)
+ - [`gong next/pick`](#gong-nextpick)
+ - [Development](#development)
### Build Status
* Develop: 
@@ -45,6 +70,20 @@ Once you input all of the details the client will attempt to login. If succeeded
[](https://asciinema.org/a/dcko3kv5xwobpf4rgj0e4ulyo)
+You can also define `~/.gong.json`:
+
+ {
+ "client":"jira",
+ "domain":"",
+ "password":"",
+ "project_prefix":"",
+ "transitions":"In Progress",
+ "username":""
+ }
+
+NOTE:
+For Passowrd get an API Token.
+https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account/
### Start working on an issue
`gong start {issue-id} --type feature`
@@ -59,6 +98,10 @@ This will do a couple of things
[](https://asciinema.org/a/c5libsysjmb5f8f8gizkbldzv)
+NOTE:
+You can define a default (branch) type with env var:
+
+ echo "export GONG_DEFAULT_BRANCH_TYPE=story" >> ~/.zshrc
### `gong browse`
While working on a branch that matches the gong regular expression (look
@@ -80,7 +123,9 @@ With this approach, I find I write much better comments to tickets. You will do
](https://asciinema.org/a/d0rcjavbv55lbq1xpsrqiyyu6)
-### `gong prepare-commit-message`
+### githooks
+
+#### `gong prepare-commit-message`
This is **not** meant to be used directly, instead it is meant to be wrapped with simple wrapper git hooks.
@@ -90,15 +135,24 @@ All you need to do is to copy them into your `.git/hooks` directory.
This will add a link to the issue to every commit. Whether you do `git commit "commit message" or edit the commit message using the editor with `git commit`
-### Install commit hooks on your repository
+#### `commit-msg`
+
+This githook will produce duplicate Jira links if using `git commit --ammend`
+You can add an alias to skip this hook and avoid duplication:
+
+ alias git-commit-ammend="git commit --amend --no-edit --no-verify"
+
+
-```
-curl https://raw.githubusercontent.com/KensoDev/gong/develop/git-hooks/prepare-commit-msg > .git/hooks/prepare-commit-msg
-chmod +x .git/hooks/prepare-commit-msg
+#### Install commit hooks on your repository
-curl https://raw.githubusercontent.com/KensoDev/gong/develop/git-hooks/commit-msg > .git/hooks/commit-msg
-chmod +x .git/hooks/commit-msg
-```
+ mkdir ~/.githooks
+ git config --global core.hooksPath ~/.githooks
+ curl https://raw.githubusercontent.com/KensoDev/gong/develop/git-hooks/prepare-commit-msg > ~/.githooks/prepare-commit-msg
+ chmod +x .git/hooks/prepare-commit-msg
+
+ curl https://raw.githubusercontent.com/KensoDev/gong/develop/git-hooks/commit-msg > ~/.githooks/commit-msg
+ chmod +x .git/hooks/commit-msg
### `gong create`
@@ -138,3 +192,18 @@ Send a message to a slack channel, tagging the issue you are working on
Show you the next items on your backlog, be able to start one without opening the browser
+## Development
+Update version:
+
+ go get
+
+Build:
+
+ cd cmd/gong/
+ ./build.sh
+
+Add gong to your PATH and restart SEHLL, e.g.:
+
+ mv gong /usr/local/bin/gong
+ exec $SHELL
+
diff --git a/client.go b/client.go
index 8645024..2260e9d 100644
--- a/client.go
+++ b/client.go
@@ -3,7 +3,6 @@ package gong
import (
"encoding/json"
"fmt"
- "github.com/segmentio/go-prompt"
"io/ioutil"
"os/user"
"path/filepath"
@@ -94,9 +93,9 @@ func Login(client Client) (bool, error) {
message := fmt.Sprintf("Please enter your %v %v", clientName, k)
promptValue := ""
if v {
- promptValue = prompt.PasswordMasked(message)
+ promptValue = PromptPasswordMasked(message)
} else {
- promptValue = prompt.String(message)
+ promptValue = PromptString(message)
}
fields[k] = client.FormatField(k, promptValue)
diff --git a/cmd/gong/.bumpversion.cfg b/cmd/gong/.bumpversion.cfg
index 47b807a..261024e 100644
--- a/cmd/gong/.bumpversion.cfg
+++ b/cmd/gong/.bumpversion.cfg
@@ -1,9 +1,8 @@
[bumpversion]
-current_version = 1.7.0
+current_version = 1.8.0
commit = False
tag = False
[bumpversion:file:main.go]
search = {current_version}
replace = {new_version}
-
diff --git a/cmd/gong/build.sh b/cmd/gong/build.sh
index ebe6648..6234c6c 100755
--- a/cmd/gong/build.sh
+++ b/cmd/gong/build.sh
@@ -1,2 +1,2 @@
bumpversion $1 --allow-dirty
-go build
\ No newline at end of file
+go build -o gong
\ No newline at end of file
diff --git a/cmd/gong/main.go b/cmd/gong/main.go
index ec2e171..80997ce 100644
--- a/cmd/gong/main.go
+++ b/cmd/gong/main.go
@@ -13,7 +13,7 @@ import (
func main() {
app := cli.NewApp()
- app.Version = "1.7.0"
+ app.Version = "1.8.0"
var branchType string
@@ -51,7 +51,7 @@ func main() {
Value: "feature",
Usage: "Type of branch to create eg: feature/{ticket-id}-ticket-title",
Destination: &branchType,
- EnvVar: "GONG_DEFAULT_BRANCH_TYPE"
+ EnvVar: "GONG_DEFAULT_BRANCH_TYPE",
},
},
Action: func(c *cli.Context) error {
diff --git a/git-hooks/commit-msg b/git-hooks/commit-msg
index b8ccf26..9b9645b 100755
--- a/git-hooks/commit-msg
+++ b/git-hooks/commit-msg
@@ -1,6 +1,18 @@
#!/bin/sh
#
# Automatically adds branch name and branch description to every commit message.
-#
-
-echo "$1\n\n$(cat $1 | gong prepare-commit-message)"
\ No newline at end of file
+# To avoid duplictaes: git commit --ammend --no-verify
+# Source: https://medium.com/@nicklee1/prepending-your-git-commit-messages-with-user-story-ids-3bfea00eab5a
+if [ -z "$BRANCHES_TO_SKIP" ]; then
+ BRANCHES_TO_SKIP=(master develop staging test)
+fi
+# Get the current branch name and check if it is excluded
+BRANCH_NAME=$(git symbolic-ref --short HEAD)
+BRANCH_EXCLUDED=$(printf "%s\n" "${BRANCHES_TO_SKIP[@]}" | grep -c "^$BRANCH_NAME$")
+# Trim it down to get the parts we're interested in
+# TRIMMED=$(echo $BRANCH_NAME | sed -e 's:^\([^-]*-[^-]*\)-.*:\1:' -e \
+# 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/')
+# If it isn't excluded, preprend the trimmed branch identifier to the given message
+if [ -n "$BRANCH_NAME" ] && ! [[ $BRANCH_EXCLUDED -eq 1 ]]; then
+ echo "$(cat $1)\n\n$(cat $1 | gong prepare-commit-message)" > $1
+fi
\ No newline at end of file
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..5a2d659
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,12 @@
+module github.com/KensoDev/gong
+
+go 1.16
+
+require (
+ github.com/andygrunwald/go-jira v1.13.0
+ github.com/fatih/color v1.10.0
+ github.com/howeyc/gopass v0.0.0-20190910152052-7cb4b85ec19c
+ github.com/urfave/cli v1.22.5
+ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c
+ gopkg.in/salsita/go-pivotaltracker.v1 v1.5.0
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..3f1f6e4
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,54 @@
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/andygrunwald/go-jira v1.13.0 h1:vvIImGgX32bHfoiyUwkNo+/YrPnRczNarvhLOncP6dE=
+github.com/andygrunwald/go-jira v1.13.0/go.mod h1:jYi4kFDbRPZTJdJOVJO4mpMMIwdB+rcZwSO58DzPd2I=
+github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
+github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
+github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
+github.com/fatih/structs v1.0.0 h1:BrX964Rv5uQ3wwS+KRUAJCBBw5PQmgJfJ6v4yly5QwU=
+github.com/fatih/structs v1.0.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
+github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 h1:zLTLjkaOFEFIOxY5BWLFLwh+cL8vOBW4XJ2aqLE/Tf0=
+github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
+github.com/howeyc/gopass v0.0.0-20190910152052-7cb4b85ec19c h1:aY2hhxLhjEAbfXOx2nRJxCXezC6CO2V/yN+OCr1srtk=
+github.com/howeyc/gopass v0.0.0-20190910152052-7cb4b85ec19c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs=
+github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
+github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
+github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/trivago/tgo v1.0.1 h1:bxatjJIXNIpV18bucU4Uk/LaoxvxuOlp/oowRHyncLQ=
+github.com/trivago/tgo v1.0.1/go.mod h1:w4dpD+3tzNIIiIfkWWa85w5/B77tlvdZckQ+6PkFnhc=
+github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU=
+github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 h1:p/H982KKEjUnLJkM3tt/LemDnOc1GiZL5FCVlORJ5zo=
+golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/salsita/go-pivotaltracker.v1 v1.5.0 h1:kryrdIZtOFISZ8LKUCyl3ihfigfdqOSXkTwWtVMz0nc=
+gopkg.in/salsita/go-pivotaltracker.v1 v1.5.0/go.mod h1:GWZI+O3bfQsZJz6JhjIMo6PjRxoxurQy+qGXaLO/I+w=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/prompt.go b/prompt.go
new file mode 100644
index 0000000..c2c21cc
--- /dev/null
+++ b/prompt.go
@@ -0,0 +1,98 @@
+// source: https://github.com/segmentio/go-prompt
+package gong
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+
+ "github.com/howeyc/gopass"
+)
+
+// String prompt.
+func PromptString(prompt string, args ...interface{}) string {
+ var s string
+ fmt.Printf(prompt+": ", args...)
+ fmt.Scanln(&s)
+ return s
+}
+
+// String prompt (required).
+func PromptStringRequired(prompt string, args ...interface{}) (s string) {
+ for strings.Trim(s, " ") == "" {
+ s = PromptString(prompt, args...)
+ }
+ return s
+}
+
+// Confirm continues prompting until the input is boolean-ish.
+func PromptConfirm(prompt string, args ...interface{}) bool {
+ for {
+ switch PromptString(prompt, args...) {
+ case "Yes", "yes", "y", "Y":
+ return true
+ case "No", "no", "n", "N":
+ return false
+ }
+ }
+}
+
+// Choose prompts for a single selection from `list`, returning in the index.
+func PromptChoose(prompt string, list []string) int {
+ fmt.Println()
+ for i, val := range list {
+ fmt.Printf(" %d) %s\n", i+1, val)
+ }
+
+ fmt.Println()
+ i := -1
+
+ for {
+ s := PromptString(prompt)
+
+ // index
+ n, err := strconv.Atoi(s)
+ if err == nil {
+ if n > 0 && n <= len(list) {
+ i = n - 1
+ break
+ } else {
+ continue
+ }
+ }
+
+ // value
+ i = indexOf(s, list)
+ if i != -1 {
+ break
+ }
+ }
+
+ return i
+}
+
+// Password prompt.
+func PromptPassword(prompt string, args ...interface{}) string {
+ fmt.Printf(prompt+": ", args...)
+ password, _ := gopass.GetPasswd()
+ s := string(password[0:])
+ return s
+}
+
+// Password prompt with mask.
+func PromptPasswordMasked(prompt string, args ...interface{}) string {
+ fmt.Printf(prompt+": ", args...)
+ password, _ := gopass.GetPasswdMasked()
+ s := string(password[0:])
+ return s
+}
+
+// index of `s` in `list`.
+func PromptIndexOf(s string, list []string) int {
+ for i, val := range list {
+ if val == s {
+ return i
+ }
+ }
+ return -1
+}