Skip to content

Commit

Permalink
feat: use SQL for database
Browse files Browse the repository at this point in the history
  • Loading branch information
moul committed Sep 22, 2018
1 parent 7a5e81e commit 8e63e7f
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 59 deletions.
38 changes: 13 additions & 25 deletions cmd_db.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,17 @@ package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"

"github.com/jinzhu/gorm"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/spf13/viper"
"go.uber.org/zap"
)

type dbOptions struct {
Path string `mapstructure:"db-path"`
Path string `mapstructure:"dbpath"`
Verbose bool
}

func (opts dbOptions) String() string {
Expand All @@ -23,7 +22,7 @@ func (opts dbOptions) String() string {
}

func dbSetupFlags(flags *pflag.FlagSet, opts *dbOptions) {
flags.StringVarP(&opts.Path, "db-path", "", "./depviz.db", "depviz database path")

viper.BindPFlags(flags)
}

Expand Down Expand Up @@ -51,10 +50,9 @@ func newDBDumpCommand() *cobra.Command {
}

func dbDump(opts *dbOptions) error {
logger().Debug("dbDump", zap.Stringer("opts", *opts))
issues, err := dbLoad(opts)
if err != nil {
return err
var issues IssueSlice
if err := db.Find(&issues).Error; err != nil {
return errors.Wrap(err, "failed to load issues")
}
out, err := json.MarshalIndent(issues, "", " ")
if err != nil {
Expand All @@ -64,21 +62,11 @@ func dbDump(opts *dbOptions) error {
return nil
}

func dbExists(opts *dbOptions) bool {
logger().Debug("dbExists", zap.Stringer("opts", *opts))
_, err := os.Stat(opts.Path)
return err == nil
}

func dbLoad(opts *dbOptions) (Issues, error) {
logger().Debug("dbLoad", zap.Stringer("opts", *opts))
var issues IssueSlice
content, err := ioutil.ReadFile(opts.Path)
if err != nil {
return nil, errors.Wrap(err, "failed to open db file")
}
if err := json.Unmarshal(content, &issues); err != nil {
return nil, errors.Wrap(err, "failed to parse db file")
func loadIssues(db *gorm.DB) (Issues, error) {
var issues []*Issue
if err := db.Find(&issues).Error; err != nil {
return nil, err
}
return issues.ToMap(), nil
slice := IssueSlice(issues)
return slice.ToMap(), nil
}
10 changes: 6 additions & 4 deletions cmd_pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@ import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"sync"

"github.com/google/go-github/github"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/spf13/viper"
Expand Down Expand Up @@ -160,6 +158,10 @@ func pull(opts *pullOptions) error {
allIssues = append(allIssues, issues...)
}

issuesJson, _ := json.MarshalIndent(allIssues, "", " ")
return errors.Wrap(ioutil.WriteFile(opts.DBOpts.Path, issuesJson, 0644), "failed to write db")
for _, issue := range allIssues {
if err := db.Save(issue).Error; err != nil {
return err
}
}
return nil
}
9 changes: 6 additions & 3 deletions cmd_run.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,18 +79,18 @@ func newRunCommand() *cobra.Command {

func run(opts *runOptions) error {
logger().Debug("run", zap.Stringer("opts", *opts))
if !opts.NoPull || !dbExists(&opts.DBOpts) {
if !opts.NoPull {
if err := pull(&opts.PullOpts); err != nil {
return err
}
}

issues, err := dbLoad(&opts.DBOpts)
issues, err := loadIssues(db)
if err != nil {
return errors.Wrap(err, "failed to load issues")
}

if err = issues.prepare(); err != nil {
if err := issues.prepare(); err != nil {
return errors.Wrap(err, "failed to prepare issues")
}

Expand All @@ -103,6 +103,9 @@ func run(opts *runOptions) error {
}

out, err := graphviz(issues, opts)
if err != nil {
return err
}

var dest io.WriteCloser
switch opts.Destination {
Expand Down
46 changes: 19 additions & 27 deletions issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,40 +28,41 @@ const (

type Issue struct {
// proxy
GitHub *github.Issue
GitLab *gitlab.Issue
GitHub *github.Issue `json:"-" gorm:"-"`
GitLab *gitlab.Issue `json:"-" gorm:"-"`

// internal
Provider Provider
DependsOn IssueSlice `json:"-"`
Blocks IssueSlice `json:"-"`
weightMultiplier int `json:"-"`
BaseWeight int `json:"-"`
IsOrphan bool `json:"-"`
Hidden bool `json:"-"`
Duplicates []string `json:"-"`
LinkedWithEpic bool `json:"-"`
Errors []error `json:"-"`
DependsOn IssueSlice `json:"-" gorm:"-"`
Blocks IssueSlice `json:"-" gorm:"-"`
weightMultiplier int `json:"-" gorm:"-"`
BaseWeight int `json:"-" gorm:"-"`
IsOrphan bool `json:"-" gorm:"-"`
Hidden bool `json:"-" gorm:"-"`
Duplicates []string `json:"-" gorm:"-"`
LinkedWithEpic bool `json:"-" gorm:"-"`
Errors []error `json:"-" gorm:"-"`

// mapping
Number int
Title string
State string
Body string
RepoURL string
URL string
Labels []*IssueLabel
Assignees []*Profile
URL string `gorm:"primary_key"`
Labels []*IssueLabel `gorm:"many2many:issue_labels;"`
Assignees []*Profile `gorm:"many2many:issue_assignees;"`
IsPR bool
}

type IssueLabel struct {
Name string
Name string `gorm:"primary_key"`
Color string
}

type Profile struct {
Name string
Username string
Username string `gorm:"primary_key"`
}

func FromGitHubIssue(input *github.Issue) *Issue {
Expand All @@ -77,6 +78,7 @@ func FromGitHubIssue(input *github.Issue) *Issue {
Title: *input.Title,
State: *input.State,
Body: body,
IsPR: input.PullRequestLinks != nil,
URL: strings.Replace(*input.HTMLURL, "/pull/", "/issues/", -1),
RepoURL: strings.Join(parts[0:len(parts)-2], "/"),
Labels: make([]*IssueLabel, 0),
Expand Down Expand Up @@ -450,24 +452,14 @@ func (issues Issues) prepare() error {
if len(issue.Duplicates) > 0 {
issue.Hidden = true
}
if issue.IsPR() {
if issue.IsPR {
issue.Hidden = true
}
}
issues.processEpicLinks()
return nil
}

func (i Issue) IsPR() bool {
switch i.Provider {
case GitHubProvider:
return i.GitHub.PullRequestLinks != nil
case GitLabProvider:
return false // only fetching issues for now
}
panic("should not happen")
}

func (issues Issues) processEpicLinks() {
for _, issue := range issues {
issue.LinkedWithEpic = !issue.Hidden && (issue.IsEpic() || issue.BlocksAnEpic() || issue.DependsOnAnEpic())
Expand Down
27 changes: 27 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"os"
"strings"

"github.com/jinzhu/gorm"
_ "github.com/mattn/go-sqlite3"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
Expand All @@ -24,6 +26,8 @@ func main() {
var (
verbose bool
cfgFile string
dbPath string
db *gorm.DB
)

func newRootCommand() *cobra.Command {
Expand All @@ -33,6 +37,8 @@ func newRootCommand() *cobra.Command {
cmd.PersistentFlags().BoolP("help", "h", false, "print usage")
cmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "verbose mode")
cmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "config file (default is ./.depviz.yml)")
cmd.PersistentFlags().StringVarP(&dbPath, "db-path", "", "$HOME/.depviz.db", "database path")

cmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
// configure zap
config := zap.NewDevelopmentConfig()
Expand Down Expand Up @@ -61,6 +67,27 @@ func newRootCommand() *cobra.Command {
return errors.Wrap(err, "cannot read config")
}
}

// configure sql
dbPath = os.ExpandEnv(dbPath)
db, err = gorm.Open("sqlite3", dbPath)
if err != nil {
return err
}
db = db.Set("gorm:auto_preload", true)
db = db.Set("gorm:association_autoupdate", true)
db.BlockGlobalUpdate(true)
db.SingularTable(true)
db.LogMode(verbose)
if err := db.AutoMigrate(
Issue{},
IssueLabel{},
Profile{},
).Error; err != nil {
return err
}
fmt.Println(dbPath, db)

return nil
}
cmd.AddCommand(
Expand Down

0 comments on commit 8e63e7f

Please sign in to comment.