create_random_bugs.go

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