1package random_bugs
  2
  3import (
  4	"math/rand"
  5	"strings"
  6	"time"
  7
  8	"github.com/icrowley/fake"
  9
 10	"github.com/MichaelMure/git-bug/entities/bug"
 11	"github.com/MichaelMure/git-bug/entities/identity"
 12	"github.com/MichaelMure/git-bug/repository"
 13)
 14
 15type opsGenerator func(bug.Interface, identity.Interface, int64)
 16
 17type Options struct {
 18	BugNumber    int
 19	PersonNumber int
 20	MinOp        int
 21	MaxOp        int
 22}
 23
 24func DefaultOptions() Options {
 25	return Options{
 26		BugNumber:    15,
 27		PersonNumber: 5,
 28		MinOp:        3,
 29		MaxOp:        20,
 30	}
 31}
 32
 33func FillRepo(repo repository.ClockedRepo, bugNumber int) {
 34	FillRepoWithSeed(repo, bugNumber, time.Now().UnixNano())
 35}
 36
 37func FillRepoWithSeed(repo repository.ClockedRepo, bugNumber int, seed int64) {
 38	options := DefaultOptions()
 39	options.BugNumber = bugNumber
 40
 41	CommitRandomBugsWithSeed(repo, options, seed)
 42}
 43
 44func CommitRandomBugs(repo repository.ClockedRepo, opts Options) {
 45	CommitRandomBugsWithSeed(repo, opts, time.Now().UnixNano())
 46}
 47
 48func CommitRandomBugsWithSeed(repo repository.ClockedRepo, opts Options, seed int64) {
 49	generateRandomPersons(repo, opts.PersonNumber)
 50
 51	bugs := generateRandomBugsWithSeed(opts, seed)
 52
 53	for _, b := range bugs {
 54		err := b.Commit(repo)
 55		if err != nil {
 56			panic(err)
 57		}
 58	}
 59}
 60
 61func generateRandomBugsWithSeed(opts Options, seed int64) []*bug.Bug {
 62	rand.Seed(seed)
 63	fake.Seed(seed)
 64
 65	// At the moment git-bug has a risk of hash collision is simple
 66	// operation (like open/close) are made with the same timestamp.
 67	// As a temporary workaround, we use here an strictly increasing
 68	// timestamp
 69	timestamp := time.Now().Unix()
 70
 71	opsGenerators := []opsGenerator{
 72		comment,
 73		comment,
 74		title,
 75		labels,
 76		open,
 77		close,
 78	}
 79
 80	result := make([]*bug.Bug, opts.BugNumber)
 81
 82	for i := 0; i < opts.BugNumber; i++ {
 83		addedLabels = []string{}
 84
 85		b, _, err := bug.Create(
 86			randomPerson(),
 87			time.Now().Unix(),
 88			fake.Sentence(),
 89			paragraphs(),
 90			nil, nil,
 91		)
 92
 93		if err != nil {
 94			panic(err)
 95		}
 96
 97		nOps := opts.MinOp
 98
 99		if opts.MaxOp > opts.MinOp {
100			nOps += rand.Intn(opts.MaxOp - opts.MinOp)
101		}
102
103		for j := 0; j < nOps; j++ {
104			index := rand.Intn(len(opsGenerators))
105			opsGenerators[index](b, randomPerson(), timestamp)
106			timestamp++
107		}
108
109		result[i] = b
110	}
111
112	return result
113}
114
115func person(repo repository.RepoClock) (*identity.Identity, error) {
116	return identity.NewIdentity(repo, fake.FullName(), fake.EmailAddress())
117}
118
119var persons []*identity.Identity
120
121func generateRandomPersons(repo repository.ClockedRepo, n int) {
122	persons = make([]*identity.Identity, n)
123	for i := range persons {
124		p, err := person(repo)
125		if err != nil {
126			panic(err)
127		}
128		err = p.Commit(repo)
129		if err != nil {
130			panic(err)
131		}
132		persons[i] = p
133	}
134}
135
136func randomPerson() identity.Interface {
137	index := rand.Intn(len(persons))
138	return persons[index]
139}
140
141func paragraphs() string {
142	p := fake.Paragraphs()
143	return strings.Replace(p, "\t", "\n\n", -1)
144}
145
146func comment(b bug.Interface, p identity.Interface, timestamp int64) {
147	_, _ = bug.AddComment(b, p, timestamp, paragraphs(), nil, nil)
148}
149
150func title(b bug.Interface, p identity.Interface, timestamp int64) {
151	_, _ = bug.SetTitle(b, p, timestamp, fake.Sentence(), nil)
152}
153
154func open(b bug.Interface, p identity.Interface, timestamp int64) {
155	_, _ = bug.Open(b, p, timestamp, nil)
156}
157
158func close(b bug.Interface, p identity.Interface, timestamp int64) {
159	_, _ = bug.Close(b, p, timestamp, nil)
160}
161
162var addedLabels []string
163
164func labels(b bug.Interface, p identity.Interface, timestamp int64) {
165	var removed []string
166	nbRemoved := rand.Intn(3)
167	for nbRemoved > 0 && len(addedLabels) > 0 {
168		index := rand.Intn(len(addedLabels))
169		removed = append(removed, addedLabels[index])
170		addedLabels[index] = addedLabels[len(addedLabels)-1]
171		addedLabels = addedLabels[:len(addedLabels)-1]
172		nbRemoved--
173	}
174
175	var added []string
176	nbAdded := rand.Intn(3)
177	for i := 0; i < nbAdded; i++ {
178		label := fake.Word()
179		added = append(added, label)
180		addedLabels = append(addedLabels, label)
181	}
182
183	// ignore error
184	// if the randomisation produce no changes, no op
185	// is added to the bug
186	_, _, _ = bug.ChangeLabels(b, p, timestamp, added, removed, nil)
187}