github.com/argoproj/argo-cd/v3@v3.2.1/applicationset/generators/pull_request_test.go (about) 1 package generators 2 3 import ( 4 "context" 5 "errors" 6 "testing" 7 8 "github.com/stretchr/testify/assert" 9 "github.com/stretchr/testify/require" 10 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 11 12 pullrequest "github.com/argoproj/argo-cd/v3/applicationset/services/pull_request" 13 argoprojiov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1" 14 ) 15 16 func TestPullRequestGithubGenerateParams(t *testing.T) { 17 ctx := t.Context() 18 cases := []struct { 19 selectFunc func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) 20 values map[string]string 21 expected []map[string]any 22 expectedErr error 23 applicationSet argoprojiov1alpha1.ApplicationSet 24 continueOnRepoNotFoundError bool 25 }{ 26 { 27 selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) { 28 return pullrequest.NewFakeService( 29 ctx, 30 []*pullrequest.PullRequest{ 31 { 32 Number: 1, 33 Title: "title1", 34 Branch: "branch1", 35 TargetBranch: "master", 36 HeadSHA: "089d92cbf9ff857a39e6feccd32798ca700fb958", 37 Author: "testName", 38 }, 39 }, 40 nil, 41 ) 42 }, 43 expected: []map[string]any{ 44 { 45 "number": "1", 46 "title": "title1", 47 "branch": "branch1", 48 "branch_slug": "branch1", 49 "target_branch": "master", 50 "target_branch_slug": "master", 51 "head_sha": "089d92cbf9ff857a39e6feccd32798ca700fb958", 52 "head_short_sha": "089d92cb", 53 "head_short_sha_7": "089d92c", 54 "author": "testName", 55 }, 56 }, 57 expectedErr: nil, 58 }, 59 { 60 selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) { 61 return pullrequest.NewFakeService( 62 ctx, 63 []*pullrequest.PullRequest{ 64 { 65 Number: 2, 66 Title: "title2", 67 Branch: "feat/areally+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature", 68 TargetBranch: "feat/anotherreally+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature", 69 HeadSHA: "9b34ff5bd418e57d58891eb0aa0728043ca1e8be", 70 Author: "testName", 71 }, 72 }, 73 nil, 74 ) 75 }, 76 expected: []map[string]any{ 77 { 78 "number": "2", 79 "title": "title2", 80 "branch": "feat/areally+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature", 81 "branch_slug": "feat-areally-long-pull-request-name-to-test-argo", 82 "target_branch": "feat/anotherreally+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature", 83 "target_branch_slug": "feat-anotherreally-long-pull-request-name-to-test", 84 "head_sha": "9b34ff5bd418e57d58891eb0aa0728043ca1e8be", 85 "head_short_sha": "9b34ff5b", 86 "head_short_sha_7": "9b34ff5", 87 "author": "testName", 88 }, 89 }, 90 expectedErr: nil, 91 }, 92 { 93 selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) { 94 return pullrequest.NewFakeService( 95 ctx, 96 []*pullrequest.PullRequest{ 97 { 98 Number: 1, 99 Title: "title1", 100 Branch: "a-very-short-sha", 101 TargetBranch: "master", 102 HeadSHA: "abcd", 103 Author: "testName", 104 }, 105 }, 106 nil, 107 ) 108 }, 109 expected: []map[string]any{ 110 { 111 "number": "1", 112 "title": "title1", 113 "branch": "a-very-short-sha", 114 "branch_slug": "a-very-short-sha", 115 "target_branch": "master", 116 "target_branch_slug": "master", 117 "head_sha": "abcd", 118 "head_short_sha": "abcd", 119 "head_short_sha_7": "abcd", 120 "author": "testName", 121 }, 122 }, 123 expectedErr: nil, 124 }, 125 { 126 selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) { 127 return pullrequest.NewFakeService( 128 ctx, 129 []*pullrequest.PullRequest{ 130 { 131 Number: 1, 132 Title: "title1", 133 Branch: "my_branch", 134 TargetBranch: "master", 135 HeadSHA: "abcd", 136 Author: "testName", 137 }, 138 }, 139 nil, 140 ) 141 }, 142 values: map[string]string{ 143 "foo": "bar", 144 "pr_branch": "{{ branch }}", 145 }, 146 expected: []map[string]any{ 147 { 148 "number": "1", 149 "title": "title1", 150 "branch": "my_branch", 151 "branch_slug": "my-branch", 152 "target_branch": "master", 153 "target_branch_slug": "master", 154 "head_sha": "abcd", 155 "head_short_sha": "abcd", 156 "head_short_sha_7": "abcd", 157 "author": "testName", 158 "values.foo": "bar", 159 "values.pr_branch": "my_branch", 160 }, 161 }, 162 expectedErr: nil, 163 }, 164 { 165 selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) { 166 return pullrequest.NewFakeService( 167 ctx, 168 nil, 169 errors.New("fake error"), 170 ) 171 }, 172 expected: nil, 173 expectedErr: errors.New("error listing repos: fake error"), 174 }, 175 { 176 selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) { 177 return pullrequest.NewFakeService( 178 ctx, 179 nil, 180 pullrequest.NewRepositoryNotFoundError(errors.New("repository not found")), 181 ) 182 }, 183 expected: []map[string]any{}, 184 expectedErr: nil, 185 continueOnRepoNotFoundError: true, 186 }, 187 { 188 selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) { 189 return pullrequest.NewFakeService( 190 ctx, 191 nil, 192 pullrequest.NewRepositoryNotFoundError(errors.New("repository not found")), 193 ) 194 }, 195 expected: nil, 196 expectedErr: errors.New("error listing repos: repository not found"), 197 continueOnRepoNotFoundError: false, 198 }, 199 { 200 selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) { 201 return pullrequest.NewFakeService( 202 ctx, 203 []*pullrequest.PullRequest{ 204 { 205 Number: 1, 206 Title: "title1", 207 Branch: "branch1", 208 TargetBranch: "master", 209 HeadSHA: "089d92cbf9ff857a39e6feccd32798ca700fb958", 210 Labels: []string{"preview"}, 211 Author: "testName", 212 }, 213 }, 214 nil, 215 ) 216 }, 217 expected: []map[string]any{ 218 { 219 "number": "1", 220 "title": "title1", 221 "branch": "branch1", 222 "branch_slug": "branch1", 223 "target_branch": "master", 224 "target_branch_slug": "master", 225 "head_sha": "089d92cbf9ff857a39e6feccd32798ca700fb958", 226 "head_short_sha": "089d92cb", 227 "head_short_sha_7": "089d92c", 228 "labels": []string{"preview"}, 229 "author": "testName", 230 }, 231 }, 232 expectedErr: nil, 233 applicationSet: argoprojiov1alpha1.ApplicationSet{ 234 Spec: argoprojiov1alpha1.ApplicationSetSpec{ 235 // Application set is using Go Template. 236 GoTemplate: true, 237 }, 238 }, 239 }, 240 { 241 selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) { 242 return pullrequest.NewFakeService( 243 ctx, 244 []*pullrequest.PullRequest{ 245 { 246 Number: 1, 247 Title: "title1", 248 Branch: "branch1", 249 TargetBranch: "master", 250 HeadSHA: "089d92cbf9ff857a39e6feccd32798ca700fb958", 251 Labels: []string{"preview"}, 252 Author: "testName", 253 }, 254 }, 255 nil, 256 ) 257 }, 258 expected: []map[string]any{ 259 { 260 "number": "1", 261 "title": "title1", 262 "branch": "branch1", 263 "branch_slug": "branch1", 264 "target_branch": "master", 265 "target_branch_slug": "master", 266 "head_sha": "089d92cbf9ff857a39e6feccd32798ca700fb958", 267 "head_short_sha": "089d92cb", 268 "head_short_sha_7": "089d92c", 269 "author": "testName", 270 }, 271 }, 272 expectedErr: nil, 273 applicationSet: argoprojiov1alpha1.ApplicationSet{ 274 Spec: argoprojiov1alpha1.ApplicationSetSpec{ 275 // Application set is using fasttemplate. 276 GoTemplate: false, 277 }, 278 }, 279 }, 280 { 281 selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) { 282 return pullrequest.NewFakeService( 283 ctx, 284 []*pullrequest.PullRequest{ 285 { 286 Number: 1, 287 Title: "title1", 288 Branch: "my_branch", 289 TargetBranch: "master", 290 HeadSHA: "abcd", 291 Author: "testName", 292 Labels: []string{"preview", "preview:team1"}, 293 }, 294 }, 295 nil, 296 ) 297 }, 298 values: map[string]string{ 299 "preview_env": "{{ regexFind \"(team1|team2)\" (.labels | join \",\") }}", 300 }, 301 expected: []map[string]any{ 302 { 303 "number": "1", 304 "title": "title1", 305 "branch": "my_branch", 306 "branch_slug": "my-branch", 307 "target_branch": "master", 308 "target_branch_slug": "master", 309 "head_sha": "abcd", 310 "head_short_sha": "abcd", 311 "head_short_sha_7": "abcd", 312 "author": "testName", 313 "labels": []string{"preview", "preview:team1"}, 314 "values": map[string]string{"preview_env": "team1"}, 315 }, 316 }, 317 expectedErr: nil, 318 applicationSet: argoprojiov1alpha1.ApplicationSet{ 319 Spec: argoprojiov1alpha1.ApplicationSetSpec{ 320 // Application set is using fasttemplate. 321 GoTemplate: true, 322 }, 323 }, 324 }, 325 } 326 327 for _, c := range cases { 328 gen := PullRequestGenerator{ 329 selectServiceProviderFunc: c.selectFunc, 330 } 331 generatorConfig := argoprojiov1alpha1.ApplicationSetGenerator{ 332 PullRequest: &argoprojiov1alpha1.PullRequestGenerator{ 333 Values: c.values, 334 ContinueOnRepoNotFoundError: c.continueOnRepoNotFoundError, 335 }, 336 } 337 338 got, gotErr := gen.GenerateParams(&generatorConfig, &c.applicationSet, nil) 339 if c.expectedErr != nil { 340 require.EqualError(t, gotErr, c.expectedErr.Error()) 341 } else { 342 require.NoError(t, gotErr) 343 } 344 assert.ElementsMatch(t, c.expected, got) 345 } 346 } 347 348 func TestAllowedSCMProviderPullRequest(t *testing.T) { 349 t.Parallel() 350 351 cases := []struct { 352 name string 353 providerConfig *argoprojiov1alpha1.PullRequestGenerator 354 }{ 355 { 356 name: "Error Github", 357 providerConfig: &argoprojiov1alpha1.PullRequestGenerator{ 358 Github: &argoprojiov1alpha1.PullRequestGeneratorGithub{ 359 API: "https://myservice.mynamespace.svc.cluster.local", 360 }, 361 }, 362 }, 363 { 364 name: "Error Gitlab", 365 providerConfig: &argoprojiov1alpha1.PullRequestGenerator{ 366 GitLab: &argoprojiov1alpha1.PullRequestGeneratorGitLab{ 367 API: "https://myservice.mynamespace.svc.cluster.local", 368 }, 369 }, 370 }, 371 { 372 name: "Error Gitea", 373 providerConfig: &argoprojiov1alpha1.PullRequestGenerator{ 374 Gitea: &argoprojiov1alpha1.PullRequestGeneratorGitea{ 375 API: "https://myservice.mynamespace.svc.cluster.local", 376 }, 377 }, 378 }, 379 { 380 name: "Error Bitbucket", 381 providerConfig: &argoprojiov1alpha1.PullRequestGenerator{ 382 BitbucketServer: &argoprojiov1alpha1.PullRequestGeneratorBitbucketServer{ 383 API: "https://myservice.mynamespace.svc.cluster.local", 384 }, 385 }, 386 }, 387 } 388 389 for _, testCase := range cases { 390 testCaseCopy := testCase 391 392 t.Run(testCaseCopy.name, func(t *testing.T) { 393 t.Parallel() 394 395 pullRequestGenerator := NewPullRequestGenerator(nil, NewSCMConfig("", []string{ 396 "github.myorg.com", 397 "gitlab.myorg.com", 398 "gitea.myorg.com", 399 "bitbucket.myorg.com", 400 "azuredevops.myorg.com", 401 }, true, true, nil, true)) 402 403 applicationSetInfo := argoprojiov1alpha1.ApplicationSet{ 404 ObjectMeta: metav1.ObjectMeta{ 405 Name: "set", 406 }, 407 Spec: argoprojiov1alpha1.ApplicationSetSpec{ 408 Generators: []argoprojiov1alpha1.ApplicationSetGenerator{{ 409 PullRequest: testCaseCopy.providerConfig, 410 }}, 411 }, 412 } 413 414 _, err := pullRequestGenerator.GenerateParams(&applicationSetInfo.Spec.Generators[0], &applicationSetInfo, nil) 415 416 require.Error(t, err, "Must return an error") 417 var expectedError ErrDisallowedSCMProvider 418 assert.ErrorAs(t, err, &expectedError) 419 }) 420 } 421 } 422 423 func TestSCMProviderDisabled_PRGenerator(t *testing.T) { 424 generator := NewPullRequestGenerator(nil, NewSCMConfig("", []string{}, false, true, nil, true)) 425 426 applicationSetInfo := argoprojiov1alpha1.ApplicationSet{ 427 ObjectMeta: metav1.ObjectMeta{ 428 Name: "set", 429 }, 430 Spec: argoprojiov1alpha1.ApplicationSetSpec{ 431 Generators: []argoprojiov1alpha1.ApplicationSetGenerator{{ 432 PullRequest: &argoprojiov1alpha1.PullRequestGenerator{ 433 Github: &argoprojiov1alpha1.PullRequestGeneratorGithub{ 434 API: "https://myservice.mynamespace.svc.cluster.local", 435 }, 436 }, 437 }}, 438 }, 439 } 440 441 _, err := generator.GenerateParams(&applicationSetInfo.Spec.Generators[0], &applicationSetInfo, nil) 442 assert.ErrorIs(t, err, ErrSCMProvidersDisabled) 443 }