Skip to content

Commit

Permalink
feat: pull request labels exposed in Pull Request generator template (a…
Browse files Browse the repository at this point in the history
…rgoproj#10204) (argoproj#11397)

Signed-off-by: maheshbaliga <[email protected]>

Signed-off-by: maheshbaliga <[email protected]>
Signed-off-by: schakrad <[email protected]>
  • Loading branch information
maheshbaliga authored and schakrad committed Mar 14, 2023
1 parent 1bcdb32 commit a50e21e
Show file tree
Hide file tree
Showing 14 changed files with 279 additions and 7 deletions.
104 changes: 104 additions & 0 deletions applicationset/controllers/applicationset_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned/fake"
"github.com/argoproj/argo-cd/v2/util/collections"
dbmocks "github.com/argoproj/argo-cd/v2/util/db/mocks"
)

Expand Down Expand Up @@ -1924,3 +1925,106 @@ func TestSetApplicationSetStatusCondition(t *testing.T) {

assert.Len(t, appSet.Status.Conditions, 3)
}

// Test app generation from a go template application set using a pull request generator
func TestGenerateAppsUsingPullRequestGenerator(t *testing.T) {
scheme := runtime.NewScheme()
client := fake.NewClientBuilder().WithScheme(scheme).Build()

for _, cases := range []struct {
name string
params []map[string]interface{}
template argov1alpha1.ApplicationSetTemplate
expectedApp []argov1alpha1.Application
}{
{
name: "Generate an application from a go template application set manifest using a pull request generator",
params: []map[string]interface{}{{
"number": "1",
"branch": "branch1",
"branch_slug": "branchSlug1",
"head_sha": "089d92cbf9ff857a39e6feccd32798ca700fb958",
"head_short_sha": "089d92cb",
"labels": []string{"label1"}}},
template: argov1alpha1.ApplicationSetTemplate{
ApplicationSetTemplateMeta: argov1alpha1.ApplicationSetTemplateMeta{
Name: "AppSet-{{.branch}}-{{.number}}",
Labels: map[string]string{
"app1": "{{index .labels 0}}",
},
},
Spec: argov1alpha1.ApplicationSpec{
Source: argov1alpha1.ApplicationSource{
RepoURL: "https://testurl/testRepo",
TargetRevision: "{{.head_short_sha}}",
},
Destination: argov1alpha1.ApplicationDestination{
Server: "https://kubernetes.default.svc",
Namespace: "AppSet-{{.branch_slug}}-{{.head_sha}}",
},
},
},
expectedApp: []argov1alpha1.Application{
{
ObjectMeta: metav1.ObjectMeta{
Name: "AppSet-branch1-1",
Labels: map[string]string{
"app1": "label1",
},
},
Spec: v1alpha1.ApplicationSpec{
Source: v1alpha1.ApplicationSource{
RepoURL: "https://testurl/testRepo",
TargetRevision: "089d92cb",
},
Destination: v1alpha1.ApplicationDestination{
Server: "https://kubernetes.default.svc",
Namespace: "AppSet-branchSlug1-089d92cbf9ff857a39e6feccd32798ca700fb958",
},
},
},
},
},
} {

t.Run(cases.name, func(t *testing.T) {

generatorMock := generatorMock{}
generator := argov1alpha1.ApplicationSetGenerator{
PullRequest: &argov1alpha1.PullRequestGenerator{},
}

generatorMock.On("GenerateParams", &generator).
Return(cases.params, nil)

generatorMock.On("GetTemplate", &generator).
Return(&cases.template, nil)

appSetReconciler := ApplicationSetReconciler{
Client: client,
Scheme: scheme,
Recorder: record.NewFakeRecorder(1),
Generators: map[string]generators.Generator{
"PullRequest": &generatorMock,
},
Renderer: &utils.Render{},
KubeClientset: kubefake.NewSimpleClientset(),
}

gotApp, _, _ := appSetReconciler.generateApplications(argov1alpha1.ApplicationSet{
Spec: argov1alpha1.ApplicationSetSpec{
GoTemplate: true,
Generators: []argov1alpha1.ApplicationSetGenerator{{
PullRequest: &argov1alpha1.PullRequestGenerator{},
}},
Template: cases.template,
},
},
)
assert.EqualValues(t, cases.expectedApp[0].ObjectMeta.Name, gotApp[0].ObjectMeta.Name)
assert.EqualValues(t, cases.expectedApp[0].Spec.Source.TargetRevision, gotApp[0].Spec.Source.TargetRevision)
assert.EqualValues(t, cases.expectedApp[0].Spec.Destination.Namespace, gotApp[0].Spec.Destination.Namespace)
assert.True(t, collections.StringMapsEqual(cases.expectedApp[0].ObjectMeta.Labels, gotApp[0].ObjectMeta.Labels))
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ spec:
template:
metadata:
name: 'myapp-{{ .branch }}-{{ .number }}'
labels:
key1: '{{ index .labels 0 }}'
spec:
source:
repoURL: 'https://github.com/myorg/myrepo.git'
Expand Down
10 changes: 8 additions & 2 deletions applicationset/generators/pull_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,19 @@ func (g *PullRequestGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha
shortSHALength = len(pull.HeadSHA)
}

params = append(params, map[string]interface{}{
paramMap := map[string]interface{}{
"number": strconv.Itoa(pull.Number),
"branch": pull.Branch,
"branch_slug": slug.Make(pull.Branch),
"head_sha": pull.HeadSHA,
"head_short_sha": pull.HeadSHA[:shortSHALength],
})
}

// PR lables will only be supported for Go Template appsets, since fasttemplate will be deprecated.
if applicationSetInfo != nil && applicationSetInfo.Spec.GoTemplate {
paramMap["labels"] = pull.Labels
}
params = append(params, paramMap)
}
return params, nil
}
Expand Down
74 changes: 70 additions & 4 deletions applicationset/generators/pull_request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ import (
func TestPullRequestGithubGenerateParams(t *testing.T) {
ctx := context.Background()
cases := []struct {
selectFunc func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error)
expected []map[string]interface{}
expectedErr error
selectFunc func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error)
expected []map[string]interface{}
expectedErr error
applicationSet argoprojiov1alpha1.ApplicationSet
}{
{
selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) {
Expand Down Expand Up @@ -107,6 +108,71 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
expected: nil,
expectedErr: fmt.Errorf("error listing repos: fake error"),
},
{
selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) {
return pullrequest.NewFakeService(
ctx,
[]*pullrequest.PullRequest{
&pullrequest.PullRequest{
Number: 1,
Branch: "branch1",
HeadSHA: "089d92cbf9ff857a39e6feccd32798ca700fb958",
Labels: []string{"preview"},
},
},
nil,
)
},
expected: []map[string]interface{}{
{
"number": "1",
"branch": "branch1",
"branch_slug": "branch1",
"head_sha": "089d92cbf9ff857a39e6feccd32798ca700fb958",
"head_short_sha": "089d92cb",
"labels": []string{"preview"},
},
},
expectedErr: nil,
applicationSet: argoprojiov1alpha1.ApplicationSet{
Spec: argoprojiov1alpha1.ApplicationSetSpec{
// Application set is using Go Template.
GoTemplate: true,
},
},
},
{
selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) {
return pullrequest.NewFakeService(
ctx,
[]*pullrequest.PullRequest{
&pullrequest.PullRequest{
Number: 1,
Branch: "branch1",
HeadSHA: "089d92cbf9ff857a39e6feccd32798ca700fb958",
Labels: []string{"preview"},
},
},
nil,
)
},
expected: []map[string]interface{}{
{
"number": "1",
"branch": "branch1",
"branch_slug": "branch1",
"head_sha": "089d92cbf9ff857a39e6feccd32798ca700fb958",
"head_short_sha": "089d92cb",
},
},
expectedErr: nil,
applicationSet: argoprojiov1alpha1.ApplicationSet{
Spec: argoprojiov1alpha1.ApplicationSetSpec{
// Application set is using fasttemplate.
GoTemplate: false,
},
},
},
}

for _, c := range cases {
Expand All @@ -117,7 +183,7 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
PullRequest: &argoprojiov1alpha1.PullRequestGenerator{},
}

got, gotErr := gen.GenerateParams(&generatorConfig, nil)
got, gotErr := gen.GenerateParams(&generatorConfig, &c.applicationSet)
assert.Equal(t, c.expectedErr, gotErr)
assert.ElementsMatch(t, c.expected, got)
}
Expand Down
1 change: 1 addition & 0 deletions applicationset/services/pull_request/bitbucket_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ func (b *BitbucketService) List(_ context.Context) ([]*PullRequest, error) {
Number: pull.ID,
Branch: pull.FromRef.DisplayID, // ID: refs/heads/main DisplayID: main
HeadSHA: pull.FromRef.LatestCommit, // This is not defined in the official docs, but works in practice
Labels: []string{}, // Not supported by library
})
}

Expand Down
6 changes: 6 additions & 0 deletions applicationset/services/pull_request/bitbucket_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,16 +122,19 @@ func TestListPullRequestPagination(t *testing.T) {
Number: 101,
Branch: "feature-101",
HeadSHA: "ab3cf2e4d1517c83e720d2585b9402dbef71f992",
Labels: []string{},
}, *pullRequests[0])
assert.Equal(t, PullRequest{
Number: 102,
Branch: "feature-102",
HeadSHA: "bb3cf2e4d1517c83e720d2585b9402dbef71f992",
Labels: []string{},
}, *pullRequests[1])
assert.Equal(t, PullRequest{
Number: 200,
Branch: "feature-200",
HeadSHA: "cb3cf2e4d1517c83e720d2585b9402dbef71f992",
Labels: []string{},
}, *pullRequests[2])
}

Expand Down Expand Up @@ -284,11 +287,13 @@ func TestListPullRequestBranchMatch(t *testing.T) {
Number: 101,
Branch: "feature-101",
HeadSHA: "ab3cf2e4d1517c83e720d2585b9402dbef71f992",
Labels: []string{},
}, *pullRequests[0])
assert.Equal(t, PullRequest{
Number: 102,
Branch: "feature-102",
HeadSHA: "bb3cf2e4d1517c83e720d2585b9402dbef71f992",
Labels: []string{},
}, *pullRequests[1])

regexp = `.*2$`
Expand All @@ -305,6 +310,7 @@ func TestListPullRequestBranchMatch(t *testing.T) {
Number: 102,
Branch: "feature-102",
HeadSHA: "bb3cf2e4d1517c83e720d2585b9402dbef71f992",
Labels: []string{},
}, *pullRequests[0])

regexp = `[\d{2}`
Expand Down
10 changes: 10 additions & 0 deletions applicationset/services/pull_request/gitea.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,17 @@ func (g *GiteaService) List(ctx context.Context) ([]*PullRequest, error) {
Number: int(pr.Index),
Branch: pr.Head.Ref,
HeadSHA: pr.Head.Sha,
Labels: getGiteaPRLabelNames(pr.Labels),
})
}
return list, nil
}

// Get the Gitea pull request label names.
func getGiteaPRLabelNames(giteaLabels []*gitea.Label) []string {
var labelNames []string
for _, giteaLabel := range giteaLabels {
labelNames = append(labelNames, giteaLabel.Name)
}
return labelNames
}
30 changes: 30 additions & 0 deletions applicationset/services/pull_request/gitea_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"net/http/httptest"
"testing"

"code.gitea.io/sdk/gitea"
"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -257,3 +258,32 @@ func TestGiteaList(t *testing.T) {
assert.Equal(t, prs[0].Branch, "test")
assert.Equal(t, prs[0].HeadSHA, "7bbaf62d92ddfafd9cc8b340c619abaec32bc09f")
}

func TestGetGiteaPRLabelNames(t *testing.T) {
Tests := []struct {
Name string
PullLabels []*gitea.Label
ExpectedResult []string
}{
{
Name: "PR has labels",
PullLabels: []*gitea.Label{
&gitea.Label{Name: "label1"},
&gitea.Label{Name: "label2"},
&gitea.Label{Name: "label3"},
},
ExpectedResult: []string{"label1", "label2", "label3"},
},
{
Name: "PR does not have labels",
PullLabels: []*gitea.Label{},
ExpectedResult: nil,
},
}
for _, test := range Tests {
t.Run(test.Name, func(t *testing.T) {
labels := getGiteaPRLabelNames(test.PullLabels)
assert.Equal(t, test.ExpectedResult, labels)
})
}
}
10 changes: 10 additions & 0 deletions applicationset/services/pull_request/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ func (g *GithubService) List(ctx context.Context) ([]*PullRequest, error) {
Number: *pull.Number,
Branch: *pull.Head.Ref,
HeadSHA: *pull.Head.SHA,
Labels: getGithubPRLabelNames(pull.Labels),
})
}
if resp.NextPage == 0 {
Expand Down Expand Up @@ -97,3 +98,12 @@ func containLabels(expectedLabels []string, gotLabels []*github.Label) bool {
}
return true
}

// Get the Github pull request label names.
func getGithubPRLabelNames(gitHubLabels []*github.Label) []string {
var labelNames []string
for _, gitHubLabel := range gitHubLabels {
labelNames = append(labelNames, *gitHubLabel.Name)
}
return labelNames
}
Loading

0 comments on commit a50e21e

Please sign in to comment.