Skip to content

Commit

Permalink
feat: add jira-github-integ plugin (devstream-io#256)
Browse files Browse the repository at this point in the history
  • Loading branch information
lfbdev authored Mar 4, 2022
1 parent a7ea948 commit b6d7f05
Show file tree
Hide file tree
Showing 15 changed files with 487 additions and 0 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ build: fmt vet ## Build dtm & plugins locally.
go build -buildmode=plugin -trimpath -gcflags="all=-N -l" -o .devstream/github-repo-scaffolding-golang-${GOOS}-${GOARCH}_${VERSION}.so ./cmd/reposcaffolding/github/golang/
go build -buildmode=plugin -trimpath -gcflags="all=-N -l" -o .devstream/devlake-${GOOS}-${GOARCH}_${VERSION}.so ./cmd/devlake/
go build -buildmode=plugin -trimpath -gcflags="all=-N -l" -o .devstream/gitlabci-golang-${GOOS}-${GOARCH}_${VERSION}.so ./cmd/gitlabci/golang
go build -buildmode=plugin -trimpath -gcflags="all=-N -l" -o .devstream/jira-github-integ-${GOOS}-${GOARCH}_${VERSION}.so ./cmd/jiragithub/
go build -trimpath -gcflags="all=-N -l" -ldflags "-X github.com/merico-dev/stream/cmd/devstream/version.Version=${VERSION}" -o dtm-${GOOS}-${GOARCH} ./cmd/devstream/

build-core: fmt vet ## Build dtm core only, without plugins, locally.
Expand Down
1 change: 1 addition & 0 deletions build/package/build_linux_amd64.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ go build -buildmode=plugin -trimpath -gcflags="all=-N -l" -o output/githubaction
go build -buildmode=plugin -trimpath -gcflags="all=-N -l" -o output/githubactions-python-${GOOS}-${GOARCH}_${VERSION}.so ./cmd/githubactions/python
go build -buildmode=plugin -trimpath -gcflags="all=-N -l" -o output/githubactions-nodejs-${GOOS}-${GOARCH}_${VERSION}.so ./cmd/githubactions/nodejs
go build -buildmode=plugin -trimpath -gcflags="all=-N -l" -o output/trello-github-integ-${GOOS}-${GOARCH}_${VERSION}.so ./cmd/trellogithub/
go build -buildmode=plugin -trimpath -gcflags="all=-N -l" -o output/jira-github-integ-${GOOS}-${GOARCH}_${VERSION}.so ./cmd/jiragithub/
go build -buildmode=plugin -trimpath -gcflags="all=-N -l" -o output/argocd-${GOOS}-${GOARCH}_${VERSION}.so ./cmd/argocd/
go build -buildmode=plugin -trimpath -gcflags="all=-N -l" -o output/argocdapp-${GOOS}-${GOARCH}_${VERSION}.so ./cmd/argocdapp/
go build -buildmode=plugin -trimpath -gcflags="all=-N -l" -o output/jenkins-${GOOS}-${GOARCH}_${VERSION}.so ./cmd/jenkins/
Expand Down
39 changes: 39 additions & 0 deletions cmd/jiragithub/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package main

import (
"github.com/merico-dev/stream/internal/pkg/plugin/jiragithub"
"github.com/merico-dev/stream/pkg/util/log"
)

// NAME is the name of this DevStream plugin.
const NAME = "jiragithub"

// Plugin is the type used by DevStream core. It's a string.
type Plugin string

// Create implements the installation of some jira-github-integ workflows.
func (p Plugin) Create(options map[string]interface{}) (map[string]interface{}, error) {
return jiragithub.Create(options)
}

// Update implements the installation of some jira-github-integ workflows.
func (p Plugin) Update(options map[string]interface{}) (map[string]interface{}, error) {
return jiragithub.Update(options)
}

// Read implements the healthy check of jira-github-integ workflows.
func (p Plugin) Read(options map[string]interface{}) (map[string]interface{}, error) {
return jiragithub.Read(options)
}

// Delete implements the installation of some jira-github-integ workflows.
func (p Plugin) Delete(options map[string]interface{}) (bool, error) {
return jiragithub.Delete(options)
}

// DevStreamPlugin is the exported variable used by the DevStream core.
var DevStreamPlugin Plugin

func main() {
log.Infof("%T: %s is a plugin for DevStream. Use it with DevStream.\n", NAME, DevStreamPlugin)
}
48 changes: 48 additions & 0 deletions docs/plugins/jira-github-integ_plugin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
## 1 `jira-github-integ` Plugin

This plugin integrates Jira with your GitHub repo.

## 2 Usage:

_Please confirm the preconditions:_

- Jira language must be English
- There should be an existing Jira project

_This plugin depends on the following two environment variables:_

- JIRA_API_TOKEN
- GITHUB_TOKEN

Set the values accordingly before using this plugin.


To create a Jira API token, see [here](https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account/).

```yaml
tools:
- name: jira-github-integ-default
# plugin profile
plugin:
# kind of this plugin
kind: jira-github-integ
# version of the plugin
version: 0.3.0
# options for the plugin
# checkout the version from the GitHub releases
options:
# the repo's owner
owner: lfbdev
# the repo where you'd like to setup GitHub Actions
repo: opendeveloper
# "base url: https://id.atlassian.net"
jiraBaseUrl: https://merico.atlassian.net
# "need real user email in cloud Jira"
jiraUserEmail: [email protected]
# "get it from project url, like 'HEAP' from https://merico.atlassian.net/jira/software/projects/HEAP/pages"
jiraProjectKey: HEAP
# main branch of the repo (to which branch the plugin will submit the workflows)
branch: master
```
Currently, all the parameters in the example above are mandatory.
11 changes: 11 additions & 0 deletions examples/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,17 @@ tools:
kanbanBoardName: kanban-name
# main branch of the repo (to which branch the plugin will submit the workflows)
branch: main
- name: jira-github-integ-golang-demo
plugin:
kind: jira-github-integ
version: 0.2.0
options:
owner: ironcore864
repo: golang-demo
jiraBaseUrl: https://merico.atlassian.net # "base url: https://id.atlassian.net"
jiraUserEmail: [email protected] # "need real user email in cloud Jira"
jiraProjectKey: PROJECT # "get it from project url, like 'DTM' from https://merico.atlassian.net/jira/software/projects/DTM/pages"
branch: main
- name: dev
plugin:
# name of the plugin
Expand Down
47 changes: 47 additions & 0 deletions internal/pkg/plugin/jiragithub/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package jiragithub

import (
"fmt"

"github.com/merico-dev/stream/pkg/util/github"
)

// Create sets up jira-github-integ workflows.
func Create(options map[string]interface{}) (map[string]interface{}, error) {
opt, err := parseAndValidateOptions(options)
if err != nil {
return nil, err
}

ghOptions := &github.Option{
Owner: opt.Owner,
Repo: opt.Repo,
NeedAuth: true,
}
ghClient, err := github.NewClient(ghOptions)
if err != nil {
return nil, err
}

content, err := renderTemplate(workflow, opt)
if err != nil {
return nil, err
}
workflow.WorkflowContent = content

if err := ghClient.AddWorkflow(workflow, opt.Branch); err != nil {
return nil, err
}

if err := setRepoSecrets(ghClient); err != nil {
return nil, err
}

return BuildState(opt.Owner, opt.Repo), nil
}

func BuildState(owner, repo string) map[string]interface{} {
res := make(map[string]interface{})
res["workflowDir"] = fmt.Sprintf("/repos/%s/%s/contents/.github/workflows", owner, repo)
return res
}
29 changes: 29 additions & 0 deletions internal/pkg/plugin/jiragithub/delete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package jiragithub

import (
"github.com/merico-dev/stream/pkg/util/github"
)

// Delete remove jira-github-integ workflows.
func Delete(options map[string]interface{}) (bool, error) {
opt, err := parseAndValidateOptions(options)
if err != nil {
return false, err
}

ghOptions := &github.Option{
Owner: opt.Owner,
Repo: opt.Repo,
NeedAuth: true,
}
ghClient, err := github.NewClient(ghOptions)
if err != nil {
return false, err
}

if err := ghClient.DeleteWorkflow(workflow, opt.Branch); err != nil {
return false, err
}

return true, nil
}
42 changes: 42 additions & 0 deletions internal/pkg/plugin/jiragithub/helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package jiragithub

import (
"fmt"

"github.com/mitchellh/mapstructure"
"github.com/spf13/viper"

"github.com/merico-dev/stream/pkg/util/github"
"github.com/merico-dev/stream/pkg/util/log"
)

func parseAndValidateOptions(options map[string]interface{}) (*Options, error) {
var opt Options
err := mapstructure.Decode(options, &opt)
if err != nil {
return nil, err
}

if errs := validate(&opt); len(errs) != 0 {
for _, e := range errs {
log.Errorf("Param error: %s.", e)
}
return nil, fmt.Errorf("incorrect params")
}

return &opt, nil
}

func setRepoSecrets(gitHubClient *github.Client) error {

// JIRA_API_TOKEN, how to get it: "https://help.siteimprove.com/support/solutions/articles/80000448174-how-to-create-an-api-token-from-your-atlassian-account"
if err := gitHubClient.AddRepoSecret("JIRA_API_TOKEN", viper.GetString("jira_api_token")); err != nil {
return err
}

if err := gitHubClient.AddRepoSecret("GH_TOKEN", viper.GetString("github_token")); err != nil {
return err
}

return nil
}
11 changes: 11 additions & 0 deletions internal/pkg/plugin/jiragithub/options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package jiragithub

// Options is the struct for configurations of the jiragithub plugin.
type Options struct {
Owner string
Repo string
JiraBaseUrl string
JiraUserEmail string
JiraProjectKey string
Branch string
}
36 changes: 36 additions & 0 deletions internal/pkg/plugin/jiragithub/read.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package jiragithub

import (
"github.com/merico-dev/stream/pkg/util/github"
)

// Read get jira-github-integ workflows.
func Read(options map[string]interface{}) (map[string]interface{}, error) {
opt, err := parseAndValidateOptions(options)
if err != nil {
return nil, err
}

ghOptions := &github.Option{
Owner: opt.Owner,
Repo: opt.Repo,
NeedAuth: true,
}
ghClient, err := github.NewClient(ghOptions)
if err != nil {
return nil, err
}

path, err := ghClient.GetWorkflowPath()
if err != nil {
return nil, err
}

return BuildReadState(path), nil
}

func BuildReadState(path string) map[string]interface{} {
res := make(map[string]interface{})
res["workflowDir"] = path
return res
}
32 changes: 32 additions & 0 deletions internal/pkg/plugin/jiragithub/render.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package jiragithub

import (
"bytes"
"html/template"

"github.com/mitchellh/mapstructure"

github "github.com/merico-dev/stream/pkg/util/github"
)

func renderTemplate(workflow *github.Workflow, options *Options) (string, error) {
var opts Options
err := mapstructure.Decode(options, &opts)
if err != nil {
return "", err
}

//if use default {{.}}, it will confict (github actions vars also use them)
t, err := template.New("jiragithub").Delims("[[", "]]").Parse(workflow.WorkflowContent)
if err != nil {
return "", err
}

var buff bytes.Buffer
err = t.Execute(&buff, opts)
if err != nil {
return "", err
}

return buff.String(), nil
}
Loading

0 comments on commit b6d7f05

Please sign in to comment.