aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Muré <batolettre@gmail.com>2018-08-02 23:37:49 +0200
committerMichael Muré <batolettre@gmail.com>2018-08-02 23:37:49 +0200
commitd8f89726fec3822d7d1dd42c52f478f37003b534 (patch)
tree567e97ee605ef3a286e42e11535fa6516321e743
parented8f7eca9a8e0d1c448a7cc6240e2b7e357cf354 (diff)
downloadgit-bug-d8f89726fec3822d7d1dd42c52f478f37003b534.tar.gz
implement media hosting in git for comments + API for the webui
-rw-r--r--bug/bug.go25
-rw-r--r--bug/comment.go2
-rw-r--r--bug/label.go2
-rw-r--r--bug/operation.go6
-rw-r--r--bug/operations/add_comment.go16
-rw-r--r--bug/operations/create.go15
-rw-r--r--bug/operations/label_change.go5
-rw-r--r--bug/operations/set_status.go5
-rw-r--r--bug/operations/set_title.go5
-rw-r--r--cache/cache.go15
-rw-r--r--commands/webui.go16
-rw-r--r--graphql/gqlgen.yml2
-rw-r--r--graphql/graph/gen_graph.go135
-rw-r--r--graphql/resolvers/mutation.go9
-rw-r--r--graphql/schema.graphql10
-rw-r--r--termui/show_bug.go2
-rw-r--r--util/hash.go40
17 files changed, 265 insertions, 45 deletions
diff --git a/bug/bug.go b/bug/bug.go
index d3cc41dd..61f58c78 100644
--- a/bug/bug.go
+++ b/bug/bug.go
@@ -259,7 +259,7 @@ func (bug *Bug) Append(op Operation) {
// Write the staging area in Git and move the operations to the packs
func (bug *Bug) Commit(repo repository.Repo) error {
if bug.staging.IsEmpty() {
- return fmt.Errorf("can't commit an empty bug")
+ return fmt.Errorf("can't commit a bug with no pending operation")
}
// Write the Ops as a Git blob containing the serialized array
@@ -272,14 +272,31 @@ func (bug *Bug) Commit(repo repository.Repo) error {
bug.rootPack = hash
}
- // Write a Git tree referencing this blob
- hash, err = repo.StoreTree([]repository.TreeEntry{
+ // Make a Git tree referencing this blob and all needed files
+ tree := []repository.TreeEntry{
// the last pack of ops
{ObjectType: repository.Blob, Hash: hash, Name: opsEntryName},
// always the first pack of ops (might be the same)
{ObjectType: repository.Blob, Hash: bug.rootPack, Name: rootEntryName},
- })
+ }
+
+ counter := 0
+ added := make(map[util.Hash]interface{})
+ for _, ops := range bug.staging.Operations {
+ for _, file := range ops.Files() {
+ if _, has := added[file]; !has {
+ tree = append(tree, repository.TreeEntry{
+ ObjectType: repository.Blob,
+ Hash: file,
+ Name: fmt.Sprintf("file%d", counter),
+ })
+ counter++
+ added[file] = struct{}{}
+ }
+ }
+ }
+ hash, err = repo.StoreTree(tree)
if err != nil {
return err
}
diff --git a/bug/comment.go b/bug/comment.go
index c0c07076..0b4fd6ad 100644
--- a/bug/comment.go
+++ b/bug/comment.go
@@ -1,6 +1,7 @@
package bug
import (
+ "github.com/MichaelMure/git-bug/util"
"github.com/dustin/go-humanize"
"time"
)
@@ -8,6 +9,7 @@ import (
type Comment struct {
Author Person
Message string
+ Files []util.Hash
// Creation time of the comment.
// Should be used only for human display, never for ordering as we can't rely on it in a distributed system.
diff --git a/bug/label.go b/bug/label.go
index ccfa15f4..b19a980f 100644
--- a/bug/label.go
+++ b/bug/label.go
@@ -11,7 +11,7 @@ func (l Label) String() string {
return string(l)
}
-// UnmarshalGQL implements the graphql.Marshaler interface
+// UnmarshalGQL implements the graphql.Unmarshaler interface
func (l *Label) UnmarshalGQL(v interface{}) error {
_, ok := v.(string)
if !ok {
diff --git a/bug/operation.go b/bug/operation.go
index 74be2fac..736c88dd 100644
--- a/bug/operation.go
+++ b/bug/operation.go
@@ -1,6 +1,9 @@
package bug
-import "time"
+import (
+ "github.com/MichaelMure/git-bug/util"
+ "time"
+)
type OperationType int
@@ -17,6 +20,7 @@ type Operation interface {
OpType() OperationType
Time() time.Time
Apply(snapshot Snapshot) Snapshot
+ Files() []util.Hash
// TODO: data validation (ex: a title is a single line)
// Validate() bool
diff --git a/bug/operations/add_comment.go b/bug/operations/add_comment.go
index f35c572b..f2e76b73 100644
--- a/bug/operations/add_comment.go
+++ b/bug/operations/add_comment.go
@@ -2,6 +2,7 @@ package operations
import (
"github.com/MichaelMure/git-bug/bug"
+ "github.com/MichaelMure/git-bug/util"
)
// AddCommentOperation will add a new comment in the bug
@@ -11,12 +12,14 @@ var _ bug.Operation = AddCommentOperation{}
type AddCommentOperation struct {
bug.OpBase
Message string
+ files []util.Hash
}
func (op AddCommentOperation) Apply(snapshot bug.Snapshot) bug.Snapshot {
comment := bug.Comment{
Message: op.Message,
Author: op.Author,
+ Files: op.files,
UnixTime: op.UnixTime,
}
@@ -25,15 +28,24 @@ func (op AddCommentOperation) Apply(snapshot bug.Snapshot) bug.Snapshot {
return snapshot
}
-func NewAddCommentOp(author bug.Person, message string) AddCommentOperation {
+func (op AddCommentOperation) Files() []util.Hash {
+ return op.files
+}
+
+func NewAddCommentOp(author bug.Person, message string, files []util.Hash) AddCommentOperation {
return AddCommentOperation{
OpBase: bug.NewOpBase(bug.AddCommentOp, author),
Message: message,
+ files: files,
}
}
// Convenience function to apply the operation
func Comment(b *bug.Bug, author bug.Person, message string) {
- addCommentOp := NewAddCommentOp(author, message)
+ CommentWithFiles(b, author, message, nil)
+}
+
+func CommentWithFiles(b *bug.Bug, author bug.Person, message string, files []util.Hash) {
+ addCommentOp := NewAddCommentOp(author, message, files)
b.Append(addCommentOp)
}
diff --git a/bug/operations/create.go b/bug/operations/create.go
index 0ee7e857..ecbafb6f 100644
--- a/bug/operations/create.go
+++ b/bug/operations/create.go
@@ -2,6 +2,7 @@ package operations
import (
"github.com/MichaelMure/git-bug/bug"
+ "github.com/MichaelMure/git-bug/util"
)
// CreateOperation define the initial creation of a bug
@@ -12,6 +13,7 @@ type CreateOperation struct {
bug.OpBase
Title string
Message string
+ files []util.Hash
}
func (op CreateOperation) Apply(snapshot bug.Snapshot) bug.Snapshot {
@@ -28,18 +30,27 @@ func (op CreateOperation) Apply(snapshot bug.Snapshot) bug.Snapshot {
return snapshot
}
-func NewCreateOp(author bug.Person, title, message string) CreateOperation {
+func (op CreateOperation) Files() []util.Hash {
+ return op.files
+}
+
+func NewCreateOp(author bug.Person, title, message string, files []util.Hash) CreateOperation {
return CreateOperation{
OpBase: bug.NewOpBase(bug.CreateOp, author),
Title: title,
Message: message,
+ files: files,
}
}
// Convenience function to apply the operation
func Create(author bug.Person, title, message string) (*bug.Bug, error) {
+ return CreateWithFiles(author, title, message, nil)
+}
+
+func CreateWithFiles(author bug.Person, title, message string, files []util.Hash) (*bug.Bug, error) {
newBug := bug.NewBug()
- createOp := NewCreateOp(author, title, message)
+ createOp := NewCreateOp(author, title, message, files)
newBug.Append(createOp)
return newBug, nil
diff --git a/bug/operations/label_change.go b/bug/operations/label_change.go
index a711faef..f289fedc 100644
--- a/bug/operations/label_change.go
+++ b/bug/operations/label_change.go
@@ -3,6 +3,7 @@ package operations
import (
"fmt"
"github.com/MichaelMure/git-bug/bug"
+ "github.com/MichaelMure/git-bug/util"
"io"
"io/ioutil"
"sort"
@@ -50,6 +51,10 @@ AddLoop:
return snapshot
}
+func (op LabelChangeOperation) Files() []util.Hash {
+ return nil
+}
+
func NewLabelChangeOperation(author bug.Person, added, removed []bug.Label) LabelChangeOperation {
return LabelChangeOperation{
OpBase: bug.NewOpBase(bug.LabelChangeOp, author),
diff --git a/bug/operations/set_status.go b/bug/operations/set_status.go
index ed6c328c..87ca14bf 100644
--- a/bug/operations/set_status.go
+++ b/bug/operations/set_status.go
@@ -2,6 +2,7 @@ package operations
import (
"github.com/MichaelMure/git-bug/bug"
+ "github.com/MichaelMure/git-bug/util"
)
// SetStatusOperation will change the status of a bug
@@ -19,6 +20,10 @@ func (op SetStatusOperation) Apply(snapshot bug.Snapshot) bug.Snapshot {
return snapshot
}
+func (op SetStatusOperation) Files() []util.Hash {
+ return nil
+}
+
func NewSetStatusOp(author bug.Person, status bug.Status) SetStatusOperation {
return SetStatusOperation{
OpBase: bug.NewOpBase(bug.SetStatusOp, author),
diff --git a/bug/operations/set_title.go b/bug/operations/set_title.go
index fab01d8a..d6186f41 100644
--- a/bug/operations/set_title.go
+++ b/bug/operations/set_title.go
@@ -2,6 +2,7 @@ package operations
import (
"github.com/MichaelMure/git-bug/bug"
+ "github.com/MichaelMure/git-bug/util"
)
// SetTitleOperation will change the title of a bug
@@ -19,6 +20,10 @@ func (op SetTitleOperation) Apply(snapshot bug.Snapshot) bug.Snapshot {
return snapshot
}
+func (op SetTitleOperation) Files() []util.Hash {
+ return nil
+}
+
func NewSetTitleOp(author bug.Person, title string) SetTitleOperation {
return SetTitleOperation{
OpBase: bug.NewOpBase(bug.SetTitleOp, author),
diff --git a/cache/cache.go b/cache/cache.go
index d2595723..b6f47c6d 100644
--- a/cache/cache.go
+++ b/cache/cache.go
@@ -7,6 +7,7 @@ import (
"github.com/MichaelMure/git-bug/bug"
"github.com/MichaelMure/git-bug/bug/operations"
"github.com/MichaelMure/git-bug/repository"
+ "github.com/MichaelMure/git-bug/util"
)
type Cacher interface {
@@ -26,6 +27,7 @@ type RepoCacher interface {
// Mutations
NewBug(title string, message string) (BugCacher, error)
+ NewBugWithFiles(title string, message string, files []util.Hash) (BugCacher, error)
}
type BugCacher interface {
@@ -34,6 +36,7 @@ type BugCacher interface {
// Mutations
AddComment(message string) error
+ AddCommentWithFiles(message string, files []util.Hash) error
ChangeLabels(added []string, removed []string) error
Open() error
Close() error
@@ -159,12 +162,16 @@ func (c *RepoCache) ClearAllBugs() {
}
func (c *RepoCache) NewBug(title string, message string) (BugCacher, error) {
+ return c.NewBugWithFiles(title, message, nil)
+}
+
+func (c *RepoCache) NewBugWithFiles(title string, message string, files []util.Hash) (BugCacher, error) {
author, err := bug.GetUser(c.repo)
if err != nil {
return nil, err
}
- b, err := operations.Create(author, title, message)
+ b, err := operations.CreateWithFiles(author, title, message, files)
if err != nil {
return nil, err
}
@@ -208,12 +215,16 @@ func (c *BugCache) ClearSnapshot() {
}
func (c *BugCache) AddComment(message string) error {
+ return c.AddCommentWithFiles(message, nil)
+}
+
+func (c *BugCache) AddCommentWithFiles(message string, files []util.Hash) error {
author, err := bug.GetUser(c.repo)
if err != nil {
return err
}
- operations.Comment(c.bug, author, message)
+ operations.CommentWithFiles(c.bug, author, message, files)
// TODO: perf --> the snapshot could simply be updated with the new op
c.ClearSnapshot()
diff --git a/commands/webui.go b/commands/webui.go
index d5560180..0389d68b 100644
--- a/commands/webui.go
+++ b/commands/webui.go
@@ -64,9 +64,9 @@ func newGitFileHandler(repo repository.Repo) http.Handler {
}
func (gfh *gitFileHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
- hash := mux.Vars(r)["hash"]
+ hash := util.Hash(mux.Vars(r)["hash"])
- if !isGitHash(hash) {
+ if !hash.IsValid() {
http.Error(rw, "invalid git hash", http.StatusBadRequest)
return
}
@@ -144,18 +144,6 @@ func (gufh *gitUploadFileHandler) ServeHTTP(rw http.ResponseWriter, r *http.Requ
rw.Write(js)
}
-func isGitHash(s string) bool {
- if len(s) != 40 {
- return false
- }
- for _, r := range s {
- if (r < 'a' || r > 'z') && (r < '0' || r > '9') {
- return false
- }
- }
- return true
-}
-
var webUICmd = &cobra.Command{
Use: "webui",
Short: "Launch the web UI",
diff --git a/graphql/gqlgen.yml b/graphql/gqlgen.yml
index 51c53b62..9be33ef7 100644
--- a/graphql/gqlgen.yml
+++ b/graphql/gqlgen.yml
@@ -17,6 +17,8 @@ models:
model: github.com/MichaelMure/git-bug/bug.Person
Label:
model: github.com/MichaelMure/git-bug/bug.Label
+ Hash:
+ model: github.com/MichaelMure/git-bug/util.Hash
Operation:
model: github.com/MichaelMure/git-bug/bug.Operation
CreateOperation:
diff --git a/graphql/graph/gen_graph.go b/graphql/graph/gen_graph.go
index 63a0c9b5..a9c40e1f 100644
--- a/graphql/graph/gen_graph.go
+++ b/graphql/graph/gen_graph.go
@@ -12,6 +12,7 @@ import (
bug "github.com/MichaelMure/git-bug/bug"
operations "github.com/MichaelMure/git-bug/bug/operations"
models "github.com/MichaelMure/git-bug/graphql/models"
+ util "github.com/MichaelMure/git-bug/util"
graphql "github.com/vektah/gqlgen/graphql"
introspection "github.com/vektah/gqlgen/neelance/introspection"
query "github.com/vektah/gqlgen/neelance/query"
@@ -40,8 +41,8 @@ type Resolvers interface {
LabelChangeOperation_date(ctx context.Context, obj *operations.LabelChangeOperation) (time.Time, error)
- Mutation_newBug(ctx context.Context, repoRef *string, title string, message string) (bug.Snapshot, error)
- Mutation_addComment(ctx context.Context, repoRef *string, prefix string, message string) (bug.Snapshot, error)
+ Mutation_newBug(ctx context.Context, repoRef *string, title string, message string, files []util.Hash) (bug.Snapshot, error)
+ Mutation_addComment(ctx context.Context, repoRef *string, prefix string, message string, files []util.Hash) (bug.Snapshot, error)
Mutation_changeLabels(ctx context.Context, repoRef *string, prefix string, added []string, removed []string) (bug.Snapshot, error)
Mutation_open(ctx context.Context, repoRef *string, prefix string) (bug.Snapshot, error)
Mutation_close(ctx context.Context, repoRef *string, prefix string) (bug.Snapshot, error)
@@ -87,8 +88,8 @@ type LabelChangeOperationResolver interface {
Date(ctx context.Context, obj *operations.LabelChangeOperation) (time.Time, error)
}
type MutationResolver interface {
- NewBug(ctx context.Context, repoRef *string, title string, message string) (bug.Snapshot, error)
- AddComment(ctx context.Context, repoRef *string, prefix string, message string) (bug.Snapshot, error)
+ NewBug(ctx context.Context, repoRef *string, title string, message string, files []util.Hash) (bug.Snapshot, error)
+ AddComment(ctx context.Context, repoRef *string, prefix string, message string, files []util.Hash) (bug.Snapshot, error)
ChangeLabels(ctx context.Context, repoRef *string, prefix string, added []string, removed []string) (bug.Snapshot, error)
Open(ctx context.Context, repoRef *string, prefix string) (bug.Snapshot, error)
Close(ctx context.Context, repoRef *string, prefix string) (bug.Snapshot, error)
@@ -139,12 +140,12 @@ func (s shortMapper) LabelChangeOperation_date(ctx context.Context, obj *operati
return s.r.LabelChangeOperation().Date(ctx, obj)
}
-func (s shortMapper) Mutation_newBug(ctx context.Context, repoRef *string, title string, message string) (bug.Snapshot, error) {
- return s.r.Mutation().NewBug(ctx, repoRef, title, message)
+func (s shortMapper) Mutation_newBug(ctx context.Context, repoRef *string, title string, message string, files []util.Hash) (bug.Snapshot, error) {
+ return s.r.Mutation().NewBug(ctx, repoRef, title, message, files)
}
-func (s shortMapper) Mutation_addComment(ctx context.Context, repoRef *string, prefix string, message string) (bug.Snapshot, error) {
- return s.r.Mutation().AddComment(ctx, repoRef, prefix, message)
+func (s shortMapper) Mutation_addComment(ctx context.Context, repoRef *string, prefix string, message string, files []util.Hash) (bug.Snapshot, error) {
+ return s.r.Mutation().AddComment(ctx, repoRef, prefix, message, files)
}
func (s shortMapper) Mutation_changeLabels(ctx context.Context, repoRef *string, prefix string, added []string, removed []string) (bug.Snapshot, error) {
@@ -264,6 +265,8 @@ func (ec *executionContext) _AddCommentOperation(ctx context.Context, sel []quer
out.Values[i] = ec._AddCommentOperation_date(ctx, field, obj)
case "message":
out.Values[i] = ec._AddCommentOperation_message(ctx, field, obj)
+ case "files":
+ out.Values[i] = ec._AddCommentOperation_files(ctx, field, obj)
default:
panic("unknown field " + strconv.Quote(field.Name))
}
@@ -324,6 +327,26 @@ func (ec *executionContext) _AddCommentOperation_message(ctx context.Context, fi
return graphql.MarshalString(res)
}
+func (ec *executionContext) _AddCommentOperation_files(ctx context.Context, field graphql.CollectedField, obj *operations.AddCommentOperation) graphql.Marshaler {
+ rctx := graphql.GetResolverContext(ctx)
+ rctx.Object = "AddCommentOperation"
+ rctx.Args = nil
+ rctx.Field = field
+ rctx.PushField(field.Alias)
+ defer rctx.Pop()
+ res := obj.Files()
+ arr1 := graphql.Array{}
+ for idx1 := range res {
+ arr1 = append(arr1, func() graphql.Marshaler {
+ rctx := graphql.GetResolverContext(ctx)
+ rctx.PushIndex(idx1)
+ defer rctx.Pop()
+ return res[idx1]
+ }())
+ }
+ return arr1
+}
+
var bugImplementors = []string{"Bug"}
// nolint: gocyclo, errcheck, gas, goconst
@@ -818,6 +841,8 @@ func (ec *executionContext) _Comment(ctx context.Context, sel []query.Selection,
out.Values[i] = ec._Comment_author(ctx, field, obj)
case "message":
out.Values[i] = ec._Comment_message(ctx, field, obj)
+ case "files":
+ out.Values[i] = ec._Comment_files(ctx, field, obj)
default:
panic("unknown field " + strconv.Quote(field.Name))
}
@@ -848,6 +873,26 @@ func (ec *executionContext) _Comment_message(ctx context.Context, field graphql.
return graphql.MarshalString(res)
}
+func (ec *executionContext) _Comment_files(ctx context.Context, field graphql.CollectedField, obj *bug.Comment) graphql.Marshaler {
+ rctx := graphql.GetResolverContext(ctx)
+ rctx.Object = "Comment"
+ rctx.Args = nil
+ rctx.Field = field
+ rctx.PushField(field.Alias)
+ defer rctx.Pop()
+ res := obj.Files
+ arr1 := graphql.Array{}
+ for idx1 := range res {
+ arr1 = append(arr1, func() graphql.Marshaler {
+ rctx := graphql.GetResolverContext(ctx)
+ rctx.PushIndex(idx1)
+ defer rctx.Pop()
+ return res[idx1]
+ }())
+ }
+ return arr1
+}
+
var commentConnectionImplementors = []string{"CommentConnection"}
// nolint: gocyclo, errcheck, gas, goconst
@@ -1007,6 +1052,8 @@ func (ec *executionContext) _CreateOperation(ctx context.Context, sel []query.Se
out.Values[i] = ec._CreateOperation_title(ctx, field, obj)
case "message":
out.Values[i] = ec._CreateOperation_message(ctx, field, obj)
+ case "files":
+ out.Values[i] = ec._CreateOperation_files(ctx, field, obj)
default:
panic("unknown field " + strconv.Quote(field.Name))
}
@@ -1078,6 +1125,26 @@ func (ec *executionContext) _CreateOperation_message(ctx context.Context, field
return graphql.MarshalString(res)
}
+func (ec *executionContext) _CreateOperation_files(ctx context.Context, field graphql.CollectedField, obj *operations.CreateOperation) graphql.Marshaler {
+ rctx := graphql.GetResolverContext(ctx)
+ rctx.Object = "CreateOperation"
+ rctx.Args = nil
+ rctx.Field = field
+ rctx.PushField(field.Alias)
+ defer rctx.Pop()
+ res := obj.Files()
+ arr1 := graphql.Array{}
+ for idx1 := range res {
+ arr1 = append(arr1, func() graphql.Marshaler {
+ rctx := graphql.GetResolverContext(ctx)
+ rctx.PushIndex(idx1)
+ defer rctx.Pop()
+ return res[idx1]
+ }())
+ }
+ return arr1
+}
+
var labelChangeOperationImplementors = []string{"LabelChangeOperation", "Operation", "Authored"}
// nolint: gocyclo, errcheck, gas, goconst
@@ -1264,6 +1331,25 @@ func (ec *executionContext) _Mutation_newBug(ctx context.Context, field graphql.
}
}
args["message"] = arg2
+ var arg3 []util.Hash
+ if tmp, ok := field.Args["files"]; ok {
+ var err error
+ var rawIf1 []interface{}
+ if tmp != nil {
+ if tmp1, ok := tmp.([]interface{}); ok {
+ rawIf1 = tmp1
+ }
+ }
+ arg3 = make([]util.Hash, len(rawIf1))
+ for idx1 := range rawIf1 {
+ err = (&arg3[idx1]).UnmarshalGQL(rawIf1[idx1])
+ }
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ }
+ args["files"] = arg3
rctx := graphql.GetResolverContext(ctx)
rctx.Object = "Mutation"
rctx.Args = args
@@ -1271,7 +1357,7 @@ func (ec *executionContext) _Mutation_newBug(ctx context.Context, field graphql.
rctx.PushField(field.Alias)
defer rctx.Pop()
resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) {
- return ec.resolvers.Mutation_newBug(ctx, args["repoRef"].(*string), args["title"].(string), args["message"].(string))
+ return ec.resolvers.Mutation_newBug(ctx, args["repoRef"].(*string), args["title"].(string), args["message"].(string), args["files"].([]util.Hash))
})
if err != nil {
ec.Error(ctx, err)
@@ -1321,6 +1407,25 @@ func (ec *executionContext) _Mutation_addComment(ctx context.Context, field grap
}
}
args["message"] = arg2
+ var arg3 []util.Hash
+ if tmp, ok := field.Args["files"]; ok {
+ var err error
+ var rawIf1 []interface{}
+ if tmp != nil {
+ if tmp1, ok := tmp.([]interface{}); ok {
+ rawIf1 = tmp1
+ }
+ }
+ arg3 = make([]util.Hash, len(rawIf1))
+ for idx1 := range rawIf1 {
+ err = (&arg3[idx1]).UnmarshalGQL(rawIf1[idx1])
+ }
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ }
+ args["files"] = arg3
rctx := graphql.GetResolverContext(ctx)
rctx.Object = "Mutation"
rctx.Args = args
@@ -1328,7 +1433,7 @@ func (ec *executionContext) _Mutation_addComment(ctx context.Context, field grap
rctx.PushField(field.Alias)
defer rctx.Pop()
resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) {
- return ec.resolvers.Mutation_addComment(ctx, args["repoRef"].(*string), args["prefix"].(string), args["message"].(string))
+ return ec.resolvers.Mutation_addComment(ctx, args["repoRef"].(*string), args["prefix"].(string), args["message"].(string), args["files"].([]util.Hash))
})
if err != nil {
ec.Error(ctx, err)
@@ -3108,6 +3213,7 @@ func (ec *executionContext) introspectType(name string) *introspection.Type {
var parsedSchema = schema.MustParse(`scalar Time
scalar Label
+scalar Hash
# Information about pagination in a connection.
type PageInfo {
@@ -3149,6 +3255,9 @@ type Comment implements Authored {
# The message of this comment.
message: String!
+
+ # All media's hash referenced in this comment
+ files: [Hash!]!
}
enum Status {
@@ -3188,6 +3297,7 @@ type CreateOperation implements Operation, Authored {
title: String!
message: String!
+ files: [Hash!]!
}
type SetTitleOperation implements Operation, Authored {
@@ -3202,6 +3312,7 @@ type AddCommentOperation implements Operation, Authored {
date: Time!
message: String!
+ files: [Hash!]!
}
type SetStatusOperation implements Operation, Authored {
@@ -3291,9 +3402,9 @@ type Query {
}
type Mutation {
- newBug(repoRef: String, title: String!, message: String!): Bug!
+ newBug(repoRef: String, title: String!, message: String!, files: [Hash!]): Bug!
- addComment(repoRef: String, prefix: String!, message: String!): Bug!
+ addComment(repoRef: String, prefix: String!, message: String!, files: [Hash!]): Bug!
changeLabels(repoRef: String, prefix: String!, added: [String!], removed: [String!]): Bug!
open(repoRef: String, prefix: String!): Bug!
close(repoRef: String, prefix: String!): Bug!
diff --git a/graphql/resolvers/mutation.go b/graphql/resolvers/mutation.go
index a85459f2..2a81716c 100644
--- a/graphql/resolvers/mutation.go
+++ b/graphql/resolvers/mutation.go
@@ -5,6 +5,7 @@ import (
"github.com/MichaelMure/git-bug/bug"
"github.com/MichaelMure/git-bug/cache"
+ "github.com/MichaelMure/git-bug/util"
)
type mutationResolver struct {
@@ -19,13 +20,13 @@ func (r mutationResolver) getRepo(repoRef *string) (cache.RepoCacher, error) {
return r.cache.DefaultRepo()
}
-func (r mutationResolver) NewBug(ctx context.Context, repoRef *string, title string, message string) (bug.Snapshot, error) {
+func (r mutationResolver) NewBug(ctx context.Context, repoRef *string, title string, message string, files []util.Hash) (bug.Snapshot, error) {
repo, err := r.getRepo(repoRef)
if err != nil {
return bug.Snapshot{}, err
}
- b, err := repo.NewBug(title, message)
+ b, err := repo.NewBugWithFiles(title, message, files)
if err != nil {
return bug.Snapshot{}, err
}
@@ -56,7 +57,7 @@ func (r mutationResolver) Commit(ctx context.Context, repoRef *string, prefix st
return *snap, nil
}
-func (r mutationResolver) AddComment(ctx context.Context, repoRef *string, prefix string, message string) (bug.Snapshot, error) {
+func (r mutationResolver) AddComment(ctx context.Context, repoRef *string, prefix string, message string, files []util.Hash) (bug.Snapshot, error) {
repo, err := r.getRepo(repoRef)
if err != nil {
return bug.Snapshot{}, err
@@ -67,7 +68,7 @@ func (r mutationResolver) AddComment(ctx context.Context, repoRef *string, prefi
return bug.Snapshot{}, err
}
- err = b.AddComment(message)
+ err = b.AddCommentWithFiles(message, files)
if err != nil {
return bug.Snapshot{}, err
}
diff --git a/graphql/schema.graphql b/graphql/schema.graphql
index 410ecde9..d4364262 100644
--- a/graphql/schema.graphql
+++ b/graphql/schema.graphql
@@ -1,5 +1,6 @@
scalar Time
scalar Label
+scalar Hash
# Information about pagination in a connection.
type PageInfo {
@@ -41,6 +42,9 @@ type Comment implements Authored {
# The message of this comment.
message: String!
+
+ # All media's hash referenced in this comment
+ files: [Hash!]!
}
enum Status {
@@ -80,6 +84,7 @@ type CreateOperation implements Operation, Authored {
title: String!
message: String!
+ files: [Hash!]!
}
type SetTitleOperation implements Operation, Authored {
@@ -94,6 +99,7 @@ type AddCommentOperation implements Operation, Authored {
date: Time!
message: String!
+ files: [Hash!]!
}
type SetStatusOperation implements Operation, Authored {
@@ -183,9 +189,9 @@ type Query {
}
type Mutation {
- newBug(repoRef: String, title: String!, message: String!): Bug!
+ newBug(repoRef: String, title: String!, message: String!, files: [Hash!]): Bug!
- addComment(repoRef: String, prefix: String!, message: String!): Bug!
+ addComment(repoRef: String, prefix: String!, message: String!, files: [Hash!]): Bug!
changeLabels(repoRef: String, prefix: String!, added: [String!], removed: [String!]): Bug!
open(repoRef: String, prefix: String!): Bug!
close(repoRef: String, prefix: String!): Bug!
diff --git a/termui/show_bug.go b/termui/show_bug.go
index 34c7a922..ad700f6a 100644
--- a/termui/show_bug.go
+++ b/termui/show_bug.go
@@ -64,7 +64,7 @@ func (sb *showBug) layout(g *gocui.Gui) error {
v.Frame = false
v.BgColor = gocui.ColorBlue
- fmt.Fprintf(v, "[q] Return [c] Add comment [t] Change title")
+ fmt.Fprintf(v, "[q] Return [c] Comment [t] Change title")
}
_, err = g.SetCurrentView(showBugView)
diff --git a/util/hash.go b/util/hash.go
index 088fd70e..df0a83b8 100644
--- a/util/hash.go
+++ b/util/hash.go
@@ -1,3 +1,43 @@
package util
+import (
+ "fmt"
+ "io"
+)
+
type Hash string
+
+func (h Hash) String() string {
+ return string(h)
+}
+
+func (h *Hash) UnmarshalGQL(v interface{}) error {
+ _, ok := v.(string)
+ if !ok {
+ return fmt.Errorf("labels must be strings")
+ }
+
+ *h = v.(Hash)
+
+ if !h.IsValid() {
+ return fmt.Errorf("invalid hash")
+ }
+
+ return nil
+}
+
+func (h Hash) MarshalGQL(w io.Writer) {
+ w.Write([]byte(`"` + h.String() + `"`))
+}
+
+func (h *Hash) IsValid() bool {
+ if len(*h) != 40 {
+ return false
+ }
+ for _, r := range *h {
+ if (r < 'a' || r > 'z') && (r < '0' || r > '9') {
+ return false
+ }
+ }
+ return true
+}