Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/commit/commit.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type Commit struct {
Message string `json:"message" mapstructure:"message"`
Summary *common.RenderedText `json:"summary,omitempty" mapstructure:"summary"`
Rendered *RenderedMessage `json:"rendered,omitempty" mapstructure:"rendered"`
Parents []CommitReference `json:"parents" mapstructure:"parents"`
Parents []CommitReference `json:"parents,omitempty" mapstructure:"parents"`
Date time.Time `json:"date" mapstructure:"date"`
Repository repository.Repository `json:"repository" mapstructure:"repository"`
Links common.Links `json:"links" mapstructure:"links"`
Expand Down
7 changes: 7 additions & 0 deletions cmd/common/selector.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package common

// Selector represents a selector for references (pipelines, branches, tags, etc.)
type Selector struct {
Type string `json:"type" mapstructure:"type"`
Pattern string `json:"pattern,omitempty" mapstructure:"pattern"`
}
45 changes: 11 additions & 34 deletions cmd/pipeline/pipeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,6 @@ type ConfigurationSource struct {
URI string `json:"uri" mapstructure:"uri"`
}

// TriggerBody represents the body for triggering a pipeline
type TriggerBody struct {
Target Target `json:"target"`
Variables []Variable `json:"variables,omitempty"`
}

// Command represents this folder's command
var Command = &cobra.Command{
Use: "pipeline",
Expand All @@ -84,18 +78,7 @@ var columns = common.Columns[Pipeline]{
return strings.Compare(strings.ToLower(a.State.Name), strings.ToLower(b.State.Name)) == -1
}},
{Name: "branch", DefaultSorter: false, Compare: func(a, b Pipeline) bool {
return strings.Compare(strings.ToLower(a.Target.RefName), strings.ToLower(b.Target.RefName)) == -1
}},
{Name: "commit", DefaultSorter: false, Compare: func(a, b Pipeline) bool {
aHash := ""
bHash := ""
if a.Target.Commit != nil {
aHash = a.Target.Commit.Hash
}
if b.Target.Commit != nil {
bHash = b.Target.Commit.Hash
}
return strings.Compare(strings.ToLower(aHash), strings.ToLower(bHash)) == -1
return strings.Compare(strings.ToLower(a.Target.GetDestination()), strings.ToLower(b.Target.GetDestination())) == -1
}},
{Name: "creator", DefaultSorter: false, Compare: func(a, b Pipeline) bool {
return strings.Compare(strings.ToLower(a.Creator.Name), strings.ToLower(b.Creator.Name)) == -1
Expand Down Expand Up @@ -161,17 +144,7 @@ func (pipeline Pipeline) GetRow(headers []string) []string {
case "state":
row = append(row, pipeline.State.String())
case "branch":
row = append(row, pipeline.Target.RefName)
case "commit":
if pipeline.Target.Commit != nil {
hash := pipeline.Target.Commit.Hash
if len(hash) > 7 {
hash = hash[:7]
}
row = append(row, hash)
} else {
row = append(row, " ")
}
row = append(row, pipeline.Target.GetDestination())
case "creator":
row = append(row, pipeline.Creator.Name)
case "duration":
Expand Down Expand Up @@ -233,16 +206,17 @@ func (pipeline Pipeline) MarshalJSON() (data []byte, err error) {
// UnmarshalJSON implements the json.Unmarshaler interface.
//
// implements json.Unmarshaler
func (pipeline *Pipeline) UnmarshalJSON(data []byte) error {
func (pipeline *Pipeline) UnmarshalJSON(data []byte) (err error) {
type surrogate Pipeline
var inner struct {
Type string `json:"type"`
surrogate
CreatedOn core.Time `json:"created_on"`
CompletedOn core.Time `json:"completed_on,omitempty"`
DurationInSeconds uint64 `json:"duration_in_seconds"`
Target json.RawMessage `json:"target"`
CreatedOn core.Time `json:"created_on"`
CompletedOn core.Time `json:"completed_on,omitempty"`
DurationInSeconds uint64 `json:"duration_in_seconds"`
}
if err := json.Unmarshal(data, &inner); err != nil {
if err = json.Unmarshal(data, &inner); err != nil {
return errors.JSONUnmarshalError.WrapIfNotMe(err)
}
if inner.Type != pipeline.GetType() {
Expand All @@ -252,5 +226,8 @@ func (pipeline *Pipeline) UnmarshalJSON(data []byte) error {
pipeline.CreatedOn = time.Time(inner.CreatedOn)
pipeline.CompletedOn = time.Time(inner.CompletedOn)
pipeline.Duration = time.Duration(inner.DurationInSeconds) * time.Second
if pipeline.Target, err = UnmarshalTarget(inner.Target); err != nil {
return errors.JSONUnmarshalError.WrapIfNotMe(err)
}
return errors.JSONUnmarshalError.Wrap(pipeline.Validate())
}
89 changes: 63 additions & 26 deletions cmd/pipeline/pipeline_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,21 +87,62 @@ func (suite *PipelineSuite) UnmarshalData(filename string, v any) error {
// *****************************************************************************

func (suite *PipelineSuite) TestCanUnmarshal() {
var pipeline pipeline.Pipeline
err := suite.UnmarshalData("pipeline.json", &pipeline)
var pl pipeline.Pipeline
err := suite.UnmarshalData("pipeline.json", &pl)
suite.Require().NoError(err)
suite.Require().NotNil(pipeline)
suite.Assert().Equal("{a1b2c3d4-e5f6-7890-abcd-ef1234567890}", pipeline.ID.String())
suite.Assert().Equal(uint64(42), pipeline.BuildNumber)
suite.Assert().Equal("COMPLETED", pipeline.State.Name)
suite.Assert().NotNil(pipeline.State.Result)
suite.Assert().Equal("SUCCESSFUL", pipeline.State.Result.Name)
suite.Assert().Equal("branch", pipeline.Target.RefType)
suite.Assert().Equal("main", pipeline.Target.RefName)
suite.Assert().Equal("abc123def456", pipeline.Target.Commit.Hash)
suite.Assert().Equal(330*time.Second, pipeline.Duration)
suite.Assert().Equal("John Developer", pipeline.Creator.Name)
suite.Assert().Equal("myworkspace/my-repo", pipeline.Repository.FullName)
suite.Assert().Equal("{a1b2c3d4-e5f6-7890-abcd-ef1234567890}", pl.ID.String())
suite.Assert().Equal(uint64(42), pl.BuildNumber)
suite.Assert().Equal("COMPLETED", pl.State.Name)
suite.Require().NotNil(pl.State.Result)
suite.Assert().Equal("SUCCESSFUL", pl.State.Result.Name)
suite.Assert().Equal(330*time.Second, pl.Duration)
suite.Assert().Equal(uuid.MustParse("12345678-1234-1234-1234-123456789012"), uuid.UUID(pl.Creator.ID))
suite.Assert().Equal("557058:12345678-abcd-efgh-ijkl-123456789012", pl.Creator.AccountID)
suite.Assert().Equal("John Developer", pl.Creator.Name)
suite.Assert().Equal("johnd", pl.Creator.Nickname)
suite.Assert().Equal("myworkspace/my-repo", pl.Repository.FullName)

suite.Require().NotNil(pl.Target)
suite.Assert().Equal("main", pl.Target.GetDestination())
suite.Assert().Equal("abc123def456", pl.Target.GetCommit().Hash)

target, ok := pl.Target.(*pipeline.ReferenceTarget)
suite.Require().True(ok)
suite.Assert().Equal("branch", target.ReferenceType)
suite.Assert().Equal("main", target.ReferenceName)
suite.Assert().Equal("abc123def456", target.Commit.Hash)
}

func (suite *PipelineSuite) TestCanUnmarshalWithPullRequest() {
var pl pipeline.Pipeline
err := suite.UnmarshalData("pipeline-pullrequest.json", &pl)
suite.Require().NoError(err)
suite.Assert().Equal("{a1b2c3d4-e5f6-7890-abcd-ef1234567890}", pl.ID.String())
suite.Assert().Equal(uint64(42), pl.BuildNumber)
suite.Assert().Equal("COMPLETED", pl.State.Name)
suite.Require().NotNil(pl.State.Result)
suite.Assert().Equal("FAILED", pl.State.Result.Name)
suite.Assert().Equal(330*time.Second, pl.Duration)
suite.Assert().Equal(uuid.MustParse("12345678-1234-1234-1234-123456789012"), uuid.UUID(pl.Creator.ID))
suite.Assert().Equal("557058:12345678-abcd-efgh-ijkl-123456789012", pl.Creator.AccountID)
suite.Assert().Equal("John Developer", pl.Creator.Name)
suite.Assert().Equal("johnd", pl.Creator.Nickname)
suite.Assert().Equal("myworkspace/my-repo", pl.Repository.FullName)

suite.Require().NotNil(pl.Target)
suite.Assert().Equal("main", pl.Target.GetDestination())
suite.Assert().Equal("3c80cde6b371", pl.Target.GetCommit().Hash)

target, ok := pl.Target.(*pipeline.PullRequestReferenceTarget)
suite.Require().True(ok)
suite.Assert().Equal("main", target.Destination)
suite.Assert().Equal("abc123def456", target.DestinationCommit.Hash)
suite.Assert().Equal("custom", target.Selector.Type)
suite.Assert().Equal("run-tests", target.Selector.Pattern)
suite.Assert().Equal("3c80cde6b371", target.Commit.Hash)
suite.Assert().Equal(uint64(62), target.PullRequest.ID)
suite.Assert().Equal("feat: add API key authentication", target.PullRequest.Title)
suite.Assert().False(target.PullRequest.IsDraft)
}

func (suite *PipelineSuite) TestCanMarshal() {
Expand All @@ -117,16 +158,12 @@ func (suite *PipelineSuite) TestCanMarshal() {
Name: "SUCCESSFUL",
},
},
Target: pipeline.Target{
Type: "pipeline_ref_target",
RefType: "branch",
RefName: "main",
Commit: &commit.Commit{
Hash: "abc123def456",
},
Selector: &pipeline.Selector{
Type: "default",
},
Target: pipeline.ReferenceTarget{
Type: "pipeline_ref_target",
ReferenceType: "branch",
ReferenceName: "main",
Commit: commit.CommitReference{Hash: "abc123def456"},
Selector: &common.Selector{Type: "default"},
},
CreatedOn: time.Date(2024, 1, 15, 10, 30, 0, 0, time.UTC),
CompletedOn: time.Date(2024, 1, 15, 10, 35, 30, 0, time.UTC),
Expand All @@ -145,13 +182,13 @@ func (suite *PipelineSuite) TestCanMarshal() {
},
Repository: pipeline.Repository{
Type: "repository",
UUID: "{repo-uuid-1234-5678-abcd}",
UUID: "{12854e6a-e6f8-44ac-b006-1521931d4c0d}",
Name: "my-repo",
FullName: "myworkspace/my-repo",
Links: common.Links{
Self: &common.Link{HREF: url.URL{Scheme: "https", Host: "api.bitbucket.org", Path: "/2.0/repositories/myworkspace/my-repo"}},
HTML: &common.Link{HREF: url.URL{Scheme: "https", Host: "bitbucket.org", Path: "/myworkspace/my-repo"}},
Avatar: &common.Link{HREF: url.URL{Scheme: "https", Host: "bytebucket.org", Path: "/ravatar/{repo-uuid}"}},
Avatar: &common.Link{HREF: url.URL{Scheme: "https", Host: "bytebucket.org", Path: "/ravatar/{12854e6a-e6f8-44ac-b006-1521931d4c0d}"}},
},
},
Links: common.Links{
Expand Down
87 changes: 24 additions & 63 deletions cmd/pipeline/target.go
Original file line number Diff line number Diff line change
@@ -1,76 +1,37 @@
package pipeline

import (
"encoding/json"
"strings"

"bitbucket.org/gildas_cherruel/bb/cmd/commit"
"github.com/gildas/go-core"
"github.com/gildas/go-errors"
)

// Target represents the target of a pipeline (branch, tag, etc.)
type Target struct {
Type string `json:"type" mapstructure:"type"`
RefType string `json:"ref_type,omitempty" mapstructure:"ref_type"`
RefName string `json:"ref_name,omitempty" mapstructure:"ref_name"`
Selector *Selector `json:"selector,omitempty" mapstructure:"selector"`
Commit *commit.Commit `json:"commit,omitempty" mapstructure:"commit"`
type Target interface {
core.TypeCarrier
GetDestination() string
GetCommit() commit.CommitReference
}

// Selector represents a pipeline selector for custom pipelines
type Selector struct {
Type string `json:"type" mapstructure:"type"`
Pattern string `json:"pattern,omitempty" mapstructure:"pattern"`
}

// GetType returns the target type
func (target Target) GetType() string {
return "pipeline_ref_target"
}

// MarshalJSON custom JSON marshalling for Target
//
// implements json.Marshaler
func (target Target) MarshalJSON() ([]byte, error) {
type surrogate Target
var commitRef *commit.CommitReference

if target.Commit != nil {
commitRef = target.Commit.GetReference()
}

data, err := json.Marshal(struct {
Type string `json:"type"`
surrogate
CommitRef *commit.CommitReference `json:"commit,omitempty"`
}{
Type: target.GetType(),
surrogate: surrogate(target),
CommitRef: commitRef,
})
return data, errors.JSONMarshalError.Wrap(err)
}

// UnmarshalJSON custom JSON unmarshalling for Target
//
// implements json.Unmarshaler
func (target *Target) UnmarshalJSON(data []byte) error {
type surrogate Target
var inner struct {
Type string `json:"type"`
surrogate
CommitReference *commit.CommitReference `json:"commit,omitempty"`
}

if err := json.Unmarshal(data, &inner); err != nil {
return errors.JSONUnmarshalError.WrapIfNotMe(err)
var targetRegistry = core.TypeRegistry{}

// UnmarshalTarget unmarshals a Target from JSON data
func UnmarshalTarget(payload []byte) (Target, error) {
target, err := targetRegistry.UnmarshalJSON(payload)
if err != nil {
if strings.HasPrefix(err.Error(), "Missing JSON Property") {
return nil, errors.JSONUnmarshalError.Wrap(errors.ArgumentMissing.With("type"))
}
if strings.HasPrefix(err.Error(), "Unsupported Type") {
keys := make([]string, 0, len(targetRegistry))
for key := range targetRegistry {
keys = append(keys, key)
}
return nil, errors.JSONUnmarshalError.Wrap(errors.InvalidType.With(strings.TrimSuffix(strings.TrimPrefix(err.Error(), `Unsupported Type "`), `"`), strings.Join(keys, ", ")))
}
return nil, err
}
if inner.Type != target.GetType() {
return errors.JSONUnmarshalError.Wrap(errors.InvalidType.With(inner.Type, target.GetType()))
}
*target = Target(inner.surrogate)
if inner.CommitReference != nil {
target.Commit = inner.CommitReference.AsCommit()
}

return nil
return target.(Target), nil
}
42 changes: 42 additions & 0 deletions cmd/pipeline/target_pullrequest_reference.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package pipeline

import (
"bitbucket.org/gildas_cherruel/bb/cmd/commit"
"bitbucket.org/gildas_cherruel/bb/cmd/common"
"bitbucket.org/gildas_cherruel/bb/cmd/pullrequest"
)

// PullRequestReferenceTarget represents a target for a pipeline that is a pull request reference.
type PullRequestReferenceTarget struct {
Source string `json:"source" mapstructure:"source"`
Destination string `json:"destination" mapstructure:"destination"`
DestinationCommit commit.CommitReference `json:"destination_commit" mapstructure:"destination_commit"`
Commit commit.CommitReference `json:"commit" mapstructure:"commit"`
Selector *common.Selector `json:"selector,omitempty" mapstructure:"selector"`
PullRequest pullrequest.PullRequestReference `json:"pullrequest" mapstructure:"pullrequest"`
}

func init() {
targetRegistry.Add(PullRequestReferenceTarget{})
}

// GetType returns the type of the PullRequestReferenceTarget.
//
// implements core.TypeCarrier
func (target PullRequestReferenceTarget) GetType() string {
return "pipeline_pullrequest_target"
}

// GetDestination returns the destination of the PullRequestReferenceTarget.
//
// implements Target
func (target PullRequestReferenceTarget) GetDestination() string {
return target.Destination
}

// GetCommit returns the commit of the PullRequestReferenceTarget.
//
// implements Target
func (target PullRequestReferenceTarget) GetCommit() commit.CommitReference {
return target.Commit
}
Loading
Loading