Skip to content

Commit

Permalink
Add modules from published build info to command summary (#1215)
Browse files Browse the repository at this point in the history
  • Loading branch information
RobiNino authored Jul 30, 2024
1 parent 79d6835 commit a84d4ae
Show file tree
Hide file tree
Showing 12 changed files with 290 additions and 55 deletions.
24 changes: 10 additions & 14 deletions artifactory/commands/buildinfo/publish.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,12 @@ func (bpc *BuildPublishCommand) Run() error {
return err
}

buildLink, err := bpc.constructBuildInfoUiUrl(servicesManager, buildInfo.Started)
majorVersion, err := utils.GetRtMajorVersion(servicesManager)
if err != nil {
return err
}

buildLink, err := bpc.constructBuildInfoUiUrl(majorVersion, buildInfo.Started)
if err != nil {
return err
}
Expand All @@ -141,7 +146,7 @@ func (bpc *BuildPublishCommand) Run() error {
return err
}

if err = recordCommandSummary(buildInfo, buildLink); err != nil {
if err = recordCommandSummary(buildInfo, buildLink, bpc.serverDetails.Url, bpc.buildConfiguration.GetProject(), majorVersion); err != nil {
return err
}

Expand All @@ -165,20 +170,11 @@ func logJsonOutput(buildInfoUiUrl string) error {
return nil
}

func (bpc *BuildPublishCommand) constructBuildInfoUiUrl(servicesManager artifactory.ArtifactoryServicesManager, buildInfoStarted string) (string, error) {
func (bpc *BuildPublishCommand) constructBuildInfoUiUrl(majorVersion int, buildInfoStarted string) (string, error) {
buildTime, err := time.Parse(buildinfo.TimeFormat, buildInfoStarted)
if errorutils.CheckError(err) != nil {
return "", err
}
artVersion, err := servicesManager.GetVersion()
if err != nil {
return "", err
}
artVersionSlice := strings.Split(artVersion, ".")
majorVersion, err := strconv.Atoi(artVersionSlice[0])
if errorutils.CheckError(err) != nil {
return "", err
}
return bpc.getBuildInfoUiUrl(majorVersion, buildTime)
}

Expand Down Expand Up @@ -236,12 +232,12 @@ func (bpc *BuildPublishCommand) getNextBuildNumber(buildName string, servicesMan
return strconv.Itoa(latestBuildNumber), nil
}

func recordCommandSummary(buildInfo *buildinfo.BuildInfo, buildLink string) (err error) {
func recordCommandSummary(buildInfo *buildinfo.BuildInfo, buildLink, serverUrl, projectKey string, majorVersion int) (err error) {
if !commandsummary.ShouldRecordSummary() {
return
}
buildInfo.BuildUrl = buildLink
buildInfoSummary, err := commandsummary.New(commandssummaries.NewBuildInfo(), "build-info")
buildInfoSummary, err := commandsummary.New(commandssummaries.NewBuildInfo(serverUrl, projectKey, majorVersion), "build-info")
if err != nil {
return
}
Expand Down
64 changes: 59 additions & 5 deletions artifactory/commands/commandssummaries/buildinfosummary.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,29 @@ package commandssummaries
import (
"fmt"
buildInfo "github.com/jfrog/build-info-go/entities"
"github.com/jfrog/jfrog-cli-core/v2/artifactory/utils"
"github.com/jfrog/jfrog-cli-core/v2/commandsummary"
"path"
"strings"
"time"
)

const timeFormat = "Jan 2, 2006 , 15:04:05"
const (
timeFormat = "Jan 2, 2006 , 15:04:05"
)

type BuildInfoSummary struct{}
type BuildInfoSummary struct {
platformUrl string
projectKey string
majorVersion int
}

func NewBuildInfo() *BuildInfoSummary {
return &BuildInfoSummary{}
func NewBuildInfo(platformUrl, projectKey string, majorVersion int) *BuildInfoSummary {
return &BuildInfoSummary{
platformUrl: platformUrl,
projectKey: projectKey,
majorVersion: majorVersion,
}
}

func (bis *BuildInfoSummary) GenerateMarkdownFromFiles(dataFilePaths []string) (finalMarkdown string, err error) {
Expand All @@ -28,14 +40,15 @@ func (bis *BuildInfoSummary) GenerateMarkdownFromFiles(dataFilePaths []string) (
}

if len(builds) > 0 {
finalMarkdown = bis.buildInfoTable(builds)
finalMarkdown = bis.buildInfoTable(builds) + bis.buildInfoModules(builds)
}
return
}

func (bis *BuildInfoSummary) buildInfoTable(builds []*buildInfo.BuildInfo) string {
// Generate a string that represents a Markdown table
var tableBuilder strings.Builder
tableBuilder.WriteString("\n\n ### Published Build Infos \n\n")
tableBuilder.WriteString("\n\n| Build Info | Time Stamp | \n")
tableBuilder.WriteString("|---------|------------| \n")
for _, build := range builds {
Expand All @@ -46,6 +59,23 @@ func (bis *BuildInfoSummary) buildInfoTable(builds []*buildInfo.BuildInfo) strin
return tableBuilder.String()
}

func (bis *BuildInfoSummary) buildInfoModules(builds []*buildInfo.BuildInfo) string {
var markdownBuilder strings.Builder
markdownBuilder.WriteString("\n\n ### Modules Published As Part of This Build \n\n")
for _, build := range builds {
for _, module := range build.Modules {
switch module.Type {
case buildInfo.Docker, buildInfo.Maven, buildInfo.Npm, buildInfo.Go, buildInfo.Generic, buildInfo.Terraform:
markdownBuilder.WriteString(bis.generateModuleMarkdown(module))
default:
// Skip unsupported module types.
continue
}
}
}
return markdownBuilder.String()
}

func parseBuildTime(timestamp string) string {
// Parse the timestamp string into a time.Time object
buildInfoTime, err := time.Parse(buildInfo.TimeFormat, timestamp)
Expand All @@ -55,3 +85,27 @@ func parseBuildTime(timestamp string) string {
// Format the time in a more human-readable format and save it in a variable
return buildInfoTime.Format(timeFormat)
}

func (bis *BuildInfoSummary) generateModuleMarkdown(module buildInfo.Module) string {
var moduleMarkdown strings.Builder
moduleMarkdown.WriteString(fmt.Sprintf("\n #### %s \n", module.Id))
artifactsTree := utils.NewFileTree()
for _, artifact := range module.Artifacts {
artifactUrlInArtifactory := bis.generateArtifactUrl(artifact)
if artifact.OriginalDeploymentRepo == "" {
// Placeholder needed to build an artifact tree when repo is missing.
artifact.OriginalDeploymentRepo = " "
}
artifactTreePath := path.Join(artifact.OriginalDeploymentRepo, artifact.Path)
artifactsTree.AddFile(artifactTreePath, artifactUrlInArtifactory)
}
moduleMarkdown.WriteString("\n\n <pre>" + artifactsTree.String() + "</pre>")
return moduleMarkdown.String()
}

func (bis *BuildInfoSummary) generateArtifactUrl(artifact buildInfo.Artifact) string {
if strings.TrimSpace(artifact.OriginalDeploymentRepo) == "" {
return ""
}
return generateArtifactUrl(bis.platformUrl, path.Join(artifact.OriginalDeploymentRepo, artifact.Path), bis.projectKey, bis.majorVersion)
}
66 changes: 64 additions & 2 deletions artifactory/commands/commandssummaries/buildinfosummary_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ package commandssummaries

import (
buildinfo "github.com/jfrog/build-info-go/entities"
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
"github.com/stretchr/testify/assert"
"os"
"path/filepath"
"strings"
"testing"
)

Expand All @@ -16,8 +20,66 @@ func TestBuildInfoTable(t *testing.T) {
BuildUrl: "http://myJFrogPlatform/builds/buildName/123",
},
}
expected := "\n\n| Build Info | Time Stamp | \n|---------|------------| \n| [buildName 123](http://myJFrogPlatform/builds/buildName/123) | May 5, 2024 , 12:47:20 |\n\n\n"
assert.Equal(t, expected, gh.buildInfoTable(builds))
assert.Equal(t, getTestDataFile(t, "table.md"), gh.buildInfoTable(builds))
}

func TestBuildInfoModules(t *testing.T) {
gh := &BuildInfoSummary{}
var builds = []*buildinfo.BuildInfo{
{
Name: "buildName",
Number: "123",
Started: "2024-05-05T12:47:20.803+0300",
BuildUrl: "http://myJFrogPlatform/builds/buildName/123",
Modules: []buildinfo.Module{
{
Type: buildinfo.Maven,
Artifacts: []buildinfo.Artifact{{
Name: "artifact1",
Path: "path/to/artifact1",
OriginalDeploymentRepo: "libs-release",
}},
// Validate that dependencies don't show.
Dependencies: []buildinfo.Dependency{{
Id: "dep1",
},
},
},
{
Type: buildinfo.Generic,
Artifacts: []buildinfo.Artifact{{
Name: "artifact2",
Path: "path/to/artifact2",
OriginalDeploymentRepo: "generic-local",
}},
},
{
// Validate that ignored types don't show.
Type: buildinfo.Gradle,
Artifacts: []buildinfo.Artifact{
{
Name: "gradleArtifact",
Path: "dir/gradleArtifact",
OriginalDeploymentRepo: "gradle-local",
},
},
},
},
},
}

assert.Equal(t, getTestDataFile(t, "modules.md"), gh.buildInfoModules(builds))
}

func getTestDataFile(t *testing.T, fileName string) string {
modulesPath := filepath.Join(".", "testdata", fileName)
content, err := os.ReadFile(modulesPath)
assert.NoError(t, err)
contentStr := string(content)
if coreutils.IsWindows() {
contentStr = strings.ReplaceAll(contentStr, "\r\n", "\n")
}
return contentStr
}

func TestParseBuildTime(t *testing.T) {
Expand Down
23 changes: 23 additions & 0 deletions artifactory/commands/commandssummaries/testdata/modules.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@


### Modules Published As Part of This Build


####


<pre>📦 libs-release
└── 📁 path
└── 📁 to
└── <a href=ui/repos/tree/General/libs-release/path/to/artifact1 target="_blank">artifact1</a>

</pre>
####


<pre>📦 generic-local
└── 📁 path
└── 📁 to
└── <a href=ui/repos/tree/General/generic-local/path/to/artifact2 target="_blank">artifact2</a>

</pre>
11 changes: 11 additions & 0 deletions artifactory/commands/commandssummaries/testdata/table.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@


### Published Build Infos



| Build Info | Time Stamp |
|---------|------------|
| [buildName 123](http://myJFrogPlatform/builds/buildName/123) | May 5, 2024 , 12:47:20 |


15 changes: 8 additions & 7 deletions artifactory/commands/commandssummaries/uploadsummary.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import (
type UploadSummary struct {
uploadTree *utils.FileTree
uploadedArtifacts ResultsWrapper
PlatformUrl string
JfrogProjectKey string
platformUrl string
projectKey string
majorVersion int
}

type UploadResult struct {
Expand All @@ -23,10 +24,11 @@ type ResultsWrapper struct {
Results []UploadResult `json:"results"`
}

func NewUploadSummary(platformUrl, projectKey string) *UploadSummary {
func NewUploadSummary(platformUrl, projectKey string, majorVersion int) *UploadSummary {
return &UploadSummary{
PlatformUrl: platformUrl,
JfrogProjectKey: projectKey,
platformUrl: platformUrl,
projectKey: projectKey,
majorVersion: majorVersion,
}
}

Expand Down Expand Up @@ -61,6 +63,5 @@ func (us *UploadSummary) generateFileTreeMarkdown() string {
}

func (us *UploadSummary) buildUiUrl(targetPath string) string {
template := "%sui/repos/tree/General/%s/?projectKey=%s"
return fmt.Sprintf(template, us.PlatformUrl, targetPath, us.JfrogProjectKey)
return generateArtifactUrl(us.platformUrl, targetPath, us.projectKey, us.majorVersion)
}
24 changes: 0 additions & 24 deletions artifactory/commands/commandssummaries/uploadsummary_test.go

This file was deleted.

23 changes: 23 additions & 0 deletions artifactory/commands/commandssummaries/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package commandssummaries

import (
"fmt"
clientUtils "github.com/jfrog/jfrog-client-go/utils"
)

const (
artifactory7UiFormat = "%sui/repos/tree/General/%s"
artifactory6UiFormat = "%sartifactory/webapp/#/artifacts/browse/tree/General/%s"
)

func generateArtifactUrl(rtUrl, pathInRt, project string, majorVersion int) string {
rtUrl = clientUtils.AddTrailingSlashIfNeeded(rtUrl)
if majorVersion == 6 {
return fmt.Sprintf(artifactory6UiFormat, rtUrl, pathInRt)
}
uri := fmt.Sprintf(artifactory7UiFormat, rtUrl, pathInRt)
if project != "" {
uri += "?projectKey=" + project
}
return uri
}
31 changes: 31 additions & 0 deletions artifactory/commands/commandssummaries/utils_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package commandssummaries

import (
"github.com/stretchr/testify/assert"
"testing"
)

const (
platformUrl = "https://myplatform.com/"
fullPath = "repo/path/file"
)

func TestGenerateArtifactUrl(t *testing.T) {
cases := []struct {
testName string
projectKey string
majorVersion int
expected string
}{
{"artifactory 7 without project", "", 7, "https://myplatform.com/ui/repos/tree/General/repo/path/file"},
{"artifactory 7 with project", "proj", 7, "https://myplatform.com/ui/repos/tree/General/repo/path/file?projectKey=proj"},
{"artifactory 6 without project", "", 6, "https://myplatform.com/artifactory/webapp/#/artifacts/browse/tree/General/repo/path/file"},
}

for _, testCase := range cases {
t.Run(testCase.testName, func(t *testing.T) {
artifactUrl := generateArtifactUrl(platformUrl, fullPath, testCase.projectKey, testCase.majorVersion)
assert.Equal(t, testCase.expected, artifactUrl)
})
}
}
Loading

0 comments on commit a84d4ae

Please sign in to comment.