From b3c37f6b6cdd3b091140ee823c8f75eab5adef82 Mon Sep 17 00:00:00 2001
From: Tian Feng <tian.feng@saucelabs.com>
Date: Tue, 31 Oct 2023 20:42:11 -0700
Subject: [PATCH 1/9] feat: Add buildURL in JSON report

---
 internal/cmd/run/run.go      |  1 +
 internal/report/json/json.go | 56 ++++++++++++++++++++++++++++++++++++
 internal/report/report.go    |  1 +
 3 files changed, 58 insertions(+)

diff --git a/internal/cmd/run/run.go b/internal/cmd/run/run.go
index 8a1a978a8..b86ab1842 100644
--- a/internal/cmd/run/run.go
+++ b/internal/cmd/run/run.go
@@ -302,6 +302,7 @@ func createReporters(c config.Reporters, ntfs config.Notifications, metadata con
 		}
 		if c.JSON.Enabled {
 			reps = append(reps, &json.Reporter{
+				Service:    buildReader,
 				WebhookURL: c.JSON.WebhookURL,
 				Filename:   c.JSON.Filename,
 			})
diff --git a/internal/report/json/json.go b/internal/report/json/json.go
index 76d20cad3..61b1cda0e 100644
--- a/internal/report/json/json.go
+++ b/internal/report/json/json.go
@@ -2,17 +2,23 @@ package json
 
 import (
 	"bytes"
+	"context"
 	"encoding/json"
+	"fmt"
 	"io"
 	"net/http"
+	"net/url"
 	"os"
+	"strings"
 
 	"github.com/rs/zerolog/log"
+	"github.com/saucelabs/saucectl/internal/build"
 	"github.com/saucelabs/saucectl/internal/report"
 )
 
 // Reporter represents struct to report in json format
 type Reporter struct {
+	Service    build.Reader
 	WebhookURL string
 	Filename   string
 	Results    []report.TestResult
@@ -26,6 +32,7 @@ func (r *Reporter) Add(t report.TestResult) {
 // Render sends the result to specified webhook WebhookURL and log the result to the specified json file
 func (r *Reporter) Render() {
 	r.cleanup()
+	r.buildData()
 	body, err := json.Marshal(r.Results)
 	if err != nil {
 		log.Error().Msgf("failed to generate test result (%v)", err)
@@ -79,3 +86,52 @@ func (r *Reporter) Reset() {
 func (r *Reporter) ArtifactRequirements() []report.ArtifactType {
 	return nil
 }
+
+func (r *Reporter) buildData() {
+	if len(r.Results) < 1 {
+		return
+	}
+
+	var vdcJobURL string
+	var rdcJobURL string
+	for _, result := range r.Results {
+		if !result.RDC && result.URL != "" {
+			vdcJobURL = result.URL
+			break
+		}
+	}
+	for _, result := range r.Results {
+		if result.RDC && result.URL != "" {
+			rdcJobURL = result.URL
+			break
+		}
+	}
+	vdcBuildURL := r.getBuildURL(vdcJobURL, build.VDC)
+	rdcBuildURL := r.getBuildURL(rdcJobURL, build.RDC)
+	for i, result := range r.Results {
+		if !result.RDC {
+			result.BuildURL = vdcBuildURL
+		} else {
+			result.BuildURL = rdcBuildURL
+		}
+		r.Results[i] = result
+	}
+}
+
+func (r *Reporter) getBuildURL(jobURL string, buildSource build.Source) string {
+	pURL, err := url.Parse(jobURL)
+	if err != nil {
+		log.Debug().Err(err).Msgf("Failed to parse job url (%s)", jobURL)
+		return ""
+	}
+	p := strings.Split(pURL.Path, "/")
+	jID := p[len(p)-1]
+
+	bID, err := r.Service.GetBuildID(context.Background(), jID, buildSource)
+	if err != nil {
+		log.Debug().Err(err).Msgf("Failed to retrieve build id for job (%s)", jID)
+		return ""
+	}
+
+	return fmt.Sprintf("%s://%s/builds/%s/%s", pURL.Scheme, pURL.Host, buildSource, bID)
+}
diff --git a/internal/report/report.go b/internal/report/report.go
index 0ac216c34..f2c3c4ac6 100644
--- a/internal/report/report.go
+++ b/internal/report/report.go
@@ -35,6 +35,7 @@ type TestResult struct {
 	URL           string        `json:"url"`
 	Artifacts     []Artifact    `json:"artifacts,omitempty"`
 	Origin        string        `json:"origin"`
+	BuildURL      string        `json:"buildURL"`
 	RDC           bool          `json:"-"`
 	TimedOut      bool          `json:"-"`
 	PassThreshold bool          `json:"-"`

From b6d3a269580786c913e5a9d13220a78e7dcb892e Mon Sep 17 00:00:00 2001
From: Tian Feng <tian.feng@saucelabs.com>
Date: Wed, 1 Nov 2023 10:03:44 -0700
Subject: [PATCH 2/9] refact reporter

---
 internal/cmd/run/run.go                  |  3 +-
 internal/report/buildtable/buildtable.go | 44 ++++---------------
 internal/report/json/json.go             | 56 ------------------------
 internal/saucecloud/cloud.go             | 25 +++++++++++
 4 files changed, 35 insertions(+), 93 deletions(-)

diff --git a/internal/cmd/run/run.go b/internal/cmd/run/run.go
index b86ab1842..d4fa2152d 100644
--- a/internal/cmd/run/run.go
+++ b/internal/cmd/run/run.go
@@ -302,7 +302,6 @@ func createReporters(c config.Reporters, ntfs config.Notifications, metadata con
 		}
 		if c.JSON.Enabled {
 			reps = append(reps, &json.Reporter{
-				Service:    buildReader,
 				WebhookURL: c.JSON.WebhookURL,
 				Filename:   c.JSON.Filename,
 			})
@@ -314,7 +313,7 @@ func createReporters(c config.Reporters, ntfs config.Notifications, metadata con
 		}
 	}
 
-	buildReporter := buildtable.New(buildReader)
+	buildReporter := buildtable.New()
 	reps = append(reps, &buildReporter)
 
 	reps = append(reps, &slack.Reporter{
diff --git a/internal/report/buildtable/buildtable.go b/internal/report/buildtable/buildtable.go
index fef8627e1..825dc32d1 100644
--- a/internal/report/buildtable/buildtable.go
+++ b/internal/report/buildtable/buildtable.go
@@ -1,15 +1,11 @@
 package buildtable
 
 import (
-	"context"
 	"fmt"
-	"net/url"
 	"os"
 	"strings"
 
 	"github.com/fatih/color"
-	"github.com/rs/zerolog/log"
-	"github.com/saucelabs/saucectl/internal/build"
 	"github.com/saucelabs/saucectl/internal/report"
 	"github.com/saucelabs/saucectl/internal/report/table"
 )
@@ -17,14 +13,12 @@ import (
 // Reporter is an implementation of report.Reporter
 // It wraps a table reporter and decorates it with additional metadata
 type Reporter struct {
-	Service        build.Reader
 	VDCTableReport table.Reporter
 	RDCTableReport table.Reporter
 }
 
-func New(svc build.Reader) Reporter {
+func New() Reporter {
 	return Reporter{
-		Service: svc,
 		VDCTableReport: table.Reporter{
 			Dst: os.Stdout,
 		},
@@ -49,18 +43,16 @@ func (r *Reporter) Render() {
 	printTitle()
 	printPadding(2)
 
-	var jURL string
-	var bURL string
 	if len(r.VDCTableReport.TestResults) > 0 {
 		r.VDCTableReport.Render()
 
-		for _, tr := range r.VDCTableReport.TestResults {
-			if tr.URL != "" {
-				jURL = tr.URL
+		var bURL string
+		for _, result := range r.VDCTableReport.TestResults {
+			if result.BuildURL != "" {
+				bURL = result.BuildURL
 				break
 			}
 		}
-		bURL = r.buildURLFromJobURL(jURL, build.VDC)
 
 		if bURL == "" {
 			bURL = "N/A"
@@ -72,13 +64,13 @@ func (r *Reporter) Render() {
 	if len(r.RDCTableReport.TestResults) > 0 {
 		r.RDCTableReport.Render()
 
-		for _, tr := range r.RDCTableReport.TestResults {
-			if tr.URL != "" {
-				jURL = tr.URL
+		var bURL string
+		for _, result := range r.RDCTableReport.TestResults {
+			if result.BuildURL != "" {
+				bURL = result.BuildURL
 				break
 			}
 		}
-		bURL = r.buildURLFromJobURL(jURL, build.RDC)
 
 		if bURL == "" {
 			bURL = "N/A"
@@ -100,24 +92,6 @@ func (r *Reporter) ArtifactRequirements() []report.ArtifactType {
 	return nil
 }
 
-func (r *Reporter) buildURLFromJobURL(jobURL string, buildSource build.Source) string {
-	pURL, err := url.Parse(jobURL)
-	if err != nil {
-		log.Debug().Err(err).Msgf("Failed to parse job url (%s)", jobURL)
-		return ""
-	}
-	p := strings.Split(pURL.Path, "/")
-	jID := p[len(p)-1]
-
-	bID, err := r.Service.GetBuildID(context.Background(), jID, buildSource)
-	if err != nil {
-		log.Debug().Err(err).Msgf("Failed to retrieve build id for job (%s)", jID)
-		return ""
-	}
-
-	return fmt.Sprintf("%s://%s/builds/%s/%s", pURL.Scheme, pURL.Host, buildSource, bID)
-}
-
 func printPadding(repeat int) {
 	fmt.Print(strings.Repeat("\n", repeat))
 }
diff --git a/internal/report/json/json.go b/internal/report/json/json.go
index 61b1cda0e..76d20cad3 100644
--- a/internal/report/json/json.go
+++ b/internal/report/json/json.go
@@ -2,23 +2,17 @@ package json
 
 import (
 	"bytes"
-	"context"
 	"encoding/json"
-	"fmt"
 	"io"
 	"net/http"
-	"net/url"
 	"os"
-	"strings"
 
 	"github.com/rs/zerolog/log"
-	"github.com/saucelabs/saucectl/internal/build"
 	"github.com/saucelabs/saucectl/internal/report"
 )
 
 // Reporter represents struct to report in json format
 type Reporter struct {
-	Service    build.Reader
 	WebhookURL string
 	Filename   string
 	Results    []report.TestResult
@@ -32,7 +26,6 @@ func (r *Reporter) Add(t report.TestResult) {
 // Render sends the result to specified webhook WebhookURL and log the result to the specified json file
 func (r *Reporter) Render() {
 	r.cleanup()
-	r.buildData()
 	body, err := json.Marshal(r.Results)
 	if err != nil {
 		log.Error().Msgf("failed to generate test result (%v)", err)
@@ -86,52 +79,3 @@ func (r *Reporter) Reset() {
 func (r *Reporter) ArtifactRequirements() []report.ArtifactType {
 	return nil
 }
-
-func (r *Reporter) buildData() {
-	if len(r.Results) < 1 {
-		return
-	}
-
-	var vdcJobURL string
-	var rdcJobURL string
-	for _, result := range r.Results {
-		if !result.RDC && result.URL != "" {
-			vdcJobURL = result.URL
-			break
-		}
-	}
-	for _, result := range r.Results {
-		if result.RDC && result.URL != "" {
-			rdcJobURL = result.URL
-			break
-		}
-	}
-	vdcBuildURL := r.getBuildURL(vdcJobURL, build.VDC)
-	rdcBuildURL := r.getBuildURL(rdcJobURL, build.RDC)
-	for i, result := range r.Results {
-		if !result.RDC {
-			result.BuildURL = vdcBuildURL
-		} else {
-			result.BuildURL = rdcBuildURL
-		}
-		r.Results[i] = result
-	}
-}
-
-func (r *Reporter) getBuildURL(jobURL string, buildSource build.Source) string {
-	pURL, err := url.Parse(jobURL)
-	if err != nil {
-		log.Debug().Err(err).Msgf("Failed to parse job url (%s)", jobURL)
-		return ""
-	}
-	p := strings.Split(pURL.Path, "/")
-	jID := p[len(p)-1]
-
-	bID, err := r.Service.GetBuildID(context.Background(), jID, buildSource)
-	if err != nil {
-		log.Debug().Err(err).Msgf("Failed to retrieve build id for job (%s)", jID)
-		return ""
-	}
-
-	return fmt.Sprintf("%s://%s/builds/%s/%s", pURL.Scheme, pURL.Host, buildSource, bID)
-}
diff --git a/internal/saucecloud/cloud.go b/internal/saucecloud/cloud.go
index dd31b2197..4c7d22aef 100644
--- a/internal/saucecloud/cloud.go
+++ b/internal/saucecloud/cloud.go
@@ -6,6 +6,7 @@ import (
 	"errors"
 	"fmt"
 	"io"
+	"net/url"
 	"os"
 	"os/signal"
 	"path"
@@ -155,6 +156,7 @@ func (r *CloudRunner) collectResults(artifactCfg config.ArtifactDownload, result
 			if res.job.ID != "" {
 				url = fmt.Sprintf("%s/tests/%s", r.Region.AppBaseURL(), res.job.ID)
 			}
+			buildURL := r.getBuildURL(url, res.job.IsRDC)
 			tr := report.TestResult{
 				Name:       res.name,
 				Duration:   res.duration,
@@ -170,6 +172,7 @@ func (r *CloudRunner) collectResults(artifactCfg config.ArtifactDownload, result
 				RDC:        res.job.IsRDC,
 				TimedOut:   res.job.TimedOut,
 				Attempts:   res.attempts,
+				BuildURL:   buildURL,
 			}
 			for _, rep := range r.Reporters {
 				rep.Add(tr)
@@ -195,6 +198,28 @@ func (r *CloudRunner) collectResults(artifactCfg config.ArtifactDownload, result
 	return passed
 }
 
+func (r *CloudRunner) getBuildURL(jobURL string, isRDC bool) string {
+	pURL, err := url.Parse(jobURL)
+	if err != nil {
+		log.Debug().Err(err).Msgf("Failed to parse job url (%s)", jobURL)
+		return ""
+	}
+	p := strings.Split(pURL.Path, "/")
+	jID := p[len(p)-1]
+
+	buildSource := build.RDC
+	if !isRDC {
+		buildSource = build.VDC
+	}
+	bID, err := r.BuildService.GetBuildID(context.Background(), jID, buildSource)
+	if err != nil {
+		log.Debug().Err(err).Msgf("Failed to retrieve build id for job (%s)", jID)
+		return ""
+	}
+
+	return fmt.Sprintf("%s://%s/builds/%s/%s", pURL.Scheme, pURL.Host, buildSource, bID)
+}
+
 func (r *CloudRunner) runJob(opts job.StartOptions) (j job.Job, skipped bool, err error) {
 	log.Info().Str("suite", opts.DisplayName).Str("region", r.Region.String()).Msg("Starting suite.")
 

From 0bf60e46cfab2a8f2bfdaa24cee3f8eb1a2f2609 Mon Sep 17 00:00:00 2001
From: Tian Feng <tian.feng@saucelabs.com>
Date: Wed, 1 Nov 2023 12:03:06 -0700
Subject: [PATCH 3/9] make buildURL omitempty

---
 internal/report/report.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/internal/report/report.go b/internal/report/report.go
index f2c3c4ac6..a2b1ab42a 100644
--- a/internal/report/report.go
+++ b/internal/report/report.go
@@ -35,7 +35,7 @@ type TestResult struct {
 	URL           string        `json:"url"`
 	Artifacts     []Artifact    `json:"artifacts,omitempty"`
 	Origin        string        `json:"origin"`
-	BuildURL      string        `json:"buildURL"`
+	BuildURL      string        `json:"buildURL,omitempty"`
 	RDC           bool          `json:"-"`
 	TimedOut      bool          `json:"-"`
 	PassThreshold bool          `json:"-"`

From 2c2e762a8a6bde1fd40d3796b357214a750b1858 Mon Sep 17 00:00:00 2001
From: Tian Feng <tian.feng@saucelabs.com>
Date: Wed, 1 Nov 2023 13:29:59 -0700
Subject: [PATCH 4/9] refine

---
 internal/saucecloud/cloud.go | 19 +++++--------------
 1 file changed, 5 insertions(+), 14 deletions(-)

diff --git a/internal/saucecloud/cloud.go b/internal/saucecloud/cloud.go
index 4c7d22aef..87e4967a6 100644
--- a/internal/saucecloud/cloud.go
+++ b/internal/saucecloud/cloud.go
@@ -6,7 +6,6 @@ import (
 	"errors"
 	"fmt"
 	"io"
-	"net/url"
 	"os"
 	"os/signal"
 	"path"
@@ -156,7 +155,7 @@ func (r *CloudRunner) collectResults(artifactCfg config.ArtifactDownload, result
 			if res.job.ID != "" {
 				url = fmt.Sprintf("%s/tests/%s", r.Region.AppBaseURL(), res.job.ID)
 			}
-			buildURL := r.getBuildURL(url, res.job.IsRDC)
+			buildURL := r.getBuildURL(res.job.ID, res.job.IsRDC)
 			tr := report.TestResult{
 				Name:       res.name,
 				Duration:   res.duration,
@@ -198,26 +197,18 @@ func (r *CloudRunner) collectResults(artifactCfg config.ArtifactDownload, result
 	return passed
 }
 
-func (r *CloudRunner) getBuildURL(jobURL string, isRDC bool) string {
-	pURL, err := url.Parse(jobURL)
-	if err != nil {
-		log.Debug().Err(err).Msgf("Failed to parse job url (%s)", jobURL)
-		return ""
-	}
-	p := strings.Split(pURL.Path, "/")
-	jID := p[len(p)-1]
-
+func (r *CloudRunner) getBuildURL(jobID string, isRDC bool) string {
 	buildSource := build.RDC
 	if !isRDC {
 		buildSource = build.VDC
 	}
-	bID, err := r.BuildService.GetBuildID(context.Background(), jID, buildSource)
+	bID, err := r.BuildService.GetBuildID(context.Background(), jobID, buildSource)
 	if err != nil {
-		log.Debug().Err(err).Msgf("Failed to retrieve build id for job (%s)", jID)
+		log.Debug().Err(err).Msgf("Failed to retrieve build id for job (%s)", jobID)
 		return ""
 	}
 
-	return fmt.Sprintf("%s://%s/builds/%s/%s", pURL.Scheme, pURL.Host, buildSource, bID)
+	return fmt.Sprintf("%s/builds/%s/%s", r.Region.AppBaseURL(), buildSource, bID)
 }
 
 func (r *CloudRunner) runJob(opts job.StartOptions) (j job.Job, skipped bool, err error) {

From a8fa20f9da0f19d5fbcbf22d5d3bd0f6919efdb3 Mon Sep 17 00:00:00 2001
From: Tian Feng <tian.feng@saucelabs.com>
Date: Wed, 1 Nov 2023 14:26:39 -0700
Subject: [PATCH 5/9] add cached build url

---
 internal/saucecloud/cloud.go | 21 +++++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/internal/saucecloud/cloud.go b/internal/saucecloud/cloud.go
index 87e4967a6..49383ae99 100644
--- a/internal/saucecloud/cloud.go
+++ b/internal/saucecloud/cloud.go
@@ -64,6 +64,8 @@ type CloudRunner struct {
 	NPMDependencies []string
 
 	interrupted bool
+	VDCBuildURL string
+	RDCBuildURL string
 }
 
 type result struct {
@@ -198,17 +200,32 @@ func (r *CloudRunner) collectResults(artifactCfg config.ArtifactDownload, result
 }
 
 func (r *CloudRunner) getBuildURL(jobID string, isRDC bool) string {
-	buildSource := build.RDC
+	var buildSource build.Source
 	if !isRDC {
+		if r.VDCBuildURL != "" {
+			return r.VDCBuildURL
+		}
 		buildSource = build.VDC
+	} else {
+		if r.RDCBuildURL != "" {
+			return r.RDCBuildURL
+		}
+		buildSource = build.RDC
 	}
+
 	bID, err := r.BuildService.GetBuildID(context.Background(), jobID, buildSource)
 	if err != nil {
 		log.Debug().Err(err).Msgf("Failed to retrieve build id for job (%s)", jobID)
 		return ""
 	}
 
-	return fmt.Sprintf("%s/builds/%s/%s", r.Region.AppBaseURL(), buildSource, bID)
+	bURL := fmt.Sprintf("%s/builds/%s/%s", r.Region.AppBaseURL(), buildSource, bID)
+	if !isRDC {
+		r.VDCBuildURL = bURL
+	} else {
+		r.RDCBuildURL = bURL
+	}
+	return bURL
 }
 
 func (r *CloudRunner) runJob(opts job.StartOptions) (j job.Job, skipped bool, err error) {

From 082d67d7696cb74761326894dd640ab820fee402 Mon Sep 17 00:00:00 2001
From: Tian Feng <tian.feng@saucelabs.com>
Date: Wed, 1 Nov 2023 14:41:28 -0700
Subject: [PATCH 6/9] re-structure the CloudRunner structure

---
 internal/saucecloud/cloud.go | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/internal/saucecloud/cloud.go b/internal/saucecloud/cloud.go
index 49383ae99..c5262c51d 100644
--- a/internal/saucecloud/cloud.go
+++ b/internal/saucecloud/cloud.go
@@ -64,6 +64,10 @@ type CloudRunner struct {
 	NPMDependencies []string
 
 	interrupted bool
+	CachedData  CachedData
+}
+
+type CachedData struct {
 	VDCBuildURL string
 	RDCBuildURL string
 }
@@ -202,13 +206,13 @@ func (r *CloudRunner) collectResults(artifactCfg config.ArtifactDownload, result
 func (r *CloudRunner) getBuildURL(jobID string, isRDC bool) string {
 	var buildSource build.Source
 	if !isRDC {
-		if r.VDCBuildURL != "" {
-			return r.VDCBuildURL
+		if r.CachedData.VDCBuildURL != "" {
+			return r.CachedData.VDCBuildURL
 		}
 		buildSource = build.VDC
 	} else {
-		if r.RDCBuildURL != "" {
-			return r.RDCBuildURL
+		if r.CachedData.RDCBuildURL != "" {
+			return r.CachedData.RDCBuildURL
 		}
 		buildSource = build.RDC
 	}
@@ -221,9 +225,9 @@ func (r *CloudRunner) getBuildURL(jobID string, isRDC bool) string {
 
 	bURL := fmt.Sprintf("%s/builds/%s/%s", r.Region.AppBaseURL(), buildSource, bID)
 	if !isRDC {
-		r.VDCBuildURL = bURL
+		r.CachedData.VDCBuildURL = bURL
 	} else {
-		r.RDCBuildURL = bURL
+		r.CachedData.RDCBuildURL = bURL
 	}
 	return bURL
 }

From 442fa0b575270d5a62ae3848f8733dc2c2a05aa8 Mon Sep 17 00:00:00 2001
From: Tian Feng <tian.feng@saucelabs.com>
Date: Wed, 1 Nov 2023 14:57:57 -0700
Subject: [PATCH 7/9] change log level

---
 internal/saucecloud/cloud.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/internal/saucecloud/cloud.go b/internal/saucecloud/cloud.go
index c5262c51d..6207c5402 100644
--- a/internal/saucecloud/cloud.go
+++ b/internal/saucecloud/cloud.go
@@ -219,7 +219,7 @@ func (r *CloudRunner) getBuildURL(jobID string, isRDC bool) string {
 
 	bID, err := r.BuildService.GetBuildID(context.Background(), jobID, buildSource)
 	if err != nil {
-		log.Debug().Err(err).Msgf("Failed to retrieve build id for job (%s)", jobID)
+		log.Warn().Err(err).Msgf("Failed to retrieve build id for job (%s)", jobID)
 		return ""
 	}
 

From cfdd18c2b98ef7cb1fbcd05adee9fc8041dddf75 Mon Sep 17 00:00:00 2001
From: Tian Feng <tian.feng@saucelabs.com>
Date: Wed, 1 Nov 2023 16:57:19 -0700
Subject: [PATCH 8/9] Update internal/saucecloud/cloud.go

Co-authored-by: Alex Plischke <alex.plischke@saucelabs.com>
---
 internal/saucecloud/cloud.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/internal/saucecloud/cloud.go b/internal/saucecloud/cloud.go
index 6207c5402..92879f315 100644
--- a/internal/saucecloud/cloud.go
+++ b/internal/saucecloud/cloud.go
@@ -64,10 +64,10 @@ type CloudRunner struct {
 	NPMDependencies []string
 
 	interrupted bool
-	CachedData  CachedData
+	Cache  Cache
 }
 
-type CachedData struct {
+type Cache struct {
 	VDCBuildURL string
 	RDCBuildURL string
 }

From 41cff9c81c1b2b53cb7fc53945c3978f93554234 Mon Sep 17 00:00:00 2001
From: Tian Feng <tian.feng@saucelabs.com>
Date: Wed, 1 Nov 2023 16:58:10 -0700
Subject: [PATCH 9/9] rename CachedData to Cache

---
 internal/saucecloud/cloud.go | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/internal/saucecloud/cloud.go b/internal/saucecloud/cloud.go
index 92879f315..f891cb8e1 100644
--- a/internal/saucecloud/cloud.go
+++ b/internal/saucecloud/cloud.go
@@ -64,7 +64,7 @@ type CloudRunner struct {
 	NPMDependencies []string
 
 	interrupted bool
-	Cache  Cache
+	Cache       Cache
 }
 
 type Cache struct {
@@ -206,13 +206,13 @@ func (r *CloudRunner) collectResults(artifactCfg config.ArtifactDownload, result
 func (r *CloudRunner) getBuildURL(jobID string, isRDC bool) string {
 	var buildSource build.Source
 	if !isRDC {
-		if r.CachedData.VDCBuildURL != "" {
-			return r.CachedData.VDCBuildURL
+		if r.Cache.VDCBuildURL != "" {
+			return r.Cache.VDCBuildURL
 		}
 		buildSource = build.VDC
 	} else {
-		if r.CachedData.RDCBuildURL != "" {
-			return r.CachedData.RDCBuildURL
+		if r.Cache.RDCBuildURL != "" {
+			return r.Cache.RDCBuildURL
 		}
 		buildSource = build.RDC
 	}
@@ -225,9 +225,9 @@ func (r *CloudRunner) getBuildURL(jobID string, isRDC bool) string {
 
 	bURL := fmt.Sprintf("%s/builds/%s/%s", r.Region.AppBaseURL(), buildSource, bID)
 	if !isRDC {
-		r.CachedData.VDCBuildURL = bURL
+		r.Cache.VDCBuildURL = bURL
 	} else {
-		r.CachedData.RDCBuildURL = bURL
+		r.Cache.RDCBuildURL = bURL
 	}
 	return bURL
 }