Quem nunca esqueceu de apontar as horas das tarefas, né!?
Já esqueceu de apontar as horas no quadro do jira ?
Se sim, esse artigo é para você!
Pois depois que fizer a implementação desse código, se verá livre desse problema.
O que é Jira ?
Jira é um software comercial desenvolvido pela empresa Australiana Atlassian. É uma ferramenta que permite o monitoramento de tarefas e acompanhamento de projetos garantindo o gerenciamento de todas as suas atividades em único lugar. Wikipédia
As vezes esquecem de colocar aquelas horas trabalhada nos cards do jira e levamos aquela "chamada" do Scrum master no dia seguinte.
Para que isso não aconteça é preciso fazer a integração da chave de autenticação, como veremos a seguir:
Primeiramente acesse a conta da atlassian, logo após abrirá a tela abaixo:
No setor indicado acima clique em "criar e gerenciar tokens de API". Essa ação irá levar a tela abaixo:
Conforme orientado acima clique em criar token de API. Abrindo assim, a tela seguinte:
Na opção de login insira um nome para o acesso, e clique no botão criar. Indo então para tela abaixo:
Pronto! Estamos com a chave de acesso para consumir a API do jira.
Depois do acesso à chave, teremos que seguir alguns passos para chegar no relatório das horas, que são estes:
- Identificar o id do sua conta no jira.
- Listar todas suas tarefas abertas.
- Contabilizar o que reportou ou não na data escolhida.
O jira disponibiliza uma documentação para o consumo dos recursos, clicando aqui.
Faremos o passo a passo no curl, para entender as chamadas e os seus retornos.
Para identificar a conta id precisamos requisitar a seguinte API:
curl -u seu_email_aqui:seu_token_aqui --location --request GET 'https://seu_dominio_aqui/rest/api/3/users/search'
O retorno esperado da chamada:
[ { "self": "https://seu_dominio_aqui/rest/api/3/user?accountId=aqui_vc_tem_seu_account_id", "accountId": "aqui_vc_tem_seu_account_id", "accountType": "atlassian", "emailAddress": "higor@example.com.br", "avatarUrls": { "48x48": "https://example.com/", "24x24": "https://example.com/", "16x16": "https://example.com/", "32x32": "https://example.com/" }, "displayName": "Higor Diego", "active": true, "locale": "pt_BR" } ]
Na resposta acima temos um accountId. Com isso, podemos analisar o retorno de todas as suas issues cadastradas por data.
Para pegar todas as suas issues com filtro de data e accountId chamaremos a seguinte API:
curl -u seu_email_aqui:seu_token_aqui --location --request POST 'https://seu_dominio_aqui/rest/api/3/search' \ --header 'Content-Type: application/json' \ --data-raw '{ "jql": "worklogDate>='2021-01-15' and worklogDate<='2021-02-15' and (worklogAuthor in ('aqui_vc_tem_seu_account_id'))", "fields":["worklog"] }'
No corpo da Http Request enviamos JQL, que representa a Linguagem de Consulta do Jira.
O retorno esperado da chamada:
{ "expand": "schema,names", "startAt": 0, "maxResults": 50, "total": 1, "issues": [ { "expand": "operations,versionedRepresentations,editmeta,changelog,renderedFields", "id": "32620", "self": "https://seu_dominio_aqui/rest/api/3/issue/326212", "key": "key_project_aqui", "fields": { "worklog": { "startAt": 0, "maxResults": 20, "total": 1, "worklogs": [ { "self": "https://seu_dominio_aqui/rest/api/3/issue/32620/worklog/326212", "author": { "self": "https://seu_dominio_aqui/rest/api/3/user?accountId=account_aqui", "accountId": "seu_acount_aqui", "avatarUrls": { "48x48": "http://", "24x24": "http://", "16x16": "http://", "32x32": "http://" }, "displayName": "Higor Diego", "active": true, "timeZone": "America/Sao_Paulo", "accountType": "atlassian" }, "updateAuthor": { "self": "https://seu_dominio_aqui/rest/api/3/user?accountId=account_aqui", "accountId": "account_aqui", "avatarUrls": { "48x48": "http://", "24x24": "http://", "16x16": "http://", "32x32": "http://" }, "displayName": "Higor Diego", "active": true, "timeZone": "America/Sao_Paulo", "accountType": "atlassian" }, "created": "2021-01-05T12:21:56.896-0300", "updated": "2021-01-05T12:21:56.896-0300", "started": "2021-01-05T12:16:53.769-0300", "timeSpent": "5m", "timeSpentSeconds": 300, "id": "5345021321323211", "issueId": "326212" } ] } } } ] }
Com base no resultado das chamadas de API, vamos agora codificar o alerta em Go.
Criaremos um arquivo chamado helper para nos auxiliares nas seguintes etapas:
- Pegar a data atual;
- Formatar a data;
- Criar o base64 para autenticação Basic;
- Converter segundos em horas.
package helpers import ( "encoding/base64" "fmt" "time" ) // BasicAuth - create basic authenticate func BasicAuth(email, token string) string { auth := email + ":" + token return fmt.Sprintf("Basic %v", base64.StdEncoding.EncodeToString([]byte(auth))) } // NowDate - func date now parse to string func NowDate() string { t := time.Now() return FormatDate(t) } // FormatDate - Parse data to string func FormatDate(t time.Time) string { return fmt.Sprintf("%d-%02d-%02d", t.Year(), t.Month(), t.Day()) } func ConvertHour(value float64) float64 { return value / 3600 }
Agora faremos um arquivo chamado integration para nos auxiliares na request http.
package integration import ( "io/ioutil" "net/http" "strings" "time" ) const ( jiraReport = "https://seu_dominio_aqui/rest/api/2/search" ) // Jira - struct type Jira struct { Hours int } // ResponseJiraIssue - struct type ResponseJiraIssue struct { Expand string `json:"expand"` Issues []struct { Expand string `json:"expand"` Fields struct { Worklog struct { MaxResults int64 `json:"maxResults"` StartAt int64 `json:"startAt"` Total int64 `json:"total"` Worklogs []struct { Author struct { AccountID string `json:"accountId"` AccountType string `json:"accountType"` Active bool `json:"active"` AvatarUrls struct { One6x16 string `json:"16x16"` Two4x24 string `json:"24x24"` Three2x32 string `json:"32x32"` Four8x48 string `json:"48x48"` } `json:"avatarUrls"` DisplayName string `json:"displayName"` Self string `json:"self"` TimeZone string `json:"timeZone"` } `json:"author"` Comment struct { Content []struct { Content []struct { Text string `json:"text"` Type string `json:"type"` } `json:"content"` Type string `json:"type"` } `json:"content"` Type string `json:"type"` Version int64 `json:"version"` } `json:"comment"` Created string `json:"created"` ID string `json:"id"` IssueID string `json:"issueId"` Self string `json:"self"` Started string `json:"started"` TimeSpent string `json:"timeSpent"` TimeSpentSeconds int64 `json:"timeSpentSeconds"` UpdateAuthor struct { AccountID string `json:"accountId"` AccountType string `json:"accountType"` Active bool `json:"active"` AvatarUrls struct { One6x16 string `json:"16x16"` Two4x24 string `json:"24x24"` Three2x32 string `json:"32x32"` Four8x48 string `json:"48x48"` } `json:"avatarUrls"` DisplayName string `json:"displayName"` Self string `json:"self"` TimeZone string `json:"timeZone"` } `json:"updateAuthor"` Updated string `json:"updated"` } `json:"worklogs"` } `json:"worklog"` } `json:"fields"` ID string `json:"id"` Key string `json:"key"` Self string `json:"self"` } `json:"issues"` MaxResults int64 `json:"maxResults"` StartAt int64 `json:"startAt"` Total int64 `json:"total"` } func mountedHttp (url, authorization, method string, body *strings.Reader) (*http.Response, error) { timeout := 5 * time.Second client := http.Client{ Timeout: timeout, } request, err := http.NewRequest(method, url, body) if err != nil { return nil, err } request.Header.Set("Content-Type", "application/json") request.Header.Set("Authorization", authorization) response, e := client.Do(request) if e != nil { return nil, e } return response, nil } // RequestHttpJiraReport - chamada http para request de issues do jira. func RequestHttpJiraReport (authorization string, body *strings.Reader) ([]byte, error) { response, err := mountedHttp(jiraReport, authorization, "POST", body) if err != nil { return nil, err } defer response.Body.Close() data, er := ioutil.ReadAll(response.Body) if er != nil { return nil, er } return data, nil }
Então criaremos um arquivo main para chamar todas as nossas funções, e revelar quantas horas foram feitas no dia.
package main import ( "encoding/json" "fmt" "github.com/higordiego/jira-tutorial/helpers" "github.com/higordiego/jira-tutorial/integration" "strings" ) const ( email = "seu_email_aqui" token = "token_aqui" accountID = "account_id" ) func main() { authorization := helpers.BasicAuth(email, token) equalData := helpers.NowDate() var jiraResponse integration.ResponseJiraIssue jql := fmt.Sprintf(`{"jql": "worklogDate>='%v' and worklogDate<='%v' and (worklogAuthor in ('%v'))", "fields":["worklog"] }`, equalData, equalData, accountID) payload := strings.NewReader(jql) result, err := integration.RequestHttpJiraReport(authorization, payload) if err != nil { panic(err.Error()) } er := json.Unmarshal(result, &jiraResponse) if er != nil { panic(er.Error()) } var count = 0.0 for _, r := range jiraResponse.Issues { for _, a := range r.Fields.Worklog.Worklogs { count += float64(a.TimeSpentSeconds) } } fmt.Printf("Suas horas trabalhadas: %.2f", helpers.ConvertHour(count)) }
E por fim, teremos o seguinte resultado no console:
Suas horas trabalhadas: 0.5
Com esse resultado podemos introduzir varias formas de aviso. Por exemplo:
- Envio de e-mail;
- Envio de mensagem por Slack ou WhatsApp;
- Alerta no Desktop.
Links úteis:
JQL: comece a usar a pesquisa avançada no Jira | Atlassian
The Go Programming Language (golang.org)
Top comments (0)