Skip to content

Commit

Permalink
New usage reporting (#426)
Browse files Browse the repository at this point in the history
  • Loading branch information
attiasas authored Aug 28, 2023
1 parent 41b5431 commit cbc2141
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 83 deletions.
7 changes: 3 additions & 4 deletions commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,14 @@ func Exec(command FrogbotCommand, commandName string) (err error) {
}

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

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

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

if err == nil {
log.Info(fmt.Sprintf("Frogbot %q command finished successfully", commandName))
Expand Down
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ require (
github.com/go-git/go-git/v5 v5.8.1
github.com/golang/mock v1.6.0
github.com/google/go-github/v45 v45.2.0
github.com/jfrog/build-info-go v1.9.8
github.com/jfrog/build-info-go v1.9.9
github.com/jfrog/froggit-go v1.13.4
github.com/jfrog/gofrog v1.3.0
github.com/jfrog/jfrog-cli-core/v2 v2.41.2
github.com/jfrog/jfrog-client-go v1.31.5
github.com/jfrog/jfrog-cli-core/v2 v2.41.4
github.com/jfrog/jfrog-client-go v1.31.6
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible
github.com/stretchr/testify v1.8.4
github.com/urfave/cli/v2 v2.25.7
Expand Down
12 changes: 6 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -875,16 +875,16 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jedib0t/go-pretty/v6 v6.4.6 h1:v6aG9h6Uby3IusSSEjHaZNXpHFhzqMmjXcPq1Rjl9Jw=
github.com/jedib0t/go-pretty/v6 v6.4.6/go.mod h1:Ndk3ase2CkQbXLLNf5QDHoYb6J9WtVfmHZu9n8rk2xs=
github.com/jfrog/build-info-go v1.9.8 h1:D8/ga+YgQpqp/CJj2zteS4/twmSy8zvm1v9lCd2Kv1M=
github.com/jfrog/build-info-go v1.9.8/go.mod h1:t31QRpH5xUJKw8XkQlAA+Aq7aanyS1rrzpcK8xSNVts=
github.com/jfrog/build-info-go v1.9.9 h1:YMA9okHawBNL8SrCWzqULSf5M4W+YnWyUhmkWSjoXEE=
github.com/jfrog/build-info-go v1.9.9/go.mod h1:t31QRpH5xUJKw8XkQlAA+Aq7aanyS1rrzpcK8xSNVts=
github.com/jfrog/froggit-go v1.13.4 h1:+pHq3iNkKFvojXCJ74sDV+UsV4Thsi03dsu36jkS7Rc=
github.com/jfrog/froggit-go v1.13.4/go.mod h1:0jRAaZZusaFFnITosmx6CA60SKryuoaCasJyUrP/c1s=
github.com/jfrog/gofrog v1.3.0 h1:o4zgsBZE4QyDbz2M7D4K6fXPTBJht+8lE87mS9bw7Gk=
github.com/jfrog/gofrog v1.3.0/go.mod h1:IFMc+V/yf7rA5WZ74CSbXe+Lgf0iApEQLxRZVzKRUR0=
github.com/jfrog/jfrog-cli-core/v2 v2.41.2 h1:Gnp93JcDAnHHCN3SHqam2K/S9yJcytS4q+MQd6vv9Ck=
github.com/jfrog/jfrog-cli-core/v2 v2.41.2/go.mod h1:YqB9rEJF1P7uGLIPUvF5qdDDf1zM5f4DneIQNkqyAfs=
github.com/jfrog/jfrog-client-go v1.31.5 h1:dYVgIJzMwX+EU9GEELKPSHFLyfW6UrrjZWMEZtAyx6A=
github.com/jfrog/jfrog-client-go v1.31.5/go.mod h1:icb00ZJN/mMMNkQduHDkzpqsXH9Flwi3f3COYexq3Nc=
github.com/jfrog/jfrog-cli-core/v2 v2.41.4 h1:+V35NN+UaKl6ZFSjAyZFZ4VijCgsORnGsHug02DROdE=
github.com/jfrog/jfrog-cli-core/v2 v2.41.4/go.mod h1:Mi3WFUzG2CU6tlLpGsMNRaKkhH/tIMuci4tjnPZ9S3M=
github.com/jfrog/jfrog-client-go v1.31.6 h1:uWuyT4BDm9s5ES6oDTBny9Gl6yf8iKFjcbmHSHQZrDc=
github.com/jfrog/jfrog-client-go v1.31.6/go.mod h1:icb00ZJN/mMMNkQduHDkzpqsXH9Flwi3f3COYexq3Nc=
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible h1:jdpOPRN1zP63Td1hDQbZW73xKmzDvZHzVdNYxhnTMDA=
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
Expand Down
54 changes: 30 additions & 24 deletions utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,23 @@ import (
"encoding/hex"
"errors"
"fmt"
"os"
"regexp"
"sort"
"strings"

"github.com/jfrog/froggit-go/vcsclient"
"github.com/jfrog/froggit-go/vcsutils"
"github.com/jfrog/gofrog/version"
"github.com/jfrog/jfrog-cli-core/v2/artifactory/utils"
"github.com/jfrog/jfrog-cli-core/v2/common/commands"
"github.com/jfrog/jfrog-cli-core/v2/utils/config"
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
"github.com/jfrog/jfrog-cli-core/v2/utils/usage"
audit "github.com/jfrog/jfrog-cli-core/v2/xray/commands/audit/generic"
"github.com/jfrog/jfrog-cli-core/v2/xray/formats"
xrayutils "github.com/jfrog/jfrog-cli-core/v2/xray/utils"
"github.com/jfrog/jfrog-client-go/artifactory/usage"
"github.com/jfrog/jfrog-client-go/utils/io/fileutils"
"github.com/jfrog/jfrog-client-go/utils/log"
"os"
"regexp"
"sort"
"strings"
)

const (
Expand Down Expand Up @@ -148,29 +148,35 @@ func Chdir(dir string) (cbk func() error, err error) {
return func() error { return os.Chdir(wd) }, err
}

func ReportUsage(commandName string, serverDetails *config.ServerDetails, usageReportSent chan<- error) {
var err error
defer func() {
// The usage reporting is meant to run asynchronously, so that the actual action isn't delayed.
// 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.
usageReportSent <- err
}()
if serverDetails.ArtifactoryUrl == "" {
return
}
log.Debug(usage.ReportUsagePrefix, "Sending info...")
serviceManager, err := utils.CreateServiceManager(serverDetails, -1, 0, false)
func ReportUsageOnCommand(commandName string, serverDetails *config.ServerDetails, repositories RepoAggregator) func() {
reporter := usage.NewUsageReporter(productId, serverDetails)
reports, err := convertToUsageReports(commandName, repositories)
if err != nil {
log.Debug(usage.ReportUsagePrefix, err.Error())
return
log.Debug(usage.ReportUsagePrefix, "Could not create usage data to report")
}
err = usage.SendReportUsage(productId, commandName, serviceManager)
if err != nil {
log.Debug(err.Error())
return
reporter.Report(reports...)
return func() {
if err = reporter.WaitForResponses(); err != nil {
log.Debug(err.Error())
}
}
}

func convertToUsageReports(commandName string, repositories RepoAggregator) (reports []usage.ReportFeature, err error) {
for _, repository := range repositories {
// Report one entry for each repository as client
if clientId, e := Md5Hash(repository.RepoName); e != nil {
err = errors.Join(err, e)
} else {
reports = append(reports, usage.ReportFeature{
FeatureId: commandName,
ClientId: clientId,
})
}
}
return
}

func Md5Hash(values ...string) (string, error) {
hash := crypto.MD5.New()
for _, ob := range values {
Expand Down
70 changes: 24 additions & 46 deletions utils/utils_test.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
package utils

import (
"bytes"
"fmt"
"github.com/jfrog/jfrog-cli-core/v2/utils/config"
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
"github.com/jfrog/jfrog-cli-core/v2/xray/formats"
"github.com/stretchr/testify/assert"
"net/http"
"net/http/httptest"
"os"
"path"
"path/filepath"
"testing"

"github.com/jfrog/jfrog-cli-core/v2/utils/config"
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
"github.com/jfrog/jfrog-cli-core/v2/xray/formats"
"github.com/stretchr/testify/assert"
)

func TestChdir(t *testing.T) {
Expand Down Expand Up @@ -44,48 +41,29 @@ func TestChdirErr(t *testing.T) {
assert.Equal(t, originCwd, cwd)
}

func TestReportUsage(t *testing.T) {
const commandName = "test-command"
server := httptest.NewServer(createUsageHandler(t, commandName))
defer server.Close()

serverDetails := &config.ServerDetails{ArtifactoryUrl: server.URL + "/"}
channel := make(chan error)
go ReportUsage(commandName, serverDetails, channel)
assert.NoError(t, <-channel)
func getDummyRepoNames() []string {
return []string{"repository1", "repository2"}
}

func TestReportUsageError(t *testing.T) {
channel := make(chan error)
go ReportUsage("", &config.ServerDetails{}, channel)
assert.NoError(t, <-channel)

channel = make(chan error)
go ReportUsage("", &config.ServerDetails{ArtifactoryUrl: "http://httpbin.org/status/404"}, channel)
assert.Error(t, <-channel)
func getDummyRepo() RepoAggregator {
repos := RepoAggregator{}
names := getDummyRepoNames()
for _, name := range names {
repos = append(repos, Repository{Params: Params{Git: Git{RepoName: name}}})
}
return repos
}

// Create HTTP handler to mock an Artifactory server suitable for report usage requests
func createUsageHandler(t *testing.T, commandName string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if r.RequestURI == "/api/system/version" {
w.WriteHeader(http.StatusOK)
_, err := w.Write([]byte(`{"version":"6.9.0"}`))
assert.NoError(t, err)
return
}
if r.RequestURI == "/api/system/usage" {
// Check request
buf := new(bytes.Buffer)
_, err := buf.ReadFrom(r.Body)
assert.NoError(t, err)
assert.Equal(t, fmt.Sprintf(`{"productId":"%s","features":[{"featureId":"%s"}]}`, productId, commandName), buf.String())

// Send response OK
w.WriteHeader(http.StatusOK)
_, err = w.Write([]byte("{}"))
assert.NoError(t, err)
}
func TestConvertToUsageReports(t *testing.T) {
const commandName = "test-command"
repoNames := getDummyRepoNames()
repo := getDummyRepo()
features, err := convertToUsageReports(commandName, repo)
assert.NoError(t, err)
assert.Len(t, features, 2)
for _, feature := range features {
assert.Equal(t, commandName, feature.FeatureId)
assert.NotContains(t, repoNames, feature.ClientId)
}
}

Expand Down

0 comments on commit cbc2141

Please sign in to comment.