Simplifies init process and adds github issue publishing
This commit is contained in:
parent
21c18b3095
commit
be543e2cc4
23 changed files with 581 additions and 390 deletions
13
cmd/add.go
13
cmd/add.go
|
@ -16,9 +16,14 @@ import (
|
|||
|
||||
func GrepAddCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "grep",
|
||||
Short: "Generates the tickets reading grep's output from stdin",
|
||||
Long: "Generates tickets for the campaign reading from the standard input the output grep. The grep command must be run with the -n flag",
|
||||
Use: "grep",
|
||||
Short: "Generates the tickets reading grep's output from stdin",
|
||||
Long: `Generates tickets for the campaign reading from the standard input the output grep. The grep command must be run with the -n flag. The generated ticket will contain three fields:
|
||||
|
||||
- filename: the filename yield by grep
|
||||
- lineNo: the line number yield by grep
|
||||
- text: the trimmed line that grep captured for the expression
|
||||
`,
|
||||
Example: ` grep -nriIF --include \*.go cobra.Command | campaigner add grep`,
|
||||
Args: cobra.NoArgs,
|
||||
Run: grepAddCmdF,
|
||||
|
@ -104,7 +109,7 @@ func parseGrepLine(line string) (*model.Ticket, error) {
|
|||
Data: map[string]interface{}{
|
||||
"filename": filename,
|
||||
"lineNo": lineNo,
|
||||
"text": text,
|
||||
"text": strings.TrimSpace(text),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
|
79
cmd/init.go
79
cmd/init.go
|
@ -1,6 +1,9 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"git.ctrlz.es/mgdelacroix/campaigner/campaign"
|
||||
|
@ -14,44 +17,78 @@ func InitCmd() *cobra.Command {
|
|||
Use: "init",
|
||||
Short: "Creates a new campaign in the current directory",
|
||||
Example: ` campaigner init \
|
||||
--jira-username johndoe \
|
||||
--jira-token secret \
|
||||
--github-token TOKEN \
|
||||
--url http://my-jira-instance.com \
|
||||
--epic ASD-27 \
|
||||
--issue-type Story \
|
||||
--repository johndoe/awesomeproject \
|
||||
-l 'Area/API' -l 'Tech/Go' \
|
||||
--summary 'Refactor {{.function}} to inject the configuration service' \
|
||||
--template ./refactor-config.tmpl`,
|
||||
Args: cobra.NoArgs,
|
||||
Run: initCmdF,
|
||||
Args: cobra.NoArgs,
|
||||
Run: initCmdF,
|
||||
}
|
||||
|
||||
cmd.Flags().StringP("url", "u", "", "The jira server URL")
|
||||
_ = cmd.MarkFlagRequired("url")
|
||||
cmd.Flags().StringP("epic", "e", "", "The epic id to associate this campaign with")
|
||||
_ = cmd.MarkFlagRequired("epic")
|
||||
cmd.Flags().StringP("summary", "s", "", "The summary of the tickets")
|
||||
_ = cmd.MarkFlagRequired("summary")
|
||||
cmd.Flags().StringP("template", "t", "", "The template path for the description of the tickets")
|
||||
_ = cmd.MarkFlagRequired("template")
|
||||
cmd.Flags().StringP("issue-type", "i", "Story", "The issue type to create the tickets as")
|
||||
cmd.Flags().String("jira-username", "", "the jira username")
|
||||
cmd.Flags().String("jira-token", "", "the jira token or password")
|
||||
cmd.Flags().String("github-token", "", "the github token")
|
||||
cmd.Flags().StringP("url", "u", "", "the jira server URL")
|
||||
cmd.Flags().StringP("epic", "e", "", "the epic id to associate this campaign with")
|
||||
cmd.Flags().StringP("repository", "r", "", "the github repository")
|
||||
cmd.Flags().StringSliceP("label", "l", []string{}, "the labels to add to the Github issues")
|
||||
cmd.Flags().StringP("summary", "s", "", "the summary of the tickets")
|
||||
cmd.Flags().StringP("template", "t", "", "the template path for the description of the tickets")
|
||||
cmd.Flags().StringP("issue-type", "i", "Story", "the issue type to create the tickets as")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func initCmdF(cmd *cobra.Command, _ []string) {
|
||||
url, _ := cmd.Flags().GetString("url")
|
||||
epic, _ := cmd.Flags().GetString("epic")
|
||||
summary, _ := cmd.Flags().GetString("summary")
|
||||
template, _ := cmd.Flags().GetString("template")
|
||||
getStringFlagOrAskIfEmpty := func(name string, question string) string {
|
||||
val, _ := cmd.Flags().GetString(name)
|
||||
if val == "" {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
fmt.Printf("%s ", question)
|
||||
answer, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
ErrorAndExit(cmd, err)
|
||||
}
|
||||
val = strings.TrimSpace(answer)
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
jiraUsername := getStringFlagOrAskIfEmpty("jira-username", "JIRA username:")
|
||||
jiraToken := getStringFlagOrAskIfEmpty("jira-token", "JIRA password or token:")
|
||||
githubToken := getStringFlagOrAskIfEmpty("github-token", "GitHub token:")
|
||||
url := getStringFlagOrAskIfEmpty("url", "JIRA server URL:")
|
||||
epic := getStringFlagOrAskIfEmpty("epic", "JIRA epic:")
|
||||
repo := getStringFlagOrAskIfEmpty("repository", "GitHub repository:")
|
||||
summary := getStringFlagOrAskIfEmpty("summary", "Ticket summary template:")
|
||||
template := getStringFlagOrAskIfEmpty("template", "Ticket description template path:")
|
||||
issueType, _ := cmd.Flags().GetString("issue-type")
|
||||
labels, _ := cmd.Flags().GetStringSlice("label")
|
||||
|
||||
project := strings.Split(epic, "-")[0]
|
||||
|
||||
cmp := &model.Campaign{
|
||||
Url: url,
|
||||
Project: project,
|
||||
Epic: epic,
|
||||
IssueType: issueType,
|
||||
Summary: summary,
|
||||
Template: template,
|
||||
Jira: model.ConfigJira{
|
||||
Url: url,
|
||||
Username: jiraUsername,
|
||||
Token: jiraToken,
|
||||
Project: project,
|
||||
Epic: epic,
|
||||
IssueType: issueType,
|
||||
},
|
||||
Github: model.ConfigGithub{
|
||||
Token: githubToken,
|
||||
Repo: repo,
|
||||
Labels: labels,
|
||||
},
|
||||
Summary: summary,
|
||||
Template: template,
|
||||
}
|
||||
if err := campaign.Save(cmp); err != nil {
|
||||
ErrorAndExit(cmd, err)
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"fmt"
|
||||
|
||||
"git.ctrlz.es/mgdelacroix/campaigner/campaign"
|
||||
"git.ctrlz.es/mgdelacroix/campaigner/config"
|
||||
"git.ctrlz.es/mgdelacroix/campaigner/github"
|
||||
"git.ctrlz.es/mgdelacroix/campaigner/jira"
|
||||
|
||||
|
@ -64,17 +63,12 @@ func jiraPublishCmdF(cmd *cobra.Command, _ []string) error {
|
|||
return fmt.Errorf("One of --all or --batch flags is required")
|
||||
}
|
||||
|
||||
cfg, err := config.ReadConfig()
|
||||
if err != nil {
|
||||
ErrorAndExit(cmd, err)
|
||||
}
|
||||
|
||||
cmp, err := campaign.Read()
|
||||
if err != nil {
|
||||
ErrorAndExit(cmd, err)
|
||||
}
|
||||
|
||||
jiraClient, err := jira.NewClient(cmp.Url, cfg.JiraUsername, cfg.JiraToken)
|
||||
jiraClient, err := jira.NewClient(cmp.Jira.Url, cmp.Jira.Username, cmp.Jira.Token)
|
||||
if err != nil {
|
||||
ErrorAndExit(cmd, err)
|
||||
}
|
||||
|
@ -104,17 +98,12 @@ func githubPublishCmdF(cmd *cobra.Command, _ []string) error {
|
|||
return fmt.Errorf("One of --all or --batch flags is required")
|
||||
}
|
||||
|
||||
cfg, err := config.ReadConfig()
|
||||
if err != nil {
|
||||
ErrorAndExit(cmd, err)
|
||||
}
|
||||
|
||||
cmp, err := campaign.Read()
|
||||
if err != nil {
|
||||
ErrorAndExit(cmd, err)
|
||||
}
|
||||
|
||||
githubClient := github.NewClient("my/repo", cfg.GithubToken)
|
||||
githubClient := github.NewClient(cmp.Github.Repo, cmp.Github.Token)
|
||||
|
||||
if all {
|
||||
count, err := githubClient.PublishAll(cmp, dryRun)
|
||||
|
|
|
@ -17,9 +17,7 @@ func RootCmd() *cobra.Command {
|
|||
AddCmd(),
|
||||
FilterCmd(),
|
||||
InitCmd(),
|
||||
StandaloneCmd(),
|
||||
StatusCmd(),
|
||||
TokenCmd(),
|
||||
PublishCmd(),
|
||||
SyncCmd(),
|
||||
)
|
||||
|
|
|
@ -1,163 +0,0 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.ctrlz.es/mgdelacroix/campaigner/config"
|
||||
"git.ctrlz.es/mgdelacroix/campaigner/jira"
|
||||
"git.ctrlz.es/mgdelacroix/campaigner/model"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func StandaloneCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "standalone",
|
||||
Short: "Standalone fire-and-forget commands",
|
||||
}
|
||||
|
||||
cmd.AddCommand(
|
||||
CreateJiraTicketStandaloneCmd(),
|
||||
GetJiraTicketStandaloneCmd(),
|
||||
)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func CreateJiraTicketStandaloneCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "create-jira-ticket",
|
||||
Short: "Creates a jira ticket from a template",
|
||||
Args: cobra.NoArgs,
|
||||
RunE: createJiraTicketStandaloneCmdF,
|
||||
}
|
||||
|
||||
cmd.Flags().String("url", "", "The jira server URL")
|
||||
_ = cmd.MarkFlagRequired("url")
|
||||
cmd.Flags().String("epic", "", "The jira epic id to associate the ticket with")
|
||||
_ = cmd.MarkFlagRequired("epic")
|
||||
cmd.Flags().String("summary", "", "The summary of the ticket")
|
||||
_ = cmd.MarkFlagRequired("summary")
|
||||
cmd.Flags().String("template", "", "The template to render the description of the ticket")
|
||||
_ = cmd.MarkFlagRequired("template")
|
||||
cmd.Flags().String("username", "", "The jira username")
|
||||
cmd.Flags().String("token", "", "The jira token")
|
||||
cmd.Flags().StringSliceP("vars", "v", []string{}, "The variables to use in the template")
|
||||
cmd.Flags().Bool("dry-run", false, "Print the ticket information instead of creating it")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func GetJiraTicketStandaloneCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "get-jira-ticket",
|
||||
Short: "Gets the ticket from jira",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: getJiraTicketStandaloneCmdF,
|
||||
}
|
||||
|
||||
cmd.Flags().String("url", "", "The jira server URL")
|
||||
_ = cmd.MarkFlagRequired("url")
|
||||
cmd.Flags().String("username", "", "The jira username")
|
||||
cmd.Flags().String("token", "", "The jira token")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func getVarMap(vars []string) (map[string]interface{}, error) {
|
||||
varMap := map[string]interface{}{}
|
||||
for _, v := range vars {
|
||||
parts := strings.Split(v, "=")
|
||||
if len(parts) < 2 {
|
||||
return nil, fmt.Errorf("cannot parse var %s", v)
|
||||
}
|
||||
varMap[parts[0]] = strings.Join(parts[1:], "=")
|
||||
}
|
||||
return varMap, nil
|
||||
}
|
||||
|
||||
func createJiraTicketStandaloneCmdF(cmd *cobra.Command, _ []string) error {
|
||||
url, _ := cmd.Flags().GetString("url")
|
||||
epic, _ := cmd.Flags().GetString("epic")
|
||||
username, _ := cmd.Flags().GetString("username")
|
||||
token, _ := cmd.Flags().GetString("token")
|
||||
summary, _ := cmd.Flags().GetString("summary")
|
||||
template, _ := cmd.Flags().GetString("template")
|
||||
vars, _ := cmd.Flags().GetStringSlice("vars")
|
||||
dryRun, _ := cmd.Flags().GetBool("dry-run")
|
||||
|
||||
project := strings.Split(epic, "-")[0]
|
||||
|
||||
if username == "" || token == "" {
|
||||
cfg, err := config.ReadConfig()
|
||||
if err != nil {
|
||||
ErrorAndExit(cmd, err)
|
||||
}
|
||||
|
||||
if username == "" {
|
||||
username = cfg.JiraUsername
|
||||
}
|
||||
if token == "" {
|
||||
token = cfg.JiraToken
|
||||
}
|
||||
}
|
||||
|
||||
varMap, err := getVarMap(vars)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error processing vars: %w", err)
|
||||
}
|
||||
|
||||
jiraClient, err := jira.NewClient(url, username, token)
|
||||
if err != nil {
|
||||
ErrorAndExit(cmd, err)
|
||||
}
|
||||
|
||||
campaign := &model.Campaign{
|
||||
Epic: epic,
|
||||
Project: project,
|
||||
Summary: summary,
|
||||
Template: template,
|
||||
}
|
||||
ticket := &model.Ticket{Data: varMap}
|
||||
|
||||
issue, err := jiraClient.PublishTicket(ticket, campaign, dryRun)
|
||||
if err != nil {
|
||||
ErrorAndExit(cmd, err)
|
||||
}
|
||||
|
||||
cmd.Printf("Ticket %s successfully created in JIRA", issue.Key)
|
||||
return nil
|
||||
}
|
||||
|
||||
func getJiraTicketStandaloneCmdF(cmd *cobra.Command, args []string) {
|
||||
url, _ := cmd.Flags().GetString("url")
|
||||
username, _ := cmd.Flags().GetString("username")
|
||||
token, _ := cmd.Flags().GetString("token")
|
||||
|
||||
if username == "" || token == "" {
|
||||
cfg, err := config.ReadConfig()
|
||||
if err != nil {
|
||||
ErrorAndExit(cmd, err)
|
||||
}
|
||||
|
||||
if username == "" {
|
||||
username = cfg.JiraUsername
|
||||
}
|
||||
if token == "" {
|
||||
token = cfg.JiraToken
|
||||
}
|
||||
}
|
||||
|
||||
jiraClient, err := jira.NewClient(url, username, token)
|
||||
if err != nil {
|
||||
ErrorAndExit(cmd, err)
|
||||
}
|
||||
|
||||
issue, err := jiraClient.GetIssue(args[0])
|
||||
if err != nil {
|
||||
ErrorAndExit(cmd, err)
|
||||
}
|
||||
|
||||
fmt.Printf("Summary: %s\nKey: %s\nStatus: %s\nAsignee: %s\n", issue.Fields.Summary, issue.Key, issue.Fields.Status.Name, issue.Fields.Assignee.DisplayName)
|
||||
}
|
79
cmd/token.go
79
cmd/token.go
|
@ -1,79 +0,0 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"git.ctrlz.es/mgdelacroix/campaigner/config"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func TokenSetJiraCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "jira USERNAME TOKEN",
|
||||
Short: "Sets the value of the jira token",
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: tokenSetJiraCmdF,
|
||||
}
|
||||
}
|
||||
|
||||
func TokenSetGithubCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "github TOKEN",
|
||||
Short: "Sets the value of the github token",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: tokenSetGithubCmdF,
|
||||
}
|
||||
}
|
||||
|
||||
func TokenSetCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "set",
|
||||
Short: "Sets the value of the platform tokens",
|
||||
}
|
||||
|
||||
cmd.AddCommand(
|
||||
TokenSetJiraCmd(),
|
||||
TokenSetGithubCmd(),
|
||||
)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func TokenCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "token",
|
||||
Short: "Subcommands related to tokens",
|
||||
}
|
||||
|
||||
cmd.AddCommand(
|
||||
TokenSetCmd(),
|
||||
)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func tokenSetJiraCmdF(cmd *cobra.Command, args []string) error {
|
||||
cfg, err := config.ReadConfig()
|
||||
if err != nil {
|
||||
ErrorAndExit(cmd, err)
|
||||
}
|
||||
|
||||
cfg.JiraUsername = args[0]
|
||||
cfg.JiraToken = args[1]
|
||||
if err := config.SaveConfig(cfg); err != nil {
|
||||
ErrorAndExit(cmd, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func tokenSetGithubCmdF(cmd *cobra.Command, args []string) error {
|
||||
cfg, err := config.ReadConfig()
|
||||
if err != nil {
|
||||
ErrorAndExit(cmd, err)
|
||||
}
|
||||
|
||||
cfg.GithubToken = args[0]
|
||||
if err := config.SaveConfig(cfg); err != nil {
|
||||
ErrorAndExit(cmd, err)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/user"
|
||||
|
||||
"git.ctrlz.es/mgdelacroix/campaigner/model"
|
||||
)
|
||||
|
||||
func getConfigPath() (string, error) {
|
||||
user, err := user.Current()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return user.HomeDir + "/.campaigner", nil
|
||||
}
|
||||
|
||||
func ReadConfig() (*model.Config, error) {
|
||||
configPath, err := getConfigPath()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err := os.Stat(configPath); err != nil {
|
||||
return &model.Config{}, nil
|
||||
}
|
||||
|
||||
fileContents, err := ioutil.ReadFile(configPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("there was a problem reading the config file: %w", err)
|
||||
}
|
||||
|
||||
var config model.Config
|
||||
if err := json.Unmarshal(fileContents, &config); err != nil {
|
||||
return nil, fmt.Errorf("there was a problem parsing the config file: %w", err)
|
||||
}
|
||||
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
func SaveConfig(config *model.Config) error {
|
||||
configPath, err := getConfigPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
marshaledConfig, err := json.MarshalIndent(config, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(configPath, marshaledConfig, 0600); err != nil {
|
||||
return fmt.Errorf("cannot save the config: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -2,10 +2,13 @@ package github
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"git.ctrlz.es/mgdelacroix/campaigner/campaign"
|
||||
"git.ctrlz.es/mgdelacroix/campaigner/model"
|
||||
|
||||
"github.com/StevenACoffman/j2m"
|
||||
"github.com/google/go-github/v29/github"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
@ -28,7 +31,28 @@ func NewClient(repo, token string) *GithubClient {
|
|||
}
|
||||
|
||||
func (c *GithubClient) PublishTicket(ticket *model.Ticket, cmp *model.Campaign, dryRun bool) (*github.Issue, error) {
|
||||
return nil, nil
|
||||
mdDescription := j2m.JiraToMD(ticket.Description)
|
||||
issueRequest := &github.IssueRequest{
|
||||
Title: &ticket.Summary,
|
||||
Body: &mdDescription,
|
||||
Labels: &cmp.Github.Labels,
|
||||
}
|
||||
|
||||
if dryRun {
|
||||
b, _ := json.MarshalIndent(issueRequest, "", " ")
|
||||
fmt.Println(string(b))
|
||||
return &github.Issue{
|
||||
Title: issueRequest.Title,
|
||||
Body: issueRequest.Body,
|
||||
}, nil
|
||||
}
|
||||
|
||||
owner, repo := cmp.RepoComponents()
|
||||
newIssue, _, err := c.Issues.Create(context.Background(), owner, repo, issueRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newIssue, nil
|
||||
}
|
||||
|
||||
func (c *GithubClient) PublishNextTicket(cmp *model.Campaign, dryRun bool) (bool, error) {
|
||||
|
@ -47,9 +71,6 @@ func (c *GithubClient) PublishNextTicket(cmp *model.Campaign, dryRun bool) (bool
|
|||
}
|
||||
|
||||
ticket.GithubLink = *issue.ID
|
||||
// move this to a publish service that can do both github and
|
||||
// jira, as we need to update a jira issue field with the github
|
||||
// link
|
||||
if err := campaign.Save(cmp); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
@ -72,7 +93,7 @@ func (c *GithubClient) PublishAll(cmp *model.Campaign, dryRun bool) (int, error)
|
|||
}
|
||||
|
||||
func (c *GithubClient) PublishBatch(cmp *model.Campaign, batch int, dryRun bool) error {
|
||||
for i := 0; i <= batch; i++ {
|
||||
for i := 1; i <= batch; i++ {
|
||||
next, err := c.PublishNextTicket(cmp, dryRun)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
2
go.mod
2
go.mod
|
@ -3,7 +3,7 @@ module git.ctrlz.es/mgdelacroix/campaigner
|
|||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/fatih/color v1.9.0 // indirect
|
||||
github.com/StevenACoffman/j2m v0.0.0-20190826163711-7d8d00c99217
|
||||
github.com/fatih/structs v1.1.0 // indirect
|
||||
github.com/google/go-github/v29 v29.0.3
|
||||
github.com/spf13/cobra v0.0.6
|
||||
|
|
13
go.sum
13
go.sum
|
@ -1,6 +1,8 @@
|
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/StevenACoffman/j2m v0.0.0-20190826163711-7d8d00c99217 h1:y2QXqPIec+mEDDToinjdFymzQZmLNRIKtuOkdomqyA4=
|
||||
github.com/StevenACoffman/j2m v0.0.0-20190826163711-7d8d00c99217/go.mod h1:y1vzL6Jab7oLzLLE2CtItTyEI6hKQnNMmqDrO+2a7Pk=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
|
@ -17,8 +19,6 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsr
|
|||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
|
||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
|
@ -38,7 +38,6 @@ github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs
|
|||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
|
||||
github.com/google/go-github/v29 v29.0.3 h1:IktKCTwU//aFHnpA+2SLIi7Oo9uhAzgsdZNbcAqhgdc=
|
||||
github.com/google/go-github/v29 v29.0.3/go.mod h1:CHKiKKPHJ0REzfwc14QMklvtHwCveD0PxlMjLlzAM5E=
|
||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||
|
@ -60,11 +59,6 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
|
|||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
|
||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
|
@ -130,9 +124,6 @@ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
|
17
jira/jira.go
17
jira/jira.go
|
@ -56,22 +56,22 @@ func (c *JiraClient) GetIssueFromTicket(ticket *model.Ticket, cmp *model.Campaig
|
|||
data := map[string]string{
|
||||
"Description": description,
|
||||
"Summary": summary,
|
||||
"Project": cmp.Project,
|
||||
"Issue Type": cmp.IssueType,
|
||||
"Epic Link": cmp.Epic,
|
||||
"Project": cmp.Jira.Project,
|
||||
"Issue Type": cmp.Jira.IssueType,
|
||||
"Epic Link": cmp.Jira.Epic,
|
||||
}
|
||||
|
||||
createMetaInfo, _, err := c.Issue.GetCreateMeta(cmp.Project)
|
||||
createMetaInfo, _, err := c.Issue.GetCreateMeta(cmp.Jira.Project)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
project := createMetaInfo.GetProjectWithKey(cmp.Project)
|
||||
project := createMetaInfo.GetProjectWithKey(cmp.Jira.Project)
|
||||
if project == nil {
|
||||
return nil, fmt.Errorf("Error retrieving project with key %s", cmp.Project)
|
||||
return nil, fmt.Errorf("Error retrieving project with key %s", cmp.Jira.Project)
|
||||
}
|
||||
|
||||
issueType := project.GetIssueTypeWithName(cmp.IssueType)
|
||||
issueType := project.GetIssueTypeWithName(cmp.Jira.IssueType)
|
||||
if issueType == nil {
|
||||
return nil, fmt.Errorf("Error retrieving issue type with name Story")
|
||||
}
|
||||
|
@ -134,6 +134,7 @@ func (c *JiraClient) PublishNextTicket(cmp *model.Campaign, dryRun bool) (bool,
|
|||
|
||||
ticket.JiraLink = issue.Key
|
||||
ticket.Summary = issue.Fields.Summary
|
||||
ticket.Description = issue.Fields.Description
|
||||
if err := campaign.Save(cmp); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
@ -156,7 +157,7 @@ func (c *JiraClient) PublishAll(cmp *model.Campaign, dryRun bool) (int, error) {
|
|||
}
|
||||
|
||||
func (c *JiraClient) PublishBatch(cmp *model.Campaign, batch int, dryRun bool) error {
|
||||
for i := 0; i <= batch; i++ {
|
||||
for i := 1; i <= batch; i++ {
|
||||
next, err := c.PublishNextTicket(cmp, dryRun)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -1,19 +1,35 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
type ConfigJira struct {
|
||||
Url string `json:"url"`
|
||||
Username string `json:"username"`
|
||||
Token string `json:"token"`
|
||||
Project string `json:"project"`
|
||||
Epic string `json:"epic"`
|
||||
IssueType string `json:"issue_type"`
|
||||
}
|
||||
|
||||
type ConfigGithub struct {
|
||||
Token string `json:"token"`
|
||||
Repo string `json:"repo"`
|
||||
Labels []string `json:"labels"`
|
||||
}
|
||||
|
||||
// ToDo: add key-value extra params as a map to allow for customfield_whatever = team
|
||||
type Campaign struct {
|
||||
Url string `json:"url"`
|
||||
Project string `json:"project"`
|
||||
Epic string `json:"epic"`
|
||||
IssueType string `json:"issue_type"`
|
||||
Summary string `json:"summary"`
|
||||
Template string `json:"template"`
|
||||
Tickets []*Ticket `json:"tickets,omitempty"`
|
||||
Jira ConfigJira `json:"jira"`
|
||||
Github ConfigGithub `json:"github"`
|
||||
Summary string `json:"summary"`
|
||||
Template string `json:"template"`
|
||||
Tickets []*Ticket `json:"tickets,omitempty"`
|
||||
}
|
||||
|
||||
func (c *Campaign) NextJiraUnpublishedTicket() *Ticket {
|
||||
|
@ -27,7 +43,7 @@ func (c *Campaign) NextJiraUnpublishedTicket() *Ticket {
|
|||
|
||||
func (c *Campaign) NextGithubUnpublishedTicket() *Ticket {
|
||||
for _, ticket := range c.Tickets {
|
||||
if ticket.JiraLink != "" && ticket.GithubLink != 0 {
|
||||
if ticket.JiraLink != "" && ticket.GithubLink == 0 {
|
||||
return ticket
|
||||
}
|
||||
}
|
||||
|
@ -35,14 +51,50 @@ func (c *Campaign) NextGithubUnpublishedTicket() *Ticket {
|
|||
}
|
||||
|
||||
func (c *Campaign) PrintStatus(w io.Writer) {
|
||||
fmt.Fprintf(w, "Url: %s\n", c.Url)
|
||||
fmt.Fprintf(w, "Project: %s\n", c.Project)
|
||||
fmt.Fprintf(w, "Epic: %s\n", c.Epic)
|
||||
fmt.Fprintf(w, "Issue Type: %s\n", c.IssueType)
|
||||
fmt.Fprintf(w, "JIRA URL: %s\n", c.Jira.Url)
|
||||
fmt.Fprintf(w, "JIRA Project: %s\n", c.Jira.Project)
|
||||
fmt.Fprintf(w, "JIRA Epic: %s\n", c.Jira.Epic)
|
||||
fmt.Fprintf(w, "JIRA Issue Type: %s\n", c.Jira.IssueType)
|
||||
fmt.Fprintf(w, "GitHub Repo: %s\n", c.Github.Repo)
|
||||
fmt.Fprintf(w, "GitHub Labels: %s\n", c.Github.Labels)
|
||||
fmt.Fprintf(w, "Summary: %s\n", c.Summary)
|
||||
fmt.Fprintf(w, "Template: %s\n", c.Template)
|
||||
fmt.Fprintln(w, "")
|
||||
|
||||
for _, ticket := range c.Tickets {
|
||||
ticket.PrintStatus(w)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Campaign) FillTicket(t *Ticket) error {
|
||||
summaryTmpl, err := template.New("").Parse(c.Summary)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var summaryBytes bytes.Buffer
|
||||
if err := summaryTmpl.Execute(&summaryBytes, t.Data); err != nil {
|
||||
return err
|
||||
}
|
||||
t.Summary = summaryBytes.String()
|
||||
|
||||
descriptionTemplate, err := template.ParseFiles(c.Template)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var descriptionBytes bytes.Buffer
|
||||
if err := descriptionTemplate.Execute(&descriptionBytes, t.Data); err != nil {
|
||||
return err
|
||||
}
|
||||
t.Description = descriptionBytes.String()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Campaign) RepoComponents() (string, string) {
|
||||
parts := strings.Split(c.Github.Repo, "/")
|
||||
if len(parts) == 2 {
|
||||
return parts[0], parts[1]
|
||||
}
|
||||
return "", ""
|
||||
}
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
package model
|
||||
|
||||
type Config struct {
|
||||
GithubToken string `json:"github_token"`
|
||||
JiraUsername string `json:"jira_username"`
|
||||
JiraToken string `json:"jira_token"`
|
||||
}
|
|
@ -6,10 +6,13 @@ import (
|
|||
)
|
||||
|
||||
type Ticket struct {
|
||||
GithubLink int64 `json:"githubLink,omitempty"`
|
||||
JiraLink string `json:"jiraLink,omitempty"`
|
||||
Summary string `json:"summary,omitempty"`
|
||||
Data map[string]interface{} `json:"data,omitempty"`
|
||||
GithubLink int64 `json:"github_link,omitempty"`
|
||||
GithubStatus string `json:"github_status,omitempty"`
|
||||
JiraLink string `json:"jira_link,omitempty"`
|
||||
JiraStatus string `json:"jira_status,omitempty"`
|
||||
Summary string `json:"summary,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Data map[string]interface{} `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
func RemoveDuplicateTickets(tickets []*Ticket, fileOnly bool) []*Ticket {
|
||||
|
@ -33,5 +36,7 @@ func RemoveDuplicateTickets(tickets []*Ticket, fileOnly bool) []*Ticket {
|
|||
}
|
||||
|
||||
func (t *Ticket) PrintStatus(w io.Writer) {
|
||||
fmt.Fprintf(w, " [%s] %s\n", t.JiraLink, t.Summary)
|
||||
if t.Summary != "" {
|
||||
fmt.Fprintf(w, "[%s] %s\n", t.JiraLink, t.Summary)
|
||||
}
|
||||
}
|
||||
|
|
12
vendor/github.com/StevenACoffman/j2m/.gitignore
generated
vendored
Normal file
12
vendor/github.com/StevenACoffman/j2m/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
21
vendor/github.com/StevenACoffman/j2m/LICENSE
generated
vendored
Normal file
21
vendor/github.com/StevenACoffman/j2m/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2019 Steve Coffman
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
15
vendor/github.com/StevenACoffman/j2m/Makefile
generated
vendored
Normal file
15
vendor/github.com/StevenACoffman/j2m/Makefile
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
.DEFAULT_GOAL := easy
|
||||
.PHONY: install clean all easy
|
||||
|
||||
bin/j2m:
|
||||
go build -o bin/j2m cmd/j2m.go
|
||||
|
||||
all: bin/j2m
|
||||
|
||||
install: bin/j2m
|
||||
cp bin/* ~/bin
|
||||
|
||||
clean:
|
||||
rm -f bin/*
|
||||
|
||||
easy: all
|
61
vendor/github.com/StevenACoffman/j2m/README.md
generated
vendored
Normal file
61
vendor/github.com/StevenACoffman/j2m/README.md
generated
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
[![GoDoc](https://godoc.org/github.com/StevenACoffman/j2m?status.svg)](https://godoc.org/github.com/StevenACoffman/j2m)
|
||||
[![GoReportcard](https://goreportcard.com/badge/github.com/StevenACoffman/j2m?status.svg)](https://goreportcard.com/report/github.com/StevenACoffman/j2m)
|
||||
|
||||
# jira-to-md
|
||||
|
||||
## JIRA to MarkDown text format converter
|
||||
Golang tool to convert from JIRA Markdown text formatting to GitHub Flavored MarkDown.
|
||||
|
||||
## Credits
|
||||
This fun toy was heavily inspired by the J2M project by Fokke Zandbergen (http://j2m.fokkezb.nl/). Major credit to Fokke, kylefarris (and other contributors) for establishing the RexExp patterns for this to work. The maintained JavaScript fork I based this on is [here](https://github.com/kylefarris/J2M)
|
||||
|
||||
## Supported Conversions
|
||||
|
||||
* Headers (H1-H6)
|
||||
* Bold
|
||||
* Italic
|
||||
* Bold + Italic
|
||||
* Un-ordered lists
|
||||
* Ordered lists
|
||||
* Programming Language-specific code blocks (with help from herbert-venancio)
|
||||
* Inline preformatted text spans
|
||||
* Un-named links
|
||||
* Named links
|
||||
* Monospaced Text
|
||||
* ~~Citations~~ (currently kinda buggy)
|
||||
* Strikethroughs
|
||||
* Inserts
|
||||
* Superscripts
|
||||
* Subscripts
|
||||
* Single-paragraph blockquotes
|
||||
* Tables
|
||||
* Panels
|
||||
|
||||
|
||||
## How to Use
|
||||
|
||||
### Markdown String
|
||||
|
||||
```
|
||||
**Some bold things**
|
||||
*Some italic stuff*
|
||||
## H2
|
||||
<http://google.com>
|
||||
```
|
||||
|
||||
### Atlassian Wiki MarkUp Syntax (JIRA)
|
||||
|
||||
We'll refer to this as the `jira` variable in the examples below.
|
||||
|
||||
```
|
||||
*Some bold things**
|
||||
_Some italic stuff_
|
||||
h2. H2
|
||||
[http://google.com]
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
```
|
||||
cat j2m.jira | j2m
|
||||
```
|
3
vendor/github.com/StevenACoffman/j2m/go.mod
generated
vendored
Normal file
3
vendor/github.com/StevenACoffman/j2m/go.mod
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
module github.com/StevenACoffman/j2m
|
||||
|
||||
go 1.12
|
153
vendor/github.com/StevenACoffman/j2m/j2m.go
generated
vendored
Normal file
153
vendor/github.com/StevenACoffman/j2m/j2m.go
generated
vendored
Normal file
|
@ -0,0 +1,153 @@
|
|||
package j2m
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type jiration struct {
|
||||
re *regexp.Regexp
|
||||
repl interface{}
|
||||
}
|
||||
|
||||
// JiraToMD takes a string in Jira Markdown, and outputs Github Markdown
|
||||
func JiraToMD(str string) string {
|
||||
jirations := []jiration{
|
||||
{ // UnOrdered Lists
|
||||
re: regexp.MustCompile(`(?m)^[ \t]*(\*+)\s+`),
|
||||
repl: func(groups []string) string {
|
||||
_, stars := groups[0], groups[1]
|
||||
return strings.Repeat(" ", len(stars)-1) + "* "
|
||||
},
|
||||
},
|
||||
{ //Ordered Lists
|
||||
re: regexp.MustCompile(`(?m)^[ \t]*(#+)\s+`),
|
||||
repl: func(groups []string) string {
|
||||
_, nums := groups[0], groups[1]
|
||||
return strings.Repeat(" ", len(nums)-1) + "1. "
|
||||
},
|
||||
},
|
||||
{ //Headers 1-6
|
||||
re: regexp.MustCompile(`(?m)^h([0-6])\.(.*)$`),
|
||||
repl: func(groups []string) string {
|
||||
_, level, content := groups[0], groups[1], groups[2]
|
||||
i, _ := strconv.Atoi(level)
|
||||
return strings.Repeat("#", i) + content
|
||||
},
|
||||
},
|
||||
{ // Bold
|
||||
re: regexp.MustCompile(`\*(\S.*)\*`),
|
||||
repl: "**$1**",
|
||||
},
|
||||
{ // Italic
|
||||
re: regexp.MustCompile(`\_(\S.*)\_`),
|
||||
repl: "*$1*",
|
||||
},
|
||||
{ // Monospaced text
|
||||
re: regexp.MustCompile(`\{\{([^}]+)\}\}`),
|
||||
repl: "`$1`",
|
||||
},
|
||||
{ // Citations (buggy)
|
||||
re: regexp.MustCompile(`\?\?((?:.[^?]|[^?].)+)\?\?`),
|
||||
repl: "<cite>$1</cite>",
|
||||
},
|
||||
{ // Inserts
|
||||
re: regexp.MustCompile(`\+([^+]*)\+`),
|
||||
repl: "<ins>$1</ins>",
|
||||
},
|
||||
{ // Superscript
|
||||
re: regexp.MustCompile(`\^([^^]*)\^`),
|
||||
repl: "<sup>$1</sup>",
|
||||
},
|
||||
{ // Subscript
|
||||
re: regexp.MustCompile(`~([^~]*)~`),
|
||||
repl: "<sub>$1</sub>",
|
||||
},
|
||||
{ // Strikethrough
|
||||
re: regexp.MustCompile(`(\s+)-(\S+.*?\S)-(\s+)`),
|
||||
repl: "$1~~$2~~$3",
|
||||
},
|
||||
{ // Code Block
|
||||
re: regexp.MustCompile(`\{code(:([a-z]+))?([:|]?(title|borderStyle|borderColor|borderWidth|bgColor|titleBGColor)=.+?)*\}`),
|
||||
repl: "```$2",
|
||||
},
|
||||
{ // Code Block End
|
||||
re: regexp.MustCompile(`{code}`),
|
||||
repl: "```",
|
||||
},
|
||||
{ // Pre-formatted text
|
||||
re: regexp.MustCompile(`{noformat}`),
|
||||
repl: "```",
|
||||
},
|
||||
{ // Un-named Links
|
||||
re: regexp.MustCompile(`(?U)\[([^|]+)\]`),
|
||||
repl: "<$1>",
|
||||
},
|
||||
{ // Images
|
||||
re: regexp.MustCompile(`!(.+)!`),
|
||||
repl: "![]($1)",
|
||||
},
|
||||
{ // Named Links
|
||||
re: regexp.MustCompile(`\[(.+?)\|(.+)\]`),
|
||||
repl: "[$1]($2)",
|
||||
},
|
||||
{ // Single Paragraph Blockquote
|
||||
re: regexp.MustCompile(`(?m)^bq\.\s+`),
|
||||
repl: "> ",
|
||||
},
|
||||
{ // Remove color: unsupported in md
|
||||
re: regexp.MustCompile(`(?m)\{color:[^}]+\}(.*)\{color\}`),
|
||||
repl: "$1",
|
||||
},
|
||||
{ // panel into table
|
||||
re: regexp.MustCompile(`(?m)\{panel:title=([^}]*)\}\n?(.*?)\n?\{panel\}`),
|
||||
repl: "\n| $1 |\n| --- |\n| $2 |",
|
||||
},
|
||||
{ //table header
|
||||
re: regexp.MustCompile(`(?m)^[ \t]*((?:\|\|.*?)+\|\|)[ \t]*$`),
|
||||
repl: func(groups []string) string {
|
||||
_, headers := groups[0], groups[1]
|
||||
reBarred := regexp.MustCompile(`\|\|`)
|
||||
|
||||
singleBarred := reBarred.ReplaceAllString(headers, "|")
|
||||
fillerRe := regexp.MustCompile(`\|[^|]+`)
|
||||
return "\n" + singleBarred + "\n" + fillerRe.ReplaceAllString(singleBarred, "| --- ")
|
||||
},
|
||||
},
|
||||
{ // remove leading-space of table headers and rows
|
||||
re: regexp.MustCompile(`(?m)^[ \t]*\|`),
|
||||
repl: "|",
|
||||
},
|
||||
}
|
||||
for _, jiration := range jirations {
|
||||
switch v := jiration.repl.(type) {
|
||||
case string:
|
||||
str = jiration.re.ReplaceAllString(str, v)
|
||||
case func([]string) string:
|
||||
str = replaceAllStringSubmatchFunc(jiration.re, str, v)
|
||||
default:
|
||||
fmt.Printf("I don't know about type %T!\n", v)
|
||||
}
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
// https://gist.github.com/elliotchance/d419395aa776d632d897
|
||||
func replaceAllStringSubmatchFunc(re *regexp.Regexp, str string, repl func([]string) string) string {
|
||||
result := ""
|
||||
lastIndex := 0
|
||||
|
||||
for _, v := range re.FindAllSubmatchIndex([]byte(str), -1) {
|
||||
groups := []string{}
|
||||
for i := 0; i < len(v); i += 2 {
|
||||
groups = append(groups, str[v[i]:v[i+1]])
|
||||
}
|
||||
|
||||
result += str[lastIndex:v[0]] + repl(groups)
|
||||
lastIndex = v[1]
|
||||
}
|
||||
|
||||
return result + str[lastIndex:]
|
||||
}
|
65
vendor/github.com/StevenACoffman/j2m/j2m.jira
generated
vendored
Normal file
65
vendor/github.com/StevenACoffman/j2m/j2m.jira
generated
vendored
Normal file
|
@ -0,0 +1,65 @@
|
|||
h1. Biggest heading
|
||||
|
||||
h2. Bigger heading
|
||||
|
||||
h1. Biggest heading
|
||||
h2. Bigger heading
|
||||
h3. Big heading
|
||||
h4. Normal heading
|
||||
h5. Small heading
|
||||
h6. Smallest heading
|
||||
|
||||
*strong*
|
||||
_emphasis_
|
||||
{{monospaced}}
|
||||
-deleted-
|
||||
+inserted+
|
||||
^superscript^
|
||||
~subscript~
|
||||
|
||||
{code:javascript}
|
||||
var hello = 'world';
|
||||
{code}
|
||||
|
||||
!http://google.com/image!
|
||||
[!http://google.com/image!|http://google.com/link]
|
||||
|
||||
[http://google.com]
|
||||
[Google|http://google.com]
|
||||
|
||||
GitHub Flavor
|
||||
-deleted-
|
||||
|
||||
{code}
|
||||
preformatted piece of text
|
||||
so _no_ further _formatting_ is done here
|
||||
{code}
|
||||
|
||||
_*Should be bold AND italic*_
|
||||
|
||||
* First li
|
||||
* Second li
|
||||
** Indented li
|
||||
*** Three columns in li
|
||||
* Back to first level li
|
||||
|
||||
# First li
|
||||
# Second li
|
||||
## Indented li
|
||||
### Three columns in li
|
||||
# Back to first level li
|
||||
|
||||
* Here's _italic_ inside li
|
||||
* here's *bold* inside li
|
||||
* Here's _*bold + italic*_ inside li
|
||||
** Here they are in one line indented: _italic_ *bold*
|
||||
|
||||
bq. Here's a long single-paragraph block quote. It should look pretty and stuff.
|
||||
|
||||
{panel:title=A title}
|
||||
Panel text
|
||||
{panel}
|
||||
|
||||
||Heading 1||Heading 2||
|
||||
|Col A1|Col A2|
|
||||
|Col B1|Col B2|
|
68
vendor/github.com/StevenACoffman/j2m/j2m.md
generated
vendored
Normal file
68
vendor/github.com/StevenACoffman/j2m/j2m.md
generated
vendored
Normal file
|
@ -0,0 +1,68 @@
|
|||
# Biggest heading
|
||||
|
||||
## Bigger heading
|
||||
|
||||
# Biggest heading
|
||||
## Bigger heading
|
||||
### Big heading
|
||||
#### Normal heading
|
||||
##### Small heading
|
||||
###### Smallest heading
|
||||
|
||||
**strong**
|
||||
*emphasis*
|
||||
`monospaced`
|
||||
~~deleted~~
|
||||
<ins>inserted</ins>
|
||||
<sup>superscript</sup>
|
||||
<sub>subscript</sub>
|
||||
|
||||
```javascript
|
||||
var hello = 'world';
|
||||
```
|
||||
|
||||
![](http://google.com/image)
|
||||
[![](http://google.com/image)](http://google.com/link)
|
||||
|
||||
<http://google.com>
|
||||
[Google](http://google.com)
|
||||
|
||||
GitHub Flavor
|
||||
~~deleted~~
|
||||
|
||||
```
|
||||
preformatted piece of text
|
||||
so *no_ further _formatting* is done here
|
||||
```
|
||||
|
||||
***Should be bold AND italic***
|
||||
|
||||
* First li
|
||||
* Second li
|
||||
* Indented li
|
||||
* Three columns in li
|
||||
* Back to first level li
|
||||
|
||||
1. First li
|
||||
1. Second li
|
||||
1. Indented li
|
||||
1. Three columns in li
|
||||
1. Back to first level li
|
||||
|
||||
* Here's *italic* inside li
|
||||
* here's **bold** inside li
|
||||
* Here's ***bold + italic*** inside li
|
||||
* Here they are in one line indented: *italic* **bold**
|
||||
|
||||
> Here's a long single-paragraph block quote. It should look pretty and stuff.
|
||||
|
||||
|
||||
| A title |
|
||||
| --- |
|
||||
| Panel text |
|
||||
|
||||
|
||||
|Heading 1|Heading 2|
|
||||
| --- | --- |
|
||||
|Col A1|Col A2|
|
||||
|Col B1|Col B2|
|
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
|
@ -1,3 +1,5 @@
|
|||
# github.com/StevenACoffman/j2m v0.0.0-20190826163711-7d8d00c99217
|
||||
github.com/StevenACoffman/j2m
|
||||
# github.com/fatih/structs v1.1.0
|
||||
github.com/fatih/structs
|
||||
# github.com/golang/protobuf v1.3.2
|
||||
|
|
Loading…
Reference in a new issue