Skip to content

Commit

Permalink
Merge pull request #239 from CircleCI-Public/CIRCLE-15461-orb-list-de…
Browse files Browse the repository at this point in the history
…tails-stats

[CIRCLE-15461] Show orb usage stats in `orb list --details`
  • Loading branch information
Zachary Scott authored Dec 26, 2018
2 parents 94e0863 + 02b2b93 commit 8153c30
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 25 deletions.
19 changes: 11 additions & 8 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,19 +235,22 @@ func (orbs *OrbsForListing) SortBy(sortBy string) {
// OrbBase represents the minimum fields we wish to serialize for orbs.
// This type can be embedded for extending orbs with more data. e.g. OrbWithData
type OrbBase struct {
Name string `json:"name"`
HighestVersion string `json:"version"`
Statistics struct {
Last30DaysBuildCount int `json:"last30DaysBuildCount"`
Last30DaysProjectCount int `json:"last30DaysProjectCount"`
Last30DaysOrganizationCount int `json:"last30DaysOrganizationCount"`
} `json:"statistics"`
Versions []struct {
Name string `json:"name"`
HighestVersion string `json:"version"`
Statistics OrbStatistics `json:"statistics"`
Versions []struct {
Version string `json:"version"`
Source string `json:"source"`
} `json:"versions"`
}

// OrbStatistics represents the data we retrieve for orb usage in the last thirty days.
type OrbStatistics struct {
Last30DaysBuildCount int `json:"last30DaysBuildCount"`
Last30DaysProjectCount int `json:"last30DaysProjectCount"`
Last30DaysOrganizationCount int `json:"last30DaysOrganizationCount"`
}

// OrbWithData extends the OrbBase type with additional data used for printing.
type OrbWithData struct {
OrbBase
Expand Down
54 changes: 37 additions & 17 deletions cmd/orb.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,8 @@ func parameterDefaultToString(parameter api.OrbElementParameter) string {
return defaultValue + "')"
}

func addOrbElementParametersToBuffer(buf *bytes.Buffer, orbElement api.OrbElement) error {
// nolint: errcheck, gosec
func addOrbElementParametersToBuffer(buf *bytes.Buffer, orbElement api.OrbElement) {
keys := make([]string, 0, len(orbElement.Parameters))
for k := range orbElement.Parameters {
keys = append(keys, k)
Expand All @@ -263,49 +264,66 @@ func addOrbElementParametersToBuffer(buf *bytes.Buffer, orbElement api.OrbElemen
parameterName := k
parameter := orbElement.Parameters[k]

var err error

defaultValueString := parameterDefaultToString(parameter)
_, err = buf.WriteString(fmt.Sprintf(" - %s: %s%s\n", parameterName, parameter.Type, defaultValueString))

if err != nil {
return err
}
_, _ = buf.WriteString(fmt.Sprintf(" - %s: %s%s\n", parameterName, parameter.Type, defaultValueString))
}

return nil
}

// nolint: errcheck, gosec
func addOrbElementsToBuffer(buf *bytes.Buffer, name string, namedOrbElements map[string]api.OrbElement) {
var err error

if len(namedOrbElements) > 0 {
keys := make([]string, 0, len(namedOrbElements))
for k := range namedOrbElements {
keys = append(keys, k)
}
sort.Strings(keys)

_, err = buf.WriteString(fmt.Sprintf(" %s:\n", name))
_, _ = buf.WriteString(fmt.Sprintf(" %s:\n", name))
for _, k := range keys {
elementName := k
orbElement := namedOrbElements[k]

parameterCount := len(orbElement.Parameters)

_, err = buf.WriteString(fmt.Sprintf(" - %s: %d parameter(s)\n", elementName, parameterCount))
_, _ = buf.WriteString(fmt.Sprintf(" - %s: %d parameter(s)\n", elementName, parameterCount))

if parameterCount > 0 {
err = addOrbElementParametersToBuffer(buf, orbElement)
addOrbElementParametersToBuffer(buf, orbElement)
}
}
}
}

// nolint: unparam, errcheck, gosec
func addOrbStatisticsToBuffer(buf *bytes.Buffer, name string, stats api.OrbStatistics) {
var (
encoded []byte
data map[string]int
)

// This will never occur. The docs for bytes.Buffer.WriteString says err
// will always be nil. The linter still expects this error to be checked.
// Roundtrip the stats to JSON so we can iterate a map since we don't care about the fields
encoded, err := json.Marshal(stats)
if err != nil {
panic(err)
}

if err := json.Unmarshal(encoded, &data); err != nil {
panic(err)
}

_, _ = buf.WriteString(fmt.Sprintf(" %s:\n", name))

// Sort the keys so we always get the same results even after the round-trip
keys := make([]string, 0, len(data))
for k := range data {
keys = append(keys, k)
}
sort.Strings(keys)

for _, key := range keys {
value := data[key]
_, _ = buf.WriteString(fmt.Sprintf(" - %s: %d\n", key, value))
}
}

func orbToDetailedString(orb api.OrbWithData) string {
Expand All @@ -315,6 +333,8 @@ func orbToDetailedString(orb api.OrbWithData) string {
addOrbElementsToBuffer(buffer, "Jobs", orb.Jobs)
addOrbElementsToBuffer(buffer, "Executors", orb.Executors)

addOrbStatisticsToBuffer(buffer, "Statistics", orb.Statistics)

return buffer.String()
}

Expand Down
4 changes: 4 additions & 0 deletions cmd/orb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1537,6 +1537,10 @@ foo/test (0.7.0)
Executors:
- default: 1 parameter(s)
- tag: string (default: 'curl-browsers')
Statistics:
- last30DaysBuildCount: 0
- last30DaysOrganizationCount: 0
- last30DaysProjectCount: 0
`))
Eventually(session).Should(gexec.Exit(0))
Expand Down

0 comments on commit 8153c30

Please sign in to comment.