Go JIRA API client

Hi folks. So, I was playing around and created a client for JIRA written in Go. It was nice to do some JSON transformation. And sending POSTS was really trivial. It’s still in it’s infancy and I have a couple of more features I want to implement, but, here is the code. package main import ( "bytes" "encoding/json" "flag" "fmt" "io/ioutil" "log" "net/http" "os" "github.com/BurntSushi/toml" ) var configFile = "~/.jira_config.toml" var parameter string var flags struct { Comment string Description string IssueKey string Priority string Resolution string Title string Project string } //Issue is a representation of a Jira Issue type Issue struct { Fields struct { Project struct { Key string `json:"key"` } `json:"project"` Summary string `json:"summary"` Description string `json:"description"` Issuetype struct { Name string `json:"name"` } `json:"issuetype"` Priority struct { ID string `json:"id"` } `json:"priority"` } `json:"fields"` } //Transition defines a transition json object. Used for starting, stoppinp //generally for state stranfer type Transition struct { Fields struct { Resolution struct { Name string `json:"name"` } `json:"resolution"` } `json:"fields"` Transition struct { ID string `json:"id"` } `json:"transition"` } //Credentials a representation of a JIRA config which helds API permissions type Credentials struct { Username string Password string URL string } func init() { flag.StringVar(&flags.Comment, "m", "Default Comment", "A Comment when changing the status of an Issue.") flag.StringVar(&flags.Description, "d", "Default Description", "Provide a description for a newly created Issue.") flag.StringVar(&flags.Priority, "p", "2", "The priority of an Issue which will be set.") flag.StringVar(&flags.IssueKey, "k", "", "Issue key of an issue.") flag.StringVar(&flags.Resolution, "r", "Done", "Resolution when an issue is closed. Ex.: Done, Fixed, Won't fix.") flag.StringVar(&flags.Title, "t", "Default Title", "Title of an Issue.") flag.StringVar(&flags.Project, "o", "IT", "Define a Project to create a ticket in.") flag.Parse() } func (cred *Credentials) initConfig() { if _, err := os.Stat(configFile); err != nil { log.Fatalf("Error using config file: %v", err) } if _, err := toml.DecodeFile(configFile, cred); err != nil { log.Fatal("Error during decoding toml config: ", err) } } func main() { if len(flag.Args()) < 1 { log.Fatal("Please provide an action to take. Usage information:") } parameter = flag.Arg() switch parameter { case "close": closeIssue(flags.IssueKey) case "start": startIssue(flags.IssueKey) case "create": createIssue() } } func closeIssue(issueKey string) { if issueKey == "" { log.Fatal("Please provide an issueID with -k") } fmt.Println("Closing issue number: ", issueKey) var trans Transition //TODO: Add the ability to define a comment for the close reason trans.Fields.Resolution.Name = flags.Resolution trans.Transition.ID = "2" marhsalledTrans, err := json.Marshal(trans) if err != nil { log.Fatal("Error occured when marshaling transition: ", err) } fmt.Println("Marshalled:", trans) sendRequest(marhsalledTrans, "POST", issueKey+"/transitions?expand=transitions.fields") } func startIssue(issueID string) { if issueID == "" { log.Fatal("Please provide an issueID with -i") } fmt.Println("Starting issue number:", issueID) } func createIssue() { fmt.Println("Creating new issue.") var issue Issue issue.Fields.Description = flags.Description issue.Fields.Priority.ID = flags.Priority issue.Fields.Summary = flags.Title issue.Fields.Project.Key = flags.Project issue.Fields.Issuetype.Name = "Task" marshalledIssue, err := json.Marshal(issue) if err != nil { log.Fatal("Error occured when Marshaling Issue:", err) } sendRequest(marshalledIssue, "POST", "") } func sendRequest(jsonStr []byte, method string, url string) { cred := &Credentials{} cred.initConfig() fmt.Println("Json:", string(jsonStr)) req, err := http.NewRequest(method, cred.URL+url, bytes.NewBuffer(jsonStr)) req.Header.Set("Content-Type", "application/json") req.SetBasicAuth(cred.Username, cred.Password) client := &http.Client{} resp, err := client.Do(req) if err != nil { panic(err) } defer resp.Body.Close() fmt.Println("response Status:", resp.Status) fmt.Println("response Headers:", resp.Header) body, _ := ioutil.ReadAll(resp.Body) fmt.Println("response Body:", string(body)) } It can also be found under my github page: GoJira Github. ...

November 20, 2015 · 3 min · hannibal

The One Hundred Day GitHub Challenge

Hello folks. Today, I present to you the One Hundred Day Github Challenge. The rules are simple: Minimum of One commit every day for a Hundred days. Commit has to be meaningful but can be as little as a fix in a Readme.md. Doesn’t matter if you are on vacation, there are no exceptions. There. Are. No. Exceptions. If you fail a day, you have to start over. No cheating. You only cheat yourself, so this is really up to you. Let me be more clear here, because it seems I wasn’t clear enough. What you make out of this challenge, it’s up to you. If you just update a readme.md for hundred days, that’s fine. Just do it every day. It’s a commitment. At least you’ll have a nice Readme. ...

November 15, 2015 · 1 min · hannibal

Go Progress Quest

Hi Folks. I started to build a Progress Quest type of web app in Go. If you’d like to join, or just tag along, please drop by here => Go Progress Quest and feel free to submit an issue if you have an idea, or would like to contribute! I will try and document the Progress. Thank you for reading! Gergely.

November 9, 2015 · 1 min · hannibal

Circular buffer in Go

I’m proud of this one too. No peaking. I like how go let’s you do this kind of stuff in a very nice way. package circular import "fmt" //TestVersion testVersion const TestVersion = 1 //Buffer buffer type type Buffer struct { buffer []byte full int size int s, e int } //NewBuffer creates a new Buffer func NewBuffer(size int) *Buffer { return &Buffer{buffer: make([]byte, size), s: 0, e: 0, size: size, full: 0} } //ReadByte reads a byte from b Buffer func (b *Buffer) ReadByte() (byte, error) { if b.full == 0 { return 0, fmt.Errorf("Danger Will Robinson: %s", b) } readByte := b.buffer[b.s] b.s = (b.s + 1) % b.size b.full-- return readByte, nil } //WriteByte writes c byte to the buffer func (b *Buffer) WriteByte(c byte) error { if b.full+1 > b.size { return fmt.Errorf("Danger Will Robinson: %s", b) } b.buffer[b.e] = c b.e = (b.e + 1) % b.size b.full++ return nil } //Overwrite overwrites the oldest byte in Buffer func (b *Buffer) Overwrite(c byte) { b.buffer[b.s] = c b.s = (b.s + 1) % b.size } //Reset resets the buffer func (b *Buffer) Reset() { *b = *NewBuffer(b.size) } func (b *Buffer) String() string { return fmt.Sprintf("Buffer: %d, %d, %d, %d", b.buffer, b.s, b.e, b.size) }

October 15, 2015 · 1 min · hannibal

Jenkins Job DSL and Groovy goodness

Hi Folks. Ever used Job DSL plugin for Jenkins? What is that you say? Well, it’s TEH most awesome plug-in for Jenkins to have, because you can CODE your job configuration and put it under source control. Today, however, I’m not going to write about that because the tutorials on Jenkins JOB DSL are very extensive and very well done. Anyone can pick them up. Today, I would like to write about a part of it which is even more interesting. And that is, extracting re-occurring parts in your job configurations. ...

October 15, 2015 · 4 min · hannibal

DataMunger Kata with Go

Quickly wrote up the Data Munger code kata in Go. Next time, I want better abstractions. And a way to select columns based on their header data. For now, this is not bad. package main import ( "bufio" "fmt" "log" "math" "os" "regexp" "strconv" "strings" ) //Data which is Data type Data struct { columnName string compareOne float64 compareTwo float64 } func main() { // datas := []Data{WeatherData{}, FootballData{}} fmt.Println("Minimum weather data:", GetDataMinimumDiff("weather.dat", , 1, 2)) fmt.Println("Minimum football data:", GetDataMinimumDiff("football.dat", 1, 6, 7)) } //GetDataMinimumDiff gathers data from file to fill up Columns. func GetDataMinimumDiff(filename string, nameColumn int, compareColOne int, compareColTwo int) Data { data := Data{} minimum := math.MaxFloat64 readLines := ReadFile(filename) for _, value := range readLines { valueArrays := strings.Split(value, ",") name := valueArrays[nameColumn] trimmedFirst, _ := strconv.ParseFloat(valueArrays[compareColOne], 64) trimmedSecond, _ := strconv.ParseFloat(valueArrays[compareColTwo], 64) diff := trimmedFirst - trimmedSecond diff = math.Abs(diff) if diff <= minimum { minimum = diff data.columnName = name data.compareOne = trimmedFirst data.compareTwo = trimmedSecond } } return data } //ReadFile reads lines from a file and gives back a string array which contains the lines. func ReadFile(fileName string) (fileLines []string) { file, err := os.Open(fileName) if err != nil { log.Fatal(err) } defer file.Close() scanner := bufio.NewScanner(file) //Skipping the first line which is the header. scanner.Scan() for scanner.Scan() { line := scanner.Text() re := regexp.MustCompile("\\w+") lines := re.FindAllString(line, -1) if len(lines) > { fileLines = append(fileLines, strings.Join(lines, ",")) } } if err := scanner.Err(); err != nil { log.Fatal(err) } return }

October 4, 2015 · 2 min · hannibal

Sieve of Eratosthenes in Go

I’m pretty proud of this one as well. package sieve //Sieve Uses the Sieve of Eratosthenes to calculate primes to a certain limit func Sieve(limit int) []int { var listOfPrimes []int markers := make([]bool, limit) for i := 2; i < limit; i++ { if !markers[i] { for j := i + i; j < limit; j += i { markers[j] = true } listOfPrimes = append(listOfPrimes, i) } } return listOfPrimes }

July 30, 2015 · 1 min · hannibal

Converting numbers into string representations

I quiet like this one. My first go program snippet without any peaking or googling. I’m proud, though it could be improved with a bit of struct magic and such and such. And it only counts ’till 1000. package main import "fmt" var words = map[int]string{1: "one", 2: "two", 3: "three", 4: "four", 5: "five", 6: "six", 7: "seven", 8: "eight", 9: "nine", 10: "ten", 11: "eleven", 12: "twelve", 13: "thirteen", 14: "fourteen", 15: "fifteen", 16: "sixteen", 17: "seventeen", 18: "eighteen", 19: "nineteen", 20: "twenty", 30: "thirty", 40: "forty", 50: "fifty", 60: "sixty", 70: "seventy", 80: "eighty", 90: "ninety"} // CountLetters count the letters in a long string number representation func CountLetters(limit int) { myLongNumberString := "" for i := 1; i <= limit; i++ { addLettersToMyString(&myLongNumberString, i) } // fmt.Println("1-9 written with letters is: ", len(myLongNumberString)) fmt.Println("The string is:", myLongNumberString) fmt.Println("Lenght of string is:", len(myLongNumberString)) } func addLettersToMyString(myString *string, num int) { if num < 20 { *myString += words[num] } if num >= 20 && num < 100 { *myString += countMiddle(num) } if num >= 100 && num < 1000 { hundred, tenth := countHundred(num) if tenth == { *myString += hundred } else if tenth >= 11 && tenth < 20 { *myString += hundred + "and" + words[tenth] } else { *myString += hundred + "and" + countMiddle(tenth) } } if num == 1000 { *myString += "onethousand" } } func countMiddle(num int) string { minues := num % 10 num -= minues return words[num] + words[minues] } func countHundred(num int) (string, int) { minues := num % 100 num -= minues return (words[(num/100)] + "hundred"), minues }

July 19, 2015 · 2 min · hannibal

Bitwise & Operator

The first, and only time so far, that I got to use the bitwise & operator. I enjoyed doing so!! And of course from now on, I’ll be looking for more opportunities to (ab)use it. package secret import "sort" const REVERSE = 16 func Handshake(code int) []string { // binary_rep := convertDecimalToBinary(code) if code < { return nil } secret_map := map[int]string { 1: "wink", 2: "double blink", 4: "close your eyes", 8: "jump", } var keys []int for k := range secret_map { keys = append(keys, k) } // To make sure iteration is always in the same order. sort.Ints(keys) code_array := make([]string, ) for _, key := range keys { if code & key == key { code_array = append(code_array, secret_map[key]) } } if code & REVERSE == REVERSE { code_array = reverse_array(code_array) } return code_array } func reverse_array (array_to_reverse []string) []string { for i, j := , len(array_to_reverse) -1 ; i < j; i, j = i + 1, j - 1 { array_to_reverse[i], array_to_reverse[j] = array_to_reverse[j], array_to_reverse[i] } return array_to_reverse }

July 15, 2015 · 1 min · hannibal

Django – RPG – Part 3

Hello folks. A small update to this. I created the model now, which is the database design for this app. It’s very simple, nothing fancy. Also, I’m writing the app with Python 3 from now on. Here is the model now: from django.db import models from django.contrib.auth.models import User # Create your models here. class Item(models.Model): name = models.CharField(max_length=100, default="Item") damage = models.IntegerField(default=) defense = models.IntegerField(default=) consumable = models.BooleanField(default=False) def __str__(self): return self.name class Inventory(models.Model): items = models.ManyToManyField(Item) def __str__(self): return self.items class Character(models.Model): # By default Django uses the primery key of the related object. # Hence, no need to specify User.id. user = models.OneToOneField(User, null=True) name = models.CharField(max_length=100) inventory = models.ForeignKey(Inventory) def __str__(self): return self.name Worth noting a few things here. The __str__ is only with Python 3. In Python 2 it would be unicode. And the OneToOne and the foreign key are automatically using Primary keys defined in the references model. The __str__ is there to return some view when you are debugging in the console instead of [<Item: Item object>]. ...

April 21, 2015 · 2 min · hannibal