create_random_bugs.go

  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/bug"
 11	"github.com/MichaelMure/git-bug/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		)
 91
 92		if err != nil {
 93			panic(err)
 94		}
 95
 96		nOps := opts.MinOp
 97
 98		if opts.MaxOp > opts.MinOp {
 99			nOps += rand.Intn(opts.MaxOp - opts.MinOp)
100		}
101
102		for j := 0; j < nOps; j++ {
103			index := rand.Intn(len(opsGenerators))
104			opsGenerators[index](b, randomPerson(), timestamp)
105			timestamp++
106		}
107
108		result[i] = b
109	}
110
111	return result
112}
113
114func GenerateRandomOperationPacks(packNumber int, opNumber int) []*bug.OperationPack {
115	return GenerateRandomOperationPacksWithSeed(packNumber, opNumber, time.Now().UnixNano())
116}
117
118func GenerateRandomOperationPacksWithSeed(packNumber int, opNumber int, seed int64) []*bug.OperationPack {
119	// Note: this is a bit crude, only generate a Create + Comments
120
121	panic("this piece of code needs to be updated to make sure that the identities " +
122		"are properly commit before usage. That is, generateRandomPersons() need to be called.")
123
124	rand.Seed(seed)
125	fake.Seed(seed)
126
127	result := make([]*bug.OperationPack, packNumber)
128
129	for i := 0; i < packNumber; i++ {
130		opp := &bug.OperationPack{}
131
132		var op bug.Operation
133
134		op = bug.NewCreateOp(
135			randomPerson(),
136			time.Now().Unix(),
137			fake.Sentence(),
138			paragraphs(),
139			nil,
140		)
141
142		opp.Append(op)
143
144		for j := 0; j < opNumber-1; j++ {
145			op = bug.NewAddCommentOp(
146				randomPerson(),
147				time.Now().Unix(),
148				paragraphs(),
149				nil,
150			)
151			opp.Append(op)
152		}
153
154		result[i] = opp
155	}
156
157	return result
158}
159
160func person() *identity.Identity {
161	return identity.NewIdentity(fake.FullName(), fake.EmailAddress())
162}
163
164var persons []*identity.Identity
165
166func generateRandomPersons(repo repository.ClockedRepo, n int) {
167	persons = make([]*identity.Identity, n)
168	for i := range persons {
169		p := person()
170		err := p.Commit(repo)
171		if err != nil {
172			panic(err)
173		}
174		persons[i] = p
175	}
176}
177
178func randomPerson() identity.Interface {
179	index := rand.Intn(len(persons))
180	return persons[index]
181}
182
183func paragraphs() string {
184	p := fake.Paragraphs()
185	return strings.Replace(p, "\t", "\n\n", -1)
186}
187
188func comment(b bug.Interface, p identity.Interface, timestamp int64) {
189	_, _ = bug.AddComment(b, p, timestamp, paragraphs())
190}
191
192func title(b bug.Interface, p identity.Interface, timestamp int64) {
193	_, _ = bug.SetTitle(b, p, timestamp, fake.Sentence())
194}
195
196func open(b bug.Interface, p identity.Interface, timestamp int64) {
197	_, _ = bug.Open(b, p, timestamp)
198}
199
200func close(b bug.Interface, p identity.Interface, timestamp int64) {
201	_, _ = bug.Close(b, p, timestamp)
202}
203
204var addedLabels []string
205
206func labels(b bug.Interface, p identity.Interface, timestamp int64) {
207	var removed []string
208	nbRemoved := rand.Intn(3)
209	for nbRemoved > 0 && len(addedLabels) > 0 {
210		index := rand.Intn(len(addedLabels))
211		removed = append(removed, addedLabels[index])
212		addedLabels[index] = addedLabels[len(addedLabels)-1]
213		addedLabels = addedLabels[:len(addedLabels)-1]
214		nbRemoved--
215	}
216
217	var added []string
218	nbAdded := rand.Intn(3)
219	for i := 0; i < nbAdded; i++ {
220		label := fake.Word()
221		added = append(added, label)
222		addedLabels = append(addedLabels, label)
223	}
224
225	// ignore error
226	// if the randomisation produce no changes, no op
227	// is added to the bug
228	_, _, _ = bug.ChangeLabels(b, p, timestamp, added, removed)
229}