Skip to content

Commit cbc2141

Browse files
authored
New usage reporting (#426)
1 parent 41b5431 commit cbc2141

File tree

5 files changed

+66
-83
lines changed

5 files changed

+66
-83
lines changed

commands.go

+3-4
Original file line numberDiff line numberDiff line change
@@ -89,15 +89,14 @@ func Exec(command FrogbotCommand, commandName string) (err error) {
8989
}
9090

9191
// Send a usage report
92-
usageReportSent := make(chan error)
93-
go utils.ReportUsage(commandName, frogbotDetails.ServerDetails, usageReportSent)
92+
waitForUsageResponse := utils.ReportUsageOnCommand(commandName, frogbotDetails.ServerDetails, frogbotDetails.Repositories)
9493

9594
// Invoke the command interface
9695
log.Info(fmt.Sprintf("Running Frogbot %q command", commandName))
9796
err = command.Run(frogbotDetails.Repositories, frogbotDetails.GitClient)
9897

99-
// Wait for a signal, letting us know that the usage reporting is done.
100-
<-usageReportSent
98+
// Wait for usage reporting to finish.
99+
waitForUsageResponse()
101100

102101
if err == nil {
103102
log.Info(fmt.Sprintf("Frogbot %q command finished successfully", commandName))

go.mod

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ require (
66
github.com/go-git/go-git/v5 v5.8.1
77
github.com/golang/mock v1.6.0
88
github.com/google/go-github/v45 v45.2.0
9-
github.com/jfrog/build-info-go v1.9.8
9+
github.com/jfrog/build-info-go v1.9.9
1010
github.com/jfrog/froggit-go v1.13.4
1111
github.com/jfrog/gofrog v1.3.0
12-
github.com/jfrog/jfrog-cli-core/v2 v2.41.2
13-
github.com/jfrog/jfrog-client-go v1.31.5
12+
github.com/jfrog/jfrog-cli-core/v2 v2.41.4
13+
github.com/jfrog/jfrog-client-go v1.31.6
1414
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible
1515
github.com/stretchr/testify v1.8.4
1616
github.com/urfave/cli/v2 v2.25.7

go.sum

+6-6
Original file line numberDiff line numberDiff line change
@@ -875,16 +875,16 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl
875875
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
876876
github.com/jedib0t/go-pretty/v6 v6.4.6 h1:v6aG9h6Uby3IusSSEjHaZNXpHFhzqMmjXcPq1Rjl9Jw=
877877
github.com/jedib0t/go-pretty/v6 v6.4.6/go.mod h1:Ndk3ase2CkQbXLLNf5QDHoYb6J9WtVfmHZu9n8rk2xs=
878-
github.com/jfrog/build-info-go v1.9.8 h1:D8/ga+YgQpqp/CJj2zteS4/twmSy8zvm1v9lCd2Kv1M=
879-
github.com/jfrog/build-info-go v1.9.8/go.mod h1:t31QRpH5xUJKw8XkQlAA+Aq7aanyS1rrzpcK8xSNVts=
878+
github.com/jfrog/build-info-go v1.9.9 h1:YMA9okHawBNL8SrCWzqULSf5M4W+YnWyUhmkWSjoXEE=
879+
github.com/jfrog/build-info-go v1.9.9/go.mod h1:t31QRpH5xUJKw8XkQlAA+Aq7aanyS1rrzpcK8xSNVts=
880880
github.com/jfrog/froggit-go v1.13.4 h1:+pHq3iNkKFvojXCJ74sDV+UsV4Thsi03dsu36jkS7Rc=
881881
github.com/jfrog/froggit-go v1.13.4/go.mod h1:0jRAaZZusaFFnITosmx6CA60SKryuoaCasJyUrP/c1s=
882882
github.com/jfrog/gofrog v1.3.0 h1:o4zgsBZE4QyDbz2M7D4K6fXPTBJht+8lE87mS9bw7Gk=
883883
github.com/jfrog/gofrog v1.3.0/go.mod h1:IFMc+V/yf7rA5WZ74CSbXe+Lgf0iApEQLxRZVzKRUR0=
884-
github.com/jfrog/jfrog-cli-core/v2 v2.41.2 h1:Gnp93JcDAnHHCN3SHqam2K/S9yJcytS4q+MQd6vv9Ck=
885-
github.com/jfrog/jfrog-cli-core/v2 v2.41.2/go.mod h1:YqB9rEJF1P7uGLIPUvF5qdDDf1zM5f4DneIQNkqyAfs=
886-
github.com/jfrog/jfrog-client-go v1.31.5 h1:dYVgIJzMwX+EU9GEELKPSHFLyfW6UrrjZWMEZtAyx6A=
887-
github.com/jfrog/jfrog-client-go v1.31.5/go.mod h1:icb00ZJN/mMMNkQduHDkzpqsXH9Flwi3f3COYexq3Nc=
884+
github.com/jfrog/jfrog-cli-core/v2 v2.41.4 h1:+V35NN+UaKl6ZFSjAyZFZ4VijCgsORnGsHug02DROdE=
885+
github.com/jfrog/jfrog-cli-core/v2 v2.41.4/go.mod h1:Mi3WFUzG2CU6tlLpGsMNRaKkhH/tIMuci4tjnPZ9S3M=
886+
github.com/jfrog/jfrog-client-go v1.31.6 h1:uWuyT4BDm9s5ES6oDTBny9Gl6yf8iKFjcbmHSHQZrDc=
887+
github.com/jfrog/jfrog-client-go v1.31.6/go.mod h1:icb00ZJN/mMMNkQduHDkzpqsXH9Flwi3f3COYexq3Nc=
888888
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible h1:jdpOPRN1zP63Td1hDQbZW73xKmzDvZHzVdNYxhnTMDA=
889889
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A=
890890
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=

utils/utils.go

+30-24
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,23 @@ import (
66
"encoding/hex"
77
"errors"
88
"fmt"
9+
"os"
10+
"regexp"
11+
"sort"
12+
"strings"
13+
914
"github.com/jfrog/froggit-go/vcsclient"
1015
"github.com/jfrog/froggit-go/vcsutils"
1116
"github.com/jfrog/gofrog/version"
12-
"github.com/jfrog/jfrog-cli-core/v2/artifactory/utils"
1317
"github.com/jfrog/jfrog-cli-core/v2/common/commands"
1418
"github.com/jfrog/jfrog-cli-core/v2/utils/config"
1519
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
20+
"github.com/jfrog/jfrog-cli-core/v2/utils/usage"
1621
audit "github.com/jfrog/jfrog-cli-core/v2/xray/commands/audit/generic"
1722
"github.com/jfrog/jfrog-cli-core/v2/xray/formats"
1823
xrayutils "github.com/jfrog/jfrog-cli-core/v2/xray/utils"
19-
"github.com/jfrog/jfrog-client-go/artifactory/usage"
2024
"github.com/jfrog/jfrog-client-go/utils/io/fileutils"
2125
"github.com/jfrog/jfrog-client-go/utils/log"
22-
"os"
23-
"regexp"
24-
"sort"
25-
"strings"
2626
)
2727

2828
const (
@@ -148,29 +148,35 @@ func Chdir(dir string) (cbk func() error, err error) {
148148
return func() error { return os.Chdir(wd) }, err
149149
}
150150

151-
func ReportUsage(commandName string, serverDetails *config.ServerDetails, usageReportSent chan<- error) {
152-
var err error
153-
defer func() {
154-
// The usage reporting is meant to run asynchronously, so that the actual action isn't delayed.
155-
// It is however important to the application to not exit before the reporting is finished. That is, in case the reporting takes longer than the action.
156-
usageReportSent <- err
157-
}()
158-
if serverDetails.ArtifactoryUrl == "" {
159-
return
160-
}
161-
log.Debug(usage.ReportUsagePrefix, "Sending info...")
162-
serviceManager, err := utils.CreateServiceManager(serverDetails, -1, 0, false)
151+
func ReportUsageOnCommand(commandName string, serverDetails *config.ServerDetails, repositories RepoAggregator) func() {
152+
reporter := usage.NewUsageReporter(productId, serverDetails)
153+
reports, err := convertToUsageReports(commandName, repositories)
163154
if err != nil {
164-
log.Debug(usage.ReportUsagePrefix, err.Error())
165-
return
155+
log.Debug(usage.ReportUsagePrefix, "Could not create usage data to report")
166156
}
167-
err = usage.SendReportUsage(productId, commandName, serviceManager)
168-
if err != nil {
169-
log.Debug(err.Error())
170-
return
157+
reporter.Report(reports...)
158+
return func() {
159+
if err = reporter.WaitForResponses(); err != nil {
160+
log.Debug(err.Error())
161+
}
171162
}
172163
}
173164

165+
func convertToUsageReports(commandName string, repositories RepoAggregator) (reports []usage.ReportFeature, err error) {
166+
for _, repository := range repositories {
167+
// Report one entry for each repository as client
168+
if clientId, e := Md5Hash(repository.RepoName); e != nil {
169+
err = errors.Join(err, e)
170+
} else {
171+
reports = append(reports, usage.ReportFeature{
172+
FeatureId: commandName,
173+
ClientId: clientId,
174+
})
175+
}
176+
}
177+
return
178+
}
179+
174180
func Md5Hash(values ...string) (string, error) {
175181
hash := crypto.MD5.New()
176182
for _, ob := range values {

utils/utils_test.go

+24-46
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
11
package utils
22

33
import (
4-
"bytes"
5-
"fmt"
6-
"github.com/jfrog/jfrog-cli-core/v2/utils/config"
7-
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
8-
"github.com/jfrog/jfrog-cli-core/v2/xray/formats"
9-
"github.com/stretchr/testify/assert"
10-
"net/http"
11-
"net/http/httptest"
124
"os"
135
"path"
146
"path/filepath"
157
"testing"
8+
9+
"github.com/jfrog/jfrog-cli-core/v2/utils/config"
10+
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
11+
"github.com/jfrog/jfrog-cli-core/v2/xray/formats"
12+
"github.com/stretchr/testify/assert"
1613
)
1714

1815
func TestChdir(t *testing.T) {
@@ -44,48 +41,29 @@ func TestChdirErr(t *testing.T) {
4441
assert.Equal(t, originCwd, cwd)
4542
}
4643

47-
func TestReportUsage(t *testing.T) {
48-
const commandName = "test-command"
49-
server := httptest.NewServer(createUsageHandler(t, commandName))
50-
defer server.Close()
51-
52-
serverDetails := &config.ServerDetails{ArtifactoryUrl: server.URL + "/"}
53-
channel := make(chan error)
54-
go ReportUsage(commandName, serverDetails, channel)
55-
assert.NoError(t, <-channel)
44+
func getDummyRepoNames() []string {
45+
return []string{"repository1", "repository2"}
5646
}
5747

58-
func TestReportUsageError(t *testing.T) {
59-
channel := make(chan error)
60-
go ReportUsage("", &config.ServerDetails{}, channel)
61-
assert.NoError(t, <-channel)
62-
63-
channel = make(chan error)
64-
go ReportUsage("", &config.ServerDetails{ArtifactoryUrl: "http://httpbin.org/status/404"}, channel)
65-
assert.Error(t, <-channel)
48+
func getDummyRepo() RepoAggregator {
49+
repos := RepoAggregator{}
50+
names := getDummyRepoNames()
51+
for _, name := range names {
52+
repos = append(repos, Repository{Params: Params{Git: Git{RepoName: name}}})
53+
}
54+
return repos
6655
}
6756

68-
// Create HTTP handler to mock an Artifactory server suitable for report usage requests
69-
func createUsageHandler(t *testing.T, commandName string) http.HandlerFunc {
70-
return func(w http.ResponseWriter, r *http.Request) {
71-
if r.RequestURI == "/api/system/version" {
72-
w.WriteHeader(http.StatusOK)
73-
_, err := w.Write([]byte(`{"version":"6.9.0"}`))
74-
assert.NoError(t, err)
75-
return
76-
}
77-
if r.RequestURI == "/api/system/usage" {
78-
// Check request
79-
buf := new(bytes.Buffer)
80-
_, err := buf.ReadFrom(r.Body)
81-
assert.NoError(t, err)
82-
assert.Equal(t, fmt.Sprintf(`{"productId":"%s","features":[{"featureId":"%s"}]}`, productId, commandName), buf.String())
83-
84-
// Send response OK
85-
w.WriteHeader(http.StatusOK)
86-
_, err = w.Write([]byte("{}"))
87-
assert.NoError(t, err)
88-
}
57+
func TestConvertToUsageReports(t *testing.T) {
58+
const commandName = "test-command"
59+
repoNames := getDummyRepoNames()
60+
repo := getDummyRepo()
61+
features, err := convertToUsageReports(commandName, repo)
62+
assert.NoError(t, err)
63+
assert.Len(t, features, 2)
64+
for _, feature := range features {
65+
assert.Equal(t, commandName, feature.FeatureId)
66+
assert.NotContains(t, repoNames, feature.ClientId)
8967
}
9068
}
9169

0 commit comments

Comments
 (0)