Naming, layout and comments: descriptive full-word names, one item per line in wrapped calls and literals, and doc comments on exported names
Short and single-letter names in application code become full words (tests keep theirs). Wrapped calls, signatures and composite literals put one item per line, and one-line function bodies are expanded. Exported names and groups of constants get doc comments, and comments refer to the renamed identifiers.
This commit is contained in:
1 parent
043e307663
commit
465358609a
78 files changed
+2374
-1402
No files matched your search
@@ -23,12 +23,12 @@ type Generator struct {
|
||||
opts options
|
||||
}
|
||||
|
||||
// NewGenerator returns a generator drawing from cat and storing releases in
|
||||
// NewGenerator returns a generator drawing from catalog and storing releases in
|
||||
// store. The same seed and store contents give the same releases. It logs to
|
||||
// slog.Default() unless given WithLogger.
|
||||
func NewGenerator(cat *Catalog, store *Store, seed int64, opts ...Option) *Generator {
|
||||
func NewGenerator(catalog *Catalog, store *Store, seed int64, opts ...Option) *Generator {
|
||||
return &Generator{
|
||||
cat: cat,
|
||||
cat: catalog,
|
||||
store: store,
|
||||
rnd: rand.New(rand.NewSource(seed)), //nolint:gosec // seeded for repeatable mock data
|
||||
opts: applyOptions(opts),
|
||||
@@ -56,7 +56,7 @@ func (g *Generator) newProcedure(at time.Time) ocds.Release {
|
||||
buyer := g.cat.buyer(g.rnd)
|
||||
ensurePartyID(&buyer)
|
||||
buyer.Roles = []string{"buyer"}
|
||||
m := g.cat.method(g.rnd)
|
||||
method := g.cat.method(g.rnd)
|
||||
|
||||
tag, status := "tender", "active"
|
||||
if g.rnd.Float64() < 0.2 {
|
||||
@@ -64,38 +64,38 @@ func (g *Generator) newProcedure(at time.Time) ocds.Release {
|
||||
}
|
||||
ocid := g.newOCID()
|
||||
|
||||
t := g.cat.subject(g.rnd)
|
||||
t.ID = ocds.ID(ocid)
|
||||
t.ProcurementMethod = m.Method
|
||||
t.ProcurementMethodDetails = m.Details
|
||||
tender := g.cat.subject(g.rnd)
|
||||
tender.ID = ocds.ID(ocid)
|
||||
tender.ProcurementMethod = method.Method
|
||||
tender.ProcurementMethodDetails = method.Details
|
||||
|
||||
factor := 0.5 + g.rnd.Float64()*1.5
|
||||
if t.Value == nil {
|
||||
if tender.Value == nil {
|
||||
amount := float64((g.rnd.Intn(5000) + 10) * 1000)
|
||||
t.Value = &ocds.Value{
|
||||
tender.Value = &ocds.Value{
|
||||
Amount: &amount,
|
||||
Currency: "GBP",
|
||||
}
|
||||
} else {
|
||||
scaleValue(t.Value, factor)
|
||||
scaleValue(tender.Value, factor)
|
||||
}
|
||||
|
||||
for i := range t.Lots {
|
||||
scaleValue(t.Lots[i].Value, factor)
|
||||
for i := range tender.Lots {
|
||||
scaleValue(tender.Lots[i].Value, factor)
|
||||
}
|
||||
|
||||
if len(t.Lots) == 0 {
|
||||
v := clone(*t.Value)
|
||||
t.Lots = []ocds.Lot{{
|
||||
if len(tender.Lots) == 0 {
|
||||
value := clone(*tender.Value)
|
||||
tender.Lots = []ocds.Lot{{
|
||||
ID: "1",
|
||||
Title: t.Title,
|
||||
Value: &v,
|
||||
Title: tender.Title,
|
||||
Value: &value,
|
||||
}}
|
||||
}
|
||||
|
||||
setStatus(&t, status)
|
||||
setStatus(&tender, status)
|
||||
if status == "active" {
|
||||
t.TenderPeriod = &ocds.Period{
|
||||
tender.TenderPeriod = &ocds.Period{
|
||||
EndDate: ptr(at.AddDate(0, 0, 30+g.rnd.Intn(30))),
|
||||
}
|
||||
}
|
||||
@@ -111,7 +111,7 @@ func (g *Generator) newProcedure(at time.Time) ocds.Release {
|
||||
ID: ocds.ID(buyer.ID),
|
||||
Name: buyer.Name,
|
||||
},
|
||||
Tender: &t,
|
||||
Tender: &tender,
|
||||
Language: "en",
|
||||
}
|
||||
}
|
||||
@@ -120,13 +120,13 @@ func (g *Generator) newProcedure(at time.Time) ocds.Release {
|
||||
// tender, and a tender either has its deadline extended (tenderUpdate) or is
|
||||
// awarded to a supplier from the catalog.
|
||||
func (g *Generator) advance(prev ocds.Release, at time.Time) ocds.Release {
|
||||
r := clone(prev)
|
||||
r.ID = g.store.NextNoticeID(at.Year())
|
||||
r.Date = at
|
||||
r.Awards = nil
|
||||
if r.Tender == nil {
|
||||
r.Tender = &ocds.Tender{
|
||||
ID: ocds.ID(r.OCID),
|
||||
release := clone(prev)
|
||||
release.ID = g.store.NextNoticeID(at.Year())
|
||||
release.Date = at
|
||||
release.Awards = nil
|
||||
if release.Tender == nil {
|
||||
release.Tender = &ocds.Tender{
|
||||
ID: ocds.ID(release.OCID),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,60 +139,60 @@ func (g *Generator) advance(prev ocds.Release, at time.Time) ocds.Release {
|
||||
next = "tenderUpdate"
|
||||
}
|
||||
}
|
||||
r.Tag = []string{next}
|
||||
release.Tag = []string{next}
|
||||
|
||||
switch next {
|
||||
case "tender":
|
||||
setStatus(r.Tender, "active")
|
||||
r.Tender.TenderPeriod = &ocds.Period{
|
||||
setStatus(release.Tender, "active")
|
||||
release.Tender.TenderPeriod = &ocds.Period{
|
||||
EndDate: ptr(at.AddDate(0, 0, 30+g.rnd.Intn(30))),
|
||||
}
|
||||
case "tenderUpdate":
|
||||
// A typical update: the deadline is extended by two weeks.
|
||||
end := at.AddDate(0, 0, 30)
|
||||
if tp := r.Tender.TenderPeriod; tp != nil && tp.EndDate != nil {
|
||||
end = *tp.EndDate
|
||||
if period := release.Tender.TenderPeriod; period != nil && period.EndDate != nil {
|
||||
end = *period.EndDate
|
||||
}
|
||||
r.Tender.TenderPeriod = &ocds.Period{
|
||||
release.Tender.TenderPeriod = &ocds.Period{
|
||||
EndDate: ptr(end.AddDate(0, 0, 14)),
|
||||
}
|
||||
case "award":
|
||||
setStatus(r.Tender, "complete")
|
||||
sup := g.cat.supplier(g.rnd)
|
||||
ensurePartyID(&sup)
|
||||
sup.Roles = []string{"supplier"}
|
||||
r.Parties = append(r.Parties, sup)
|
||||
setStatus(release.Tender, "complete")
|
||||
supplier := g.cat.supplier(g.rnd)
|
||||
ensurePartyID(&supplier)
|
||||
supplier.Roles = []string{"supplier"}
|
||||
release.Parties = append(release.Parties, supplier)
|
||||
|
||||
var value *ocds.Value
|
||||
if r.Tender.Value != nil {
|
||||
v := clone(*r.Tender.Value)
|
||||
scaleValue(&v, 0.8+g.rnd.Float64()*0.2)
|
||||
value = &v
|
||||
if release.Tender.Value != nil {
|
||||
scaled := clone(*release.Tender.Value)
|
||||
scaleValue(&scaled, 0.8+g.rnd.Float64()*0.2)
|
||||
value = &scaled
|
||||
}
|
||||
|
||||
var lotIDs []string
|
||||
for _, lot := range r.Tender.Lots {
|
||||
for _, lot := range release.Tender.Lots {
|
||||
if lot.ID != "" {
|
||||
lotIDs = append(lotIDs, lot.ID)
|
||||
}
|
||||
}
|
||||
|
||||
r.Awards = []ocds.Award{{
|
||||
release.Awards = []ocds.Award{{
|
||||
ID: "1",
|
||||
Status: "active",
|
||||
Date: ptr(at),
|
||||
Value: value,
|
||||
Suppliers: []ocds.OrganizationReference{
|
||||
{
|
||||
ID: ocds.ID(sup.ID),
|
||||
Name: sup.Name,
|
||||
ID: ocds.ID(supplier.ID),
|
||||
Name: supplier.Name,
|
||||
},
|
||||
},
|
||||
RelatedLots: lotIDs,
|
||||
}}
|
||||
}
|
||||
|
||||
return r
|
||||
return release
|
||||
}
|
||||
|
||||
// newOCID returns a random ocid not already in the store.
|
||||
@@ -224,25 +224,25 @@ func (g *Generator) CatchUp(
|
||||
start = last
|
||||
}
|
||||
|
||||
n := 0
|
||||
for t := start.Add(g.gap(min, max)); !t.After(now); t = t.Add(g.gap(min, max)) {
|
||||
if err := g.store.AppendNoSync(g.Make(t)); err != nil {
|
||||
return n, err
|
||||
count := 0
|
||||
for when := start.Add(g.gap(min, max)); !when.After(now); when = when.Add(g.gap(min, max)) {
|
||||
if err := g.store.AppendNoSync(g.Make(when)); err != nil {
|
||||
return count, err
|
||||
}
|
||||
n++
|
||||
count++
|
||||
}
|
||||
|
||||
return n, g.store.Sync()
|
||||
return count, g.store.Sync()
|
||||
}
|
||||
|
||||
// Run publishes a new release after a random gap between min and max until ctx ends.
|
||||
func (g *Generator) Run(ctx context.Context, min, max time.Duration) {
|
||||
logger := g.opts.logger("generator")
|
||||
for {
|
||||
d := g.gap(min, max)
|
||||
logger.Info("next release", "in", d.Round(time.Second))
|
||||
gap := g.gap(min, max)
|
||||
logger.Info("next release", "in", gap.Round(time.Second))
|
||||
|
||||
timer := time.NewTimer(d)
|
||||
timer := time.NewTimer(gap)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
timer.Stop()
|
||||
@@ -250,46 +250,51 @@ func (g *Generator) Run(ctx context.Context, min, max time.Duration) {
|
||||
case <-timer.C:
|
||||
}
|
||||
|
||||
r := g.Make(time.Now())
|
||||
if err := g.store.Append(r); err != nil {
|
||||
release := g.Make(time.Now())
|
||||
if err := g.store.Append(release); err != nil {
|
||||
logger.Error("storing release failed", "error", err)
|
||||
continue
|
||||
}
|
||||
|
||||
logger.Info("published release", "release_id", r.ID, "tag", r.Tag[0], "ocid", r.OCID)
|
||||
logger.Info(
|
||||
"published release",
|
||||
"release_id", release.ID,
|
||||
"tag", release.Tag[0],
|
||||
"ocid", release.OCID,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- helpers ----------
|
||||
|
||||
func ptr[T any](v T) *T { return &v }
|
||||
func ptr[T any](value T) *T { return &value }
|
||||
|
||||
func setStatus(t *ocds.Tender, status string) {
|
||||
t.Status = status
|
||||
for i := range t.Lots {
|
||||
t.Lots[i].Status = status
|
||||
func setStatus(tender *ocds.Tender, status string) {
|
||||
tender.Status = status
|
||||
for i := range tender.Lots {
|
||||
tender.Lots[i].Status = status
|
||||
}
|
||||
}
|
||||
|
||||
// scaleValue multiplies v's amounts by f, rounded to the nearest 100.
|
||||
func scaleValue(v *ocds.Value, f float64) {
|
||||
if v == nil {
|
||||
// scaleValue multiplies value's amounts by factor, rounded to the nearest 100.
|
||||
func scaleValue(value *ocds.Value, factor float64) {
|
||||
if value == nil {
|
||||
return
|
||||
}
|
||||
for _, a := range []**float64{&v.Amount, &v.AmountGross} {
|
||||
if *a != nil {
|
||||
*a = ptr(math.Round(**a*f/100) * 100)
|
||||
for _, amount := range []**float64{&value.Amount, &value.AmountGross} {
|
||||
if *amount != nil {
|
||||
*amount = ptr(math.Round(**amount*factor/100) * 100)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ensurePartyID gives p an id derived from its name if it has none, so the
|
||||
// ensurePartyID gives party an id derived from its name if it has none, so the
|
||||
// same organisation always gets the same id.
|
||||
func ensurePartyID(p *ocds.Organization) {
|
||||
if p.ID != "" {
|
||||
func ensurePartyID(party *ocds.Organization) {
|
||||
if party.ID != "" {
|
||||
return
|
||||
}
|
||||
h := fnv.New32a()
|
||||
h.Write([]byte(p.Name)) //nolint:gosec // never fails
|
||||
p.ID = fmt.Sprintf("GB-FTS-%d", h.Sum32()%1000000)
|
||||
hasher := fnv.New32a()
|
||||
hasher.Write([]byte(party.Name)) //nolint:gosec // never fails
|
||||
party.ID = fmt.Sprintf("GB-FTS-%d", hasher.Sum32()%1000000)
|
||||
}
|
||||
Reference in new issue
Block a user