├── .gitignore ├── images └── header.png ├── vcsutils ├── testdata │ ├── a.tar.gz │ └── hello_world.zip ├── webhookparser │ ├── common_test.go │ ├── webhookparser_test.go │ ├── factory.go │ ├── factory_test.go │ └── testdata │ │ ├── bitbucketserver │ │ ├── pushpayload.json │ │ ├── tagcreatepayload.json │ │ ├── tagdeletepayload.json │ │ ├── prcreatepayload.json │ │ ├── prdeletepayload.json │ │ ├── prdeclinepayload.json │ │ ├── prupdatepayload.json │ │ └── prmergepayload.json │ │ ├── gitlab │ │ ├── tagdeletepayload.json │ │ ├── pushpayload.json │ │ ├── tagcreatepayload.json │ │ ├── propenpayload.json │ │ ├── prclosepayload.json │ │ ├── prreopenpayload.json │ │ ├── prupdatepayload.json │ │ └── prmergepayload.json │ │ └── bitbucketcloud │ │ ├── tagdeletepayload.json │ │ ├── tagcreatepayload.json │ │ ├── prcreatepayload.json │ │ └── prupdatepayload.json ├── consts_test.go ├── logger.go ├── retryexecutor_test.go ├── consts.go └── retryexecutor.go ├── .frogbot └── frogbot-config.yml ├── vcsclient ├── testdata │ ├── azurerepos │ │ ├── hello_world.zip │ │ ├── commits_statuses.json │ │ ├── commits.json │ │ └── resourcesResponse.json │ ├── gitlab │ │ ├── hello-world-main.tar.gz │ │ ├── merge_request_changes.json │ │ ├── merge_request_notes_response.json │ │ ├── merge_requests_by_commit_response.json │ │ ├── merge_request_diff_versions.json │ │ ├── commit_single_response.json │ │ ├── pull_request_comments_list_response.json │ │ ├── new_merge_request_thread.json │ │ ├── commit_list_response.json │ │ ├── commits_statuses.json │ │ ├── merge_request_discussion_items.json │ │ ├── pull_requests_list_response.json │ │ ├── get_merge_request_response.json │ │ ├── repository_response.json │ │ ├── compare_commits.json │ │ └── get_project_response.json │ ├── bitbucketserver │ │ ├── hello-world-main.tar.gz │ │ ├── commits_statuses_bad_decode.json │ │ ├── commit_single_response.json │ │ ├── repository_response.json │ │ ├── commits_statuses.json │ │ ├── add_ssh_key_response.json │ │ ├── commit_list_response.json │ │ ├── pull_requests_list_response.json │ │ ├── pull_request_comments_list_response.json │ │ └── get_pull_request_response_nil.json │ ├── bitbucketcloud │ │ ├── add_ssh_key_response.json │ │ ├── pull_request_reviews_response.json │ │ ├── commits_statuses.json │ │ ├── pull_requests_associated_with_commit_response.json │ │ ├── get_commit_status_response.json │ │ ├── compare_commits.json │ │ ├── commit_single_response.json │ │ ├── repository_response.json │ │ ├── pull_request_comments_list_response.json │ │ └── get_pull_request_response.json │ └── github │ │ ├── pull_request_reviews_response.json │ │ ├── repository_environment_response.json │ │ ├── commit_single_response.json │ │ └── pull_request_comments_list_response.json ├── factory_test.go ├── gitlabcommon.go ├── factory.go ├── bitbucketcommon_test.go └── common_test.go ├── .github ├── ISSUE_TEMPLATE │ ├── question.md │ ├── bug_report.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md ├── release.yml └── workflows │ ├── cla.yml │ ├── analysis.yml │ ├── test.yml │ ├── frogbot-scan-pull-request.yml │ └── frogbot-scan-repository.yml ├── THIRD_PARTY_NOTICES └── go.mod /.gitignore: -------------------------------------------------------------------------------- 1 | .idea -------------------------------------------------------------------------------- /images/header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfrog/froggit-go/HEAD/images/header.png -------------------------------------------------------------------------------- /vcsutils/testdata/a.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfrog/froggit-go/HEAD/vcsutils/testdata/a.tar.gz -------------------------------------------------------------------------------- /vcsutils/testdata/hello_world.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfrog/froggit-go/HEAD/vcsutils/testdata/hello_world.zip -------------------------------------------------------------------------------- /.frogbot/frogbot-config.yml: -------------------------------------------------------------------------------- 1 | - params: 2 | git: 3 | repoName: froggit-go 4 | branches: 5 | - master -------------------------------------------------------------------------------- /vcsclient/testdata/azurerepos/hello_world.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfrog/froggit-go/HEAD/vcsclient/testdata/azurerepos/hello_world.zip -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: ❓ Question 3 | about: Ask a question 4 | title: "" 5 | labels: question 6 | assignees: "" 7 | --- 8 | -------------------------------------------------------------------------------- /vcsclient/testdata/gitlab/hello-world-main.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfrog/froggit-go/HEAD/vcsclient/testdata/gitlab/hello-world-main.tar.gz -------------------------------------------------------------------------------- /vcsclient/testdata/bitbucketserver/hello-world-main.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfrog/froggit-go/HEAD/vcsclient/testdata/bitbucketserver/hello-world-main.tar.gz -------------------------------------------------------------------------------- /vcsutils/webhookparser/common_test.go: -------------------------------------------------------------------------------- 1 | package webhookparser 2 | 3 | import ( 4 | "io" 5 | ) 6 | 7 | const ( 8 | expectedOwner = "yahavi" 9 | expectedRepoName = "hello-world" 10 | expectedBranch = "main" 11 | expectedSourceBranch = "dev" 12 | ) 13 | 14 | var token = []byte("abc123") 15 | 16 | func close(closer io.Closer) { 17 | _ = closer.Close() 18 | } 19 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | - [ ] All [tests](https://github.com/jfrog/froggit-go/actions/workflows/test.yml) passed. If this feature is not already covered by the tests, I added new tests. 2 | - [ ] I used `go fmt ./...` for formatting the code before submitting the pull request. 3 | - [ ] This feature is included on all supported VCS providers - GitHub, Bitbucket cloud, Bitbucket server, GitLab and Azure Repos. 4 | - [ ] I added the relevant documentation for the new feature. 5 | 6 | --- 7 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | changelog: 2 | exclude: 3 | labels: 4 | - ignore for release 5 | categories: 6 | - title: Breaking Changes 🚨 7 | labels: 8 | - breaking change 9 | - title: Exciting New Features 🎉 10 | labels: 11 | - new feature 12 | - title: Improvements 🌱 13 | labels: 14 | - improvement 15 | - title: Bug Fixes 🛠 16 | labels: 17 | - bug 18 | - title: Other Changes 📚 19 | labels: 20 | - "*" 21 | -------------------------------------------------------------------------------- /vcsclient/testdata/bitbucketserver/commits_statuses_bad_decode.json: -------------------------------------------------------------------------------- 1 | { 2 | "values": [ 3 | { 4 | "key": "Title 1", 5 | "url": "https://example.com/page1", 6 | "state": "active", 7 | "description": "Description 1", 8 | "name": "Creator 1" 9 | }, 10 | { 11 | "key": "Title 2", 12 | "url": "https://example.com/page2", 13 | "state": "inactive", 14 | "description": "Description 2", 15 | "name": {"invalid_key": "invalid_value"} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /vcsutils/consts_test.go: -------------------------------------------------------------------------------- 1 | package vcsutils 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestVcsProviderString(t *testing.T) { 10 | assert.Equal(t, "GitHub", GitHub.String()) 11 | assert.Equal(t, "GitLab", GitLab.String()) 12 | assert.Equal(t, "Bitbucket Server", BitbucketServer.String()) 13 | assert.Equal(t, "Bitbucket Cloud", BitbucketCloud.String()) 14 | assert.Equal(t, "Azure Repos", AzureRepos.String()) 15 | assert.Equal(t, "", (VcsProvider(5)).String()) 16 | } 17 | -------------------------------------------------------------------------------- /vcsclient/testdata/gitlab/merge_request_changes.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "old_path": "README", 4 | "new_path": "README", 5 | "a_mode": "100644", 6 | "b_mode": "100644", 7 | "diff": "@@ -1 +1 @@\\ -Title\\ +README", 8 | "new_file": false, 9 | "renamed_file": false, 10 | "deleted_file": false 11 | }, 12 | { 13 | "old_path": "VERSION", 14 | "new_path": "VERSION", 15 | "a_mode": "100644", 16 | "b_mode": "100644", 17 | "diff": "@@\\ -1.9.7\\ +1.9.8", 18 | "new_file": false, 19 | "renamed_file": false, 20 | "deleted_file": false 21 | } 22 | ] -------------------------------------------------------------------------------- /vcsclient/testdata/gitlab/merge_request_notes_response.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 1, 4 | "author": { 5 | "username": "reviewer1" 6 | }, 7 | "body": "Looks good to me", 8 | "resolvable": true, 9 | "created_at": "2023-01-01T12:00:00Z", 10 | "commit_id": "commitsha1" 11 | }, 12 | { 13 | "id": 2, 14 | "author": { 15 | "username": "reviewer2" 16 | }, 17 | "body": "Please fix this issue", 18 | "resolvable": false, 19 | "created_at": "2023-01-01T12:00:00Z", 20 | "commit_id": "commitsha2" 21 | } 22 | ] -------------------------------------------------------------------------------- /vcsutils/webhookparser/webhookparser_test.go: -------------------------------------------------------------------------------- 1 | package webhookparser 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestBranchStatus(t *testing.T) { 10 | assert.Equal(t, WebhookInfoBranchStatusDeleted, branchStatus(true, false)) 11 | assert.Equal(t, WebhookInfoBranchStatusCreated, branchStatus(false, true)) 12 | assert.Equal(t, WebhookInfoBranchStatusUpdated, branchStatus(true, true)) 13 | // this one should never happen 14 | assert.Equal(t, WebhookInfoBranchStatusUpdated, branchStatus(false, false)) 15 | } 16 | -------------------------------------------------------------------------------- /vcsclient/testdata/gitlab/merge_requests_by_commit_response.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "iid": 1, 4 | "web_url": "https://gitlab.example.com/my-group/my-project/merge_requests/1", 5 | "description": "Fix bug", 6 | "source_branch": "feature-branch", 7 | "target_branch": "main", 8 | "source_project_id": 1, 9 | "target_project_id": 1, 10 | "Author": { 11 | "name": "John Doe", 12 | "username": "johndoe", 13 | "avatar_url": "https://gitlab.example.com/uploads/user/avatar/1/avatar.png", 14 | "web_url": "https://gitlab.example.com/johndoe" 15 | } 16 | } 17 | ] -------------------------------------------------------------------------------- /vcsclient/testdata/bitbucketcloud/add_ssh_key_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 123, 3 | "key": "ssh-rsa AAAA...", 4 | "label": "My deploy key", 5 | "type": "deploy_key", 6 | "created_on": "2018-08-15T23:50:59.993890+00:00", 7 | "repository": { 8 | "full_name": "mleu/test", 9 | "name": "test", 10 | "type": "repository", 11 | "uuid": "{85d08b4e-571d-44e9-a507-fa476535aa98}" 12 | }, 13 | "links": { 14 | "self": { 15 | "href": "https://api.bitbucket.org/2.0/repositories/mleu/test/deploy-keys/123" 16 | } 17 | }, 18 | "last_used": null, 19 | "comment": "mleu@C02W454JHTD8" 20 | } -------------------------------------------------------------------------------- /vcsclient/testdata/bitbucketserver/commit_single_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "abcdef0123abcdef4567abcdef8987abcdef6543", 3 | "displayId": "abcdef0123a", 4 | "author": { 5 | "name": "charlie", 6 | "emailAddress": "charlie@example.com" 7 | }, 8 | "authorTimestamp": 1636089306104, 9 | "committer": { 10 | "name": "mark", 11 | "emailAddress": "mark@example.com" 12 | }, 13 | "committerTimestamp": 1636089306104, 14 | "message": "WIP on feature 1", 15 | "parents": [ 16 | { 17 | "id": "bbcdef0123abcdef4567abcdef8987abcdef6543", 18 | "displayId": "bbcdef0" 19 | } 20 | ] 21 | } -------------------------------------------------------------------------------- /.github/workflows/cla.yml: -------------------------------------------------------------------------------- 1 | name: "CLA Assistant" 2 | on: 3 | # issue_comment triggers this action on each comment on issues and pull requests 4 | issue_comment: 5 | types: [ created ] 6 | pull_request_target: 7 | types: [ opened,synchronize ] 8 | 9 | jobs: 10 | CLAssistant: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Run CLA Check 14 | uses: jfrog/.github/actions/cla@main 15 | with: 16 | event_comment_body: ${{ github.event.comment.body }} 17 | event_name: ${{ github.event_name }} 18 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 19 | CLA_SIGN_TOKEN: ${{ secrets.CLA_SIGN_TOKEN }} -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🐞 Bug report 3 | about: Create a report to help us improve 4 | title: "" 5 | labels: bug 6 | assignees: "" 7 | --- 8 | 9 | **Describe the bug** 10 | A clear and concise description of what the bug is. 11 | 12 | **To Reproduce** 13 | Steps to reproduce the behavior 14 | 15 | **Expected behavior** 16 | A clear and concise description of what you expected to happen. 17 | 18 | **Screenshots** 19 | If applicable, add screenshots to help explain your problem. 20 | 21 | **Versions** 22 | 23 | - Froggit-Go version: 24 | - Operating system: 25 | 26 | **Additional context** 27 | Add any other context about the problem here. 28 | -------------------------------------------------------------------------------- /vcsutils/webhookparser/factory.go: -------------------------------------------------------------------------------- 1 | package webhookparser 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/jfrog/froggit-go/vcsutils" 7 | ) 8 | 9 | func createWebhookParser(logger vcsutils.Log, origin WebhookOrigin) webhookParser { 10 | origin.OriginURL = strings.TrimSuffix(origin.OriginURL, "/") 11 | switch origin.VcsProvider { 12 | case vcsutils.GitHub: 13 | return newGitHubWebhookParser(logger, origin.OriginURL) 14 | case vcsutils.GitLab: 15 | return newGitLabWebhookParser(logger) 16 | case vcsutils.BitbucketServer: 17 | return newBitbucketServerWebhookParser(logger, origin.OriginURL) 18 | case vcsutils.BitbucketCloud: 19 | return newBitbucketCloudWebhookParser(logger) 20 | } 21 | return nil 22 | } 23 | -------------------------------------------------------------------------------- /vcsclient/testdata/bitbucketcloud/pull_request_reviews_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "pagelen": 10, 3 | "values": [ 4 | { 5 | "id": 301545835, 6 | "user": { 7 | "display_name": "user" 8 | }, 9 | "content": { 10 | "raw": "I’m a comment" 11 | }, 12 | "created_on": "2022-05-16T11:04:07.075827+00:00", 13 | "state": "approved" 14 | }, 15 | { 16 | "id": 301545836, 17 | "user": { 18 | "display_name": "another_user" 19 | }, 20 | "content": { 21 | "raw": "Another comment" 22 | }, 23 | "created_on": "2022-05-16T12:04:07.075827+00:00", 24 | "state": "changes_requested" 25 | } 26 | ], 27 | "page": 1, 28 | "size": 2 29 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: ⭐️ Feature request 3 | about: Suggest an idea for this project 4 | title: "" 5 | labels: feature request 6 | assignees: "" 7 | --- 8 | 9 | **Is your feature request related to a problem? Please describe.** 10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 11 | 12 | **Describe the solution you'd like to see** 13 | A clear and concise description of the new feature. 14 | 15 | **Describe alternatives you've considered** 16 | If applicable, a clear and concise description of any alternative solutions or features you've considered. 17 | 18 | **Additional context** 19 | Add any other context or screenshots about the feature request here. 20 | -------------------------------------------------------------------------------- /vcsutils/webhookparser/factory_test.go: -------------------------------------------------------------------------------- 1 | package webhookparser 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | 8 | "github.com/jfrog/froggit-go/vcsutils" 9 | ) 10 | 11 | func TestCreateWebhookParser(t *testing.T) { 12 | assert.IsType(t, &gitHubWebhookParser{}, newParser(vcsutils.GitHub)) 13 | assert.IsType(t, &gitLabWebhookParser{}, newParser(vcsutils.GitLab)) 14 | assert.IsType(t, &bitbucketServerWebhookParser{}, newParser(vcsutils.BitbucketServer)) 15 | assert.IsType(t, &bitbucketCloudWebhookParser{}, newParser(vcsutils.BitbucketCloud)) 16 | assert.Nil(t, newParser(5)) 17 | } 18 | 19 | func newParser(provider vcsutils.VcsProvider) webhookParser { 20 | return createWebhookParser( 21 | vcsutils.EmptyLogger{}, 22 | WebhookOrigin{ 23 | VcsProvider: provider, 24 | }) 25 | } 26 | -------------------------------------------------------------------------------- /.github/workflows/analysis.yml: -------------------------------------------------------------------------------- 1 | name: "Static Analysis" 2 | on: 3 | push: 4 | branches: 5 | - '**' 6 | tags-ignore: 7 | - '**' 8 | pull_request: 9 | jobs: 10 | Static-Check: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout Source 14 | uses: actions/checkout@v4 15 | 16 | - name: Setup Go with cache 17 | uses: jfrog/.github/actions/install-go-with-cache@main 18 | 19 | - name: Run golangci linter 20 | uses: jfrog/.github/actions/golangci-lint@main 21 | 22 | Go-Sec: 23 | runs-on: ubuntu-latest 24 | steps: 25 | - name: Checkout Source 26 | uses: actions/checkout@v4 27 | 28 | - name: Setup Go with cache 29 | uses: jfrog/.github/actions/install-go-with-cache@main 30 | 31 | - name: Run Go-Sec scanner 32 | uses: jfrog/.github/actions/gosec-scanner@main -------------------------------------------------------------------------------- /vcsclient/testdata/gitlab/merge_request_diff_versions.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 110, 4 | "head_commit_sha": "33e2ee8579fda5bc36accc9c6fbd0b4fefda9e30", 5 | "base_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd", 6 | "start_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd", 7 | "created_at": "2016-07-26T14:44:48.926Z", 8 | "merge_request_id": 105, 9 | "state": "collected", 10 | "real_size": "1", 11 | "patch_id_sha": "d504412d5b6e6739647e752aff8e468dde093f2f" 12 | }, 13 | { 14 | "id": 108, 15 | "head_commit_sha": "3eed087b29835c48015768f839d76e5ea8f07a24", 16 | "base_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd", 17 | "start_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd", 18 | "created_at": "2016-07-25T14:21:33.028Z", 19 | "merge_request_id": 105, 20 | "state": "collected", 21 | "real_size": "1", 22 | "patch_id_sha": "72c30d1f0115fc1d2bb0b29b24dc2982cbcdfd32" 23 | } 24 | ] -------------------------------------------------------------------------------- /vcsclient/testdata/gitlab/commit_single_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "author_email": "user@example.com", 3 | "author_name": "Example User", 4 | "authored_date": "2021-11-08T14:56:28.000+00:00", 5 | "committed_date": "2021-11-08T14:56:28.000+00:00", 6 | "committer_email": "admin@example.com", 7 | "committer_name": "Administrator", 8 | "created_at": "2021-11-08T14:56:28.000+00:00", 9 | "id": "ff4a54b88fbd387ac4d9e8cdeb54b049978e450a", 10 | "last_pipeline": null, 11 | "message": "Initial commit", 12 | "parent_ids": [ 13 | "667fb1d7f3854da3ee036ba3ad711c87c8b37fbd" 14 | ], 15 | "project_id": 2, 16 | "short_id": "ff4a54b8", 17 | "stats": { 18 | "additions": 1, 19 | "deletions": 0, 20 | "total": 1 21 | }, 22 | "status": null, 23 | "title": "Initial commit", 24 | "trailers": {}, 25 | "web_url": "https://gitlab.example.com/thedude/gitlab-foss/-/commit/ff4a54b88fbd387ac4d9e8cdeb54b049978e450a" 26 | } -------------------------------------------------------------------------------- /vcsclient/testdata/bitbucketserver/repository_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "slug": "jfrog-setup-cli", 3 | "id": 1, 4 | "name": "Test repo", 5 | "scmId": "git", 6 | "state": "AVAILABLE", 7 | "statusMessage": "Available", 8 | "forkable": true, 9 | "project": { 10 | "key": "PRJ", 11 | "id": 1, 12 | "name": "My Cool Project", 13 | "description": "The description for my cool project.", 14 | "public": true, 15 | "type": "NORMAL", 16 | "links": { 17 | "self": [ 18 | { 19 | "href": "https://link/to/project" 20 | } 21 | ] 22 | } 23 | }, 24 | "public": true, 25 | "links": { 26 | "clone": [ 27 | { 28 | "href": "ssh://git@bitbucket.org:jfrog/repo-1.git", 29 | "name": "ssh" 30 | }, 31 | { 32 | "href": "https://bitbucket.org/jfrog/repo-1.git", 33 | "name": "http" 34 | } 35 | ], 36 | "self": [ 37 | { 38 | "href": "https://link/to/repository" 39 | } 40 | ] 41 | } 42 | } -------------------------------------------------------------------------------- /vcsclient/testdata/bitbucketcloud/commits_statuses.json: -------------------------------------------------------------------------------- 1 | { 2 | "values": [ 3 | { 4 | "uuid": "", 5 | "key": "", 6 | "refname": "", 7 | "url": "", 8 | "state": "INPROGRESS", 9 | "name": "", 10 | "description": "", 11 | "created_on": "2016-01-27T09:33:07Z", 12 | "updated_on": "2016-01-27T09:33:07Z" 13 | }, 14 | { 15 | "uuid": "", 16 | "key": "", 17 | "refname": "", 18 | "url": "", 19 | "state": "SUCCESSFUL", 20 | "name": "", 21 | "description": "", 22 | "created_on": "2016-01-27T09:33:07Z", 23 | "updated_on": "2016-01-27T09:33:07Z" 24 | }, 25 | { 26 | "uuid": "", 27 | "key": "", 28 | "refname": "", 29 | "url": "", 30 | "state": "FAILED", 31 | "name": "", 32 | "description": "", 33 | "created_on": "2016-01-27T09:33:07Z", 34 | "updated_on": "2016-01-27T09:33:07Z" 35 | } 36 | ] 37 | } -------------------------------------------------------------------------------- /vcsclient/testdata/bitbucketcloud/pull_requests_associated_with_commit_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "pagelen": 10, 3 | "values": [ 4 | { 5 | "id": 1, 6 | "source": { 7 | "branch": { 8 | "name": "source-branch" 9 | }, 10 | "repository": { 11 | "full_name": "workspace/source-repo" 12 | } 13 | }, 14 | "destination": { 15 | "branch": { 16 | "name": "target-branch" 17 | }, 18 | "repository": { 19 | "full_name": "workspace/target-repo" 20 | } 21 | } 22 | }, 23 | { 24 | "id": 2, 25 | "source": { 26 | "branch": { 27 | "name": "source-branch-2" 28 | }, 29 | "repository": { 30 | "full_name": "workspace/source-repo-2" 31 | } 32 | }, 33 | "destination": { 34 | "branch": { 35 | "name": "target-branch-2" 36 | }, 37 | "repository": { 38 | "full_name": "workspace/target-repo-2" 39 | } 40 | } 41 | } 42 | ], 43 | "page": 1, 44 | "size": 2 45 | } -------------------------------------------------------------------------------- /vcsclient/testdata/bitbucketserver/commits_statuses.json: -------------------------------------------------------------------------------- 1 | { 2 | "values": [ 3 | { 4 | "uuid": "", 5 | "key": "", 6 | "refname": "", 7 | "url": "", 8 | "state": "INPROGRESS", 9 | "name": "", 10 | "description": "this is pending", 11 | "created_on": "2016-01-27T09:33:07Z", 12 | "updated_on": "2016-01-27T09:33:07Z" 13 | }, 14 | { 15 | "uuid": "", 16 | "key": "", 17 | "refname": "", 18 | "url": "", 19 | "state": "SUCCESSFUL", 20 | "name": "", 21 | "description": "this is successful", 22 | "created_on": "2016-01-27T09:33:07Z", 23 | "updated_on": "2016-01-27T09:33:07Z" 24 | }, 25 | { 26 | "uuid": "", 27 | "key": "", 28 | "refname": "", 29 | "url": "", 30 | "state": "FAILED", 31 | "name": "", 32 | "description": "this is a failure", 33 | "created_on": "2016-01-27T09:33:07Z", 34 | "updated_on": "2016-01-27T09:33:07Z" 35 | } 36 | ] 37 | } -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | on: 3 | push: 4 | branches: 5 | - '**' 6 | tags-ignore: 7 | - '**' 8 | pull_request: 9 | jobs: 10 | test: 11 | runs-on: ${{ matrix.os }}-latest 12 | strategy: 13 | fail-fast: false 14 | matrix: 15 | os: [ ubuntu, windows, macos ] 16 | steps: 17 | - uses: actions/checkout@v4 18 | 19 | - name: Start FastCI Optimization 20 | uses: jfrog-fastci/fastci@main 21 | with: 22 | github_token: ${{secrets.GITHUB_TOKEN}} 23 | fastci_otel_token: ${{ secrets.FASTCI_TOKEN }} 24 | enabled_optimizations: 'go_test_junit_optimization' 25 | 26 | - name: Setup Go with cache 27 | uses: jfrog/.github/actions/install-go-with-cache@main 28 | 29 | # Run tests 30 | - name: Tests 31 | run: go test -v -race -covermode atomic -coverprofile=covprofile ./... 32 | 33 | # Generate code coverage 34 | - name: Send coverage 35 | run: | 36 | go install github.com/mattn/goveralls@latest 37 | goveralls -coverprofile=covprofile -service=github 38 | env: 39 | COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }} 40 | if: runner.os == 'Linux' 41 | -------------------------------------------------------------------------------- /vcsclient/testdata/gitlab/pull_request_comments_list_response.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 302, 4 | "body": "closed", 5 | "attachment": null, 6 | "author": { 7 | "id": 1, 8 | "username": "pipin", 9 | "email": "admin@example.com", 10 | "name": "Pip", 11 | "state": "active", 12 | "created_at": "2013-09-30T13:46:01Z" 13 | }, 14 | "created_at": "2013-10-02T09:22:45Z", 15 | "updated_at": "2013-10-02T10:22:45Z", 16 | "system": true, 17 | "noteable_id": 377, 18 | "noteable_type": "Issue", 19 | "noteable_iid": 377, 20 | "resolvable": false, 21 | "confidential": false 22 | }, 23 | { 24 | "id": 305, 25 | "body": "Text of the comment\r\n", 26 | "attachment": null, 27 | "author": { 28 | "id": 1, 29 | "username": "pipin", 30 | "email": "admin@example.com", 31 | "name": "Pip", 32 | "state": "active", 33 | "created_at": "2013-09-30T13:46:01Z" 34 | }, 35 | "created_at": "2013-10-02T09:56:03Z", 36 | "updated_at": "2013-10-02T09:56:03Z", 37 | "system": true, 38 | "noteable_id": 121, 39 | "noteable_type": "Issue", 40 | "noteable_iid": 121, 41 | "resolvable": false, 42 | "confidential": true 43 | } 44 | ] -------------------------------------------------------------------------------- /vcsclient/testdata/bitbucketserver/add_ssh_key_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": { 3 | "id": 1, 4 | "text": "ssh-rsa AAAA...", 5 | "label": "My deploy key" 6 | }, 7 | "repository": { 8 | "slug": "my-repo", 9 | "id": 1, 10 | "name": "My repo", 11 | "scmId": "git", 12 | "state": "AVAILABLE", 13 | "statusMessage": "Available", 14 | "forkable": true, 15 | "project": { 16 | "key": "PRJ", 17 | "id": 1, 18 | "name": "My Cool Project", 19 | "description": "The description for my cool project.", 20 | "public": true, 21 | "type": "NORMAL", 22 | "links": { 23 | "self": [ 24 | { 25 | "href": "https://link/to/project" 26 | } 27 | ] 28 | } 29 | }, 30 | "public": true, 31 | "links": { 32 | "clone": [ 33 | { 34 | "href": "ssh://git@/PRJ/my-repo.git", 35 | "name": "ssh" 36 | }, 37 | { 38 | "href": "https:///scm/PRJ/my-repo.git", 39 | "name": "http" 40 | } 41 | ], 42 | "self": [ 43 | { 44 | "href": "https://link/to/repository" 45 | } 46 | ] 47 | } 48 | }, 49 | "permission": "REPO_WRITE" 50 | } -------------------------------------------------------------------------------- /vcsutils/logger.go: -------------------------------------------------------------------------------- 1 | package vcsutils 2 | 3 | const ( 4 | SuccessfulRepoDownload = "repository downloaded successfully. Starting with repository extraction..." 5 | SuccessfulRepoExtraction = "Extracted repository successfully" 6 | CreatingPullRequest = "Creating new pull request:" 7 | 8 | UpdatingPullRequest = "Updating details of pull request ID:" 9 | FetchingOpenPullRequests = "Fetching open pull requests in" 10 | FetchingPullRequestById = "Fetching pull requests by id in" 11 | UploadingCodeScanning = "Uploading code scanning for:" 12 | 13 | FailedForkedRepositoryExtraction = "Failed to extract forked repository owner" 14 | 15 | SuccessfulSnapshotUpload = "Successfully uploaded snapshot to dependency graph, status:" 16 | ) 17 | 18 | type Log interface { 19 | Debug(a ...interface{}) 20 | Info(a ...interface{}) 21 | Warn(a ...interface{}) 22 | Error(a ...interface{}) 23 | Output(a ...interface{}) 24 | } 25 | 26 | type EmptyLogger struct{} 27 | 28 | func (el EmptyLogger) Debug(_ ...interface{}) { 29 | } 30 | 31 | func (el EmptyLogger) Info(_ ...interface{}) { 32 | } 33 | 34 | func (el EmptyLogger) Warn(_ ...interface{}) { 35 | } 36 | 37 | func (el EmptyLogger) Error(_ ...interface{}) { 38 | } 39 | 40 | func (el EmptyLogger) Output(_ ...interface{}) { 41 | } 42 | -------------------------------------------------------------------------------- /vcsutils/webhookparser/testdata/bitbucketserver/pushpayload.json: -------------------------------------------------------------------------------- 1 | {"eventKey":"repo:refs_changed","date":"2021-09-09T12:06:32+0300","actor":{"name":"yahavi","emailAddress":"yahavi@jfrog.com","id":721,"displayName":"Yahav Itzhak","active":true,"slug":"yahavi","type":"NORMAL","links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"repository":{"slug":"hello-world","id":2041,"name":"hello-world","hierarchyId":"aa146c1c8852cf49e15e","scmId":"git","state":"AVAILABLE","statusMessage":"Available","forkable":true,"project":{"key":"~YAHAVI","id":605,"name":"Yahav Itzhak","type":"PERSONAL","owner":{"name":"yahavi","emailAddress":"yahavi@jfrog.com","id":721,"displayName":"Yahav Itzhak","active":true,"slug":"yahavi","type":"NORMAL","links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"public":false,"links":{"clone":[{"href":"ssh://git@git.acme.info/~yahavi/hello-world.git","name":"ssh"},{"href":"https://git.acme.info/scm/~yahavi/hello-world.git","name":"http"}],"self":[{"href":"https://git.acme.info/users/yahavi/repos/hello-world/browse"}]}},"changes":[{"ref":{"id":"refs/heads/main","displayId":"main","type":"BRANCH"},"refId":"refs/heads/main","fromHash":"0000000000000000000000000000000000000000","toHash":"929d3054cf60e11a38672966f948bb5d95f48f0e","type":"ADD"}]} -------------------------------------------------------------------------------- /vcsutils/webhookparser/testdata/gitlab/tagdeletepayload.json: -------------------------------------------------------------------------------- 1 | {"object_kind":"tag_push","event_name":"tag_push","before":"45abefa4485f0e03fa5db86a998d16a0a1df07b7","after":"0000000000000000000000000000000000000000","ref":"refs/tags/first_tag","checkout_sha":null,"message":null,"user_id":14190195,"user_name":"Rob Ivanov","user_username":"robinov","user_email":null,"user_avatar":"https://secure.gravatar.com/avatar/a47aec620663eaa2bfeaa0540e580fd5?s=80&d=identicon","project_id":44896137,"project":{"id":44896137,"name":"webhooktest","description":null,"web_url":"https://gitlab.com/grobinov/webhooktest","avatar_url":null,"git_ssh_url":"git@gitlab.com:grobinov/webhooktest.git","git_http_url":"https://gitlab.com/grobinov/webhooktest.git","namespace":"grobinov","visibility_level":0,"path_with_namespace":"grobinov/webhooktest","default_branch":"main","ci_config_path":"","homepage":"https://gitlab.com/grobinov/webhooktest","url":"git@gitlab.com:grobinov/webhooktest.git","ssh_url":"git@gitlab.com:grobinov/webhooktest.git","http_url":"https://gitlab.com/grobinov/webhooktest.git"},"commits":[],"total_commits_count":0,"push_options":{},"repository":{"name":"webhooktest","url":"git@gitlab.com:grobinov/webhooktest.git","description":null,"homepage":"https://gitlab.com/grobinov/webhooktest","git_http_url":"https://gitlab.com/grobinov/webhooktest.git","git_ssh_url":"git@gitlab.com:grobinov/webhooktest.git","visibility_level":0}} -------------------------------------------------------------------------------- /vcsclient/testdata/gitlab/new_merge_request_thread.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "ec358c38875d5133b171208e64415b8583acaed1", 3 | "individual_note": false, 4 | "notes": [ 5 | { 6 | "id": 1544943809, 7 | "type": "DiffNote", 8 | "body": "test comment body", 9 | "attachment": null, 10 | "author": { 11 | "id": 13377328, 12 | "username": "jfrog", 13 | "name": "JFrog", 14 | "state": "active", 15 | "avatar_url": "https://secure.gravatar.com/avatar/005f2d268f06e85fcae3e48c96217dd3?s=80\u0026d=identicon", 16 | "web_url": "https://gitlab.com/omerz1" 17 | }, 18 | "created_at": "2023-09-06T07:48:45.081Z", 19 | "updated_at": "2023-09-06T07:48:45.081Z", 20 | "system": false, 21 | "noteable_id": 247767421, 22 | "noteable_type": "MergeRequest", 23 | "project_id": 47457684, 24 | "commit_id": null, 25 | "position": { 26 | "base_sha": "b840235eecc4d6bca96839a94ad141fc6e9e9170", 27 | "start_sha": "b840235eecc4d6bca96839a94ad141fc6e9e9170", 28 | "head_sha": "204c25f7d0a81b9163eb4bdda18a8ed279a32fa6", 29 | "old_path": null, 30 | "new_path": ".gitlab-ci.yml", 31 | "position_type": "text", 32 | "old_line": null, 33 | "new_line": 14, 34 | "line_range": null 35 | }, 36 | "resolvable": true, 37 | "resolved": false, 38 | "resolved_by": null, 39 | "resolved_at": null, 40 | "confidential": false, 41 | "internal": false, 42 | "noteable_iid": 12, 43 | "commands_changes": {} 44 | } 45 | ] 46 | } -------------------------------------------------------------------------------- /vcsutils/webhookparser/testdata/bitbucketserver/tagcreatepayload.json: -------------------------------------------------------------------------------- 1 | {"eventKey":"repo:refs_changed","date":"2023-04-20T09:32:35+0000","actor":{"name":"pavlos","emailAddress":"pavlos@jfrog.com","active":true,"displayName":"Pavlo Strokov[EXT]","id":133948,"slug":"pavlos","type":"NORMAL","links":{"self":[{"href":"https://git.jfrog.info/users/pavlos"}]}},"repository":{"slug":"integration-test","id":31103,"name":"integration-test","description":"To test froggit-go and integration project","hierarchyId":"b705b5bd6f7b29b09165","scmId":"git","state":"AVAILABLE","statusMessage":"Available","forkable":true,"project":{"key":"~PAVLOS","id":902,"name":"Pavlo Strokov[EXT]","type":"PERSONAL","owner":{"name":"pavlos","emailAddress":"pavlos@jfrog.com","active":true,"displayName":"Pavlo Strokov[EXT]","id":133948,"slug":"pavlos","type":"NORMAL","links":{"self":[{"href":"https://git.jfrog.info/users/pavlos"}]}},"links":{"self":[{"href":"https://git.jfrog.info/users/pavlos"}]}},"public":false,"archived":false,"links":{"clone":[{"href":"https://git.jfrog.info/scm/~pavlos/integration-test.git","name":"http"},{"href":"ssh://git@git.jfrog.info/~pavlos/integration-test.git","name":"ssh"}],"self":[{"href":"https://git.jfrog.info/users/pavlos/repos/integration-test/browse"}]}},"changes":[{"ref":{"id":"refs/tags/tag_intg","displayId":"tag_intg","type":"TAG"},"refId":"refs/tags/tag_intg","fromHash":"0000000000000000000000000000000000000000","toHash":"32e1a97a1a09a735ab77b4f0fb26cb5550cc2713","type":"ADD"}]} -------------------------------------------------------------------------------- /vcsclient/factory_test.go: -------------------------------------------------------------------------------- 1 | package vcsclient 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/jfrog/froggit-go/vcsutils" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | const ( 11 | apiEndpoint string = "apiEndpoint" 12 | ) 13 | 14 | func TestClientBuilder(t *testing.T) { 15 | for _, vcsProvider := range []vcsutils.VcsProvider{vcsutils.GitHub, vcsutils.GitLab, vcsutils.BitbucketCloud, vcsutils.BitbucketServer, vcsutils.AzureRepos} { 16 | t.Run(vcsProvider.String(), func(t *testing.T) { 17 | clientBuilder := NewClientBuilder(vcsProvider).ApiEndpoint(apiEndpoint).Username(username).Token(token).Project(project) 18 | assert.NotNil(t, clientBuilder) 19 | assert.Equal(t, vcsProvider, clientBuilder.vcsProvider) 20 | assert.Equal(t, apiEndpoint, clientBuilder.vcsInfo.APIEndpoint) 21 | assert.Equal(t, username, clientBuilder.vcsInfo.Username) 22 | assert.Equal(t, token, clientBuilder.vcsInfo.Token) 23 | assert.Equal(t, project, clientBuilder.vcsInfo.Project) 24 | }) 25 | } 26 | } 27 | 28 | func TestNegativeGitlabClient(t *testing.T) { 29 | vcsClient, err := NewClientBuilder(vcsutils.GitLab).ApiEndpoint("https://bad^endpoint").Build() 30 | assert.Nil(t, vcsClient) 31 | assert.Error(t, err) 32 | } 33 | 34 | func TestNegativeBitbucketCloudClient(t *testing.T) { 35 | vcsClient, err := NewClientBuilder(vcsutils.BitbucketCloud).ApiEndpoint("https://bad^endpoint").Build() 36 | assert.Nil(t, vcsClient) 37 | assert.Error(t, err) 38 | } 39 | -------------------------------------------------------------------------------- /vcsutils/webhookparser/testdata/bitbucketserver/tagdeletepayload.json: -------------------------------------------------------------------------------- 1 | {"eventKey":"repo:refs_changed","date":"2023-04-20T14:05:36+0000","actor":{"name":"pavlos","emailAddress":"pavlos@jfrog.com","active":true,"displayName":"Pavlo Strokov[EXT]","id":133948,"slug":"pavlos","type":"NORMAL","links":{"self":[{"href":"https://git.jfrog.info/users/pavlos"}]}},"repository":{"slug":"integration-test","id":31103,"name":"integration-test","description":"To test froggit-go and integration project","hierarchyId":"b705b5bd6f7b29b09165","scmId":"git","state":"AVAILABLE","statusMessage":"Available","forkable":true,"project":{"key":"~PAVLOS","id":902,"name":"Pavlo Strokov[EXT]","type":"PERSONAL","owner":{"name":"pavlos","emailAddress":"pavlos@jfrog.com","active":true,"displayName":"Pavlo Strokov[EXT]","id":133948,"slug":"pavlos","type":"NORMAL","links":{"self":[{"href":"https://git.jfrog.info/users/pavlos"}]}},"links":{"self":[{"href":"https://git.jfrog.info/users/pavlos"}]}},"public":false,"archived":false,"links":{"clone":[{"href":"https://git.jfrog.info/scm/~pavlos/integration-test.git","name":"http"},{"href":"ssh://git@git.jfrog.info/~pavlos/integration-test.git","name":"ssh"}],"self":[{"href":"https://git.jfrog.info/users/pavlos/repos/integration-test/browse"}]}},"changes":[{"ref":{"id":"refs/tags/tag_intg","displayId":"tag_intg","type":"TAG"},"refId":"refs/tags/tag_intg","fromHash":"32e1a97a1a09a735ab77b4f0fb26cb5550cc2713","toHash":"0000000000000000000000000000000000000000","type":"DELETE"}]} -------------------------------------------------------------------------------- /vcsclient/testdata/gitlab/commit_list_response.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "ed899a2f4b50b4370feeea94676502b42383c746", 4 | "short_id": "ed899a2f4b5", 5 | "title": "Replace sanitize with escape once", 6 | "author_name": "Example User", 7 | "author_email": "user@example.com", 8 | "authored_date": "2012-09-20T11:50:22+03:00", 9 | "committer_name": "Administrator", 10 | "committer_email": "admin@example.com", 11 | "committed_date": "2012-09-20T11:50:22+03:00", 12 | "created_at": "2012-09-20T11:50:22+03:00", 13 | "message": "Replace sanitize with escape once", 14 | "parent_ids": [ 15 | "6104942438c14ec7bd21c6cd5bd995272b3faff6" 16 | ], 17 | "web_url": "https://gitlab.example.com/thedude/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" 18 | }, 19 | { 20 | "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6", 21 | "short_id": "6104942438c", 22 | "title": "Sanitize for network graph", 23 | "author_name": "randx", 24 | "author_email": "user@example.com", 25 | "committer_name": "ExampleName", 26 | "committer_email": "user@example.com", 27 | "committed_date": "2012-09-20T11:50:22+03:00", 28 | "created_at": "2012-09-20T09:06:12+03:00", 29 | "message": "Sanitize for network graph", 30 | "parent_ids": [ 31 | "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba" 32 | ], 33 | "web_url": "https://gitlab.example.com/thedude/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746" 34 | } 35 | ] -------------------------------------------------------------------------------- /vcsclient/testdata/bitbucketserver/commit_list_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "size": 1, 3 | "limit": 25, 4 | "isLastPage": true, 5 | "values": [ 6 | { 7 | "id": "def0123abcdef4567abcdef8987abcdef6543abc", 8 | "displayId": "def0123abcd", 9 | "author": { 10 | "name": "charlie", 11 | "emailAddress": "charlie@example.com" 12 | }, 13 | "authorTimestamp": 1548720847609, 14 | "committer": { 15 | "name": "mark", 16 | "emailAddress": "mark@example.com" 17 | }, 18 | "committerTimestamp": 1548720847610, 19 | "message": "More work on feature 1", 20 | "parents": [ 21 | { 22 | "id": "abcdef0123abcdef4567abcdef8987abcdef6543", 23 | "displayId": "abcdef0" 24 | }, 25 | { 26 | "id": "qwerty0123abcdef4567abcdef8987abcdef6543", 27 | "displayId": "abcdef0" 28 | } 29 | ] 30 | }, 31 | { 32 | "id": "def0123abcdef4567abcdef8987abcdef6543abc", 33 | "displayId": "def0123abcd", 34 | "author": { 35 | "name": "marly", 36 | "emailAddress": "marly@example.com" 37 | }, 38 | "authorTimestamp": 1548720847609, 39 | "committer": { 40 | "name": "marly", 41 | "emailAddress": "marly@example.com" 42 | }, 43 | "committerTimestamp": 1548720847610, 44 | "message": "More work on feature 2", 45 | "parents": [ 46 | { 47 | "id": "abcdef0123abcdef4567abcdef8987abcdef6543", 48 | "displayId": "abcdef0" 49 | }, 50 | { 51 | "id": "qwerty0123abcdef4567abcdef8987abcdef6543", 52 | "displayId": "abcdef0" 53 | } 54 | ] 55 | } 56 | ], 57 | "start": 0, 58 | "authorCount": 1, 59 | "totalCount": 1 60 | } -------------------------------------------------------------------------------- /vcsutils/webhookparser/testdata/gitlab/pushpayload.json: -------------------------------------------------------------------------------- 1 | {"object_kind":"push","event_name":"push","before":"450cd4687e3644d544ca4cb3a7a355fea9e6f0dc","after":"450cd4687e3644d544ca4cb3a7a355fea9e6f0dc","ref":"refs/heads/main","checkout_sha":"450cd4687e3644d544ca4cb3a7a355fea9e6f0dc","message":null,"user_id":7768088,"user_name":"Yahav Itzhak","user_username":"yahavi","user_email":"","user_avatar":"https://secure.gravatar.com/avatar/9680da1674e22a1de17acb19bb233ebf?s=80&d=identicon","project_id":29221198,"project":{"id":29221198,"name":"hello-world","description":"","web_url":"https://gitlab.com/yahavi/hello-world","avatar_url":null,"git_ssh_url":"git@gitlab.com:yahavi/hello-world.git","git_http_url":"https://gitlab.com/yahavi/hello-world.git","namespace":"Yahav Itzhak","visibility_level":20,"path_with_namespace":"yahavi/hello-world","default_branch":"main","ci_config_path":"","homepage":"https://gitlab.com/yahavi/hello-world","url":"git@gitlab.com:yahavi/hello-world.git","ssh_url":"git@gitlab.com:yahavi/hello-world.git","http_url":"https://gitlab.com/yahavi/hello-world.git"},"commits":[{"id":"450cd4687e3644d544ca4cb3a7a355fea9e6f0dc","message":"Initial commit","title":"Initial commit","timestamp":"2021-08-30T07:01:23+00:00","url":"https://gitlab.com/yahavi/hello-world/-/commit/450cd4687e3644d544ca4cb3a7a355fea9e6f0dc","author":{"name":"Yahav Itzhak","email":"yahavitz@gmail.com"},"added":["README.md"],"modified":[],"removed":[]}],"total_commits_count":1,"push_options":{},"repository":{"name":"hello-world","url":"git@gitlab.com:yahavi/hello-world.git","description":"","homepage":"https://gitlab.com/yahavi/hello-world","git_http_url":"https://gitlab.com/yahavi/hello-world.git","git_ssh_url":"git@gitlab.com:yahavi/hello-world.git","visibility_level":20}} -------------------------------------------------------------------------------- /vcsutils/webhookparser/testdata/gitlab/tagcreatepayload.json: -------------------------------------------------------------------------------- 1 | {"object_kind":"tag_push","event_name":"tag_push","before":"0000000000000000000000000000000000000000","after":"45abefa4485f0e03fa5db86a998d16a0a1df07b7","ref":"refs/tags/first_tag","checkout_sha":"0497394e95db76bd27a177955694e06987da47e7","message":"This is a first tag","user_id":14190195,"user_name":"Rob Ivanov","user_username":"robinov","user_email":null,"user_avatar":"https://secure.gravatar.com/avatar/a47aec620663eaa2bfeaa0540e580fd5?s=80&d=identicon","project_id":44896137,"project":{"id":44896137,"name":"webhooktest","description":null,"web_url":"https://gitlab.com/grobinov/webhooktest","avatar_url":null,"git_ssh_url":"git@gitlab.com:grobinov/webhooktest.git","git_http_url":"https://gitlab.com/grobinov/webhooktest.git","namespace":"grobinov","visibility_level":0,"path_with_namespace":"grobinov/webhooktest","default_branch":"main","ci_config_path":"","homepage":"https://gitlab.com/grobinov/webhooktest","url":"git@gitlab.com:grobinov/webhooktest.git","ssh_url":"git@gitlab.com:grobinov/webhooktest.git","http_url":"https://gitlab.com/grobinov/webhooktest.git"},"commits":[{"id":"0497394e95db76bd27a177955694e06987da47e7","message":"Initial commit","title":"Initial commit","timestamp":"2023-04-04T13:43:44+00:00","url":"https://gitlab.com/grobinov/webhooktest/-/commit/0497394e95db76bd27a177955694e06987da47e7","author":{"name":"Rob Ivanov","email":"pavlos@jfrog.com"},"added":["README.md"],"modified":[],"removed":[]}],"total_commits_count":1,"push_options":{},"repository":{"name":"webhooktest","url":"git@gitlab.com:grobinov/webhooktest.git","description":null,"homepage":"https://gitlab.com/grobinov/webhooktest","git_http_url":"https://gitlab.com/grobinov/webhooktest.git","git_ssh_url":"git@gitlab.com:grobinov/webhooktest.git","visibility_level":0}} -------------------------------------------------------------------------------- /vcsclient/testdata/bitbucketcloud/get_commit_status_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "values": [ 3 | { 4 | "links": { 5 | "self": { 6 | "href": "", 7 | "name": "" 8 | }, 9 | "commit": { 10 | "href": "", 11 | "name": "" 12 | } 13 | }, 14 | "uuid": "", 15 | "key": "", 16 | "refname": "", 17 | "url": "", 18 | "state": "FAILED", 19 | "name": "", 20 | "description": "", 21 | "created_on": "", 22 | "updated_on": "" 23 | }, 24 | { 25 | "links": { 26 | "self": { 27 | "href": "", 28 | "name": "" 29 | }, 30 | "commit": { 31 | "href": "", 32 | "name": "" 33 | } 34 | }, 35 | "uuid": "", 36 | "key": "", 37 | "refname": "", 38 | "url": "", 39 | "state": "PENDING", 40 | "name": "", 41 | "description": "", 42 | "created_on": "", 43 | "updated_on": "" 44 | }, 45 | { 46 | "links": { 47 | "self": { 48 | "href": "", 49 | "name": "" 50 | }, 51 | "commit": { 52 | "href": "", 53 | "name": "" 54 | } 55 | }, 56 | "uuid": "", 57 | "key": "", 58 | "refname": "", 59 | "url": "", 60 | "state": "SUCCESS", 61 | "name": "", 62 | "description": "", 63 | "created_on": "", 64 | "updated_on": "" 65 | } 66 | ], 67 | "page": 1, 68 | "pagelen": 10, 69 | "size": 2 70 | } -------------------------------------------------------------------------------- /vcsclient/gitlabcommon.go: -------------------------------------------------------------------------------- 1 | package vcsclient 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | var errGitLabCodeScanningNotSupported = errors.New("code scanning is not supported on Gitlab") 8 | var errGitLabGetRepoEnvironmentInfoNotSupported = errors.New("get repository environment info is currently not supported on Gitlab") 9 | var errGitLabCreateBranchNotSupported = errors.New("creating a branch is not supported on Gitlab") 10 | var errGitLabAllowWorkflowsNotSupported = errors.New("allow workflows is not supported on Gitlab") 11 | var errGitLLabAddOrganizationSecretNotSupported = errors.New("adding organization secret is not supported on Gitlab") 12 | var errGitLabCreateOrgVariableNotSupported = errors.New("creating organization variable is not supported on Gitlab") 13 | var errGitLabCommitAndPushFilesNotSupported = errors.New("commit and push files is not supported on Gitlab") 14 | var errGitLabGetCollaboratorsNotSupported = errors.New("get collaborators is not supported on Gitlab") 15 | var errGitLabGetRepoTeamsByPermissionsNotSupported = errors.New("get repository Teams By permissions is not supported on Gitlab") 16 | var errGitLabCreateOrUpdateEnvironmentNotSupported = errors.New("create or update environment is not supported on Gitlab") 17 | var errGitLabMergePullRequestNotSupported = errors.New("merging pull request is not supported on Gitlab") 18 | var errGitLabListAppRepositories = errors.New("list app repositories is not supported on GitLab") 19 | var errGitlabCreatePullRequestDetailedNotSupported = errors.New("creating pull request detailed is not supported on Gitlab") 20 | var errGitLabUploadSnapshotToDependencyGraphNotSupported = errors.New("uploading snapshot to dependency graph UI is not supported on Gitlab") 21 | 22 | const ( 23 | // https://docs.gitlab.com/ee/api/merge_requests.html#create-mr 24 | gitlabMergeRequestDetailsSizeLimit = 1048576 25 | // https://docs.gitlab.com/ee/api/notes.html#create-new-merge-request-note 26 | gitlabMergeRequestCommentSizeLimit = 1000000 27 | ) 28 | -------------------------------------------------------------------------------- /vcsclient/testdata/github/pull_request_reviews_response.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 80, 4 | "node_id": "MDE3OlB1bGxSZXF1ZXN0UmV2aWV3ODA=", 5 | "user": { 6 | "login": "octocat", 7 | "id": 1, 8 | "node_id": "MDQ6VXNlcjE=", 9 | "avatar_url": "https://github.com/images/error/octocat_happy.gif", 10 | "gravatar_id": "", 11 | "url": "https://api.github.com/users/octocat", 12 | "html_url": "https://github.com/octocat", 13 | "followers_url": "https://api.github.com/users/octocat/followers", 14 | "following_url": "https://api.github.com/users/octocat/following{/other_user}", 15 | "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", 16 | "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", 17 | "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", 18 | "organizations_url": "https://api.github.com/users/octocat/orgs", 19 | "repos_url": "https://api.github.com/users/octocat/repos", 20 | "events_url": "https://api.github.com/users/octocat/events{/privacy}", 21 | "received_events_url": "https://api.github.com/users/octocat/received_events", 22 | "type": "User", 23 | "site_admin": false 24 | }, 25 | "body": "This is close to perfect! Please address the suggested inline change.", 26 | "state": "CHANGES_REQUESTED", 27 | "html_url": "https://github.com/octocat/Hello-World/pull/12#pullrequestreview-80", 28 | "pull_request_url": "https://api.github.com/repos/octocat/Hello-World/pulls/12", 29 | "_links": { 30 | "html": { 31 | "href": "https://github.com/octocat/Hello-World/pull/12#pullrequestreview-80" 32 | }, 33 | "pull_request": { 34 | "href": "https://api.github.com/repos/octocat/Hello-World/pulls/12" 35 | } 36 | }, 37 | "submitted_at": "2019-11-17T17:43:43Z", 38 | "commit_id": "ecdd80bb57125d7ba9641ffaa4d7d2c19d3f3091", 39 | "author_association": "COLLABORATOR" 40 | } 41 | ] -------------------------------------------------------------------------------- /vcsclient/factory.go: -------------------------------------------------------------------------------- 1 | package vcsclient 2 | 3 | import ( 4 | "github.com/jfrog/froggit-go/vcsutils" 5 | ) 6 | 7 | // ClientBuilder builds VcsClient 8 | type ClientBuilder struct { 9 | vcsProvider vcsutils.VcsProvider 10 | vcsInfo VcsInfo 11 | logger vcsutils.Log 12 | } 13 | 14 | // NewClientBuilder creates new ClientBuilder 15 | func NewClientBuilder(vcsProvider vcsutils.VcsProvider) *ClientBuilder { 16 | return &ClientBuilder{vcsProvider: vcsProvider, logger: vcsutils.EmptyLogger{}} 17 | } 18 | 19 | // ApiEndpoint sets the API endpoint 20 | func (builder *ClientBuilder) ApiEndpoint(apiEndpoint string) *ClientBuilder { 21 | builder.vcsInfo.APIEndpoint = apiEndpoint 22 | return builder 23 | } 24 | 25 | // Username sets the username 26 | func (builder *ClientBuilder) Username(username string) *ClientBuilder { 27 | builder.vcsInfo.Username = username 28 | return builder 29 | } 30 | 31 | // Token sets the access token 32 | func (builder *ClientBuilder) Token(token string) *ClientBuilder { 33 | builder.vcsInfo.Token = token 34 | return builder 35 | } 36 | 37 | // Logger sets the logger 38 | func (builder *ClientBuilder) Logger(logger vcsutils.Log) *ClientBuilder { 39 | builder.logger = logger 40 | return builder 41 | } 42 | 43 | // Project sets the project 44 | func (builder *ClientBuilder) Project(project string) *ClientBuilder { 45 | builder.vcsInfo.Project = project 46 | return builder 47 | } 48 | 49 | // Build builds the VcsClient 50 | func (builder *ClientBuilder) Build() (VcsClient, error) { 51 | switch builder.vcsProvider { 52 | case vcsutils.GitHub: 53 | return NewGitHubClient(builder.vcsInfo, builder.logger) 54 | case vcsutils.GitLab: 55 | return NewGitLabClient(builder.vcsInfo, builder.logger) 56 | case vcsutils.BitbucketServer: 57 | return NewBitbucketServerClient(builder.vcsInfo, builder.logger) 58 | case vcsutils.BitbucketCloud: 59 | return NewBitbucketCloudClient(builder.vcsInfo, builder.logger) 60 | case vcsutils.AzureRepos: 61 | return NewAzureReposClient(builder.vcsInfo, builder.logger) 62 | } 63 | return nil, nil 64 | } 65 | -------------------------------------------------------------------------------- /THIRD_PARTY_NOTICES: -------------------------------------------------------------------------------- 1 | JFrog 2 | 3 | THIRD-PARTY SOFTWARE NOTICES AND INFORMATION 4 | Do Not Translate or Localize 5 | 6 | This project incorporates various components from those projects listed below. JFrog is using such components under the following original copyright notices and the licenses: 7 | 8 | 1. stretchr/testify (https://github.com/stretchr/testify) - Copyright (c) 2012-2020, Mat Ryer, Tyler Bunnell and contributors; Licensed under MIT License (https://github.com/stretchr/testify/blob/master/LICENSE) 9 | 2. google/go-github (https://github.com/google/go-github) - Copyright (c) 2013, The go-github AUTHORS; Licensed under BSD 3-Clause "New" or "Revised" License (https://github.com/google/go-github/blob/master/LICENSE) 10 | 3. google/uuid (https://github.com/google/uuid) - Copyright (c) 2009,2014 Google Inc; Licensed under BSD 3-Clause "New" or "Revised" License (https://github.com/google/uuid/blob/master/LICENSE) 11 | 4. ktrysmt/go-bitbucket (https://github.com/ktrysmt/go-bitbucket) - Licensed under Apache License 2.0 (https://github.com/ktrysmt/go-bitbucket/blob/master/LICENSE) 12 | 5. gfleury/go-bitbucket-v1 (https://github.com/gfleury/go-bitbucket-v1) - Copyright (c) 2018 George S. Fleury, Licensed under MIT License (https://github.com/gfleury/go-bitbucket-v1/blob/master/LICENSE) 13 | 6. xanzy/go-gitlab (https://github.com/xanzy/go-gitlab) - Licensed under Apache License 2.0 (https://github.com/xanzy/go-gitlab/blob/master/LICENSE) 14 | 7. golang.org/x/crypto (https://cs.opensource.google/go/x/crypto) - Copyright (c) 2009 The Go Authors; Licensed under BSD-3-Clause License (https://cs.opensource.google/go/x/crypto/+/master:LICENSE) 15 | 8. golang.org/x/oauth2 (https://cs.opensource.google/go/x/oauth2) - Copyright (c) 2009 The Go Authors; Licensed under BSD-3-Clause License (https://cs.opensource.google/go/x/oauth2/+/master:LICENSE) 16 | 9. mitchellh/mapstructure (https://github.com/mitchellh/mapstructure) - Copyright (c) 2013 Mitchell Hashimoto; Licensed under MIT License (https://github.com/mitchellh/mapstructure/blob/master/LICENSE) 17 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/jfrog/froggit-go 2 | 3 | go 1.23.0 4 | 5 | require ( 6 | github.com/gfleury/go-bitbucket-v1 v0.0.0-20230825095122-9bc1711434ab 7 | github.com/go-git/go-git/v5 v5.16.0 8 | github.com/google/go-github/v74 v74.0.0 9 | github.com/google/uuid v1.6.0 10 | github.com/grokify/mogo v0.64.12 11 | github.com/jfrog/gofrog v1.7.6 12 | github.com/ktrysmt/go-bitbucket v0.9.80 13 | github.com/microsoft/azure-devops-go-api/azuredevops/v7 v7.1.0 14 | github.com/mitchellh/mapstructure v1.5.0 15 | github.com/stretchr/testify v1.10.0 16 | github.com/xanzy/go-gitlab v0.110.0 17 | golang.org/x/crypto v0.37.0 18 | golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c 19 | golang.org/x/oauth2 v0.20.0 20 | ) 21 | 22 | require ( 23 | dario.cat/mergo v1.0.0 // indirect 24 | github.com/Microsoft/go-winio v0.6.2 // indirect 25 | github.com/ProtonMail/go-crypto v1.1.6 // indirect 26 | github.com/cloudflare/circl v1.6.1 // indirect 27 | github.com/cyphar/filepath-securejoin v0.4.1 // indirect 28 | github.com/davecgh/go-spew v1.1.1 // indirect 29 | github.com/emirpasic/gods v1.18.1 // indirect 30 | github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect 31 | github.com/go-git/go-billy/v5 v5.6.2 // indirect 32 | github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect 33 | github.com/google/go-querystring v1.1.0 // indirect 34 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect 35 | github.com/hashicorp/go-retryablehttp v0.7.7 // indirect 36 | github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect 37 | github.com/kevinburke/ssh_config v1.2.0 // indirect 38 | github.com/pjbgf/sha1cd v0.3.2 // indirect 39 | github.com/pmezard/go-difflib v1.0.0 // indirect 40 | github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect 41 | github.com/skeema/knownhosts v1.3.1 // indirect 42 | github.com/xanzy/ssh-agent v0.3.3 // indirect 43 | golang.org/x/net v0.39.0 // indirect 44 | golang.org/x/sys v0.32.0 // indirect 45 | golang.org/x/time v0.3.0 // indirect 46 | gopkg.in/warnings.v0 v0.1.2 // indirect 47 | gopkg.in/yaml.v3 v3.0.1 // indirect 48 | ) 49 | -------------------------------------------------------------------------------- /vcsclient/testdata/github/repository_environment_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 458044593, 3 | "node_id": "EN_kwDOFo0fF84bTTSx", 4 | "name": "frogbot", 5 | "url": "https://api.github.com/repos/superfrog/test-repo/environments/frogbot", 6 | "html_url": "https://github.com/superfrog/test-repo/deployments/activity_log?environments_filter=frogbot", 7 | "created_at": "2022-04-07T05:57:50Z", 8 | "updated_at": "2022-04-07T05:57:50Z", 9 | "protection_rules": [ 10 | { 11 | "id": 210348, 12 | "node_id": "GA_kwDOFo0fF84AAzWs", 13 | "type": "required_reviewers", 14 | "reviewers": [ 15 | { 16 | "type": "User", 17 | "reviewer": { 18 | "login": "superfrog", 19 | "id": 11367982, 20 | "node_id": "MDQ6VXNlcjExMzY3OTgy", 21 | "avatar_url": "https://avatars.githubusercontent.com/u/11367982?v=4", 22 | "gravatar_id": "", 23 | "url": "https://api.github.com/users/superfrog", 24 | "html_url": "https://github.com/superfrog", 25 | "followers_url": "https://api.github.com/users/superfrog/followers", 26 | "following_url": "https://api.github.com/users/superfrog/following{/other_user}", 27 | "gists_url": "https://api.github.com/users/superfrog/gists{/gist_id}", 28 | "starred_url": "https://api.github.com/users/superfrog/starred{/owner}{/repo}", 29 | "subscriptions_url": "https://api.github.com/users/superfrog/subscriptions", 30 | "organizations_url": "https://api.github.com/users/superfrog/orgs", 31 | "repos_url": "https://api.github.com/users/superfrog/repos", 32 | "events_url": "https://api.github.com/users/superfrog/events{/privacy}", 33 | "received_events_url": "https://api.github.com/users/superfrog/received_events", 34 | "type": "User", 35 | "site_admin": false 36 | } 37 | } 38 | ] 39 | } 40 | ], 41 | "deployment_branch_policy": null 42 | } -------------------------------------------------------------------------------- /vcsclient/testdata/azurerepos/commits_statuses.json: -------------------------------------------------------------------------------- 1 | { 2 | "count": 1, 3 | "value": [ 4 | { 5 | "state": "succeeded", 6 | "description": "The build is successful", 7 | "context": { 8 | "name": "Build123", 9 | "genre": "continuous-integration" 10 | }, 11 | "creationDate": "2016-01-27T09:33:07Z", 12 | "createdBy": { 13 | "id": "278d5cd2-584d-4b63-824a-2ba458937249", 14 | "displayName": "Norman Paulk", 15 | "uniqueName": "Fabrikamfiber16", 16 | "url": "https://dev.azure.com/fabrikam/_apis/Identities/278d5cd2-584d-4b63-824a-2ba458937249", 17 | "imageUrl": "https://dev.azure.com/fabrikam/_api/_common/identityImage?id=278d5cd2-584d-4b63-824a-2ba458937249" 18 | }, 19 | "targetUrl": "https://ci.fabrikam.com/my-project/build/123 " 20 | }, 21 | { 22 | "state": "pending", 23 | "description": "The build is pending", 24 | "context": { 25 | "name": "Build123", 26 | "genre": "continuous-integration" 27 | }, 28 | "creationDate": "2016-01-27T09:33:07Z", 29 | "createdBy": { 30 | "id": "278d5cd2-584d-4b63-824a-2ba458937249", 31 | "displayName": "Norman Paulk", 32 | "uniqueName": "Fabrikamfiber16", 33 | "url": "https://dev.azure.com/fabrikam/_apis/Identities/278d5cd2-584d-4b63-824a-2ba458937249", 34 | "imageUrl": "https://dev.azure.com/fabrikam/_api/_common/identityImage?id=278d5cd2-584d-4b63-824a-2ba458937249" 35 | }, 36 | "targetUrl": "https://ci.fabrikam.com/my-project/build/123 " 37 | }, 38 | { 39 | "state": "failed", 40 | "description": "The build has failed", 41 | "context": { 42 | "name": "Build123", 43 | "genre": "continuous-integration" 44 | }, 45 | "creationDate": "2016-01-27T09:33:07Z", 46 | "createdBy": { 47 | "id": "278d5cd2-584d-4b63-824a-2ba458937249", 48 | "displayName": "Norman Paulk", 49 | "uniqueName": "Fabrikamfiber16", 50 | "url": "https://dev.azure.com/fabrikam/_apis/Identities/278d5cd2-584d-4b63-824a-2ba458937249", 51 | "imageUrl": "https://dev.azure.com/fabrikam/_api/_common/identityImage?id=278d5cd2-584d-4b63-824a-2ba458937249" 52 | }, 53 | "targetUrl": "https://ci.fabrikam.com/my-project/build/123 " 54 | } 55 | ] 56 | } -------------------------------------------------------------------------------- /vcsclient/testdata/gitlab/commits_statuses.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "status" : "success", 4 | "created_at" : "2016-01-19T08:40:25.934Z", 5 | "started_at" : null, 6 | "name" : "bundler:audit", 7 | "allow_failure" : true, 8 | "author" : { 9 | "username" : "janedoe", 10 | "state" : "active", 11 | "web_url" : "https://gitlab.example.com/janedoe", 12 | "avatar_url" : "https://gitlab.example.com/uploads/user/avatar/28/jane-doe-400-400.png", 13 | "id" : 28, 14 | "name" : "Jane Doe" 15 | }, 16 | "description" : "this is my description", 17 | "sha" : "18f3e63d05582537db6d183d9d557be09e1f90c8", 18 | "target_url" : "https://gitlab.example.com/janedoe/gitlab-foss/builds/91", 19 | "finished_at" : null, 20 | "id" : 91, 21 | "ref" : "master" 22 | }, 23 | { 24 | "started_at" : null, 25 | "name" : "test", 26 | "allow_failure" : false, 27 | "status" : "pending", 28 | "created_at" : "2016-01-19T08:40:25.832Z", 29 | "target_url" : "https://gitlab.example.com/janedoe/gitlab-foss/builds/90", 30 | "id" : 90, 31 | "finished_at" : null, 32 | "ref" : "master", 33 | "sha" : "18f3e63d05582537db6d183d9d557be09e1f90c8", 34 | "author" : { 35 | "id" : 28, 36 | "name" : "Jane Doe", 37 | "username" : "janedoe", 38 | "web_url" : "https://gitlab.example.com/janedoe", 39 | "state" : "active", 40 | "avatar_url" : "https://gitlab.example.com/uploads/user/avatar/28/jane-doe-400-400.png" 41 | }, 42 | "description" : null 43 | }, 44 | { 45 | "started_at" : null, 46 | "name" : "test", 47 | "allow_failure" : false, 48 | "status" : "failure", 49 | "created_at" : "2016-01-19T08:40:25.832Z", 50 | "target_url" : "https://gitlab.example.com/janedoe/gitlab-foss/builds/90", 51 | "id" : 90, 52 | "finished_at" : null, 53 | "ref" : "master", 54 | "sha" : "18f3e63d05582537db6d183d9d557be09e1f90c8", 55 | "author" : { 56 | "id" : 28, 57 | "name" : "Jane Doe", 58 | "username" : "janedoe", 59 | "web_url" : "https://gitlab.example.com/janedoe", 60 | "state" : "active", 61 | "avatar_url" : "https://gitlab.example.com/uploads/user/avatar/28/jane-doe-400-400.png" 62 | }, 63 | "description" : null 64 | } 65 | ] -------------------------------------------------------------------------------- /vcsclient/testdata/gitlab/merge_request_discussion_items.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "6a9c1750b37d513a43987b574953fceb50b03ce7", 4 | "individual_note": false, 5 | "notes": [ 6 | { 7 | "id": 1126, 8 | "type": "DiscussionNote", 9 | "body": "discussion text", 10 | "attachment": null, 11 | "author": { 12 | "id": 1, 13 | "name": "root", 14 | "username": "root", 15 | "state": "active", 16 | "avatar_url": "https://www.gravatar.com/avatar/00afb8fb6ab07c3ee3e9c1f38777e2f4?s=80&d=identicon", 17 | "web_url": "http://localhost:3000/root" 18 | }, 19 | "created_at": "2018-03-03T21:54:39.668Z", 20 | "updated_at": "2018-03-03T21:54:39.668Z", 21 | "system": false, 22 | "noteable_id": 3, 23 | "noteable_type": "Merge request", 24 | "project_id": 5, 25 | "noteable_iid": null, 26 | "resolved": false, 27 | "resolvable": true, 28 | "resolved_by": null, 29 | "resolved_at": null 30 | }, 31 | { 32 | "id": 1129, 33 | "type": "DiscussionNote", 34 | "body": "reply to the discussion", 35 | "attachment": null, 36 | "author": { 37 | "id": 1, 38 | "name": "root", 39 | "username": "root", 40 | "state": "active", 41 | "avatar_url": "https://www.gravatar.com/avatar/00afb8fb6ab07c3ee3e9c1f38777e2f4?s=80&d=identicon", 42 | "web_url": "http://localhost:3000/root" 43 | }, 44 | "created_at": "2018-03-04T13:38:02.127Z", 45 | "updated_at": "2018-03-04T13:38:02.127Z", 46 | "system": false, 47 | "noteable_id": 3, 48 | "noteable_type": "Merge request", 49 | "project_id": 5, 50 | "noteable_iid": null, 51 | "resolved": false, 52 | "resolvable": true, 53 | "resolved_by": null 54 | } 55 | ] 56 | }, 57 | { 58 | "id": "87805b7c09016a7058e91bdbe7b29d1f284a39e6", 59 | "individual_note": true, 60 | "notes": [ 61 | { 62 | "id": 1128, 63 | "type": null, 64 | "body": "a single comment", 65 | "attachment": null, 66 | "author": { 67 | "id": 1, 68 | "name": "root", 69 | "username": "root", 70 | "state": "active", 71 | "avatar_url": "https://www.gravatar.com/avatar/00afb8fb6ab07c3ee3e9c1f38777e2f4?s=80&d=identicon", 72 | "web_url": "http://localhost:3000/root" 73 | }, 74 | "created_at": "2018-03-04T09:17:22.520Z", 75 | "updated_at": "2018-03-04T09:17:22.520Z", 76 | "system": false, 77 | "noteable_id": 3, 78 | "noteable_type": "Merge request", 79 | "project_id": 5, 80 | "noteable_iid": null, 81 | "resolved": false, 82 | "resolvable": true, 83 | "resolved_by": null 84 | } 85 | ] 86 | } 87 | ] -------------------------------------------------------------------------------- /vcsutils/webhookparser/testdata/bitbucketserver/prcreatepayload.json: -------------------------------------------------------------------------------- 1 | {"eventKey":"pr:opened","date":"2021-09-09T12:11:01+0300","actor":{"name":"yahavi","emailAddress":"yahavi@jfrog.com","id":721,"displayName":"Yahav Itzhak","active":true,"slug":"yahavi","type":"NORMAL","links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"pullRequest":{"id":3,"version":0,"title":"Update README.md","state":"OPEN","open":true,"closed":false,"createdDate":1631178661307,"updatedDate":1631178661307,"fromRef":{"id":"refs/heads/dev","displayId":"dev","latestCommit":"b3fc2f0a02761b443fca72022a2ac897cc2ceb3a","repository":{"slug":"hello-world","id":2041,"name":"hello-world","hierarchyId":"aa146c1c8852cf49e15e","scmId":"git","state":"AVAILABLE","statusMessage":"Available","forkable":true,"project":{"key":"~YAHAVI","id":605,"name":"Yahav Itzhak","type":"PERSONAL","owner":{"name":"yahavi","emailAddress":"yahavi@jfrog.com","id":721,"displayName":"Yahav Itzhak","active":true,"slug":"yahavi","type":"NORMAL","links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"public":false,"links":{"clone":[{"href":"ssh://git@git.acme.info/~yahavi/hello-world.git","name":"ssh"},{"href":"https://git.acme.info/scm/~yahavi/hello-world.git","name":"http"}],"self":[{"href":"https://git.acme.info/users/yahavi/repos/hello-world/browse"}]}}},"toRef":{"id":"refs/heads/main","displayId":"main","latestCommit":"929d3054cf60e11a38672966f948bb5d95f48f0e","repository":{"slug":"hello-world","id":2041,"name":"hello-world","hierarchyId":"aa146c1c8852cf49e15e","scmId":"git","state":"AVAILABLE","statusMessage":"Available","forkable":true,"project":{"key":"~YAHAVI","id":605,"name":"Yahav Itzhak","type":"PERSONAL","owner":{"name":"yahavi","emailAddress":"yahavi@jfrog.com","id":721,"displayName":"Yahav Itzhak","active":true,"slug":"yahavi","type":"NORMAL","links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"public":false,"links":{"clone":[{"href":"ssh://git@git.acme.info/~yahavi/hello-world.git","name":"ssh"},{"href":"https://git.acme.info/scm/~yahavi/hello-world.git","name":"http"}],"self":[{"href":"https://git.acme.info/users/yahavi/repos/hello-world/browse"}]}}},"locked":false,"author":{"user":{"name":"yahavi","emailAddress":"yahavi@jfrog.com","id":721,"displayName":"Yahav Itzhak","active":true,"slug":"yahavi","type":"NORMAL","links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"role":"AUTHOR","approved":false,"status":"UNAPPROVED"},"reviewers":[],"participants":[],"links":{"self":[{"href":"https://git.acme.info/users/yahavi/repos/hello-world/pull-requests/3"}]}}} -------------------------------------------------------------------------------- /vcsclient/testdata/azurerepos/commits.json: -------------------------------------------------------------------------------- 1 | { 2 | "count":3, 3 | "value":[ 4 | { 5 | "commitId":"86d6919952702f9ab03bc95b45687f145a663de0", 6 | "author":{ 7 | "name":"Test User", 8 | "email":"testuser@jfrog.com", 9 | "date":"2022-11-07T09:16:41Z" 10 | }, 11 | "committer":{ 12 | "name":"Test User", 13 | "email":"testuser@jfrog.com", 14 | "date":"2022-11-07T09:16:41Z" 15 | }, 16 | "comment":"Updated package.json", 17 | "changeCounts":{ 18 | "Add":0, 19 | "Edit":1, 20 | "Delete":0 21 | }, 22 | "url":"https://dev.azure.com/testuser/0b8072c4-ad86-4edb-a8f2-06dbc07e3e2d/_apis/git/repositories/94c1dba8-d9d9-4600-94b4-1a51acb43220/commits/86d6919952702f9ab03bc95b45687f145a663de0", 23 | "remoteUrl":"https://dev.azure.com/testuser/test/_git/test/commit/86d6919952702f9ab03bc95b45687f145a663de0" 24 | }, 25 | { 26 | "commitId":"4aa8367809020c4e97af29e2b57f7528d5d27702", 27 | "author":{ 28 | "name":"Test User", 29 | "email":"testuser@jfrog.com", 30 | "date":"2022-10-31T07:29:03Z" 31 | }, 32 | "committer":{ 33 | "name":"Test User", 34 | "email":"testuser@jfrog.com", 35 | "date":"2022-10-31T07:29:03Z" 36 | }, 37 | "comment":"Set up CI with Azure Pipelines", 38 | "commentTruncated":true, 39 | "changeCounts":{ 40 | "Add":1, 41 | "Edit":0, 42 | "Delete":0 43 | }, 44 | "url":"https://dev.azure.com/testuser/0b8072c4-ad86-4edb-a8f2-06dbc07e3e2d/_apis/git/repositories/94c1dba8-d9d9-4600-94b4-1a51acb43220/commits/4aa8367809020c4e97af29e2b57f7528d5d27702", 45 | "remoteUrl":"https://dev.azure.com/testuser/test/_git/test/commit/4aa8367809020c4e97af29e2b57f7528d5d27702" 46 | }, 47 | { 48 | "commitId":"3779104c35804e15b6fdf4fee303e717cd6c1352", 49 | "author":{ 50 | "name":"Test User", 51 | "email":"testuser@jfrog.com", 52 | "date":"2022-10-31T07:26:40Z" 53 | }, 54 | "committer":{ 55 | "name":"Test User", 56 | "email":"testuser@jfrog.com", 57 | "date":"2022-10-31T07:26:40Z" 58 | }, 59 | "comment":"first commit", 60 | "changeCounts":{ 61 | "Add":2180, 62 | "Edit":0, 63 | "Delete":0 64 | }, 65 | "url":"https://dev.azure.com/testuser/0b8072c4-ad86-4edb-a8f2-06dbc07e3e2d/_apis/git/repositories/94c1dba8-d9d9-4600-94b4-1a51acb43220/commits/3779104c35804e15b6fdf4fee303e717cd6c1352", 66 | "remoteUrl":"https://dev.azure.com/testuser/test/_git/test/commit/3779104c35804e15b6fdf4fee303e717cd6c1352" 67 | } 68 | ] 69 | } -------------------------------------------------------------------------------- /vcsutils/retryexecutor_test.go: -------------------------------------------------------------------------------- 1 | package vcsutils 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "github.com/stretchr/testify/assert" 7 | "testing" 8 | ) 9 | 10 | func TestRetryExecutorSuccess(t *testing.T) { 11 | retriesToPerform := 10 12 | breakRetriesAt := 4 13 | runCount := 0 14 | executor := RetryExecutor{ 15 | MaxRetries: retriesToPerform, 16 | RetriesIntervalMilliSecs: 0, 17 | ErrorMessage: "Testing RetryExecutor", 18 | ExecutionHandler: func() (bool, error) { 19 | runCount++ 20 | if runCount == breakRetriesAt { 21 | return false, nil 22 | } 23 | return true, nil 24 | }, 25 | Logger: EmptyLogger{}, 26 | } 27 | 28 | assert.NoError(t, executor.Execute()) 29 | assert.Equal(t, breakRetriesAt, runCount) 30 | } 31 | 32 | func TestRetryExecutorTimeoutWithDefaultError(t *testing.T) { 33 | retriesToPerform := 5 34 | runCount := 0 35 | 36 | executor := RetryExecutor{ 37 | MaxRetries: retriesToPerform, 38 | RetriesIntervalMilliSecs: 0, 39 | ErrorMessage: "Testing RetryExecutor", 40 | ExecutionHandler: func() (bool, error) { 41 | runCount++ 42 | return true, nil 43 | }, 44 | Logger: EmptyLogger{}, 45 | } 46 | 47 | assert.Equal(t, executor.Execute(), RetryExecutorTimeoutError{executor.getTimeoutErrorMsg()}) 48 | assert.Equal(t, retriesToPerform+1, runCount) 49 | } 50 | 51 | func TestRetryExecutorTimeoutWithCustomError(t *testing.T) { 52 | retriesToPerform := 5 53 | runCount := 0 54 | 55 | executionHandler := errors.New("retry failed due to reason") 56 | 57 | executor := RetryExecutor{ 58 | MaxRetries: retriesToPerform, 59 | RetriesIntervalMilliSecs: 0, 60 | ErrorMessage: "Testing RetryExecutor", 61 | ExecutionHandler: func() (bool, error) { 62 | runCount++ 63 | return true, executionHandler 64 | }, 65 | Logger: EmptyLogger{}, 66 | } 67 | 68 | assert.Equal(t, executor.Execute(), executionHandler) 69 | assert.Equal(t, retriesToPerform+1, runCount) 70 | } 71 | 72 | func TestRetryExecutorCancel(t *testing.T) { 73 | retriesToPerform := 5 74 | runCount := 0 75 | 76 | retryContext, cancelFunc := context.WithCancel(context.Background()) 77 | executor := RetryExecutor{ 78 | Context: retryContext, 79 | MaxRetries: retriesToPerform, 80 | RetriesIntervalMilliSecs: 0, 81 | ErrorMessage: "Testing RetryExecutor", 82 | ExecutionHandler: func() (bool, error) { 83 | runCount++ 84 | return true, nil 85 | }, 86 | Logger: EmptyLogger{}, 87 | } 88 | 89 | cancelFunc() 90 | assert.EqualError(t, executor.Execute(), context.Canceled.Error()) 91 | assert.Equal(t, 1, runCount) 92 | } 93 | -------------------------------------------------------------------------------- /vcsutils/webhookparser/testdata/bitbucketserver/prdeletepayload.json: -------------------------------------------------------------------------------- 1 | {"eventKey":"pr:deleted","date":"2021-12-06T14:43:01+0200","actor":{"name":"yahavi","emailAddress":"yahavi@jfrog.com","id":721,"displayName":"Yahav Itzhak","active":true,"slug":"yahavi","type":"NORMAL","links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"pullRequest":{"id":3,"version":0,"title":"Update README.md","state":"OPEN","open":true,"closed":false,"createdDate":1631178661307,"updatedDate":1638794581247,"closedDate":1638794581247,"fromRef":{"id":"refs/heads/dev","displayId":"dev","latestCommit":"b3fc2f0a02761b443fca72022a2ac897cc2ceb3a","repository":{"slug":"hello-world","id":2041,"name":"hello-world","hierarchyId":"aa146c1c8852cf49e15e","scmId":"git","state":"AVAILABLE","statusMessage":"Available","forkable":true,"project":{"key":"~YAHAVI","id":605,"name":"Yahav Itzhak","type":"PERSONAL","owner":{"name":"yahavi","emailAddress":"yahavi@jfrog.com","id":721,"displayName":"Yahav Itzhak","active":true,"slug":"yahavi","type":"NORMAL","links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"public":false,"links":{"clone":[{"href":"ssh://git@git.acme.info/~yahavi/hello-world.git","name":"ssh"},{"href":"https://git.acme.info/scm/~yahavi/hello-world.git","name":"http"}],"self":[{"href":"https://git.acme.info/users/yahavi/repos/hello-world/browse"}]}}},"toRef":{"id":"refs/heads/main","displayId":"main","latestCommit":"929d3054cf60e11a38672966f948bb5d95f48f0e","repository":{"slug":"hello-world","id":2041,"name":"hello-world","hierarchyId":"aa146c1c8852cf49e15e","scmId":"git","state":"AVAILABLE","statusMessage":"Available","forkable":true,"project":{"key":"~YAHAVI","id":605,"name":"Yahav Itzhak","type":"PERSONAL","owner":{"name":"yahavi","emailAddress":"yahavi@jfrog.com","id":721,"displayName":"Yahav Itzhak","active":true,"slug":"yahavi","type":"NORMAL","links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"public":false,"links":{"clone":[{"href":"ssh://git@git.acme.info/~yahavi/hello-world.git","name":"ssh"},{"href":"https://git.acme.info/scm/~yahavi/hello-world.git","name":"http"}],"self":[{"href":"https://git.acme.info/users/yahavi/repos/hello-world/browse"}]}}},"locked":false,"author":{"user":{"name":"yahavi","emailAddress":"yahavi@jfrog.com","id":721,"displayName":"Yahav Itzhak","active":true,"slug":"yahavi","type":"NORMAL","links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"role":"AUTHOR","approved":false,"status":"UNAPPROVED"},"reviewers":[],"participants":[],"links":{"self":[{"href":"https://git.acme.info/users/yahavi/repos/hello-world/pull-requests/3"}]}}} -------------------------------------------------------------------------------- /vcsutils/webhookparser/testdata/bitbucketserver/prdeclinepayload.json: -------------------------------------------------------------------------------- 1 | {"eventKey":"pr:declined","date":"2021-12-06T14:42:01+0200","actor":{"name":"yahavi","emailAddress":"yahavi@jfrog.com","id":721,"displayName":"Yahav Itzhak","active":true,"slug":"yahavi","type":"NORMAL","links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"pullRequest":{"id":3,"version":0,"title":"Update README.md","state":"DECLINED","open":false,"closed":true,"createdDate":1631178661307,"updatedDate":1638794521247,"closedDate":1638794521247,"fromRef":{"id":"refs/heads/dev","displayId":"dev","latestCommit":"b3fc2f0a02761b443fca72022a2ac897cc2ceb3a","repository":{"slug":"hello-world","id":2041,"name":"hello-world","hierarchyId":"aa146c1c8852cf49e15e","scmId":"git","state":"AVAILABLE","statusMessage":"Available","forkable":true,"project":{"key":"~YAHAVI","id":605,"name":"Yahav Itzhak","type":"PERSONAL","owner":{"name":"yahavi","emailAddress":"yahavi@jfrog.com","id":721,"displayName":"Yahav Itzhak","active":true,"slug":"yahavi","type":"NORMAL","links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"public":false,"links":{"clone":[{"href":"ssh://git@git.acme.info/~yahavi/hello-world.git","name":"ssh"},{"href":"https://git.acme.info/scm/~yahavi/hello-world.git","name":"http"}],"self":[{"href":"https://git.acme.info/users/yahavi/repos/hello-world/browse"}]}}},"toRef":{"id":"refs/heads/main","displayId":"main","latestCommit":"929d3054cf60e11a38672966f948bb5d95f48f0e","repository":{"slug":"hello-world","id":2041,"name":"hello-world","hierarchyId":"aa146c1c8852cf49e15e","scmId":"git","state":"AVAILABLE","statusMessage":"Available","forkable":true,"project":{"key":"~YAHAVI","id":605,"name":"Yahav Itzhak","type":"PERSONAL","owner":{"name":"yahavi","emailAddress":"yahavi@jfrog.com","id":721,"displayName":"Yahav Itzhak","active":true,"slug":"yahavi","type":"NORMAL","links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"public":false,"links":{"clone":[{"href":"ssh://git@git.acme.info/~yahavi/hello-world.git","name":"ssh"},{"href":"https://git.acme.info/scm/~yahavi/hello-world.git","name":"http"}],"self":[{"href":"https://git.acme.info/users/yahavi/repos/hello-world/browse"}]}}},"locked":false,"author":{"user":{"name":"yahavi","emailAddress":"yahavi@jfrog.com","id":721,"displayName":"Yahav Itzhak","active":true,"slug":"yahavi","type":"NORMAL","links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"role":"AUTHOR","approved":false,"status":"UNAPPROVED"},"reviewers":[],"participants":[],"links":{"self":[{"href":"https://git.acme.info/users/yahavi/repos/hello-world/pull-requests/3"}]}}} -------------------------------------------------------------------------------- /vcsutils/webhookparser/testdata/bitbucketserver/prupdatepayload.json: -------------------------------------------------------------------------------- 1 | {"eventKey":"pr:from_ref_updated","date":"2021-09-09T12:36:25+0300","actor":{"name":"yahavi","emailAddress":"yahavi@jfrog.com","id":721,"displayName":"Yahav Itzhak","active":true,"slug":"yahavi","type":"NORMAL","links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"pullRequest":{"id":3,"version":0,"title":"Update README.md","state":"OPEN","open":true,"closed":false,"createdDate":1631178661307,"updatedDate":1631180185186,"fromRef":{"id":"refs/heads/dev","displayId":"dev","latestCommit":"4116e7fd0dffeff395c4697653912ad4c19e1c5b","repository":{"slug":"hello-world","id":2041,"name":"hello-world","hierarchyId":"aa146c1c8852cf49e15e","scmId":"git","state":"AVAILABLE","statusMessage":"Available","forkable":true,"project":{"key":"~YAHAVI","id":605,"name":"Yahav Itzhak","type":"PERSONAL","owner":{"name":"yahavi","emailAddress":"yahavi@jfrog.com","id":721,"displayName":"Yahav Itzhak","active":true,"slug":"yahavi","type":"NORMAL","links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"public":false,"links":{"clone":[{"href":"ssh://git@git.acme.info/~yahavi/hello-world.git","name":"ssh"},{"href":"https://git.acme.info/scm/~yahavi/hello-world.git","name":"http"}],"self":[{"href":"https://git.acme.info/users/yahavi/repos/hello-world/browse"}]}}},"toRef":{"id":"refs/heads/main","displayId":"main","latestCommit":"929d3054cf60e11a38672966f948bb5d95f48f0e","repository":{"slug":"hello-world","id":2041,"name":"hello-world","hierarchyId":"aa146c1c8852cf49e15e","scmId":"git","state":"AVAILABLE","statusMessage":"Available","forkable":true,"project":{"key":"~YAHAVI","id":605,"name":"Yahav Itzhak","type":"PERSONAL","owner":{"name":"yahavi","emailAddress":"yahavi@jfrog.com","id":721,"displayName":"Yahav Itzhak","active":true,"slug":"yahavi","type":"NORMAL","links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"public":false,"links":{"clone":[{"href":"ssh://git@git.acme.info/~yahavi/hello-world.git","name":"ssh"},{"href":"https://git.acme.info/scm/~yahavi/hello-world.git","name":"http"}],"self":[{"href":"https://git.acme.info/users/yahavi/repos/hello-world/browse"}]}}},"locked":false,"author":{"user":{"name":"yahavi","emailAddress":"yahavi@jfrog.com","id":721,"displayName":"Yahav Itzhak","active":true,"slug":"yahavi","type":"NORMAL","links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"role":"AUTHOR","approved":false,"status":"UNAPPROVED"},"reviewers":[],"participants":[],"links":{"self":[{"href":"https://git.acme.info/users/yahavi/repos/hello-world/pull-requests/3"}]}},"previousFromHash":"b3fc2f0a02761b443fca72022a2ac897cc2ceb3a"} -------------------------------------------------------------------------------- /vcsclient/testdata/bitbucketcloud/compare_commits.json: -------------------------------------------------------------------------------- 1 | { 2 | "pagelen": 500, 3 | "values": [ 4 | { 5 | "type": "diffstat", 6 | "status": "modified", 7 | "lines_removed": 1, 8 | "lines_added": 2, 9 | "old": { 10 | "path": "setup.py", 11 | "escaped_path": "setup.py", 12 | "type": "commit_file", 13 | "links": { 14 | "self": { 15 | "href": "https://api.bitbucket.org/2.0/repositories/bitbucket/geordi/src/e1749643d655d7c7014001a6c0f58abaf42ad850/setup.py" 16 | } 17 | } 18 | }, 19 | "new": { 20 | "path": "setup.py", 21 | "escaped_path": "setup.py", 22 | "type": "commit_file", 23 | "links": { 24 | "self": { 25 | "href": "https://api.bitbucket.org/2.0/repositories/bitbucket/geordi/src/d222fa235229c55dad20b190b0b571adf737d5a6/setup.py" 26 | } 27 | } 28 | } 29 | }, 30 | { 31 | "type": "diffstat", 32 | "status": "modified", 33 | "lines_removed": 1, 34 | "lines_added": 2, 35 | "old": { 36 | "path": "some/full.py", 37 | "escaped_path": "some%2Ffull.py", 38 | "type": "commit_file", 39 | "links": { 40 | "self": { 41 | "href": "https://api.bitbucket.org/2.0/repositories/bitbucket/geordi/src/e1749643d655d7c7054001a6c0f58abaf42ad850/some%2Ffull.py" 42 | } 43 | } 44 | }, 45 | "new": { 46 | "path": "some/full.py", 47 | "escaped_path": "some%2Ffull.py", 48 | "type": "commit_file", 49 | "links": { 50 | "self": { 51 | "href": "https://api.bitbucket.org/2.0/repositories/bitbucket/geordi/src/d222fa23522dc55dad20b190b0b571adf737d5a6/some%2Ffull.py" 52 | } 53 | } 54 | } 55 | }, 56 | { 57 | "type": "diffstat", 58 | "status": "modified", 59 | "lines_removed": 1, 60 | "lines_added": 2, 61 | "old": { 62 | "path": "some/full.py", 63 | "escaped_path": "some%2Ffull.py", 64 | "type": "commit_file", 65 | "links": { 66 | "self": { 67 | "href": "https://api.bitbucket.org/2.0/repositories/bitbucket/geordi/src/e1749643d655d7c7054001a6c0f58abaf42ad850/some%2Ffull.py" 68 | } 69 | } 70 | }, 71 | "new": { 72 | "path": "some/full.py", 73 | "escaped_path": "some%2Ffull.py", 74 | "type": "commit_file", 75 | "links": { 76 | "self": { 77 | "href": "https://api.bitbucket.org/2.0/repositories/bitbucket/geordi/src/d222fa23522dc55dad20b190b0b571adf737d5a6/some%2Ffull.py" 78 | } 79 | } 80 | } 81 | } 82 | ], 83 | "page": 1, 84 | "size": 2 85 | } -------------------------------------------------------------------------------- /vcsutils/webhookparser/testdata/bitbucketserver/prmergepayload.json: -------------------------------------------------------------------------------- 1 | {"eventKey":"pr:merged","date":"2021-12-06T14:41:01+0200","actor":{"name":"yahavi","emailAddress":"yahavi@jfrog.com","id":721,"displayName":"Yahav Itzhak","active":true,"slug":"yahavi","type":"NORMAL","links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"pullRequest":{"id":3,"version":0,"title":"Update README.md","state":"MERGED","open":false,"closed":true,"createdDate":1631178661307,"updatedDate":1638794461247,"closedDate":1638794461247,"fromRef":{"id":"refs/heads/dev","displayId":"dev","latestCommit":"b3fc2f0a02761b443fca72022a2ac897cc2ceb3a","repository":{"slug":"hello-world","id":2041,"name":"hello-world","hierarchyId":"aa146c1c8852cf49e15e","scmId":"git","state":"AVAILABLE","statusMessage":"Available","forkable":true,"project":{"key":"~YAHAVI","id":605,"name":"Yahav Itzhak","type":"PERSONAL","owner":{"name":"yahavi","emailAddress":"yahavi@jfrog.com","id":721,"displayName":"Yahav Itzhak","active":true,"slug":"yahavi","type":"NORMAL","links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"public":false,"links":{"clone":[{"href":"ssh://git@git.acme.info/~yahavi/hello-world.git","name":"ssh"},{"href":"https://git.acme.info/scm/~yahavi/hello-world.git","name":"http"}],"self":[{"href":"https://git.acme.info/users/yahavi/repos/hello-world/browse"}]}}},"toRef":{"id":"refs/heads/main","displayId":"main","latestCommit":"929d3054cf60e11a38672966f948bb5d95f48f0e","repository":{"slug":"hello-world","id":2041,"name":"hello-world","hierarchyId":"aa146c1c8852cf49e15e","scmId":"git","state":"AVAILABLE","statusMessage":"Available","forkable":true,"project":{"key":"~YAHAVI","id":605,"name":"Yahav Itzhak","type":"PERSONAL","owner":{"name":"yahavi","emailAddress":"yahavi@jfrog.com","id":721,"displayName":"Yahav Itzhak","active":true,"slug":"yahavi","type":"NORMAL","links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"public":false,"links":{"clone":[{"href":"ssh://git@git.acme.info/~yahavi/hello-world.git","name":"ssh"},{"href":"https://git.acme.info/scm/~yahavi/hello-world.git","name":"http"}],"self":[{"href":"https://git.acme.info/users/yahavi/repos/hello-world/browse"}]}}},"locked":false,"author":{"user":{"name":"yahavi","emailAddress":"yahavi@jfrog.com","id":721,"displayName":"Yahav Itzhak","active":true,"slug":"yahavi","type":"NORMAL","links":{"self":[{"href":"https://git.acme.info/users/yahavi"}]}},"role":"AUTHOR","approved":false,"status":"UNAPPROVED"},"reviewers":[],"participants":[],"properties":{"mergeCommit":{"displayId":"7e48f426f0a","id":"7e48f426f0a6e47c5b5e862c31be6ca965f82c9c"}},"links":{"self":[{"href":"https://git.acme.info/users/yahavi/repos/hello-world/pull-requests/3"}]}}} -------------------------------------------------------------------------------- /vcsutils/consts.go: -------------------------------------------------------------------------------- 1 | package vcsutils 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | const ( 9 | branchPrefix = "refs/heads/" 10 | TagPrefix = "refs/tags/" 11 | NumberOfCommitsToFetch = 50 12 | ErrNoCommentsProvided = "could not add a pull request review comment, no comments were provided" 13 | ) 14 | 15 | // VcsProvider is an enum represents the VCS provider type 16 | type VcsProvider int 17 | 18 | const ( 19 | // GitHub VCS provider 20 | GitHub VcsProvider = iota 21 | // GitLab VCS provider 22 | GitLab 23 | // BitbucketServer VCS provider 24 | BitbucketServer 25 | // BitbucketCloud VCS provider 26 | BitbucketCloud 27 | // AzureRepos VCS provider 28 | AzureRepos 29 | ) 30 | 31 | func (v *VcsProvider) UnmarshalYAML(unmarshal func(interface{}) error) error { 32 | var s string 33 | if err := unmarshal(&s); err != nil { 34 | return err 35 | } 36 | 37 | switch strings.ToLower(s) { 38 | case "github": 39 | *v = GitHub 40 | case "gitlab": 41 | *v = GitLab 42 | case "bitbucket": 43 | *v = BitbucketServer 44 | default: 45 | return fmt.Errorf("invalid VcsProvider: %s", s) 46 | } 47 | return nil 48 | } 49 | 50 | func (v VcsProvider) MarshalYAML() (interface{}, error) { 51 | switch v { 52 | case GitHub: 53 | return "github", nil 54 | case GitLab: 55 | return "gitlab", nil 56 | case BitbucketServer: 57 | return "bitbucket", nil 58 | default: 59 | return nil, fmt.Errorf("invalid VcsProvider: %d", v) 60 | } 61 | } 62 | 63 | // String representation of the VcsProvider 64 | func (v VcsProvider) String() string { 65 | switch v { 66 | case GitHub: 67 | return "GitHub" 68 | case GitLab: 69 | return "GitLab" 70 | case BitbucketServer: 71 | return "Bitbucket Server" 72 | case BitbucketCloud: 73 | return "Bitbucket Cloud" 74 | case AzureRepos: 75 | return "Azure Repos" 76 | default: 77 | return "" 78 | } 79 | } 80 | 81 | // WebhookEvent is the event type of the incoming webhook 82 | type WebhookEvent string 83 | 84 | const ( 85 | // PrRejected the pull request is rejected 86 | PrRejected WebhookEvent = "PrRejected" 87 | // PrEdited the pull request is edited 88 | PrEdited WebhookEvent = "PrEdited" 89 | // PrMerged the pull request is merged 90 | PrMerged WebhookEvent = "PrMerged" 91 | // PrOpened a pull request is opened 92 | PrOpened WebhookEvent = "PrOpened" 93 | // Push a commit is pushed to the source branch 94 | Push WebhookEvent = "Push" 95 | // TagPushed a new tag is pushed 96 | TagPushed WebhookEvent = "TagPushed" 97 | // TagRemoved a tag is removed 98 | TagRemoved WebhookEvent = "TagRemoved" 99 | ) 100 | 101 | type PullRequestState string 102 | 103 | const ( 104 | Open PullRequestState = "open" 105 | Closed PullRequestState = "closed" 106 | ) 107 | -------------------------------------------------------------------------------- /vcsutils/retryexecutor.go: -------------------------------------------------------------------------------- 1 | package vcsutils 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "time" 8 | ) 9 | 10 | type ExecutionHandlerFunc func() (bool, error) 11 | 12 | type RetryExecutor struct { 13 | // The context 14 | Context context.Context 15 | 16 | // The amount of retries to perform. 17 | MaxRetries int 18 | 19 | // Number of milliseconds to sleep between retries. 20 | RetriesIntervalMilliSecs int 21 | 22 | // Message to display when retrying. 23 | ErrorMessage string 24 | 25 | // Prefix to print at the beginning of each log. 26 | LogMsgPrefix string 27 | 28 | // ExecutionHandler is the operation to run with retries. 29 | ExecutionHandler ExecutionHandlerFunc 30 | 31 | // Logger for logs 32 | Logger Log 33 | } 34 | 35 | func (runner *RetryExecutor) Execute() error { 36 | var err error 37 | var shouldRetry bool 38 | for i := 0; i <= runner.MaxRetries; i++ { 39 | // Run ExecutionHandler 40 | shouldRetry, err = runner.ExecutionHandler() 41 | 42 | // If we should not retry, return. 43 | if !shouldRetry { 44 | return err 45 | } 46 | if cancelledErr := runner.checkCancelled(); cancelledErr != nil { 47 | return cancelledErr 48 | } 49 | 50 | // Print retry log message 51 | runner.LogRetry(i, err) 52 | 53 | // Going to sleep for RetryInterval milliseconds 54 | if runner.RetriesIntervalMilliSecs > 0 && i < runner.MaxRetries { 55 | time.Sleep(time.Millisecond * time.Duration(runner.RetriesIntervalMilliSecs)) 56 | } 57 | } 58 | // If the error is not nil, return it and log the timeout message. Otherwise, generate new error. 59 | if err != nil { 60 | runner.Logger.Error(runner.getTimeoutErrorMsg()) 61 | return err 62 | } 63 | return RetryExecutorTimeoutError{runner.getTimeoutErrorMsg()} 64 | } 65 | 66 | // Error of this type will be returned if the executor reaches timeout and no other error is returned by the execution handler. 67 | type RetryExecutorTimeoutError struct { 68 | errMsg string 69 | } 70 | 71 | func (retryErr RetryExecutorTimeoutError) Error() string { 72 | return retryErr.errMsg 73 | } 74 | 75 | func (runner *RetryExecutor) getTimeoutErrorMsg() string { 76 | prefix := "" 77 | if runner.LogMsgPrefix != "" { 78 | prefix = runner.LogMsgPrefix + " " 79 | } 80 | return fmt.Sprintf("%sexecutor timeout after %v attempts with %v milliseconds wait intervals", prefix, runner.MaxRetries, runner.RetriesIntervalMilliSecs) 81 | } 82 | 83 | func (runner *RetryExecutor) LogRetry(attemptNumber int, err error) { 84 | message := fmt.Sprintf("%s(Attempt %v)", runner.LogMsgPrefix, attemptNumber+1) 85 | if runner.ErrorMessage != "" { 86 | message = fmt.Sprintf("%s - %s", message, runner.ErrorMessage) 87 | } 88 | if err != nil { 89 | message = fmt.Sprintf("%s: %s", message, err.Error()) 90 | } 91 | 92 | if err != nil || runner.ErrorMessage != "" { 93 | runner.Logger.Warn(message) 94 | } else { 95 | runner.Logger.Debug(message) 96 | } 97 | } 98 | 99 | func (runner *RetryExecutor) checkCancelled() error { 100 | if runner.Context == nil { 101 | return nil 102 | } 103 | contextErr := runner.Context.Err() 104 | if errors.Is(contextErr, context.Canceled) { 105 | runner.Logger.Info("Retry executor was cancelled") 106 | return contextErr 107 | } 108 | return nil 109 | } 110 | -------------------------------------------------------------------------------- /vcsutils/webhookparser/testdata/gitlab/propenpayload.json: -------------------------------------------------------------------------------- 1 | {"object_kind":"merge_request","event_type":"merge_request","user":{"id":7768088,"name":"Yahav Itzhak","username":"yahavi","avatar_url":"https://secure.gravatar.com/avatar/9680da1674e22a1de17acb19bb233ebf?s=80&d=identicon","email":"yahavitz@gmail.com"},"project":{"id":29221198,"name":"hello-world","description":"","web_url":"https://gitlab.com/yahavi/hello-world","avatar_url":null,"git_ssh_url":"git@gitlab.com:yahavi/hello-world.git","git_http_url":"https://gitlab.com/yahavi/hello-world.git","namespace":"Yahav Itzhak","visibility_level":20,"path_with_namespace":"yahavi/hello-world","default_branch":"main","ci_config_path":"","homepage":"https://gitlab.com/yahavi/hello-world","url":"git@gitlab.com:yahavi/hello-world.git","ssh_url":"git@gitlab.com:yahavi/hello-world.git","http_url":"https://gitlab.com/yahavi/hello-world.git"},"object_attributes":{"assignee_id":null,"author_id":7768088,"created_at":"2021-09-09 15:40:47 UTC","description":"","head_pipeline_id":null,"id":116211116,"iid":1,"last_edited_at":null,"last_edited_by_id":null,"merge_commit_sha":null,"merge_error":null,"merge_params":{"force_remove_source_branch":"1"},"merge_status":"preparing","merge_user_id":null,"merge_when_pipeline_succeeds":false,"milestone_id":null,"source_branch":"dev","source_project_id":29221198,"state_id":1,"target_branch":"main","target_project_id":29221198,"time_estimate":0,"title":"Update README.md","updated_at":"2021-09-09 15:40:47 UTC","updated_by_id":null,"url":"https://gitlab.com/yahavi/hello-world/-/merge_requests/1","source":{"id":29221198,"name":"hello-world","description":"","web_url":"https://gitlab.com/yahavi/hello-world","avatar_url":null,"git_ssh_url":"git@gitlab.com:yahavi/hello-world.git","git_http_url":"https://gitlab.com/yahavi/hello-world.git","namespace":"Yahav Itzhak","visibility_level":20,"path_with_namespace":"yahavi/hello-world","default_branch":"main","ci_config_path":"","homepage":"https://gitlab.com/yahavi/hello-world","url":"git@gitlab.com:yahavi/hello-world.git","ssh_url":"git@gitlab.com:yahavi/hello-world.git","http_url":"https://gitlab.com/yahavi/hello-world.git"},"target":{"id":29221198,"name":"hello-world","description":"","web_url":"https://gitlab.com/yahavi/hello-world","avatar_url":null,"git_ssh_url":"git@gitlab.com:yahavi/hello-world.git","git_http_url":"https://gitlab.com/yahavi/hello-world.git","namespace":"Yahav Itzhak","visibility_level":20,"path_with_namespace":"yahavi/hello-world","default_branch":"main","ci_config_path":"","homepage":"https://gitlab.com/yahavi/hello-world","url":"git@gitlab.com:yahavi/hello-world.git","ssh_url":"git@gitlab.com:yahavi/hello-world.git","http_url":"https://gitlab.com/yahavi/hello-world.git"},"last_commit":{"id":"72108853aa0eac9d1b72fe34710aeed256d193d5","message":"Update README.md","title":"Update README.md","timestamp":"2021-09-09T15:40:29+00:00","url":"https://gitlab.com/yahavi/hello-world/-/commit/72108853aa0eac9d1b72fe34710aeed256d193d5","author":{"name":"Yahav Itzhak","email":"yahavitz@gmail.com"}},"work_in_progress":false,"total_time_spent":0,"time_change":0,"human_total_time_spent":null,"human_time_change":null,"human_time_estimate":null,"assignee_ids":[],"state":"opened","action":"open"},"labels":[],"changes":{"merge_status":{"previous":"unchecked","current":"preparing"}},"repository":{"name":"hello-world","url":"git@gitlab.com:yahavi/hello-world.git","description":"","homepage":"https://gitlab.com/yahavi/hello-world"}} -------------------------------------------------------------------------------- /vcsutils/webhookparser/testdata/gitlab/prclosepayload.json: -------------------------------------------------------------------------------- 1 | {"object_kind":"merge_request","event_type":"merge_request","user":{"id":7768088,"name":"Yahav Itzhak","username":"yahavi","avatar_url":"https://secure.gravatar.com/avatar/9680da1674e22a1de17acb19bb233ebf?s=80&d=identicon","email":"yahavitz@gmail.com"},"project":{"id":29221198,"name":"hello-world","description":"","web_url":"https://gitlab.com/yahavi/hello-world","avatar_url":null,"git_ssh_url":"git@gitlab.com:yahavi/hello-world.git","git_http_url":"https://gitlab.com/yahavi/hello-world.git","namespace":"Yahav Itzhak","visibility_level":20,"path_with_namespace":"yahavi/hello-world","default_branch":"main","ci_config_path":"","homepage":"https://gitlab.com/yahavi/hello-world","url":"git@gitlab.com:yahavi/hello-world.git","ssh_url":"git@gitlab.com:yahavi/hello-world.git","http_url":"https://gitlab.com/yahavi/hello-world.git"},"object_attributes":{"assignee_id":null,"author_id":7768088,"created_at":"2021-09-09 15:40:47 UTC","description":"","head_pipeline_id":null,"id":116211116,"iid":1,"last_edited_at":null,"last_edited_by_id":null,"merge_commit_sha":null,"merge_error":null,"merge_params":{"force_remove_source_branch":"1"},"merge_status":"can_be_merged","merge_user_id":null,"merge_when_pipeline_succeeds":false,"milestone_id":null,"source_branch":"dev","source_project_id":29221198,"state_id":1,"target_branch":"main","target_project_id":29221198,"time_estimate":0,"title":"Update README.md","updated_at":"2021-12-07 08:07:33 UTC","updated_by_id":null,"url":"https://gitlab.com/yahavi/hello-world/-/merge_requests/1","source":{"id":29221198,"name":"hello-world","description":"","web_url":"https://gitlab.com/yahavi/hello-world","avatar_url":null,"git_ssh_url":"git@gitlab.com:yahavi/hello-world.git","git_http_url":"https://gitlab.com/yahavi/hello-world.git","namespace":"Yahav Itzhak","visibility_level":20,"path_with_namespace":"yahavi/hello-world","default_branch":"main","ci_config_path":"","homepage":"https://gitlab.com/yahavi/hello-world","url":"git@gitlab.com:yahavi/hello-world.git","ssh_url":"git@gitlab.com:yahavi/hello-world.git","http_url":"https://gitlab.com/yahavi/hello-world.git"},"target":{"id":29221198,"name":"hello-world","description":"","web_url":"https://gitlab.com/yahavi/hello-world","avatar_url":null,"git_ssh_url":"git@gitlab.com:yahavi/hello-world.git","git_http_url":"https://gitlab.com/yahavi/hello-world.git","namespace":"Yahav Itzhak","visibility_level":20,"path_with_namespace":"yahavi/hello-world","default_branch":"main","ci_config_path":"","homepage":"https://gitlab.com/yahavi/hello-world","url":"git@gitlab.com:yahavi/hello-world.git","ssh_url":"git@gitlab.com:yahavi/hello-world.git","http_url":"https://gitlab.com/yahavi/hello-world.git"},"last_commit":{"id":"3fcd302505fb3df664143df4ddcb6cfc50ff2ea8","message":"Update README.md","title":"Update README.md","timestamp":"2021-09-09T15:44:24+00:00","url":"https://gitlab.com/yahavi/hello-world/-/commit/3fcd302505fb3df664143df4ddcb6cfc50ff2ea8","author":{"name":"Yahav Itzhak","email":"yahavitz@gmail.com"}},"work_in_progress":false,"total_time_spent":0,"time_change":0,"human_total_time_spent":null,"human_time_change":null,"human_time_estimate":null,"assignee_ids":[],"state":"closed","action":"close"},"labels":[],"changes":{"updated_at":{"previous":"2021-12-07 08:02:49 UTC","current":"2021-12-07 08:07:33 UTC"}},"repository":{"name":"hello-world","url":"git@gitlab.com:yahavi/hello-world.git","description":"","homepage":"https://gitlab.com/yahavi/hello-world"}} -------------------------------------------------------------------------------- /vcsutils/webhookparser/testdata/gitlab/prreopenpayload.json: -------------------------------------------------------------------------------- 1 | {"object_kind":"merge_request","event_type":"merge_request","user":{"id":7768088,"name":"Yahav Itzhak","username":"yahavi","avatar_url":"https://secure.gravatar.com/avatar/9680da1674e22a1de17acb19bb233ebf?s=80&d=identicon","email":"yahavitz@gmail.com"},"project":{"id":29221198,"name":"hello-world","description":"","web_url":"https://gitlab.com/yahavi/hello-world","avatar_url":null,"git_ssh_url":"git@gitlab.com:yahavi/hello-world.git","git_http_url":"https://gitlab.com/yahavi/hello-world.git","namespace":"Yahav Itzhak","visibility_level":20,"path_with_namespace":"yahavi/hello-world","default_branch":"main","ci_config_path":"","homepage":"https://gitlab.com/yahavi/hello-world","url":"git@gitlab.com:yahavi/hello-world.git","ssh_url":"git@gitlab.com:yahavi/hello-world.git","http_url":"https://gitlab.com/yahavi/hello-world.git"},"object_attributes":{"assignee_id":null,"author_id":7768088,"created_at":"2021-09-09 15:40:47 UTC","description":"","head_pipeline_id":null,"id":116211116,"iid":1,"last_edited_at":null,"last_edited_by_id":null,"merge_commit_sha":null,"merge_error":null,"merge_params":{"force_remove_source_branch":"1"},"merge_status":"can_be_merged","merge_user_id":null,"merge_when_pipeline_succeeds":false,"milestone_id":null,"source_branch":"dev","source_project_id":29221198,"state_id":1,"target_branch":"main","target_project_id":29221198,"time_estimate":0,"title":"Update README.md","updated_at":"2021-12-07 08:30:56 UTC","updated_by_id":null,"url":"https://gitlab.com/yahavi/hello-world/-/merge_requests/1","source":{"id":29221198,"name":"hello-world","description":"","web_url":"https://gitlab.com/yahavi/hello-world","avatar_url":null,"git_ssh_url":"git@gitlab.com:yahavi/hello-world.git","git_http_url":"https://gitlab.com/yahavi/hello-world.git","namespace":"Yahav Itzhak","visibility_level":20,"path_with_namespace":"yahavi/hello-world","default_branch":"main","ci_config_path":"","homepage":"https://gitlab.com/yahavi/hello-world","url":"git@gitlab.com:yahavi/hello-world.git","ssh_url":"git@gitlab.com:yahavi/hello-world.git","http_url":"https://gitlab.com/yahavi/hello-world.git"},"target":{"id":29221198,"name":"hello-world","description":"","web_url":"https://gitlab.com/yahavi/hello-world","avatar_url":null,"git_ssh_url":"git@gitlab.com:yahavi/hello-world.git","git_http_url":"https://gitlab.com/yahavi/hello-world.git","namespace":"Yahav Itzhak","visibility_level":20,"path_with_namespace":"yahavi/hello-world","default_branch":"main","ci_config_path":"","homepage":"https://gitlab.com/yahavi/hello-world","url":"git@gitlab.com:yahavi/hello-world.git","ssh_url":"git@gitlab.com:yahavi/hello-world.git","http_url":"https://gitlab.com/yahavi/hello-world.git"},"last_commit":{"id":"3fcd302505fb3df664143df4ddcb6cfc50ff2ea8","message":"Update README.md","title":"Update README.md","timestamp":"2021-09-09T15:44:24+00:00","url":"https://gitlab.com/yahavi/hello-world/-/commit/3fcd302505fb3df664143df4ddcb6cfc50ff2ea8","author":{"name":"Yahav Itzhak","email":"yahavitz@gmail.com"}},"work_in_progress":false,"total_time_spent":0,"time_change":0,"human_total_time_spent":null,"human_time_change":null,"human_time_estimate":null,"assignee_ids":[],"state":"opened","action":"reopen"},"labels":[],"changes":{"state_id":{"previous":2,"current":1},"updated_at":{"previous":"2021-12-07 08:07:33 UTC","current":"2021-12-07 08:30:56 UTC"}},"repository":{"name":"hello-world","url":"git@gitlab.com:yahavi/hello-world.git","description":"","homepage":"https://gitlab.com/yahavi/hello-world"}} -------------------------------------------------------------------------------- /vcsutils/webhookparser/testdata/gitlab/prupdatepayload.json: -------------------------------------------------------------------------------- 1 | {"object_kind":"merge_request","event_type":"merge_request","user":{"id":7768088,"name":"Yahav Itzhak","username":"yahavi","avatar_url":"https://secure.gravatar.com/avatar/9680da1674e22a1de17acb19bb233ebf?s=80&d=identicon","email":"yahavitz@gmail.com"},"project":{"id":29221198,"name":"hello-world","description":"","web_url":"https://gitlab.com/yahavi/hello-world","avatar_url":null,"git_ssh_url":"git@gitlab.com:yahavi/hello-world.git","git_http_url":"https://gitlab.com/yahavi/hello-world.git","namespace":"Yahav Itzhak","visibility_level":20,"path_with_namespace":"yahavi/hello-world","default_branch":"main","ci_config_path":"","homepage":"https://gitlab.com/yahavi/hello-world","url":"git@gitlab.com:yahavi/hello-world.git","ssh_url":"git@gitlab.com:yahavi/hello-world.git","http_url":"https://gitlab.com/yahavi/hello-world.git"},"object_attributes":{"assignee_id":null,"author_id":7768088,"created_at":"2021-09-09 15:40:47 UTC","description":"","head_pipeline_id":null,"id":116211116,"iid":1,"last_edited_at":null,"last_edited_by_id":null,"merge_commit_sha":null,"merge_error":null,"merge_params":{"force_remove_source_branch":"1"},"merge_status":"unchecked","merge_user_id":null,"merge_when_pipeline_succeeds":false,"milestone_id":null,"source_branch":"dev","source_project_id":29221198,"state_id":1,"target_branch":"main","target_project_id":29221198,"time_estimate":0,"title":"Update README.md","updated_at":"2021-09-09 15:44:26 UTC","updated_by_id":null,"url":"https://gitlab.com/yahavi/hello-world/-/merge_requests/1","source":{"id":29221198,"name":"hello-world","description":"","web_url":"https://gitlab.com/yahavi/hello-world","avatar_url":null,"git_ssh_url":"git@gitlab.com:yahavi/hello-world.git","git_http_url":"https://gitlab.com/yahavi/hello-world.git","namespace":"Yahav Itzhak","visibility_level":20,"path_with_namespace":"yahavi/hello-world","default_branch":"main","ci_config_path":"","homepage":"https://gitlab.com/yahavi/hello-world","url":"git@gitlab.com:yahavi/hello-world.git","ssh_url":"git@gitlab.com:yahavi/hello-world.git","http_url":"https://gitlab.com/yahavi/hello-world.git"},"target":{"id":29221198,"name":"hello-world","description":"","web_url":"https://gitlab.com/yahavi/hello-world","avatar_url":null,"git_ssh_url":"git@gitlab.com:yahavi/hello-world.git","git_http_url":"https://gitlab.com/yahavi/hello-world.git","namespace":"Yahav Itzhak","visibility_level":20,"path_with_namespace":"yahavi/hello-world","default_branch":"main","ci_config_path":"","homepage":"https://gitlab.com/yahavi/hello-world","url":"git@gitlab.com:yahavi/hello-world.git","ssh_url":"git@gitlab.com:yahavi/hello-world.git","http_url":"https://gitlab.com/yahavi/hello-world.git"},"last_commit":{"id":"3fcd302505fb3df664143df4ddcb6cfc50ff2ea8","message":"Update README.md","title":"Update README.md","timestamp":"2021-09-09T15:44:24+00:00","url":"https://gitlab.com/yahavi/hello-world/-/commit/3fcd302505fb3df664143df4ddcb6cfc50ff2ea8","author":{"name":"Yahav Itzhak","email":"yahavitz@gmail.com"}},"work_in_progress":false,"total_time_spent":0,"time_change":0,"human_total_time_spent":null,"human_time_change":null,"human_time_estimate":null,"assignee_ids":[],"state":"opened","action":"update","oldrev":"72108853aa0eac9d1b72fe34710aeed256d193d5"},"labels":[],"changes":{"updated_at":{"previous":"2021-09-09 15:40:47 UTC","current":"2021-09-09 15:44:26 UTC"}},"repository":{"name":"hello-world","url":"git@gitlab.com:yahavi/hello-world.git","description":"","homepage":"https://gitlab.com/yahavi/hello-world"}} -------------------------------------------------------------------------------- /vcsutils/webhookparser/testdata/gitlab/prmergepayload.json: -------------------------------------------------------------------------------- 1 | {"object_kind":"merge_request","event_type":"merge_request","user":{"id":7768088,"name":"Yahav Itzhak","username":"yahavi","avatar_url":"https://secure.gravatar.com/avatar/9680da1674e22a1de17acb19bb233ebf?s=80&d=identicon","email":"yahavitz@gmail.com"},"project":{"id":29221198,"name":"hello-world","description":"","web_url":"https://gitlab.com/yahavi/hello-world","avatar_url":null,"git_ssh_url":"git@gitlab.com:yahavi/hello-world.git","git_http_url":"https://gitlab.com/yahavi/hello-world.git","namespace":"Yahav Itzhak","visibility_level":20,"path_with_namespace":"yahavi/hello-world","default_branch":"main","ci_config_path":"","homepage":"https://gitlab.com/yahavi/hello-world","url":"git@gitlab.com:yahavi/hello-world.git","ssh_url":"git@gitlab.com:yahavi/hello-world.git","http_url":"https://gitlab.com/yahavi/hello-world.git"},"object_attributes":{"assignee_id":null,"author_id":7768088,"created_at":"2021-09-09 15:40:47 UTC","description":"","head_pipeline_id":null,"id":116211116,"iid":1,"last_edited_at":null,"last_edited_by_id":null,"merge_commit_sha":"115b4dcd1147ffb55743160075c7127e80fb8f51","merge_error":null,"merge_params":{"force_remove_source_branch":"1"},"merge_status":"can_be_merged","merge_user_id":null,"merge_when_pipeline_succeeds":false,"milestone_id":null,"source_branch":"dev","source_project_id":29221198,"state_id":1,"target_branch":"main","target_project_id":29221198,"time_estimate":0,"title":"Update README.md","updated_at":"2021-12-07 08:35:19 UTC","updated_by_id":null,"url":"https://gitlab.com/yahavi/hello-world/-/merge_requests/1","source":{"id":29221198,"name":"hello-world","description":"","web_url":"https://gitlab.com/yahavi/hello-world","avatar_url":null,"git_ssh_url":"git@gitlab.com:yahavi/hello-world.git","git_http_url":"https://gitlab.com/yahavi/hello-world.git","namespace":"Yahav Itzhak","visibility_level":20,"path_with_namespace":"yahavi/hello-world","default_branch":"main","ci_config_path":"","homepage":"https://gitlab.com/yahavi/hello-world","url":"git@gitlab.com:yahavi/hello-world.git","ssh_url":"git@gitlab.com:yahavi/hello-world.git","http_url":"https://gitlab.com/yahavi/hello-world.git"},"target":{"id":29221198,"name":"hello-world","description":"","web_url":"https://gitlab.com/yahavi/hello-world","avatar_url":null,"git_ssh_url":"git@gitlab.com:yahavi/hello-world.git","git_http_url":"https://gitlab.com/yahavi/hello-world.git","namespace":"Yahav Itzhak","visibility_level":20,"path_with_namespace":"yahavi/hello-world","default_branch":"main","ci_config_path":"","homepage":"https://gitlab.com/yahavi/hello-world","url":"git@gitlab.com:yahavi/hello-world.git","ssh_url":"git@gitlab.com:yahavi/hello-world.git","http_url":"https://gitlab.com/yahavi/hello-world.git"},"last_commit":{"id":"3fcd302505fb3df664143df4ddcb6cfc50ff2ea8","message":"Update README.md","title":"Update README.md","timestamp":"2021-09-09T15:44:24+00:00","url":"https://gitlab.com/yahavi/hello-world/-/commit/3fcd302505fb3df664143df4ddcb6cfc50ff2ea8","author":{"name":"Yahav Itzhak","email":"yahavitz@gmail.com"}},"work_in_progress":false,"total_time_spent":0,"time_change":0,"human_total_time_spent":null,"human_time_change":null,"human_time_estimate":null,"assignee_ids":[],"state":"merged","action":"merge"},"labels":[],"changes":{"state_id":{"previous":4,"current":3},"updated_at":{"previous":"2021-12-07 08:35:19 UTC","current":"2021-12-07 08:35:19 UTC"}},"repository":{"name":"hello-world","url":"git@gitlab.com:yahavi/hello-world.git","description":"","homepage":"https://gitlab.com/yahavi/hello-world"}} -------------------------------------------------------------------------------- /vcsutils/webhookparser/testdata/bitbucketcloud/tagdeletepayload.json: -------------------------------------------------------------------------------- 1 | {"push":{"changes":[{"old":{"name":"tag_intg","type":"tag","message":"test webhook event\n","date":"2023-04-21T06:30:32+00:00","tagger":{},"target":{"type":"commit","hash":"a0649fd18af888f98aace00db6aec703e95121ce","date":"2023-02-10T08:53:09+00:00","author":{"type":"author","raw":"Pavlo Strokov [EXT] ","user":{"display_name":"Pavlo Strokov [EXT]","links":{"self":{"href":"https://api.bitbucket.org/2.0/users/%7B3ffc0f79-f00f-442e-9a6d-c3f27587d9da%7D"},"avatar":{"href":"https://secure.gravatar.com/avatar/a47aec620663eaa2bfeaa0540e580fd5?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FPS-2.png"},"html":{"href":"https://bitbucket.org/%7B3ffc0f79-f00f-442e-9a6d-c3f27587d9da%7D/"}},"type":"user","uuid":"{3ffc0f79-f00f-442e-9a6d-c3f27587d9da}","account_id":"62d66f8104a004286c0283a1","nickname":"Pavlo Strokov[EXT]"}},"message":"Initial commit","summary":{"type":"rendered","raw":"Initial commit","markup":"markdown","html":"

Initial commit

"},"links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/avadakedabra/rest-api-test/commit/a0649fd18af888f98aace00db6aec703e95121ce"},"html":{"href":"https://bitbucket.org/avadakedabra/rest-api-test/commits/a0649fd18af888f98aace00db6aec703e95121ce"}},"parents":[],"rendered":{},"properties":{}},"links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/avadakedabra/rest-api-test/refs/tags/tag_intg"},"commits":{"href":"https://api.bitbucket.org/2.0/repositories/avadakedabra/rest-api-test/commits/tag_intg"},"html":{"href":"https://bitbucket.org/avadakedabra/rest-api-test/commits/tag/tag_intg"}}},"new":null,"truncated":false,"created":false,"forced":false,"closed":true}]},"repository":{"type":"repository","full_name":"avadakedabra/rest-api-test","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/avadakedabra/rest-api-test"},"html":{"href":"https://bitbucket.org/avadakedabra/rest-api-test"},"avatar":{"href":"https://bytebucket.org/ravatar/%7Bbd97c8f8-7098-45db-8272-d22d5e8e1342%7D?ts=go"}},"name":"rest-api-test","scm":"git","website":null,"owner":{"display_name":"avadakedabra","links":{"self":{"href":"https://api.bitbucket.org/2.0/workspaces/%7Be17cd5cd-4463-420e-ae0b-9061860c8dcb%7D"},"avatar":{"href":"https://bitbucket.org/account/avadakedabra/avatar/"},"html":{"href":"https://bitbucket.org/%7Be17cd5cd-4463-420e-ae0b-9061860c8dcb%7D/"}},"type":"team","uuid":"{e17cd5cd-4463-420e-ae0b-9061860c8dcb}","username":"avadakedabra"},"workspace":{"type":"workspace","uuid":"{e17cd5cd-4463-420e-ae0b-9061860c8dcb}","name":"avadakedabra","slug":"avadakedabra","links":{"avatar":{"href":"https://bitbucket.org/workspaces/avadakedabra/avatar/?ts=1676019072"},"html":{"href":"https://bitbucket.org/avadakedabra/"},"self":{"href":"https://api.bitbucket.org/2.0/workspaces/avadakedabra"}}},"is_private":false,"project":{"type":"project","key":"EX","uuid":"{7f2b61e7-614e-47f2-8faf-8b80059beddb}","name":"experiments","links":{"self":{"href":"https://api.bitbucket.org/2.0/workspaces/avadakedabra/projects/EX"},"html":{"href":"https://bitbucket.org/avadakedabra/workspace/projects/EX"},"avatar":{"href":"https://bitbucket.org/account/user/avadakedabra/projects/EX/avatar/32?ts=1676019187"}}},"uuid":"{bd97c8f8-7098-45db-8272-d22d5e8e1342}"},"actor":{"display_name":"avadakedabra","links":{"self":{"href":"https://api.bitbucket.org/2.0/workspaces/%7Be17cd5cd-4463-420e-ae0b-9061860c8dcb%7D"},"avatar":{"href":"https://bitbucket.org/account/avadakedabra/avatar/"},"html":{"href":"https://bitbucket.org/%7Be17cd5cd-4463-420e-ae0b-9061860c8dcb%7D/"}},"type":"team","uuid":"{e17cd5cd-4463-420e-ae0b-9061860c8dcb}","username":"avadakedabra"}} -------------------------------------------------------------------------------- /vcsclient/bitbucketcommon_test.go: -------------------------------------------------------------------------------- 1 | package vcsclient 2 | 3 | import ( 4 | "github.com/jfrog/froggit-go/vcsutils" 5 | "testing" 6 | "time" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestBitbucketClient_getBitbucketCommitState(t *testing.T) { 12 | assert.Equal(t, "SUCCESSFUL", getBitbucketCommitState(Pass)) 13 | assert.Equal(t, "FAILED", getBitbucketCommitState(Fail)) 14 | assert.Equal(t, "FAILED", getBitbucketCommitState(Error)) 15 | assert.Equal(t, "INPROGRESS", getBitbucketCommitState(InProgress)) 16 | assert.Equal(t, "", getBitbucketCommitState(5)) 17 | } 18 | 19 | func TestBitbucketParseCommitStatuses(t *testing.T) { 20 | rawStatuses := map[string]interface{}{ 21 | "values": []BitbucketCommitInfo{ 22 | { 23 | State: "SUCCESSFUL", 24 | Description: "Build successful", 25 | Url: "https://example.com/build/1234", 26 | Title: "jenkins", 27 | DateAdded: 1619189054828, 28 | }, 29 | { 30 | State: "FAILED", 31 | Description: "Build failed", 32 | Url: "https://example.com/build/5678", 33 | Title: "jenkins", 34 | DateAdded: 1619189055832, 35 | }, 36 | }, 37 | } 38 | 39 | provider := vcsutils.BitbucketServer 40 | expectedStatuses := []CommitStatusInfo{ 41 | { 42 | State: Pass, 43 | Description: "Build successful", 44 | DetailsUrl: "https://example.com/build/1234", 45 | Creator: "jenkins", 46 | CreatedAt: time.Unix(1619189054, 828000000).UTC(), 47 | }, 48 | { 49 | State: Fail, 50 | Description: "Build failed", 51 | DetailsUrl: "https://example.com/build/5678", 52 | Creator: "jenkins", 53 | CreatedAt: time.Unix(1619189055, 832000000).UTC(), 54 | }, 55 | } 56 | 57 | statuses, err := bitbucketParseCommitStatuses(rawStatuses, provider) 58 | assert.NoError(t, err) 59 | assert.Equal(t, expectedStatuses, statuses) 60 | } 61 | 62 | func TestGetCommitStatusInfoByBitbucketProvider_BitbucketServer(t *testing.T) { 63 | commitStatus := &BitbucketCommitInfo{ 64 | State: "SUCCESSFUL", 65 | Description: "Build successful", 66 | Url: "https://example.com/build/1234", 67 | Title: "jenkins", 68 | DateAdded: 1619189054828, 69 | } 70 | 71 | expectedStatus := CommitStatusInfo{ 72 | State: Pass, 73 | Description: "Build successful", 74 | DetailsUrl: "https://example.com/build/1234", 75 | Creator: "jenkins", 76 | CreatedAt: time.Unix(1619189054, 828000000).UTC(), 77 | } 78 | 79 | status, err := getCommitStatusInfoByBitbucketProvider(commitStatus, vcsutils.BitbucketServer) 80 | assert.NoError(t, err) 81 | assert.Equal(t, expectedStatus, status) 82 | } 83 | 84 | func TestGetCommitStatusInfoByBitbucketProvider_BitbucketCloud(t *testing.T) { 85 | commitStatus := &BitbucketCommitInfo{ 86 | State: "success", 87 | Description: "Test commit", 88 | Url: "https://example.com/commit", 89 | Creator: "John Doe", 90 | CreatedOn: "2022-01-01T12:34:56.789Z", 91 | UpdatedOn: "2022-01-02T23:45:01.234Z", 92 | } 93 | 94 | expectedResult := CommitStatusInfo{ 95 | State: Pass, 96 | Description: "Test commit", 97 | DetailsUrl: "https://example.com/commit", 98 | Creator: "John Doe", 99 | CreatedAt: time.Date(2022, 1, 1, 12, 34, 56, 789000000, time.UTC), 100 | LastUpdatedAt: time.Date(2022, 1, 2, 23, 45, 1, 234000000, time.UTC), 101 | } 102 | 103 | result, err := getCommitStatusInfoByBitbucketProvider(commitStatus, vcsutils.BitbucketCloud) 104 | assert.NoError(t, err) 105 | assert.Equal(t, expectedResult, result) 106 | } 107 | -------------------------------------------------------------------------------- /vcsclient/testdata/bitbucketcloud/commit_single_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "rendered": { 3 | "message": { 4 | "html": "

Update image name

", 5 | "markup": "markdown", 6 | "raw": "Update image name\n", 7 | "type": "rendered" 8 | } 9 | }, 10 | "hash": "f62ea5359e7af59880b4a5e23e0ce6c1b32b5d3c", 11 | "repository": { 12 | "full_name": "user2/setup-jfrog-cli", 13 | "links": { 14 | "avatar": { 15 | "href": "https://bytebucket.org/ravatar/%7Bd5f8a3f0-0cf1-43e9-8451-5379417d6c7c%7D?ts=default" 16 | }, 17 | "html": { 18 | "href": "https://bitbucket.org/user2/setup-jfrog-cli" 19 | }, 20 | "self": { 21 | "href": "https://api.bitbucket.org/2.0/repositories/user2/setup-jfrog-cli" 22 | } 23 | }, 24 | "name": "setup-jfrog-cli", 25 | "type": "repository", 26 | "uuid": "{d5f8a3f0-0cf1-43e9-8451-5379417d6c7c}" 27 | }, 28 | "links": { 29 | "approve": { 30 | "href": "https://api.bitbucket.org/2.0/repositories/user2/setup-jfrog-cli/commit/f62ea5359e7af59880b4a5e23e0ce6c1b32b5d3c/approve" 31 | }, 32 | "comments": { 33 | "href": "https://api.bitbucket.org/2.0/repositories/user2/setup-jfrog-cli/commit/f62ea5359e7af59880b4a5e23e0ce6c1b32b5d3c/comments" 34 | }, 35 | "diff": { 36 | "href": "https://api.bitbucket.org/2.0/repositories/user2/setup-jfrog-cli/diff/f62ea5359e7af59880b4a5e23e0ce6c1b32b5d3c" 37 | }, 38 | "html": { 39 | "href": "https://bitbucket.org/user2/setup-jfrog-cli/commits/f62ea5359e7af59880b4a5e23e0ce6c1b32b5d3c" 40 | }, 41 | "patch": { 42 | "href": "https://api.bitbucket.org/2.0/repositories/user2/setup-jfrog-cli/patch/f62ea5359e7af59880b4a5e23e0ce6c1b32b5d3c" 43 | }, 44 | "self": { 45 | "href": "https://api.bitbucket.org/2.0/repositories/user2/setup-jfrog-cli/commit/f62ea5359e7af59880b4a5e23e0ce6c1b32b5d3c" 46 | }, 47 | "statuses": { 48 | "href": "https://api.bitbucket.org/2.0/repositories/user2/setup-jfrog-cli/commit/f62ea5359e7af59880b4a5e23e0ce6c1b32b5d3c/statuses" 49 | } 50 | }, 51 | "author": { 52 | "raw": "user ", 53 | "type": "author", 54 | "user": { 55 | "account_id": "5d74edb2098f0b0daa7630de", 56 | "display_name": "user", 57 | "links": { 58 | "avatar": { 59 | "href": "https://secure.gravatar.com/avatar/477cdb6499e58f28541b52307a3c5bbc?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FRN-1.png" 60 | }, 61 | "html": { 62 | "href": "https://bitbucket.org/%7B1658dec0-6727-44ba-b680-15f84e664746%7D/" 63 | }, 64 | "self": { 65 | "href": "https://api.bitbucket.org/2.0/users/%7B1658dec0-6727-44ba-b680-15f84e664746%7D" 66 | } 67 | }, 68 | "nickname": "user", 69 | "type": "user", 70 | "uuid": "{1658dec0-6727-44ba-b680-15f84e664746}" 71 | } 72 | }, 73 | "summary": { 74 | "html": "

Update image name

", 75 | "markup": "markdown", 76 | "raw": "Update image name\n", 77 | "type": "rendered" 78 | }, 79 | "participants": [], 80 | "parents": [ 81 | { 82 | "hash": "f62ea5359e7af59880b4a5e23e0ce6c1b32b5d3c", 83 | "links": { 84 | "html": { 85 | "href": "https://bitbucket.org/user2/setup-jfrog-cli/commits/f62ea5359e7af59880b4a5e23e0ce6c1b32b5d3c" 86 | }, 87 | "self": { 88 | "href": "https://api.bitbucket.org/2.0/repositories/user2/setup-jfrog-cli/commit/f62ea5359e7af59880b4a5e23e0ce6c1b32b5d3c" 89 | } 90 | }, 91 | "type": "commit" 92 | } 93 | ], 94 | "date": "2020-06-01T16:54:09+00:00", 95 | "message": "Update image name\n", 96 | "type": "commit" 97 | } -------------------------------------------------------------------------------- /vcsutils/webhookparser/testdata/bitbucketcloud/tagcreatepayload.json: -------------------------------------------------------------------------------- 1 | {"push":{"changes":[{"old":null,"new":{"name":"tag_intg","type":"tag","message":"test webhook event\n","date":"2023-04-21T06:30:32+00:00","tagger":{},"target":{"type":"commit","hash":"a0649fd18af888f98aace00db6aec703e95121ce","date":"2023-02-10T08:53:09+00:00","author":{"type":"author","raw":"Pavlo Strokov [EXT] ","user":{"display_name":"Pavlo Strokov [EXT]","links":{"self":{"href":"https://api.bitbucket.org/2.0/users/%7B3ffc0f79-f00f-442e-9a6d-c3f27587d9da%7D"},"avatar":{"href":"https://secure.gravatar.com/avatar/a47aec620663eaa2bfeaa0540e580fd5?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FPS-2.png"},"html":{"href":"https://bitbucket.org/%7B3ffc0f79-f00f-442e-9a6d-c3f27587d9da%7D/"}},"type":"user","uuid":"{3ffc0f79-f00f-442e-9a6d-c3f27587d9da}","account_id":"62d66f8104a004286c0283a1","nickname":"Pavlo Strokov[EXT]"}},"message":"Initial commit","summary":{"type":"rendered","raw":"Initial commit","markup":"markdown","html":"

Initial commit

"},"links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/avadakedabra/rest-api-test/commit/a0649fd18af888f98aace00db6aec703e95121ce"},"html":{"href":"https://bitbucket.org/avadakedabra/rest-api-test/commits/a0649fd18af888f98aace00db6aec703e95121ce"}},"parents":[],"rendered":{},"properties":{}},"links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/avadakedabra/rest-api-test/refs/tags/tag_intg"},"commits":{"href":"https://api.bitbucket.org/2.0/repositories/avadakedabra/rest-api-test/commits/tag_intg"},"html":{"href":"https://bitbucket.org/avadakedabra/rest-api-test/commits/tag/tag_intg"}}},"truncated":false,"created":true,"forced":false,"closed":false,"links":{"commits":{"href":"https://api.bitbucket.org/2.0/repositories/avadakedabra/rest-api-test/commits?include=a0649fd18af888f98aace00db6aec703e95121ce"}}}]},"repository":{"type":"repository","full_name":"avadakedabra/rest-api-test","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/avadakedabra/rest-api-test"},"html":{"href":"https://bitbucket.org/avadakedabra/rest-api-test"},"avatar":{"href":"https://bytebucket.org/ravatar/%7Bbd97c8f8-7098-45db-8272-d22d5e8e1342%7D?ts=go"}},"name":"rest-api-test","scm":"git","website":null,"owner":{"display_name":"avadakedabra","links":{"self":{"href":"https://api.bitbucket.org/2.0/workspaces/%7Be17cd5cd-4463-420e-ae0b-9061860c8dcb%7D"},"avatar":{"href":"https://bitbucket.org/account/avadakedabra/avatar/"},"html":{"href":"https://bitbucket.org/%7Be17cd5cd-4463-420e-ae0b-9061860c8dcb%7D/"}},"type":"team","uuid":"{e17cd5cd-4463-420e-ae0b-9061860c8dcb}","username":"avadakedabra"},"workspace":{"type":"workspace","uuid":"{e17cd5cd-4463-420e-ae0b-9061860c8dcb}","name":"avadakedabra","slug":"avadakedabra","links":{"avatar":{"href":"https://bitbucket.org/workspaces/avadakedabra/avatar/?ts=1676019072"},"html":{"href":"https://bitbucket.org/avadakedabra/"},"self":{"href":"https://api.bitbucket.org/2.0/workspaces/avadakedabra"}}},"is_private":false,"project":{"type":"project","key":"EX","uuid":"{7f2b61e7-614e-47f2-8faf-8b80059beddb}","name":"experiments","links":{"self":{"href":"https://api.bitbucket.org/2.0/workspaces/avadakedabra/projects/EX"},"html":{"href":"https://bitbucket.org/avadakedabra/workspace/projects/EX"},"avatar":{"href":"https://bitbucket.org/account/user/avadakedabra/projects/EX/avatar/32?ts=1676019187"}}},"uuid":"{bd97c8f8-7098-45db-8272-d22d5e8e1342}"},"actor":{"display_name":"avadakedabra","links":{"self":{"href":"https://api.bitbucket.org/2.0/workspaces/%7Be17cd5cd-4463-420e-ae0b-9061860c8dcb%7D"},"avatar":{"href":"https://bitbucket.org/account/avadakedabra/avatar/"},"html":{"href":"https://bitbucket.org/%7Be17cd5cd-4463-420e-ae0b-9061860c8dcb%7D/"}},"type":"team","uuid":"{e17cd5cd-4463-420e-ae0b-9061860c8dcb}","username":"avadakedabra"}} -------------------------------------------------------------------------------- /vcsclient/testdata/gitlab/pull_requests_list_response.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 1, 4 | "iid": 302, 5 | "project_id": 3, 6 | "title": "test1", 7 | "description": "hello world", 8 | "state": "opened", 9 | "merge_user": { 10 | "id": 87854, 11 | "name": "Douwe Maan", 12 | "username": "DouweM", 13 | "state": "active", 14 | "avatar_url": "https://gitlab.example.com/uploads/-/system/user/avatar/87854/avatar.png", 15 | "web_url": "https://gitlab.com/DouweM" 16 | }, 17 | "merged_at": "2018-09-07T11:16:17.520Z", 18 | "closed_by": null, 19 | "closed_at": null, 20 | "created_at": "2017-04-29T08:46:00Z", 21 | "updated_at": "2017-04-29T08:46:00Z", 22 | "target_branch": "master", 23 | "source_branch": "test1", 24 | "upvotes": 0, 25 | "downvotes": 0, 26 | "author": { 27 | "id": 1, 28 | "name": "Administrator", 29 | "username": "admin", 30 | "state": "active", 31 | "avatar_url": null, 32 | "web_url" : "https://gitlab.example.com/admin" 33 | }, 34 | "assignee": { 35 | "id": 1, 36 | "name": "Administrator", 37 | "username": "admin", 38 | "state": "active", 39 | "avatar_url": null, 40 | "web_url" : "https://gitlab.example.com/admin" 41 | }, 42 | "assignees": [{ 43 | "name": "Miss Monserrate Beier", 44 | "username": "axel.block", 45 | "id": 12, 46 | "state": "active", 47 | "avatar_url": "https://www.gravatar.com/avatar/46f6f7dc858ada7be1853f7fb96e81da?s=80&d=identicon", 48 | "web_url": "https://gitlab.example.com/axel.block" 49 | }], 50 | "reviewers": [{ 51 | "id": 2, 52 | "name": "Sam Bauch", 53 | "username": "kenyatta_oconnell", 54 | "state": "active", 55 | "avatar_url": "https://www.gravatar.com/avatar/956c92487c6f6f7616b536927e22c9a0?s=80&d=identicon", 56 | "web_url": "https://gitlab.example.com//kenyatta_oconnell" 57 | }], 58 | "source_project_id": 2, 59 | "target_project_id": 2, 60 | "labels": [ 61 | "Community contribution", 62 | "Manage" 63 | ], 64 | "draft": false, 65 | "work_in_progress": false, 66 | "milestone": { 67 | "id": 5, 68 | "iid": 1, 69 | "project_id": 3, 70 | "title": "v2.0", 71 | "description": "hello world", 72 | "state": "closed", 73 | "created_at": "2015-02-02T19:49:26.013Z", 74 | "updated_at": "2015-02-02T19:49:26.013Z", 75 | "due_date": "2018-09-22", 76 | "start_date": "2018-08-08", 77 | "web_url": "https://gitlab.example.com/my-group/my-project/milestones/1" 78 | }, 79 | "merge_when_pipeline_succeeds": true, 80 | "merge_status": "can_be_merged", 81 | "sha": "8888888888888888888888888888888888888888", 82 | "merge_commit_sha": null, 83 | "squash_commit_sha": null, 84 | "user_notes_count": 1, 85 | "discussion_locked": null, 86 | "should_remove_source_branch": true, 87 | "force_remove_source_branch": false, 88 | "allow_collaboration": false, 89 | "allow_maintainer_to_push": false, 90 | "web_url": "https://gitlab.example.com/my-group/my-project/merge_requests/1", 91 | "references": { 92 | "short": "!1", 93 | "relative": "!1", 94 | "full": "my-group/my-project!1" 95 | }, 96 | "time_stats": { 97 | "time_estimate": 0, 98 | "total_time_spent": 0, 99 | "human_time_estimate": null, 100 | "human_total_time_spent": null 101 | }, 102 | "squash": false, 103 | "task_completion_status":{ 104 | "count":0, 105 | "completed_count":0 106 | }, 107 | "has_conflicts": false, 108 | "blocking_discussions_resolved": true 109 | } 110 | ] 111 | 112 | -------------------------------------------------------------------------------- /vcsclient/testdata/bitbucketcloud/repository_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "has_wiki": false, 3 | "fork_policy": "allow_forks", 4 | "workspace": { 5 | "slug": "jfrog", 6 | "type": "workspace", 7 | "name": "JFrog", 8 | "links": null, 9 | "uuid": "{08229d9e-bfc7-4ca4-bec3-ee3fbfbaa0d2}" 10 | }, 11 | "scm": "git", 12 | "full_name": "jfrog/jfrog-setup-cli", 13 | "name": "jfrog-setup-cli", 14 | "mainbranch": { 15 | "type": "branch", 16 | "name": "master" 17 | }, 18 | "updated_on": "2020-06-22T12:32:49.604972+00:00", 19 | "description": "", 20 | "website": null, 21 | "language": "", 22 | "created_on": "2020-06-01T18:20:00.848673+00:00", 23 | "has_issues": true, 24 | "owner": { 25 | "username": "jfrog", 26 | "display_name": "JFrog", 27 | "type": "team", 28 | "uuid": "{08229d9e-bfc7-4ca4-bec3-ee3fbfbaa0d2}", 29 | "links": { 30 | "self": { 31 | "href": "https://api.bitbucket.org/2.0/workspaces/%7B08229d9e-bfc7-4ca4-bec3-ee3fbfbaa0d2%7D" 32 | }, 33 | "html": { 34 | "href": "https://bitbucket.org/%7B08229d9e-bfc7-4ca4-bec3-ee3fbfbaa0d2%7D/" 35 | }, 36 | "avatar": { 37 | "href": "https://bitbucket.org/account/jfrog/avatar/" 38 | } 39 | } 40 | }, 41 | "size": 458232, 42 | "uuid": "{7715225f-38e7-49d7-b9cf-479f39044395}", 43 | "links": { 44 | "forks": { 45 | "href": "https://api.bitbucket.org/2.0/repositories/jfrog/jfrog-setup-cli/forks" 46 | }, 47 | "issues": { 48 | "href": "https://api.bitbucket.org/2.0/repositories/jfrog/jfrog-setup-cli/issues" 49 | }, 50 | "watchers": { 51 | "href": "https://api.bitbucket.org/2.0/repositories/jfrog/jfrog-setup-cli/watchers" 52 | }, 53 | "branches": { 54 | "href": "https://api.bitbucket.org/2.0/repositories/jfrog/jfrog-setup-cli/refs/branches" 55 | }, 56 | "commits": { 57 | "href": "https://api.bitbucket.org/2.0/repositories/jfrog/jfrog-setup-cli/commits" 58 | }, 59 | "html": { 60 | "href": "https://bitbucket.org/jfrog/jfrog-setup-cli" 61 | }, 62 | "avatar": { 63 | "href": "https://bytebucket.org/ravatar/%7B7715225f-38e7-49d7-b9cf-479f39044395%7D?ts=2553958" 64 | }, 65 | "hooks": { 66 | "href": "https://api.bitbucket.org/2.0/repositories/jfrog/jfrog-setup-cli/hooks" 67 | }, 68 | "downloads": { 69 | "href": "https://api.bitbucket.org/2.0/repositories/jfrog/jfrog-setup-cli/downloads" 70 | }, 71 | "pullrequests": { 72 | "href": "https://api.bitbucket.org/2.0/repositories/jfrog/jfrog-setup-cli/pullrequests" 73 | }, 74 | "clone": [ 75 | { 76 | "href": "https://bitbucket.org/jfrog/jfrog-setup-cli.git", 77 | "name": "https" 78 | }, 79 | { 80 | "href": "git@bitbucket.org:jfrog/jfrog-setup-cli.git", 81 | "name": "ssh" 82 | } 83 | ], 84 | "source": { 85 | "href": "https://api.bitbucket.org/2.0/repositories/jfrog/jfrog-setup-cli/src" 86 | }, 87 | "tags": { 88 | "href": "https://api.bitbucket.org/2.0/repositories/jfrog/jfrog-setup-cli/refs/tags" 89 | }, 90 | "self": { 91 | "href": "https://api.bitbucket.org/2.0/repositories/jfrog/jfrog-setup-cli" 92 | } 93 | }, 94 | "project": { 95 | "links": { 96 | "self": { 97 | "href": "https://api.bitbucket.org/2.0/workspaces/jfrog/projects/PROJ" 98 | }, 99 | "html": { 100 | "href": "https://bitbucket.org/jfrog/workspace/projects/PROJ" 101 | }, 102 | "avatar": { 103 | "href": "https://bitbucket.org/account/user/jfrog/projects/PROJ/avatar/32?ts=1591045050" 104 | } 105 | }, 106 | "type": "project", 107 | "name": "jfrog", 108 | "key": "PROJ", 109 | "uuid": "{c23ff002-f633-4fb0-8ab8-ec70a5701784}" 110 | }, 111 | "type": "repository", 112 | "slug": "jfrog-setup-cli", 113 | "is_private": false 114 | } -------------------------------------------------------------------------------- /vcsclient/testdata/bitbucketserver/pull_requests_list_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "size": 1, 3 | "limit": 25, 4 | "isLastPage": true, 5 | "values": [ 6 | { 7 | "id": 101, 8 | "version": 1, 9 | "title": "Talking Nerdy", 10 | "description": "hello world", 11 | "state": "OPEN", 12 | "open": true, 13 | "closed": false, 14 | "createdDate": 1359075920, 15 | "updatedDate": 1359085920, 16 | "fromRef": { 17 | "id": "refs/heads/feature-ABC-123", 18 | "repository": { 19 | "slug": "repo-1", 20 | "name": null, 21 | "project": { 22 | "key": "jfrogForked" 23 | } 24 | }, 25 | "displayId": "feature-ABC-123" 26 | }, 27 | "toRef": { 28 | "id": "refs/heads/master", 29 | "repository": { 30 | "slug": "repo-1", 31 | "name": null, 32 | "project": { 33 | "key": "jfrog" 34 | } 35 | }, 36 | "displayId": "master" 37 | }, 38 | "locked": false, 39 | "author": { 40 | "user": { 41 | "name": "tom", 42 | "emailAddress": "tom@example.com", 43 | "id": 115026, 44 | "displayName": "Tom", 45 | "active": true, 46 | "slug": "tom", 47 | "type": "NORMAL" 48 | }, 49 | "role": "AUTHOR", 50 | "approved": true, 51 | "status": "APPROVED" 52 | }, 53 | "reviewers": [ 54 | { 55 | "user": { 56 | "name": "jcitizen", 57 | "emailAddress": "jane@example.com", 58 | "id": 101, 59 | "displayName": "Jane Citizen", 60 | "active": true, 61 | "slug": "jcitizen", 62 | "type": "NORMAL" 63 | }, 64 | "lastReviewedCommit": "7549846524f8aed2bd1c0249993ae1bf9d3c9998", 65 | "role": "REVIEWER", 66 | "approved": true, 67 | "status": "APPROVED" 68 | } 69 | ], 70 | "participants": [ 71 | { 72 | "user": { 73 | "name": "harry", 74 | "emailAddress": "harry@example.com", 75 | "id": 99049120, 76 | "displayName": "Harry", 77 | "active": true, 78 | "slug": "harry", 79 | "type": "NORMAL" 80 | }, 81 | "role": "PARTICIPANT", 82 | "approved": true, 83 | "status": "APPROVED" 84 | }, 85 | { 86 | "user": { 87 | "name": "dick", 88 | "emailAddress": "dick@example.com", 89 | "id": 3083181, 90 | "displayName": "Dick", 91 | "active": true, 92 | "slug": "dick", 93 | "type": "NORMAL" 94 | }, 95 | "role": "PARTICIPANT", 96 | "approved": false, 97 | "status": "UNAPPROVED" 98 | } 99 | ], 100 | "links": { 101 | "self": [ 102 | { 103 | "href": "https://link/to/pullrequest" 104 | } 105 | ] 106 | } 107 | } 108 | ], 109 | "start": 0 110 | } -------------------------------------------------------------------------------- /vcsclient/testdata/github/commit_single_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://api.github.com/repos/octocat/Hello-World/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e", 3 | "sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e", 4 | "node_id": "MDY6Q29tbWl0NmRjYjA5YjViNTc4NzVmMzM0ZjYxYWViZWQ2OTVlMmU0MTkzZGI1ZQ==", 5 | "html_url": "https://github.com/octocat/Hello-World/commit/6dcb09b5b57875f334f61aebed695e2e4193db5e", 6 | "comments_url": "https://api.github.com/repos/octocat/Hello-World/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e/comments", 7 | "commit": { 8 | "url": "https://api.github.com/repos/octocat/Hello-World/git/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e", 9 | "author": { 10 | "name": "Monalisa Octocat", 11 | "email": "support@github.com", 12 | "date": "2011-04-14T16:00:49Z" 13 | }, 14 | "committer": { 15 | "name": "Joconde Octocat", 16 | "email": "support2@github.com", 17 | "date": "2011-04-14T16:00:50Z" 18 | }, 19 | "message": "Fix all the bugs", 20 | "tree": { 21 | "url": "https://api.github.com/repos/octocat/Hello-World/tree/6dcb09b5b57875f334f61aebed695e2e4193db5e", 22 | "sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e" 23 | }, 24 | "comment_count": 0, 25 | "verification": { 26 | "verified": false, 27 | "reason": "unsigned", 28 | "signature": null, 29 | "payload": null 30 | } 31 | }, 32 | "author": { 33 | "login": "octocat", 34 | "id": 1, 35 | "node_id": "MDQ6VXNlcjE=", 36 | "avatar_url": "https://github.com/images/error/octocat_happy.gif", 37 | "gravatar_id": "", 38 | "url": "https://api.github.com/users/octocat", 39 | "html_url": "https://github.com/octocat", 40 | "followers_url": "https://api.github.com/users/octocat/followers", 41 | "following_url": "https://api.github.com/users/octocat/following{/other_user}", 42 | "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", 43 | "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", 44 | "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", 45 | "organizations_url": "https://api.github.com/users/octocat/orgs", 46 | "repos_url": "https://api.github.com/users/octocat/repos", 47 | "events_url": "https://api.github.com/users/octocat/events{/privacy}", 48 | "received_events_url": "https://api.github.com/users/octocat/received_events", 49 | "type": "User", 50 | "site_admin": false 51 | }, 52 | "committer": { 53 | "login": "octocat", 54 | "id": 1, 55 | "node_id": "MDQ6VXNlcjE=", 56 | "avatar_url": "https://github.com/images/error/octocat_happy.gif", 57 | "gravatar_id": "", 58 | "url": "https://api.github.com/users/octocat", 59 | "html_url": "https://github.com/octocat", 60 | "followers_url": "https://api.github.com/users/octocat/followers", 61 | "following_url": "https://api.github.com/users/octocat/following{/other_user}", 62 | "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", 63 | "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", 64 | "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", 65 | "organizations_url": "https://api.github.com/users/octocat/orgs", 66 | "repos_url": "https://api.github.com/users/octocat/repos", 67 | "events_url": "https://api.github.com/users/octocat/events{/privacy}", 68 | "received_events_url": "https://api.github.com/users/octocat/received_events", 69 | "type": "User", 70 | "site_admin": false 71 | }, 72 | "parents": [ 73 | { 74 | "url": "https://api.github.com/repos/octocat/Hello-World/commits/5dcb09b5b57875f334f61aebed695e2e4193db5e", 75 | "sha": "5dcb09b5b57875f334f61aebed695e2e4193db5e" 76 | } 77 | ], 78 | "stats": { 79 | "additions": 104, 80 | "deletions": 4, 81 | "total": 108 82 | }, 83 | "files": [ 84 | { 85 | "filename": "file1.txt", 86 | "additions": 10, 87 | "deletions": 2, 88 | "changes": 12, 89 | "status": "modified", 90 | "raw_url": "https://github.com/octocat/Hello-World/raw/7ca483543807a51b6079e54ac4cc392bc29ae284/file1.txt", 91 | "blob_url": "https://github.com/octocat/Hello-World/blob/7ca483543807a51b6079e54ac4cc392bc29ae284/file1.txt", 92 | "patch": "@@ -29,7 +29,7 @@\n....." 93 | } 94 | ] 95 | } -------------------------------------------------------------------------------- /vcsclient/common_test.go: -------------------------------------------------------------------------------- 1 | package vcsclient 2 | 3 | import ( 4 | "encoding/json" 5 | "net/http" 6 | "net/http/httptest" 7 | "testing" 8 | "time" 9 | 10 | "github.com/jfrog/froggit-go/vcsutils" 11 | "github.com/stretchr/testify/assert" 12 | ) 13 | 14 | const ( 15 | owner = "jfrog" 16 | token = "abc123" 17 | basicAuthHeader = "Basic ZnJvZ2dlcjphYmMxMjM=" 18 | project = "jfrog-project" 19 | ) 20 | 21 | var ( 22 | repo1 = "repo-1" 23 | repo2 = "repo-2" 24 | username = "frogger" 25 | branch1 = "branch-1" 26 | branch2 = "branch-2" 27 | labelName = "🚀 label-name" 28 | envName = "frogbot" 29 | ) 30 | 31 | type createHandlerFunc func(t *testing.T, expectedUri string, response []byte, expectedStatusCode int) http.HandlerFunc 32 | type createPostHandlerFunc func(t *testing.T, expectedUri string, response []byte, expectedRequestBody []byte, 33 | expectedStatusCode int, expectedHttpMethod string) http.HandlerFunc 34 | 35 | func createServerAndClient(t *testing.T, vcsProvider vcsutils.VcsProvider, basicAuth bool, response interface{}, 36 | expectedURI string, createHandlerFunc createHandlerFunc) (VcsClient, func()) { 37 | return createServerAndClientReturningStatus(t, vcsProvider, basicAuth, response, expectedURI, http.StatusOK, createHandlerFunc) 38 | } 39 | 40 | func createServerAndClientReturningStatus(t *testing.T, vcsProvider vcsutils.VcsProvider, basicAuth bool, response interface{}, 41 | expectedURI string, expectedStatusCode int, createHandlerFunc createHandlerFunc) (VcsClient, func()) { 42 | client, _, cleanUp := createServerWithUrlAndClientReturningStatus(t, vcsProvider, basicAuth, response, 43 | expectedURI, expectedStatusCode, createHandlerFunc) 44 | return client, cleanUp 45 | } 46 | 47 | func createServerWithUrlAndClientReturningStatus(t *testing.T, vcsProvider vcsutils.VcsProvider, basicAuth bool, 48 | response interface{}, expectedURI string, expectedStatusCode int, 49 | createHandlerFunc createHandlerFunc) (VcsClient, string, func()) { 50 | var byteResponse []byte 51 | var ok bool 52 | if byteResponse, ok = response.([]byte); !ok { 53 | // Response is not a byte array - unmarshal is needed 54 | var err error 55 | byteResponse, err = json.Marshal(response) 56 | assert.NoError(t, err) 57 | } 58 | server := httptest.NewServer(createHandlerFunc(t, expectedURI, byteResponse, expectedStatusCode)) 59 | client := buildClient(t, vcsProvider, basicAuth, server) 60 | return client, server.URL, server.Close 61 | } 62 | 63 | func createBodyHandlingServerAndClient(t *testing.T, vcsProvider vcsutils.VcsProvider, basicAuth bool, response interface{}, 64 | expectedURI string, expectedStatusCode int, expectedRequestBody []byte, expectedHTTPMethod string, 65 | createPostHandlerFunc createPostHandlerFunc) (VcsClient, func()) { 66 | var byteResponse []byte 67 | var ok bool 68 | if byteResponse, ok = response.([]byte); !ok { 69 | // Response is not a byte array - unmarshal is needed 70 | var err error 71 | byteResponse, err = json.Marshal(response) 72 | assert.NoError(t, err) 73 | } 74 | server := httptest.NewServer(createPostHandlerFunc(t, expectedURI, byteResponse, expectedRequestBody, 75 | expectedStatusCode, expectedHTTPMethod)) 76 | client := buildClient(t, vcsProvider, basicAuth, server) 77 | return client, server.Close 78 | } 79 | 80 | func buildClient(t *testing.T, vcsProvider vcsutils.VcsProvider, basicAuth bool, server *httptest.Server) VcsClient { 81 | clientBuilder := NewClientBuilder(vcsProvider).ApiEndpoint(server.URL).Token(token) 82 | if basicAuth { 83 | clientBuilder = clientBuilder.Username("frogger") 84 | } 85 | client, err := clientBuilder.Build() 86 | assert.NoError(t, err) 87 | return client 88 | } 89 | 90 | func createWaitingServerAndClient(t *testing.T, provider vcsutils.VcsProvider, waitDuration time.Duration) (VcsClient, func()) { 91 | server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 92 | if waitDuration > 0 { 93 | time.Sleep(waitDuration) 94 | } 95 | w.WriteHeader(http.StatusOK) 96 | })) 97 | clientBuilder := NewClientBuilder(provider).ApiEndpoint(server.URL).Token(token) 98 | client, err := clientBuilder.Build() 99 | assert.NoError(t, err) 100 | return client, server.Close 101 | } 102 | 103 | func getAllProviders() []vcsutils.VcsProvider { 104 | return []vcsutils.VcsProvider{ 105 | vcsutils.GitHub, vcsutils.GitLab, vcsutils.BitbucketServer, vcsutils.BitbucketCloud, 106 | } 107 | } 108 | 109 | func getNonBitbucketProviders() []vcsutils.VcsProvider { 110 | return []vcsutils.VcsProvider{ 111 | vcsutils.GitHub, vcsutils.GitLab, 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /vcsclient/testdata/azurerepos/resourcesResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "value": [ 3 | { 4 | "id": "e81700f7-3be2-46de-8624-2eb35882fcaa", 5 | "area": "Location", 6 | "resourceName": "ResourceAreas", 7 | "routeTemplate": "_apis/{resource}/{areaId}", 8 | "resourceVersion": 1, 9 | "minVersion": "3.2", 10 | "maxVersion": "7.1", 11 | "releasedVersion": "0.0" 12 | }, 13 | { 14 | "id": "d5b216de-d8d5-4d32-ae76-51df755b16d3", 15 | "area": "Location", 16 | "resourceName": "ResourceAreas", 17 | "routeTemplate": "_apis/{resource}/{areaId}/listBranches", 18 | "resourceVersion": 1, 19 | "minVersion": "3.2", 20 | "maxVersion": "7.1", 21 | "releasedVersion": "0.0" 22 | }, 23 | { 24 | "id": "ab6e2e5d-a0b7-4153-b64a-a4efe0d49449", 25 | "area": "Location", 26 | "resourceName": "ResourceAreas", 27 | "routeTemplate": "_apis/{resource}/{areaId}/pullRequestComments", 28 | "resourceVersion": 1, 29 | "minVersion": "3.2", 30 | "maxVersion": "7.1", 31 | "releasedVersion": "0.0" 32 | }, 33 | { 34 | "id": "9946fd70-0d40-406e-b686-b4744cbbcc37", 35 | "area": "Location", 36 | "resourceName": "ResourceAreas", 37 | "routeTemplate": "_apis/{resource}/{areaId}/getPullRequests", 38 | "resourceVersion": 1, 39 | "minVersion": "3.2", 40 | "maxVersion": "7.1", 41 | "releasedVersion": "0.0" 42 | }, 43 | { 44 | "id": "c2570c3b-5b3f-41b8-98bf-5407bfde8d58", 45 | "area": "Location", 46 | "resourceName": "ResourceAreas", 47 | "routeTemplate": "_apis/{resource}/{areaId}/getCommits", 48 | "resourceVersion": 1, 49 | "minVersion": "3.2", 50 | "maxVersion": "7.1", 51 | "releasedVersion": "0.0" 52 | }, 53 | { 54 | "id": "c257043b-5b3f-41b8-98bf-5407bfde8d58", 55 | "area": "Location", 56 | "resourceName": "ResourceAreas", 57 | "routeTemplate": "_apis/{resource}/{areaId}/unsupportedTest", 58 | "resourceVersion": 1, 59 | "minVersion": "3.2", 60 | "maxVersion": "7.1", 61 | "releasedVersion": "0.0" 62 | }, 63 | { 64 | "id": "615588d5-c0c7-4b88-88f8-e625306446e8", 65 | "area": "Location", 66 | "resourceName": "ResourceAreas", 67 | "routeTemplate": "_apis/{resource}/{areaId}", 68 | "resourceVersion": 1, 69 | "minVersion": "3.2", 70 | "maxVersion": "7.1", 71 | "releasedVersion": "0.0" 72 | }, 73 | { 74 | "id": "428dd4fb-fda5-4722-af02-9313b80305da", 75 | "area": "Location", 76 | "resourceName": "ResourceAreas", 77 | "routeTemplate": "_apis/{resource}/commitStatus", 78 | "resourceVersion": 1, 79 | "minVersion": "3.2", 80 | "maxVersion": "7.1", 81 | "releasedVersion": "0.0" 82 | }, 83 | { 84 | "id": "fb93c0db-47ed-4a31-8c20-47552878fb44", 85 | "area": "Location", 86 | "resourceName": "ResourceAreas", 87 | "routeTemplate": "_apis/{resource}/DownloadFileFromRepo", 88 | "resourceVersion": 1, 89 | "minVersion": "3.2", 90 | "maxVersion": "7.1", 91 | "releasedVersion": "0.0" 92 | }, 93 | { 94 | "id": "965a3ec7-5ed8-455a-bdcb-835a5ea7fe7b", 95 | "area": "Location", 96 | "resourceName": "ResourceAreas", 97 | "routeTemplate": "_apis/{resource}/deletePullRequestComments", 98 | "resourceVersion": 1, 99 | "minVersion": "3.2", 100 | "maxVersion": "7.1", 101 | "releasedVersion": "0.0" 102 | }, 103 | { 104 | "id": "225f7195-f9c7-4d14-ab28-a83f7ff77e1f", 105 | "area": "Location", 106 | "resourceName": "ResourceAreas", 107 | "routeTemplate": "_apis/{resource}/getRepository", 108 | "resourceVersion": 1, 109 | "minVersion": "3.2", 110 | "maxVersion": "7.1", 111 | "releasedVersion": "0.0" 112 | }, 113 | { 114 | "id": "01a46dea-7d46-4d40-bc84-319e7c260d99", 115 | "area": "Location", 116 | "resourceName": "ResourceAreas", 117 | "routeTemplate": "_apis/{resource}/{areaId}/getPullRequests/{pullRequestId}", 118 | "resourceVersion": 1, 119 | "minVersion": "3.2", 120 | "maxVersion": "7.1", 121 | "releasedVersion": "0.0" 122 | }, 123 | { 124 | "id": "4b6702c7-aa35-4b89-9c96-b9abf6d3e540", 125 | "area": "Location", 126 | "resourceName": "ResourceAreas", 127 | "routeTemplate": "/_apis/git/repositories/repo/pullRequests/{pullRequestId}/reviewers", 128 | "resourceVersion": 1, 129 | "minVersion": "3.2", 130 | "maxVersion": "7.1", 131 | "releasedVersion": "0.0" 132 | } 133 | ], 134 | "count": 2 135 | } -------------------------------------------------------------------------------- /vcsclient/testdata/gitlab/get_merge_request_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 1, 3 | "iid": 133, 4 | "project_id": 15513260, 5 | "title": "Manual job rules", 6 | "description": "", 7 | "state": "opened", 8 | "created_at": "2022-05-13T07:26:38.402Z", 9 | "updated_at": "2022-05-14T03:38:31.354Z", 10 | "merged_by": null, 11 | "merge_user": null, 12 | "merged_at": null, 13 | "prepared_at": "2018-09-04T11:16:17.520Z", 14 | "closed_by": null, 15 | "closed_at": null, 16 | "target_branch": "master", 17 | "source_branch": "manual-job-rules", 18 | "user_notes_count": 0, 19 | "upvotes": 0, 20 | "downvotes": 0, 21 | "author": { 22 | "id": 4155490, 23 | "username": "marcel.amirault", 24 | "name": "Marcel Amirault", 25 | "state": "active", 26 | "avatar_url": "https://gitlab.com/uploads/-/system/user/avatar/4155490/avatar.png", 27 | "web_url": "https://gitlab.com/marcel.amirault" 28 | }, 29 | "assignees": [], 30 | "assignee": null, 31 | "reviewers": [], 32 | "source_project_id": 15513260, 33 | "target_project_id": 15513260, 34 | "labels": [], 35 | "draft": false, 36 | "work_in_progress": false, 37 | "milestone": null, 38 | "merge_when_pipeline_succeeds": false, 39 | "merge_status": "can_be_merged", 40 | "detailed_merge_status": "can_be_merged", 41 | "sha": "e82eb4a098e32c796079ca3915e07487fc4db24c", 42 | "merge_commit_sha": null, 43 | "squash_commit_sha": null, 44 | "discussion_locked": null, 45 | "should_remove_source_branch": null, 46 | "force_remove_source_branch": true, 47 | "reference": "!133", 48 | "references": { 49 | "short": "!133", 50 | "relative": "!133", 51 | "full": "marcel.amirault/test-project!133" 52 | }, 53 | "web_url": "https://gitlab.com/marcel.amirault/test-project/-/merge_requests/133", 54 | "time_stats": { 55 | "time_estimate": 0, 56 | "total_time_spent": 0, 57 | "human_time_estimate": null, 58 | "human_total_time_spent": null 59 | }, 60 | "squash": false, 61 | "task_completion_status": { 62 | "count": 0, 63 | "completed_count": 0 64 | }, 65 | "has_conflicts": false, 66 | "blocking_discussions_resolved": true, 67 | "approvals_before_merge": null, 68 | "subscribed": true, 69 | "changes_count": "1", 70 | "latest_build_started_at": "2022-05-13T09:46:50.032Z", 71 | "latest_build_finished_at": null, 72 | "first_deployed_to_production_at": null, 73 | "pipeline": { 74 | "id": 538317940, 75 | "iid": 1877, 76 | "project_id": 15513260, 77 | "sha": "1604b0c46c395822e4e9478777f8e54ac99fe5b9", 78 | "ref": "refs/merge-requests/133/merge", 79 | "status": "failed", 80 | "source": "merge_request_event", 81 | "created_at": "2022-05-13T09:46:39.560Z", 82 | "updated_at": "2022-05-13T09:47:20.706Z", 83 | "web_url": "https://gitlab.com/marcel.amirault/test-project/-/pipelines/538317940" 84 | }, 85 | "head_pipeline": { 86 | "id": 538317940, 87 | "iid": 1877, 88 | "project_id": 15513260, 89 | "sha": "1604b0c46c395822e4e9478777f8e54ac99fe5b9", 90 | "ref": "refs/merge-requests/133/merge", 91 | "status": "failed", 92 | "source": "merge_request_event", 93 | "created_at": "2022-05-13T09:46:39.560Z", 94 | "updated_at": "2022-05-13T09:47:20.706Z", 95 | "web_url": "https://gitlab.com/marcel.amirault/test-project/-/pipelines/538317940", 96 | "before_sha": "1604b0c46c395822e4e9478777f8e54ac99fe5b9", 97 | "tag": false, 98 | "yaml_errors": null, 99 | "user": { 100 | "id": 4155490, 101 | "username": "marcel.amirault", 102 | "name": "Marcel Amirault", 103 | "state": "active", 104 | "avatar_url": "https://gitlab.com/uploads/-/system/user/avatar/4155490/avatar.png", 105 | "web_url": "https://gitlab.com/marcel.amirault" 106 | }, 107 | "started_at": "2022-05-13T09:46:50.032Z", 108 | "finished_at": "2022-05-13T09:47:20.697Z", 109 | "committed_at": null, 110 | "duration": 30, 111 | "queued_duration": 10, 112 | "coverage": null, 113 | "detailed_status": { 114 | "icon": "status_failed", 115 | "text": "failed", 116 | "label": "failed", 117 | "group": "failed", 118 | "tooltip": "failed", 119 | "has_details": true, 120 | "details_path": "/marcel.amirault/test-project/-/pipelines/538317940", 121 | "illustration": null, 122 | "favicon": "/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png" 123 | } 124 | }, 125 | "diff_refs": { 126 | "base_sha": "1162f719d711319a2efb2a35566f3bfdadee8bab", 127 | "head_sha": "e82eb4a098e32c796079ca3915e07487fc4db24c", 128 | "start_sha": "1162f719d711319a2efb2a35566f3bfdadee8bab" 129 | }, 130 | "merge_error": null, 131 | "first_contribution": false, 132 | "user": { 133 | "can_merge": true 134 | } 135 | } -------------------------------------------------------------------------------- /vcsclient/testdata/github/pull_request_comments_list_response.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "url": "https://api.github.com/repos/octocat/Hello-World/pulls/comments/1", 4 | "pull_request_review_id": 42, 5 | "id": 10, 6 | "node_id": "MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDEw", 7 | "diff_hunk": "@@ -16,33 +16,40 @@ public class Connection : IConnection...", 8 | "path": "file1.txt", 9 | "position": 1, 10 | "original_position": 4, 11 | "commit_id": "6dcb09b5b57875f334f61aebed695e2e4193db5e", 12 | "original_commit_id": "9c48853fa3dc5c1c3d6f1f1cd1f2743e72652840", 13 | "in_reply_to_id": 8, 14 | "user": { 15 | "login": "octocat", 16 | "id": 1, 17 | "node_id": "MDQ6VXNlcjE=", 18 | "avatar_url": "https://github.com/images/error/octocat_happy.gif", 19 | "gravatar_id": "", 20 | "url": "https://api.github.com/users/octocat", 21 | "html_url": "https://github.com/octocat", 22 | "followers_url": "https://api.github.com/users/octocat/followers", 23 | "following_url": "https://api.github.com/users/octocat/following{/other_user}", 24 | "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", 25 | "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", 26 | "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", 27 | "organizations_url": "https://api.github.com/users/octocat/orgs", 28 | "repos_url": "https://api.github.com/users/octocat/repos", 29 | "events_url": "https://api.github.com/users/octocat/events{/privacy}", 30 | "received_events_url": "https://api.github.com/users/octocat/received_events", 31 | "type": "User", 32 | "site_admin": false 33 | }, 34 | "body": "Great stuff!", 35 | "created_at": "2011-04-14T16:00:49Z", 36 | "updated_at": "2011-04-14T16:00:49Z", 37 | "html_url": "https://github.com/octocat/Hello-World/pull/1#discussion-diff-1", 38 | "pull_request_url": "https://api.github.com/repos/octocat/Hello-World/pulls/1", 39 | "author_association": "NONE", 40 | "_links": { 41 | "self": { 42 | "href": "https://api.github.com/repos/octocat/Hello-World/pulls/comments/1" 43 | }, 44 | "html": { 45 | "href": "https://github.com/octocat/Hello-World/pull/1#discussion-diff-1" 46 | }, 47 | "pull_request": { 48 | "href": "https://api.github.com/repos/octocat/Hello-World/pulls/1" 49 | } 50 | }, 51 | "start_line": 1, 52 | "original_start_line": 1, 53 | "start_side": "RIGHT", 54 | "line": 2, 55 | "original_line": 2, 56 | "side": "RIGHT" 57 | }, 58 | { 59 | "url": "https://api.github.com/repos/octocat/Hello-World/pulls/comments/1", 60 | "pull_request_review_id": 43, 61 | "id": 11, 62 | "node_id": "MDI0OlB1bGxSZXF1ZXk0UmV2aWV3Q29tbWVudDEw", 63 | "diff_hunk": "@@ -16,33 +16,40 @@ public class Connection : IConnection...", 64 | "path": "file1.txt", 65 | "position": 1, 66 | "original_position": 4, 67 | "commit_id": "6dcb09b5b57875f334f61aebed695e2e4193db5e", 68 | "original_commit_id": "9c48853fa3dc5c1c3d6f1f1cd1f2743e72652840", 69 | "in_reply_to_id": 8, 70 | "user": { 71 | "login": "octocat", 72 | "id": 1, 73 | "node_id": "MDQ6VXNlcjE=", 74 | "avatar_url": "https://github.com/images/error/octocat_happy.gif", 75 | "gravatar_id": "", 76 | "url": "https://api.github.com/users/octocat", 77 | "html_url": "https://github.com/octocat", 78 | "followers_url": "https://api.github.com/users/octocat/followers", 79 | "following_url": "https://api.github.com/users/octocat/following{/other_user}", 80 | "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", 81 | "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", 82 | "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", 83 | "organizations_url": "https://api.github.com/users/octocat/orgs", 84 | "repos_url": "https://api.github.com/users/octocat/repos", 85 | "events_url": "https://api.github.com/users/octocat/events{/privacy}", 86 | "received_events_url": "https://api.github.com/users/octocat/received_events", 87 | "type": "User", 88 | "site_admin": false 89 | }, 90 | "body": "LGTM", 91 | "created_at": "2011-04-14T16:01:49Z", 92 | "updated_at": "2011-04-14T16:01:49Z", 93 | "html_url": "https://github.com/octocat/Hello-World/pull/1#discussion-diff-1", 94 | "pull_request_url": "https://api.github.com/repos/octocat/Hello-World/pulls/1", 95 | "author_association": "NONE", 96 | "_links": { 97 | "self": { 98 | "href": "https://api.github.com/repos/octocat/Hello-World/pulls/comments/1" 99 | }, 100 | "html": { 101 | "href": "https://github.com/octocat/Hello-World/pull/1#discussion-diff-1" 102 | }, 103 | "pull_request": { 104 | "href": "https://api.github.com/repos/octocat/Hello-World/pulls/1" 105 | } 106 | }, 107 | "start_line": 1, 108 | "original_start_line": 1, 109 | "start_side": "RIGHT", 110 | "line": 2, 111 | "original_line": 2, 112 | "side": "RIGHT" 113 | } 114 | ] 115 | -------------------------------------------------------------------------------- /vcsclient/testdata/bitbucketcloud/pull_request_comments_list_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "pagelen": 10, 3 | "values": [ 4 | { 5 | "links": { 6 | "self": { 7 | "href": "https://api.bitbucket.org/2.0/repositories/user17/test/pullrequests/3/comments/301545835" 8 | }, 9 | "html": { 10 | "href": "https://bitbucket.org/user17/test/pull-requests/3/_/diff#comment-301545835" 11 | } 12 | }, 13 | "deleted": false, 14 | "pullrequest": { 15 | "type": "pullrequest", 16 | "id": 3, 17 | "links": { 18 | "self": { 19 | "href": "https://api.bitbucket.org/2.0/repositories/user17/test/pullrequests/3" 20 | }, 21 | "html": { 22 | "href": "https://bitbucket.org/user17/test/pull-requests/3" 23 | } 24 | }, 25 | "title": "A change" 26 | }, 27 | "content": { 28 | "raw": "I’m a comment ", 29 | "markup": "markdown", 30 | "html": "

I’m a comment

", 31 | "type": "rendered" 32 | }, 33 | "created_on": "2022-05-16T11:04:07.075827+00:00", 34 | "user": { 35 | "display_name": "user", 36 | "uuid": "{337d7a24-7ebf-4174-8bd9-59bbb900d5e5}", 37 | "links": { 38 | "self": { 39 | "href": "https://api.bitbucket.org/2.0/users/%7B337d7a24-7ebf-4174-8bd9-59bbb900d5e5%7D" 40 | }, 41 | "html": { 42 | "href": "https://bitbucket.org/%7B337d7a24-7ebf-4174-8bd9-59bbb900d5e5%7D/" 43 | }, 44 | "avatar": { 45 | "href": "https://secure.gravatar.com/avatar/269028300673421314978c2b6f7c16b6?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FTA-4.png" 46 | } 47 | }, 48 | "type": "user", 49 | "nickname": "user", 50 | "account_id": "62601f86efc8a5006a559ff8" 51 | }, 52 | "updated_on": "2022-05-16T11:04:07.075911+00:00", 53 | "type": "pullrequest_comment", 54 | "id": 301545835 55 | }, 56 | { 57 | "links": { 58 | "self": { 59 | "href": "https://api.bitbucket.org/2.0/repositories/user17/test/pullrequests/3/comments/301546211" 60 | }, 61 | "html": { 62 | "href": "https://bitbucket.org/user17/test/pull-requests/3/_/diff#comment-301546211" 63 | } 64 | }, 65 | "parent": { 66 | "id": 301545835, 67 | "links": { 68 | "self": { 69 | "href": "https://api.bitbucket.org/2.0/repositories/user17/test/pullrequests/3/comments/301545835" 70 | }, 71 | "html": { 72 | "href": "https://bitbucket.org/user17/test/pull-requests/3/_/diff#comment-301545835" 73 | } 74 | } 75 | }, 76 | "deleted": false, 77 | "pullrequest": { 78 | "type": "pullrequest", 79 | "id": 3, 80 | "links": { 81 | "self": { 82 | "href": "https://api.bitbucket.org/2.0/repositories/user17/test/pullrequests/3" 83 | }, 84 | "html": { 85 | "href": "https://bitbucket.org/user17/test/pull-requests/3" 86 | } 87 | }, 88 | "title": "A change" 89 | }, 90 | "content": { 91 | "raw": "I’m a replay to a comment", 92 | "markup": "markdown", 93 | "html": "

I’m a replay to a comment

", 94 | "type": "rendered" 95 | }, 96 | "created_on": "2022-05-16T11:05:33.886756+00:00", 97 | "user": { 98 | "display_name": "user", 99 | "uuid": "{337d7a24-7ebf-4174-8bd9-59bbb900d5e5}", 100 | "links": { 101 | "self": { 102 | "href": "https://api.bitbucket.org/2.0/users/%7B337d7a24-7ebf-4174-8bd9-59bbb900d5e5%7D" 103 | }, 104 | "html": { 105 | "href": "https://bitbucket.org/%7B337d7a24-7ebf-4174-8bd9-59bbb900d5e5%7D/" 106 | }, 107 | "avatar": { 108 | "href": "https://secure.gravatar.com/avatar/269028300673421314978c2b6f7c16b6?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FTA-4.png" 109 | } 110 | }, 111 | "type": "user", 112 | "nickname": "user", 113 | "account_id": "62601f86efc8a5006a559ff8" 114 | }, 115 | "updated_on": "2022-05-16T11:05:33.889646+00:00", 116 | "type": "pullrequest_comment", 117 | "id": 301546211 118 | } 119 | ], 120 | "page": 1, 121 | "size": 2 122 | } -------------------------------------------------------------------------------- /vcsclient/testdata/gitlab/repository_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 3, 3 | "description": null, 4 | "default_branch": "master", 5 | "visibility": "private", 6 | "ssh_url_to_repo": "git@example.com:diaspora/diaspora-project-site.git", 7 | "http_url_to_repo": "https://example.com/diaspora/diaspora-project-site.git", 8 | "web_url": "https://example.com/diaspora/diaspora-project-site", 9 | "readme_url": "https://example.com/diaspora/diaspora-project-site/blob/master/README.md", 10 | "topics": [ 11 | "example", 12 | "disapora project" 13 | ], 14 | "owner": { 15 | "id": 3, 16 | "name": "Diaspora", 17 | "created_at": "2013-09-30T13:46:02Z" 18 | }, 19 | "name": "Diaspora Project Site", 20 | "name_with_namespace": "Diaspora / Diaspora Project Site", 21 | "path": "diaspora-project-site", 22 | "path_with_namespace": "diaspora/diaspora-project-site", 23 | "issues_enabled": true, 24 | "open_issues_count": 1, 25 | "merge_requests_enabled": true, 26 | "jobs_enabled": true, 27 | "wiki_enabled": true, 28 | "snippets_enabled": false, 29 | "can_create_merge_request_in": true, 30 | "resolve_outdated_diff_discussions": false, 31 | "container_registry_access_level": "disabled", 32 | "container_expiration_policy": { 33 | "cadence": "7d", 34 | "enabled": false, 35 | "keep_n": null, 36 | "older_than": null, 37 | "name_regex_delete": null, 38 | "name_regex_keep": null, 39 | "next_run_at": "2020-01-07T21:42:58.658Z" 40 | }, 41 | "created_at": "2013-09-30T13:46:02Z", 42 | "last_activity_at": "2013-09-30T13:46:02Z", 43 | "creator_id": 3, 44 | "namespace": { 45 | "id": 3, 46 | "name": "Diaspora", 47 | "path": "diaspora", 48 | "kind": "group", 49 | "full_path": "diaspora", 50 | "avatar_url": "https://localhost:3000/uploads/group/avatar/3/foo.jpg", 51 | "web_url": "https://localhost:3000/groups/diaspora" 52 | }, 53 | "import_status": "none", 54 | "import_error": null, 55 | "permissions": { 56 | "project_access": { 57 | "access_level": 10, 58 | "notification_level": 3 59 | }, 60 | "group_access": { 61 | "access_level": 50, 62 | "notification_level": 3 63 | } 64 | }, 65 | "archived": false, 66 | "avatar_url": "https://example.com/uploads/project/avatar/3/uploads/avatar.png", 67 | "license_url": "https://example.com/diaspora/diaspora-client/blob/master/LICENSE", 68 | "license": { 69 | "key": "lgpl-3.0", 70 | "name": "GNU Lesser General Public License v3.0", 71 | "nickname": "GNU LGPLv3", 72 | "html_url": "https://choosealicense.com/licenses/lgpl-3.0/", 73 | "source_url": "https://www.gnu.org/licenses/lgpl-3.0.txt" 74 | }, 75 | "shared_runners_enabled": true, 76 | "forks_count": 0, 77 | "star_count": 0, 78 | "runners_token": "b8bc4a7a29eb76ea83cf79e4908c2b", 79 | "ci_default_git_depth": 50, 80 | "ci_forward_deployment_enabled": true, 81 | "public_jobs": true, 82 | "shared_with_groups": [ 83 | { 84 | "group_id": 4, 85 | "group_name": "Twitter", 86 | "group_full_path": "twitter", 87 | "group_access_level": 30 88 | }, 89 | { 90 | "group_id": 3, 91 | "group_name": "Gitlab Org", 92 | "group_full_path": "gitlab-org", 93 | "group_access_level": 10 94 | } 95 | ], 96 | "repository_storage": "default", 97 | "only_allow_merge_if_pipeline_succeeds": false, 98 | "allow_merge_on_skipped_pipeline": false, 99 | "restrict_user_defined_variables": false, 100 | "only_allow_merge_if_all_discussions_are_resolved": false, 101 | "remove_source_branch_after_merge": false, 102 | "printing_merge_requests_link_enabled": true, 103 | "request_access_enabled": false, 104 | "merge_method": "merge", 105 | "squash_option": "default_on", 106 | "auto_devops_enabled": true, 107 | "auto_devops_deploy_strategy": "continuous", 108 | "approvals_before_merge": 0, 109 | "mirror": false, 110 | "mirror_user_id": 45, 111 | "mirror_trigger_builds": false, 112 | "only_mirror_protected_branches": false, 113 | "mirror_overwrites_diverged_branches": false, 114 | "external_authorization_classification_label": null, 115 | "packages_enabled": true, 116 | "service_desk_enabled": false, 117 | "service_desk_address": null, 118 | "autoclose_referenced_issues": true, 119 | "suggestion_commit_message": null, 120 | "marked_for_deletion_on": "2020-04-03", 121 | "compliance_frameworks": [ "sox" ], 122 | "statistics": { 123 | "commit_count": 37, 124 | "storage_size": 1038090, 125 | "repository_size": 1038090, 126 | "wiki_size" : 0, 127 | "lfs_objects_size": 0, 128 | "job_artifacts_size": 0, 129 | "pipeline_artifacts_size": 0, 130 | "packages_size": 0, 131 | "snippets_size": 0, 132 | "uploads_size": 0 133 | }, 134 | "container_registry_image_prefix": "registry.example.com/diaspora/diaspora-client", 135 | "_links": { 136 | "self": "https://example.com/api/v4/projects", 137 | "issues": "https://example.com/api/v4/projects/1/issues", 138 | "merge_requests": "https://example.com/api/v4/projects/1/merge_requests", 139 | "repo_branches": "https://example.com/api/v4/projects/1/repository_branches", 140 | "labels": "https://example.com/api/v4/projects/1/labels", 141 | "events": "https://example.com/api/v4/projects/1/events", 142 | "members": "https://example.com/api/v4/projects/1/members" 143 | } 144 | } -------------------------------------------------------------------------------- /vcsclient/testdata/gitlab/compare_commits.json: -------------------------------------------------------------------------------- 1 | { 2 | "commit": { 3 | "id": "1c0a893703a70558fcf7bb13348847a1302b2c49", 4 | "short_id": "1c0a8937", 5 | "created_at": "2023-02-13T10:18:53.000+01:00", 6 | "parent_ids": ["9cee818844e23dfa5922155d113a950ff86ff2e7"], 7 | "title": "Update Slack notes", 8 | "message": "Update Slack notes\n", 9 | "author_name": "Ashraf Khamis", 10 | "author_email": "akhamis@gitlab.com", 11 | "authored_date": "2023-02-13T10:18:53.000+01:00", 12 | "committer_name": "Ashraf Khamis", 13 | "committer_email": "akhamis@gitlab.com", 14 | "committed_date": "2023-02-13T10:18:53.000+01:00", 15 | "trailers": {}, 16 | "web_url": "https://gitlab.com/gitlab-org/gitlab/-/commit/1c0a893703a70558fcf7bb13348847a1302b2c49" 17 | }, 18 | "commits": [{ 19 | "id": "1c0a893703a70558fcf7bb13348847a1302b2c49", 20 | "short_id": "1c0a8937", 21 | "created_at": "2023-02-13T10:18:53.000+01:00", 22 | "parent_ids": ["9cee818844e23dfa5922155d113a950ff86ff2e7"], 23 | "title": "Update Slack notes", 24 | "message": "Update Slack notes\n", 25 | "author_name": "Ashraf Khamis", 26 | "author_email": "akhamis@gitlab.com", 27 | "authored_date": "2023-02-13T10:18:53.000+01:00", 28 | "committer_name": "Ashraf Khamis", 29 | "committer_email": "akhamis@gitlab.com", 30 | "committed_date": "2023-02-13T10:18:53.000+01:00", 31 | "trailers": {}, 32 | "web_url": "https://gitlab.com/gitlab-org/gitlab/-/commit/1c0a893703a70558fcf7bb13348847a1302b2c49" 33 | }], 34 | "diffs": [{ 35 | "diff": "@@ -7,11 +7,11 @@ info: To determine the technical writer assigned to the Stage/Group associated w\n # GitLab for Slack app **(FREE SAAS)**\n \n NOTE:\n-The GitLab for Slack app is only configurable for GitLab SaaS customers.\n-Self-managed GitLab customers should configure\n-[Slack slash commands](slack_slash_commands.md) and [Slack notifications](slack.md) instead. See\n-[Slack application integration for self-managed instances](https://gitlab.com/groups/gitlab-org/-/epics/1211)\n-for our plans to make the app configurable for all GitLab installations.\n+This feature is only configurable on GitLab.com.\n+For self-managed GitLab instances, use\n+[Slack slash commands](slack_slash_commands.md) and [Slack notifications](slack.md) instead.\n+For more information about our plans to make the app configurable for all GitLab installations,\n+see [epic 1211](https://gitlab.com/groups/gitlab-org/-/epics/1211).\n \n Slack provides a native application that you can enable with your project's\n integrations on GitLab.com.\n", 36 | "new_path": "doc/user/project/integrations/gitlab_slack_application.md", 37 | "old_path": "doc/user/project/integrations/gitlab_slack_application.md", 38 | "a_mode": "100644", 39 | "b_mode": "100644", 40 | "new_file": false, 41 | "renamed_file": false, 42 | "deleted_file": false 43 | }, { 44 | "diff": "@@ -7,10 +7,10 @@ info: To determine the technical writer assigned to the Stage/Group associated w\n # Slack notifications integration **(FREE)**\n \n WARNING:\n-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/372411) for GitLab SaaS customers\n+This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/372411) on GitLab.com\n in GitLab 15.10 and is [planned for removal](https://gitlab.com/groups/gitlab-org/-/epics/8673).\n-GitLab SaaS customers can use the [GitLab for Slack app](gitlab_slack_application.md) instead.\n-Self-managed GitLab customers can continue to use this feature.\n+Use the [GitLab for Slack app](gitlab_slack_application.md) instead.\n+On self-managed GitLab instances, you can continue to use this feature.\n \n The Slack notifications integration enables your GitLab project to send events\n (such as issue creation) to your existing Slack team as notifications. Setting up\n", 45 | "new_path": "doc/user/project/integrations/slack.md", 46 | "old_path": "doc/user/project/integrations/slack.md", 47 | "a_mode": "100644", 48 | "b_mode": "100644", 49 | "new_file": false, 50 | "renamed_file": false, 51 | "deleted_file": false 52 | }, { 53 | "diff": "@@ -6,6 +6,10 @@ info: To determine the technical writer assigned to the Stage/Group associated w\n \n # Slack slash commands **(FREE SELF)**\n \n+NOTE:\n+This feature is only configurable on self-managed GitLab instances.\n+For GitLab.com, use the [GitLab for Slack app](gitlab_slack_application.md) instead.\n+\n If you want to control and view GitLab content while you're\n working in Slack, you can use Slack slash commands.\n To use Slack slash commands, you must configure both Slack and GitLab.\n@@ -13,9 +17,6 @@ To use Slack slash commands, you must configure both Slack and GitLab.\n GitLab can also send events (for example, `issue created`) to Slack as notifications.\n The [Slack notifications service](slack.md) is configured separately.\n \n-NOTE:\n-The Slack slash commands are only configurable on self-managed GitLab instances. For GitLab.com, use the [GitLab for Slack app](gitlab_slack_application.md) instead.\n-\n ## Configure GitLab and Slack\n \n Slack slash command integrations\n", 54 | "new_path": "doc/user/project/integrations/slack_slash_commands.md", 55 | "old_path": "doc/user/project/integrations/slack_slash_commands_2.md", 56 | "a_mode": "100644", 57 | "b_mode": "100644", 58 | "new_file": false, 59 | "renamed_file": false, 60 | "deleted_file": false 61 | }], 62 | "compare_timeout": false, 63 | "compare_same_ref": false, 64 | "web_url": "https://gitlab.com/gitlab-org/gitlab/-/compare/9cee818844e23dfa5922155d113a950ff86ff2e7...1c0a893703a70558fcf7bb13348847a1302b2c49" 65 | } -------------------------------------------------------------------------------- /vcsclient/testdata/bitbucketcloud/get_pull_request_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "comment_count": 0, 3 | "task_count": 0, 4 | "type": "pullrequest", 5 | "id": 1, 6 | "title": "s", 7 | "description": "s", 8 | "rendered": { 9 | "title": { 10 | "type": "rendered", 11 | "raw": "s", 12 | "markup": "markdown", 13 | "html": "

s

" 14 | }, 15 | "description": { 16 | "type": "rendered", 17 | "raw": "s", 18 | "markup": "markdown", 19 | "html": "

s

" 20 | } 21 | }, 22 | "state": "CLOSED", 23 | "merge_commit": null, 24 | "close_source_branch": false, 25 | "closed_by": null, 26 | "author": { 27 | "display_name": "fname lname", 28 | "links": { 29 | "self": { 30 | "href": "https://api.bitbucket.org/2.0/users/%7B0488ed53-e751-4504-a343-1a43d72590a4%7D" 31 | }, 32 | "avatar": { 33 | "href": "https://secure.gravatar.com/avatar/4a0ffac6cc540dd6983b35ec3bd4df94?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FED-1.png" 34 | }, 35 | "html": { 36 | "href": "https://bitbucket.org/%7B0488ed53-e751-4504-a343-1a43d72590a4%7D/" 37 | } 38 | }, 39 | "type": "user", 40 | "uuid": "{0488ed53-e751-4504-a343-1a43d72590a4}", 41 | "account_id": "63f32b584e86f362d399cdc2", 42 | "nickname": "fname lname" 43 | }, 44 | "reason": "", 45 | "created_on": "2023-06-20T09:00:47.082738+00:00", 46 | "updated_on": "2023-06-20T09:00:47.725250+00:00", 47 | "destination": { 48 | "branch": { 49 | "name": "main" 50 | }, 51 | "commit": { 52 | "type": "commit", 53 | "hash": "9a1e81efaa1c", 54 | "links": { 55 | "self": { 56 | "href": "https://api.bitbucket.org/2.0/repositories/workspace/froggit/commit/9a1e81efaa1c" 57 | }, 58 | "html": { 59 | "href": "https://bitbucket.org/workspace/froggit/commits/9a1e81efaa1c" 60 | } 61 | } 62 | }, 63 | "repository": { 64 | "type": "repository", 65 | "full_name": "workspace/froggit", 66 | "links": { 67 | "self": { 68 | "href": "https://api.bitbucket.org/2.0/repositories/workspace/froggit" 69 | }, 70 | "html": { 71 | "href": "https://bitbucket.org/workspace/froggit" 72 | }, 73 | "avatar": { 74 | "href": "https://bytebucket.org/ravatar/%7Bacb2b52e-67f2-48bf-96f1-b441b5acb810%7D?ts=default" 75 | } 76 | }, 77 | "name": "froggit", 78 | "uuid": "{acb2b52e-67f2-48bf-96f1-b441b5acb810}" 79 | } 80 | }, 81 | "source": { 82 | "branch": { 83 | "name": "pr" 84 | }, 85 | "commit": { 86 | "type": "commit", 87 | "hash": "18f5e1ecb37e", 88 | "links": { 89 | "self": { 90 | "href": "https://api.bitbucket.org/2.0/repositories/workspace/froggit/commit/18f5e1ecb37e" 91 | }, 92 | "html": { 93 | "href": "https://bitbucket.org/workspace/froggit/commits/18f5e1ecb37e" 94 | } 95 | } 96 | }, 97 | "repository": { 98 | "type": "repository", 99 | "full_name": "forkedWorkspace/froggit", 100 | "links": { 101 | "self": { 102 | "href": "https://api.bitbucket.org/2.0/repositories/workspace/froggit" 103 | }, 104 | "html": { 105 | "href": "https://bitbucket.org/workspace/froggit" 106 | }, 107 | "avatar": { 108 | "href": "https://bytebucket.org/ravatar/%7Bacb2b52e-67f2-48bf-96f1-b441b5acb810%7D?ts=default" 109 | } 110 | }, 111 | "name": "froggit", 112 | "uuid": "{acb2b52e-67f2-48bf-96f1-b441b5acb810}" 113 | } 114 | }, 115 | "reviewers": [], 116 | "participants": [], 117 | "links": { 118 | "self": { 119 | "href": "https://api.bitbucket.org/2.0/repositories/workspace/froggit/pullrequests/1" 120 | }, 121 | "html": { 122 | "href": "https://bitbucket.org/workspace/froggit/pull-requests/1" 123 | }, 124 | "commits": { 125 | "href": "https://api.bitbucket.org/2.0/repositories/workspace/froggit/pullrequests/1/commits" 126 | }, 127 | "approve": { 128 | "href": "https://api.bitbucket.org/2.0/repositories/workspace/froggit/pullrequests/1/approve" 129 | }, 130 | "request-changes": { 131 | "href": "https://api.bitbucket.org/2.0/repositories/workspace/froggit/pullrequests/1/request-changes" 132 | }, 133 | "diff": { 134 | "href": "https://api.bitbucket.org/2.0/repositories/workspace/froggit/diff/workspace/froggit:18f5e1ecb37e%0D9a1e81efaa1c?from_pullrequest_id=1&topic=true" 135 | }, 136 | "diffstat": { 137 | "href": "https://api.bitbucket.org/2.0/repositories/workspace/froggit/diffstat/workspace/froggit:18f5e1ecb37e%0D9a1e81efaa1c?from_pullrequest_id=1&topic=true" 138 | }, 139 | "comments": { 140 | "href": "https://api.bitbucket.org/2.0/repositories/workspace/froggit/pullrequests/1/comments" 141 | }, 142 | "activity": { 143 | "href": "https://api.bitbucket.org/2.0/repositories/workspace/froggit/pullrequests/1/activity" 144 | }, 145 | "merge": { 146 | "href": "https://api.bitbucket.org/2.0/repositories/workspace/froggit/pullrequests/1/merge" 147 | }, 148 | "decline": { 149 | "href": "https://api.bitbucket.org/2.0/repositories/workspace/froggit/pullrequests/1/decline" 150 | }, 151 | "statuses": { 152 | "href": "https://api.bitbucket.org/2.0/repositories/workspace/froggit/pullrequests/1/statuses" 153 | } 154 | }, 155 | "summary": { 156 | "type": "rendered", 157 | "raw": "s", 158 | "markup": "markdown", 159 | "html": "

s

" 160 | } 161 | } -------------------------------------------------------------------------------- /vcsclient/testdata/gitlab/get_project_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 47457684, 3 | "description": null, 4 | "name": "frogbot-demo", 5 | "name_with_namespace": "test / frogbot-demo", 6 | "path": "frogbot-demo", 7 | "path_with_namespace": "test/frogbot-demo", 8 | "created_at": "2023-07-06T06:55:07.521Z", 9 | "default_branch": "main", 10 | "tag_list": [], 11 | "topics": [], 12 | "ssh_url_to_repo": "git@gitlab.com:test/frogbot-demo.git", 13 | "http_url_to_repo": "https://gitlab.com/test/frogbot-demo.git", 14 | "web_url": "https://gitlab.com/test/frogbot-demo", 15 | "readme_url": "https://gitlab.com/test/frogbot-demo/-/blob/main/README.md", 16 | "forks_count": 0, 17 | "avatar_url": null, 18 | "star_count": 0, 19 | "last_activity_at": "2023-07-06T08:23:22.766Z", 20 | "namespace": { 21 | "id": 62039166, 22 | "name": "test", 23 | "path": "test", 24 | "kind": "group", 25 | "full_path": "test", 26 | "parent_id": null, 27 | "avatar_url": null, 28 | "web_url": "https://gitlab.com/groups/test" 29 | }, 30 | "container_registry_image_prefix": "registry.gitlab.com/test/frogbot-demo", 31 | "_links": { 32 | "self": "https://gitlab.com/api/v4/projects/47457684", 33 | "issues": "https://gitlab.com/api/v4/projects/47457684/issues", 34 | "merge_requests": "https://gitlab.com/api/v4/projects/47457684/merge_requests", 35 | "repo_branches": "https://gitlab.com/api/v4/projects/47457684/repository/branches", 36 | "labels": "https://gitlab.com/api/v4/projects/47457684/labels", 37 | "events": "https://gitlab.com/api/v4/projects/47457684/events", 38 | "members": "https://gitlab.com/api/v4/projects/47457684/members", 39 | "cluster_agents": "https://gitlab.com/api/v4/projects/47457684/cluster_agents" 40 | }, 41 | "packages_enabled": true, 42 | "empty_repo": false, 43 | "archived": false, 44 | "visibility": "private", 45 | "resolve_outdated_diff_discussions": false, 46 | "container_expiration_policy": { 47 | "cadence": "1d", 48 | "enabled": false, 49 | "keep_n": 10, 50 | "older_than": "90d", 51 | "name_regex": ".*", 52 | "name_regex_keep": null, 53 | "next_run_at": "2023-07-07T06:55:07.560Z" 54 | }, 55 | "issues_enabled": true, 56 | "merge_requests_enabled": true, 57 | "wiki_enabled": true, 58 | "jobs_enabled": true, 59 | "snippets_enabled": true, 60 | "container_registry_enabled": true, 61 | "service_desk_enabled": true, 62 | "service_desk_address": "contact-project+test-frogbot-demo-47457684-issue-@incoming.gitlab.com", 63 | "can_create_merge_request_in": true, 64 | "issues_access_level": "enabled", 65 | "repository_access_level": "enabled", 66 | "merge_requests_access_level": "enabled", 67 | "forking_access_level": "enabled", 68 | "wiki_access_level": "enabled", 69 | "builds_access_level": "enabled", 70 | "snippets_access_level": "enabled", 71 | "pages_access_level": "private", 72 | "analytics_access_level": "enabled", 73 | "container_registry_access_level": "enabled", 74 | "security_and_compliance_access_level": "private", 75 | "releases_access_level": "enabled", 76 | "environments_access_level": "enabled", 77 | "feature_flags_access_level": "enabled", 78 | "infrastructure_access_level": "enabled", 79 | "monitor_access_level": "enabled", 80 | "emails_disabled": false, 81 | "emails_enabled": true, 82 | "shared_runners_enabled": true, 83 | "lfs_enabled": true, 84 | "creator_id": 13377328, 85 | "import_url": null, 86 | "import_type": null, 87 | "import_status": "none", 88 | "import_error": null, 89 | "open_issues_count": 0, 90 | "description_html": "", 91 | "updated_at": "2023-07-06T08:53:22.050Z", 92 | "ci_default_git_depth": 20, 93 | "ci_forward_deployment_enabled": true, 94 | "ci_forward_deployment_rollback_allowed": true, 95 | "ci_job_token_scope_enabled": false, 96 | "ci_separated_caches": true, 97 | "ci_allow_fork_pipelines_to_run_in_parent_project": true, 98 | "build_git_strategy": "fetch", 99 | "keep_latest_artifact": true, 100 | "restrict_user_defined_variables": false, 101 | "runners_token": "GR1348941eo_AAkjv4niyY222E4nz", 102 | "runner_token_expiration_interval": null, 103 | "group_runners_enabled": true, 104 | "auto_cancel_pending_pipelines": "enabled", 105 | "build_timeout": 3600, 106 | "auto_devops_enabled": false, 107 | "auto_devops_deploy_strategy": "continuous", 108 | "ci_config_path": "", 109 | "public_jobs": true, 110 | "shared_with_groups": [], 111 | "only_allow_merge_if_pipeline_succeeds": false, 112 | "allow_merge_on_skipped_pipeline": null, 113 | "request_access_enabled": true, 114 | "only_allow_merge_if_all_discussions_are_resolved": false, 115 | "remove_source_branch_after_merge": true, 116 | "printing_merge_request_link_enabled": true, 117 | "merge_method": "merge", 118 | "squash_option": "default_off", 119 | "enforce_auth_checks_on_uploads": true, 120 | "suggestion_commit_message": null, 121 | "merge_commit_template": null, 122 | "squash_commit_template": null, 123 | "issue_branch_template": null, 124 | "autoclose_referenced_issues": true, 125 | "approvals_before_merge": 0, 126 | "mirror": false, 127 | "external_authorization_classification_label": "", 128 | "marked_for_deletion_at": null, 129 | "marked_for_deletion_on": null, 130 | "requirements_enabled": true, 131 | "requirements_access_level": "enabled", 132 | "security_and_compliance_enabled": true, 133 | "compliance_frameworks": [], 134 | "issues_template": null, 135 | "merge_requests_template": null, 136 | "merge_pipelines_enabled": false, 137 | "merge_trains_enabled": false, 138 | "only_allow_merge_if_all_status_checks_passed": false, 139 | "allow_pipeline_trigger_approve_deployment": false, 140 | "permissions": { 141 | "project_access": null, 142 | "group_access": { 143 | "access_level": 50, 144 | "notification_level": 3 145 | } 146 | } 147 | } -------------------------------------------------------------------------------- /.github/workflows/frogbot-scan-pull-request.yml: -------------------------------------------------------------------------------- 1 | name: "Frogbot Scan Pull Request" 2 | on: 3 | pull_request_target: 4 | types: [ opened, synchronize ] 5 | permissions: 6 | pull-requests: write 7 | contents: read 8 | jobs: 9 | scan-pull-request: 10 | runs-on: ubuntu-latest 11 | # A pull request needs to be approved before Frogbot scans it. Any GitHub user who is associated with the 12 | # "frogbot" GitHub environment can approve the pull request to be scanned. 13 | environment: frogbot 14 | steps: 15 | - name: Setup Go with cache 16 | uses: jfrog/.github/actions/install-go-with-cache@main 17 | 18 | - uses: jfrog/frogbot@v2 19 | env: 20 | JFROG_CLI_LOG_LEVEL: "DEBUG" 21 | # [Mandatory] 22 | # JFrog platform URL (This functionality requires version 3.29.0 or above of Xray) 23 | JF_URL: ${{ secrets.FROGBOT_URL }} 24 | 25 | # [Mandatory if JF_USER and JF_PASSWORD are not provided] 26 | # JFrog access token with 'read' permissions on Xray service 27 | JF_ACCESS_TOKEN: ${{ secrets.FROGBOT_ACCESS_TOKEN }} 28 | 29 | # [Mandatory] 30 | # The GitHub token is automatically generated for the job 31 | JF_GIT_TOKEN: ${{ secrets.GITHUB_TOKEN }} 32 | 33 | # [Optional, default: https://api.github.com] 34 | # API endpoint to GitHub 35 | # JF_GIT_API_ENDPOINT: https://github.example.com 36 | 37 | # [Optional] 38 | # By default, the Frogbot workflows download the Frogbot executable as well as other tools 39 | # needed from https://releases.jfrog.io 40 | # If the machine that runs Frogbot has no access to the internet, follow these steps to allow the 41 | # executable to be downloaded from an Artifactory instance, which the machine has access to: 42 | # 43 | # 1. Login to the Artifactory UI, with a user who has admin credentials. 44 | # 2. Create a Remote Repository with the following properties set. 45 | # Under the 'Basic' tab: 46 | # Package Type: Generic 47 | # URL: https://releases.jfrog.io 48 | # Under the 'Advanced' tab: 49 | # Uncheck the 'Store Artifacts Locally' option 50 | # 3. Set the value of the 'JF_RELEASES_REPO' variable with the Repository Key you created. 51 | # JF_RELEASES_REPO: "" 52 | 53 | # [Optional] 54 | # Configure the SMTP server to enable Frogbot to send emails with detected secrets in pull request scans. 55 | # SMTP server URL including should the relevant port: (Example: smtp.server.com:8080) 56 | JF_SMTP_SERVER: ${{ secrets.JF_SMTP_SERVER }} 57 | 58 | # [Mandatory if JF_SMTP_SERVER is set] 59 | # The username required for authenticating with the SMTP server. 60 | JF_SMTP_USER: ${{ secrets.JF_SMTP_USER }} 61 | 62 | # [Mandatory if JF_SMTP_SERVER is set] 63 | # The password associated with the username required for authentication with the SMTP server. 64 | JF_SMTP_PASSWORD: ${{ secrets.JF_SMTP_PASSWORD }} 65 | 66 | # [Optional] 67 | # List of comma separated email addresses to receive email notifications about secrets 68 | # detected during pull request scanning. The notification is also sent to the email set 69 | # in the committer git profile regardless of whether this variable is set or not. 70 | JF_EMAIL_RECEIVERS: "eco-system@jfrog.com" 71 | 72 | ########################################################################## 73 | ## If your project uses a 'frogbot-config.yml' file, you can define ## 74 | ## the following variables inside the file, instead of here. ## 75 | ########################################################################## 76 | 77 | # [Mandatory if the two conditions below are met] 78 | # 1. The project uses yarn 2, NuGet or .NET Core to download its dependencies 79 | # 2. The `installCommand` variable isn't set in your frogbot-config.yml file. 80 | # 81 | # The command that installs the project dependencies (e.g "nuget restore") 82 | # JF_INSTALL_DEPS_CMD: "" 83 | 84 | # [Optional, default: "."] 85 | # Relative path to the root of the project in the Git repository 86 | # JF_WORKING_DIR: path/to/project/dir 87 | 88 | # [Optional] 89 | # Xray Watches. Learn more about them here: https://www.jfrog.com/confluence/display/JFROG/Configuring+Xray+Watches 90 | # JF_WATCHES: ,... 91 | 92 | # [Optional] 93 | # JFrog project. Learn more about it here: https://www.jfrog.com/confluence/display/JFROG/Projects 94 | # JF_PROJECT: 95 | 96 | # [Optional, default: "FALSE"] 97 | # Displays all existing vulnerabilities, including the ones that were added by the pull request. 98 | # JF_INCLUDE_ALL_VULNERABILITIES: "TRUE" 99 | 100 | # [Optional, default: "TRUE"] 101 | # Fails the Frogbot task if any security issue is found. 102 | # JF_FAIL: "FALSE" 103 | 104 | # [Optional] 105 | # Frogbot will download the project dependencies if they're not cached locally. To download the 106 | # dependencies from a virtual repository in Artifactory, set the name of the repository. There's no 107 | # need to set this value, if it is set in the frogbot-config.yml file. 108 | # JF_DEPS_REPO: "" 109 | 110 | # [Optional, Default: "FALSE"] 111 | # If TRUE, Frogbot creates a single pull request with all the fixes. 112 | # If false, Frogbot creates a separate pull request for each fix. 113 | # JF_GIT_AGGREGATE_FIXES: "FALSE" 114 | 115 | # [Optional, Default: "FALSE"] 116 | # Handle vulnerabilities with fix versions only 117 | # JF_FIXABLE_ONLY: "TRUE" 118 | 119 | # [Optional] 120 | # Set the minimum severity for vulnerabilities that should be fixed and commented on in pull requests 121 | # The following values are accepted: Low, Medium, High or Critical 122 | # JF_MIN_SEVERITY: "" -------------------------------------------------------------------------------- /vcsutils/webhookparser/testdata/bitbucketcloud/prcreatepayload.json: -------------------------------------------------------------------------------- 1 | {"pullrequest":{"rendered":{"description":{"raw":"* README.md edited online with Bitbucket\r\n* README.md edited online with Bitbucket\r\n\r\n‌","markup":"markdown","html":"
    \n
  • README.md edited online with Bitbucket
  • \n
  • README.md edited online with Bitbucket
  • \n
\n

","type":"rendered"},"title":{"raw":"Dev","markup":"markdown","html":"

Dev

","type":"rendered"}},"type":"pullrequest","description":"* README.md edited online with Bitbucket\r\n* README.md edited online with Bitbucket\r\n\r\n‌","links":{"decline":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world/pullrequests/2/decline"},"diffstat":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world/diffstat/yahavi/hello-world:363994ee7c2e%0Dfa8c303777d0?from_pullrequest_id=2"},"commits":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world/pullrequests/2/commits"},"self":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world/pullrequests/2"},"comments":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world/pullrequests/2/comments"},"merge":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world/pullrequests/2/merge"},"html":{"href":"https://bitbucket.org/yahavi/hello-world/pull-requests/2"},"activity":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world/pullrequests/2/activity"},"request-changes":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world/pullrequests/2/request-changes"},"diff":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world/diff/yahavi/hello-world:363994ee7c2e%0Dfa8c303777d0?from_pullrequest_id=2"},"approve":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world/pullrequests/2/approve"},"statuses":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world/pullrequests/2/statuses"}},"title":"Dev","close_source_branch":false,"reviewers":[],"id":2,"destination":{"commit":{"hash":"fa8c303777d0","type":"commit","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world/commit/fa8c303777d0"},"html":{"href":"https://bitbucket.org/yahavi/hello-world/commits/fa8c303777d0"}}},"repository":{"links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world"},"html":{"href":"https://bitbucket.org/yahavi/hello-world"},"avatar":{"href":"https://bytebucket.org/ravatar/%7Bba44938d-74fb-41e2-8f0e-fbbee86358e8%7D?ts=default"}},"type":"repository","name":"hello-world","full_name":"yahavi/hello-world","uuid":"{ba44938d-74fb-41e2-8f0e-fbbee86358e8}"},"branch":{"name":"main"}},"created_on":"2021-09-05T08:47:45.138935+00:00","summary":{"raw":"* README.md edited online with Bitbucket\r\n* README.md edited online with Bitbucket\r\n\r\n‌","markup":"markdown","html":"
    \n
  • README.md edited online with Bitbucket
  • \n
  • README.md edited online with Bitbucket
  • \n
\n

","type":"rendered"},"source":{"commit":{"hash":"363994ee7c2e","type":"commit","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world/commit/363994ee7c2e"},"html":{"href":"https://bitbucket.org/yahavi/hello-world/commits/363994ee7c2e"}}},"repository":{"links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world"},"html":{"href":"https://bitbucket.org/yahavi/hello-world"},"avatar":{"href":"https://bytebucket.org/ravatar/%7Bba44938d-74fb-41e2-8f0e-fbbee86358e8%7D?ts=default"}},"type":"repository","name":"hello-world","full_name":"yahavi/hello-world","uuid":"{ba44938d-74fb-41e2-8f0e-fbbee86358e8}"},"branch":{"name":"dev"}},"comment_count":0,"state":"OPEN","task_count":0,"participants":[],"reason":"","updated_on":"2021-09-05T08:47:45.374098+00:00","author":{"display_name":"Yahav Itzhak","uuid":"{1afb3b20-e42f-4cef-9610-765590780396}","links":{"self":{"href":"https://api.bitbucket.org/2.0/users/%7B1afb3b20-e42f-4cef-9610-765590780396%7D"},"html":{"href":"https://bitbucket.org/%7B1afb3b20-e42f-4cef-9610-765590780396%7D/"},"avatar":{"href":"https://secure.gravatar.com/avatar/9680da1674e22a1de17acb19bb233ebf?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FYI-5.png"}},"type":"user","nickname":"yahavi","account_id":"557058:40514458-78b7-4960-a0bd-2fcd157761fe"},"merge_commit":null,"closed_by":null},"repository":{"scm":"git","website":null,"uuid":"{ba44938d-74fb-41e2-8f0e-fbbee86358e8}","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world"},"html":{"href":"https://bitbucket.org/yahavi/hello-world"},"avatar":{"href":"https://bytebucket.org/ravatar/%7Bba44938d-74fb-41e2-8f0e-fbbee86358e8%7D?ts=default"}},"project":{"links":{"self":{"href":"https://api.bitbucket.org/2.0/workspaces/yahavi/projects/HEL"},"html":{"href":"https://bitbucket.org/yahavi/workspace/projects/HEL"},"avatar":{"href":"https://bitbucket.org/account/user/yahavi/projects/HEL/avatar/32?ts=1630824344"}},"type":"project","name":"hello-world","key":"HEL","uuid":"{0e3bc2fd-7733-4b68-881e-11b8f9630efa}"},"full_name":"yahavi/hello-world","owner":{"display_name":"Yahav Itzhak","uuid":"{1afb3b20-e42f-4cef-9610-765590780396}","links":{"self":{"href":"https://api.bitbucket.org/2.0/users/%7B1afb3b20-e42f-4cef-9610-765590780396%7D"},"html":{"href":"https://bitbucket.org/%7B1afb3b20-e42f-4cef-9610-765590780396%7D/"},"avatar":{"href":"https://secure.gravatar.com/avatar/9680da1674e22a1de17acb19bb233ebf?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FYI-5.png"}},"type":"user","nickname":"yahavi","account_id":"557058:40514458-78b7-4960-a0bd-2fcd157761fe"},"workspace":{"slug":"yahavi","type":"workspace","name":"Yahav Itzhak","links":{"self":{"href":"https://api.bitbucket.org/2.0/workspaces/yahavi"},"html":{"href":"https://bitbucket.org/yahavi/"},"avatar":{"href":"https://bitbucket.org/workspaces/yahavi/avatar/?ts=1543655805"}},"uuid":"{1afb3b20-e42f-4cef-9610-765590780396}"},"type":"repository","is_private":false,"name":"hello-world"},"actor":{"display_name":"Yahav Itzhak","uuid":"{1afb3b20-e42f-4cef-9610-765590780396}","links":{"self":{"href":"https://api.bitbucket.org/2.0/users/%7B1afb3b20-e42f-4cef-9610-765590780396%7D"},"html":{"href":"https://bitbucket.org/%7B1afb3b20-e42f-4cef-9610-765590780396%7D/"},"avatar":{"href":"https://secure.gravatar.com/avatar/9680da1674e22a1de17acb19bb233ebf?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FYI-5.png"}},"type":"user","nickname":"yahavi","account_id":"557058:40514458-78b7-4960-a0bd-2fcd157761fe"}} -------------------------------------------------------------------------------- /vcsutils/webhookparser/testdata/bitbucketcloud/prupdatepayload.json: -------------------------------------------------------------------------------- 1 | {"pullrequest":{"rendered":{"description":{"raw":"* README.md edited online with Bitbucket\r\n* README.md edited online with Bitbucket\r\n\r\n‌","markup":"markdown","html":"
    \n
  • README.md edited online with Bitbucket
  • \n
  • README.md edited online with Bitbucket
  • \n
\n

","type":"rendered"},"title":{"raw":"Dev","markup":"markdown","html":"

Dev

","type":"rendered"}},"type":"pullrequest","description":"* README.md edited online with Bitbucket\r\n* README.md edited online with Bitbucket\r\n\r\n‌","links":{"decline":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world/pullrequests/2/decline"},"diffstat":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world/diffstat/yahavi/hello-world:1147000c51dc%0D78c315141e83?from_pullrequest_id=2"},"commits":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world/pullrequests/2/commits"},"self":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world/pullrequests/2"},"comments":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world/pullrequests/2/comments"},"merge":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world/pullrequests/2/merge"},"html":{"href":"https://bitbucket.org/yahavi/hello-world/pull-requests/2"},"activity":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world/pullrequests/2/activity"},"request-changes":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world/pullrequests/2/request-changes"},"diff":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world/diff/yahavi/hello-world:1147000c51dc%0D78c315141e83?from_pullrequest_id=2"},"approve":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world/pullrequests/2/approve"},"statuses":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world/pullrequests/2/statuses"}},"title":"Dev","close_source_branch":false,"reviewers":[],"id":2,"destination":{"commit":{"hash":"78c315141e83","type":"commit","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world/commit/78c315141e83"},"html":{"href":"https://bitbucket.org/yahavi/hello-world/commits/78c315141e83"}}},"repository":{"links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world"},"html":{"href":"https://bitbucket.org/yahavi/hello-world"},"avatar":{"href":"https://bytebucket.org/ravatar/%7Bba44938d-74fb-41e2-8f0e-fbbee86358e8%7D?ts=default"}},"type":"repository","name":"hello-world","full_name":"yahavi/hello-world","uuid":"{ba44938d-74fb-41e2-8f0e-fbbee86358e8}"},"branch":{"name":"main"}},"created_on":"2021-09-05T08:47:45.138935+00:00","summary":{"raw":"* README.md edited online with Bitbucket\r\n* README.md edited online with Bitbucket\r\n\r\n‌","markup":"markdown","html":"
    \n
  • README.md edited online with Bitbucket
  • \n
  • README.md edited online with Bitbucket
  • \n
\n

","type":"rendered"},"source":{"commit":{"hash":"1147000c51dc","type":"commit","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world/commit/1147000c51dc"},"html":{"href":"https://bitbucket.org/yahavi/hello-world/commits/1147000c51dc"}}},"repository":{"links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world"},"html":{"href":"https://bitbucket.org/yahavi/hello-world"},"avatar":{"href":"https://bytebucket.org/ravatar/%7Bba44938d-74fb-41e2-8f0e-fbbee86358e8%7D?ts=default"}},"type":"repository","name":"hello-world","full_name":"yahavi/hello-world","uuid":"{ba44938d-74fb-41e2-8f0e-fbbee86358e8}"},"branch":{"name":"dev"}},"comment_count":0,"state":"OPEN","task_count":0,"participants":[],"reason":"","updated_on":"2021-09-05T12:16:10.006190+00:00","author":{"display_name":"Yahav Itzhak","uuid":"{1afb3b20-e42f-4cef-9610-765590780396}","links":{"self":{"href":"https://api.bitbucket.org/2.0/users/%7B1afb3b20-e42f-4cef-9610-765590780396%7D"},"html":{"href":"https://bitbucket.org/%7B1afb3b20-e42f-4cef-9610-765590780396%7D/"},"avatar":{"href":"https://secure.gravatar.com/avatar/9680da1674e22a1de17acb19bb233ebf?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FYI-5.png"}},"type":"user","nickname":"yahavi","account_id":"557058:40514458-78b7-4960-a0bd-2fcd157761fe"},"merge_commit":null,"closed_by":null},"repository":{"scm":"git","website":null,"uuid":"{ba44938d-74fb-41e2-8f0e-fbbee86358e8}","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/yahavi/hello-world"},"html":{"href":"https://bitbucket.org/yahavi/hello-world"},"avatar":{"href":"https://bytebucket.org/ravatar/%7Bba44938d-74fb-41e2-8f0e-fbbee86358e8%7D?ts=default"}},"project":{"links":{"self":{"href":"https://api.bitbucket.org/2.0/workspaces/yahavi/projects/HEL"},"html":{"href":"https://bitbucket.org/yahavi/workspace/projects/HEL"},"avatar":{"href":"https://bitbucket.org/account/user/yahavi/projects/HEL/avatar/32?ts=1630824344"}},"type":"project","name":"hello-world","key":"HEL","uuid":"{0e3bc2fd-7733-4b68-881e-11b8f9630efa}"},"full_name":"yahavi/hello-world","owner":{"display_name":"Yahav Itzhak","uuid":"{1afb3b20-e42f-4cef-9610-765590780396}","links":{"self":{"href":"https://api.bitbucket.org/2.0/users/%7B1afb3b20-e42f-4cef-9610-765590780396%7D"},"html":{"href":"https://bitbucket.org/%7B1afb3b20-e42f-4cef-9610-765590780396%7D/"},"avatar":{"href":"https://secure.gravatar.com/avatar/9680da1674e22a1de17acb19bb233ebf?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FYI-5.png"}},"type":"user","nickname":"yahavi","account_id":"557058:40514458-78b7-4960-a0bd-2fcd157761fe"},"workspace":{"slug":"yahavi","type":"workspace","name":"Yahav Itzhak","links":{"self":{"href":"https://api.bitbucket.org/2.0/workspaces/yahavi"},"html":{"href":"https://bitbucket.org/yahavi/"},"avatar":{"href":"https://bitbucket.org/workspaces/yahavi/avatar/?ts=1543655805"}},"uuid":"{1afb3b20-e42f-4cef-9610-765590780396}"},"type":"repository","is_private":false,"name":"hello-world"},"actor":{"display_name":"Yahav Itzhak","uuid":"{1afb3b20-e42f-4cef-9610-765590780396}","links":{"self":{"href":"https://api.bitbucket.org/2.0/users/%7B1afb3b20-e42f-4cef-9610-765590780396%7D"},"html":{"href":"https://bitbucket.org/%7B1afb3b20-e42f-4cef-9610-765590780396%7D/"},"avatar":{"href":"https://secure.gravatar.com/avatar/9680da1674e22a1de17acb19bb233ebf?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FYI-5.png"}},"type":"user","nickname":"yahavi","account_id":"557058:40514458-78b7-4960-a0bd-2fcd157761fe"}} -------------------------------------------------------------------------------- /vcsclient/testdata/bitbucketserver/pull_request_comments_list_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "size": 3, 3 | "limit": 25, 4 | "isLastPage": true, 5 | "values": [ 6 | { 7 | "id": 101, 8 | "createdDate": 1359065920, 9 | "user": { 10 | "name": "jcitizen", 11 | "emailAddress": "jane@example.com", 12 | "id": 101, 13 | "displayName": "Jane Citizen", 14 | "active": true, 15 | "slug": "jcitizen", 16 | "type": "NORMAL" 17 | }, 18 | "action": "COMMENTED", 19 | "commentAction": "ADDED", 20 | "comment": { 21 | "properties": { 22 | "key": "value" 23 | }, 24 | "id": 1, 25 | "version": 1, 26 | "text": "A measured reply.", 27 | "author": { 28 | "name": "jcitizen", 29 | "emailAddress": "jane@example.com", 30 | "id": 101, 31 | "displayName": "Jane Citizen", 32 | "active": true, 33 | "slug": "jcitizen", 34 | "type": "NORMAL" 35 | }, 36 | "createdDate": 1548720847370, 37 | "updatedDate": 1548720847370, 38 | "comments": [ 39 | { 40 | "properties": { 41 | "key": "value" 42 | }, 43 | "id": 1, 44 | "version": 1, 45 | "text": "An insightful comment.", 46 | "author": { 47 | "name": "jcitizen", 48 | "emailAddress": "jane@example.com", 49 | "id": 101, 50 | "displayName": "Jane Citizen", 51 | "active": true, 52 | "slug": "jcitizen", 53 | "type": "NORMAL" 54 | }, 55 | "createdDate": 1548720847365, 56 | "updatedDate": 1548720847365, 57 | "comments": [], 58 | "tasks": [], 59 | "permittedOperations": { 60 | "editable": true, 61 | "deletable": true 62 | } 63 | } 64 | ], 65 | "tasks": [], 66 | "permittedOperations": { 67 | "editable": true, 68 | "deletable": true 69 | } 70 | }, 71 | "commentAnchor": { 72 | "line": 1, 73 | "lineType": "CONTEXT", 74 | "fileType": "FROM", 75 | "path": "path/to/file", 76 | "srcPath": "path/to/file" 77 | } 78 | }, 79 | { 80 | "id": 101, 81 | "createdDate": 1359065920, 82 | "user": { 83 | "name": "jcitizen", 84 | "emailAddress": "jane@example.com", 85 | "id": 101, 86 | "displayName": "Jane Citizen", 87 | "active": true, 88 | "slug": "jcitizen", 89 | "type": "NORMAL" 90 | }, 91 | "action": "RESCOPED", 92 | "fromHash": "abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde", 93 | "previousFromHash": "bcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdea", 94 | "previousToHash": "cdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeab", 95 | "toHash": "ddeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabc", 96 | "added": { 97 | "commits": [ 98 | { 99 | "id": "abcdef0123abcdef4567abcdef8987abcdef6543", 100 | "displayId": "abcdef0123a", 101 | "author": { 102 | "name": "charlie", 103 | "emailAddress": "charlie@example.com" 104 | }, 105 | "authorTimestamp": 1548720847608, 106 | "committer": { 107 | "name": "charlie", 108 | "emailAddress": "charlie@example.com" 109 | }, 110 | "committerTimestamp": 1548720847608, 111 | "message": "WIP on feature 1", 112 | "parents": [ 113 | { 114 | "id": "abcdef0123abcdef4567abcdef8987abcdef6543", 115 | "displayId": "abcdef0" 116 | } 117 | ] 118 | } 119 | ], 120 | "total": 1 121 | }, 122 | "removed": { 123 | "commits": [ 124 | { 125 | "id": "def0123abcdef4567abcdef8987abcdef6543abc", 126 | "displayId": "def0123abcd", 127 | "author": { 128 | "name": "charlie", 129 | "emailAddress": "charlie@example.com" 130 | }, 131 | "authorTimestamp": 1548720847609, 132 | "committer": { 133 | "name": "charlie", 134 | "emailAddress": "charlie@example.com" 135 | }, 136 | "committerTimestamp": 1548720847609, 137 | "message": "More work on feature 1", 138 | "parents": [ 139 | { 140 | "id": "abcdef0123abcdef4567abcdef8987abcdef6543", 141 | "displayId": "abcdef0" 142 | } 143 | ] 144 | } 145 | ], 146 | "total": 1 147 | } 148 | }, 149 | { 150 | "id": 101, 151 | "createdDate": 1359085920, 152 | "user": { 153 | "name": "jcitizen", 154 | "emailAddress": "jane@example.com", 155 | "id": 101, 156 | "displayName": "Jane Citizen", 157 | "active": true, 158 | "slug": "jcitizen", 159 | "type": "NORMAL" 160 | }, 161 | "action": "MERGED" 162 | } 163 | ], 164 | "start": 0 165 | } -------------------------------------------------------------------------------- /vcsclient/testdata/bitbucketserver/get_pull_request_response_nil.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 6, 3 | "version": 0, 4 | "title": "New vul 2", 5 | "description": "* add vul\n* test", 6 | "state": "OPEN", 7 | "open": true, 8 | "closed": false, 9 | "createdDate": 1686651080688, 10 | "updatedDate": 1686651080688, 11 | "fromRef": { 12 | "id": "refs/heads/new_vul_2", 13 | "displayId": "new_vul_2", 14 | "latestCommit": "7121b72f7c2a4bdd953bcddd80c037cb598db690", 15 | "type": "BRANCH", 16 | "repository": { 17 | "slug": "repoName", 18 | "id": 35731, 19 | "name": "repoName", 20 | "hierarchyId": "38d6f6b604eee2af0b68", 21 | "scmId": "git", 22 | "state": "AVAILABLE", 23 | "statusMessage": "Available", 24 | "forkable": true, 25 | "origin": { 26 | "slug": "repoName", 27 | "id": 115, 28 | "name": "repoName", 29 | "hierarchyId": "38d6f3b609eee2af0b68", 30 | "scmId": "git", 31 | "state": "AVAILABLE", 32 | "statusMessage": "Available", 33 | "forkable": true, 34 | "public": false, 35 | "archived": false, 36 | "links": { 37 | "clone": [ 38 | { 39 | "href": "https://git.bbServerHost.info/scm/repoName/repoName.git", 40 | "name": "http" 41 | }, 42 | { 43 | "href": "ssh://git@git.bbServerHost.info/repoName/repoName.git", 44 | "name": "ssh" 45 | } 46 | ], 47 | "self": [ 48 | { 49 | "href": "https://git.bbServerHost.info/projects/repoName/repos/repoName/browse" 50 | } 51 | ] 52 | } 53 | }, 54 | "public": false, 55 | "archived": false, 56 | "links": { 57 | "clone": [ 58 | { 59 | "href": "ssh://git@git.bbServerHost.info/~owner/repoName.git", 60 | "name": "ssh" 61 | }, 62 | { 63 | "href": "https://git.bbServerHost.info/scm/~owner/repoName.git", 64 | "name": "http" 65 | } 66 | ], 67 | "self": [ 68 | { 69 | "href": "https://git.bbServerHost.info/users/owner/repos/repoName/browse" 70 | } 71 | ] 72 | } 73 | } 74 | }, 75 | "toRef": { 76 | "id": "refs/heads/master", 77 | "displayId": "master", 78 | "latestCommit": "49ee0968441e2cae00e714c1d7852a6565ce12c7", 79 | "type": "BRANCH", 80 | "repository": { 81 | "slug": "repoName", 82 | "id": 32731, 83 | "name": "repoName", 84 | "hierarchyId": "38d6f4b609eee2af0b68", 85 | "scmId": "git", 86 | "state": "AVAILABLE", 87 | "statusMessage": "Available", 88 | "forkable": true, 89 | "origin": { 90 | "slug": "repoName", 91 | "id": 1215, 92 | "name": "repoName", 93 | "hierarchyId": "38f6f6b609eee2af0b68", 94 | "scmId": "git", 95 | "state": "AVAILABLE", 96 | "statusMessage": "Available", 97 | "forkable": true, 98 | "project": { 99 | "key": "repoName", 100 | "id": 1210, 101 | "name": "repoName", 102 | "description": "repoName", 103 | "public": false, 104 | "type": "NORMAL", 105 | "links": { 106 | "self": [ 107 | { 108 | "href": "https://git.bbServerHost.info/projects/repoName" 109 | } 110 | ] 111 | } 112 | }, 113 | "public": false, 114 | "archived": false, 115 | "links": { 116 | "clone": [ 117 | { 118 | "href": "https://git.bbServerHost.info/scm/repoName/repoName.git", 119 | "name": "http" 120 | }, 121 | { 122 | "href": "ssh://git@git.bbServerHost.info/repoName/repoName.git", 123 | "name": "ssh" 124 | } 125 | ], 126 | "self": [ 127 | { 128 | "href": "https://git.bbServerHost.info/projects/repoName/repos/repoName/browse" 129 | } 130 | ] 131 | } 132 | }, 133 | "project": { 134 | "key": "~targetOwner", 135 | "id": 2424, 136 | "name": "some name", 137 | "type": "PERSONAL", 138 | "owner": { 139 | "name": "owner", 140 | "emailAddress": "owner@bbServerHost.com", 141 | "active": true, 142 | "displayName": "some name", 143 | "id": 2198757, 144 | "slug": "owner", 145 | "type": "NORMAL", 146 | "links": { 147 | "self": [ 148 | { 149 | "href": "https://git.bbServerHost.info/users/owner" 150 | } 151 | ] 152 | } 153 | }, 154 | "links": { 155 | "self": [ 156 | { 157 | "href": "https://git.bbServerHost.info/users/owner" 158 | } 159 | ] 160 | } 161 | }, 162 | "public": false, 163 | "archived": false, 164 | "links": { 165 | "clone": [ 166 | { 167 | "href": "ssh://git@git.bbServerHost.info/~owner/repoName.git", 168 | "name": "ssh" 169 | }, 170 | { 171 | "href": "https://git.bbServerHost.info/scm/~owner/repoName.git", 172 | "name": "http" 173 | } 174 | ], 175 | "self": [ 176 | { 177 | "href": "https://git.bbServerHost.info/users/owner/repos/repoName/browse" 178 | } 179 | ] 180 | } 181 | } 182 | }, 183 | "locked": false, 184 | "author": { 185 | "user": { 186 | "name": "owner", 187 | "emailAddress": "owner@bbServerHost.com", 188 | "active": true, 189 | "displayName": "some name", 190 | "id": 2114757, 191 | "slug": "owner", 192 | "type": "NORMAL", 193 | "links": { 194 | "self": [ 195 | { 196 | "href": "https://git.bbServerHost.info/users/owner" 197 | } 198 | ] 199 | } 200 | }, 201 | "role": "AUTHOR", 202 | "approved": false, 203 | "status": "UNAPPROVED" 204 | }, 205 | "reviewers": [], 206 | "participants": [], 207 | "links": { 208 | "self": [ 209 | { 210 | "href": "https://git.bbServerHost.info/users/owner/repos/repoName/pull-requests/6" 211 | } 212 | ] 213 | } 214 | } -------------------------------------------------------------------------------- /.github/workflows/frogbot-scan-repository.yml: -------------------------------------------------------------------------------- 1 | name: "Frogbot Scan Repository" 2 | on: 3 | workflow_dispatch: 4 | schedule: 5 | # The repository will be scanned once a day at 00:00 GMT. 6 | - cron: "0 0 * * *" 7 | permissions: 8 | contents: write 9 | pull-requests: write 10 | security-events: write 11 | jobs: 12 | scan-repository: 13 | runs-on: ubuntu-latest 14 | strategy: 15 | matrix: 16 | # The repository scanning will be triggered periodically on the following branches. 17 | branch: [ "master" ] 18 | steps: 19 | - name: Setup Go with cache 20 | uses: jfrog/.github/actions/install-go-with-cache@main 21 | 22 | - uses: jfrog/frogbot@v2 23 | env: 24 | JFROG_CLI_LOG_LEVEL: "DEBUG" 25 | # [Mandatory] 26 | # JFrog platform URL (This functionality requires version 3.29.0 or above of Xray) 27 | JF_URL: ${{ secrets.FROGBOT_URL }} 28 | 29 | # [Mandatory if JF_USER and JF_PASSWORD are not provided] 30 | # JFrog access token with 'read' permissions on Xray service 31 | JF_ACCESS_TOKEN: ${{ secrets.FROGBOT_ACCESS_TOKEN }} 32 | 33 | # [Mandatory if JF_ACCESS_TOKEN is not provided] 34 | # JFrog username with 'read' permissions for Xray. Must be provided with JF_PASSWORD 35 | # JF_USER: ${{ secrets.JF_USER }} 36 | 37 | # [Mandatory if JF_ACCESS_TOKEN is not provided] 38 | # JFrog password. Must be provided with JF_USER 39 | # JF_PASSWORD: ${{ secrets.JF_PASSWORD }} 40 | 41 | # [Mandatory] 42 | # The GitHub token is automatically generated for the job 43 | JF_GIT_TOKEN: ${{ secrets.GITHUB_TOKEN }} 44 | 45 | # [Mandatory] 46 | # The name of the branch on which Frogbot will perform the scan 47 | JF_GIT_BASE_BRANCH: ${{ matrix.branch }} 48 | 49 | # [Optional, default: https://api.github.com] 50 | # API endpoint to GitHub 51 | # JF_GIT_API_ENDPOINT: https://github.example.com 52 | 53 | # [Optional] 54 | # By default, the Frogbot workflows download the Frogbot executable as well as other tools 55 | # needed from https://releases.jfrog.io 56 | # If the machine that runs Frogbot has no access to the internet, follow these steps to allow the 57 | # executable to be downloaded from an Artifactory instance, which the machine has access to: 58 | # 59 | # 1. Login to the Artifactory UI, with a user who has admin credentials. 60 | # 2. Create a Remote Repository with the following properties set. 61 | # Under the 'Basic' tab: 62 | # Package Type: Generic 63 | # URL: https://releases.jfrog.io 64 | # Under the 'Advanced' tab: 65 | # Uncheck the 'Store Artifacts Locally' option 66 | # 3. Set the value of the 'JF_RELEASES_REPO' variable with the Repository Key you created. 67 | # JF_RELEASES_REPO: "" 68 | 69 | ########################################################################## 70 | ## If your project uses a 'frogbot-config.yml' file, you can define ## 71 | ## the following variables inside the file, instead of here. ## 72 | ########################################################################## 73 | 74 | # [Optional, default: "."] 75 | # Relative path to the root of the project in the Git repository 76 | # JF_WORKING_DIR: path/to/project/dir 77 | 78 | # [Optional] 79 | # Xray Watches. Learn more about them here: https://www.jfrog.com/confluence/display/JFROG/Configuring+Xray+Watches 80 | # JF_WATCHES: ,... 81 | 82 | # [Optional] 83 | # JFrog project. Learn more about it here: https://www.jfrog.com/confluence/display/JFROG/Projects 84 | # JF_PROJECT: 85 | 86 | # [Optional, default: "TRUE"] 87 | # Fails the Frogbot task if any security issue is found. 88 | # JF_FAIL: "FALSE" 89 | 90 | # [Optional] 91 | # Frogbot will download the project dependencies, if they're not cached locally. To download the 92 | # dependencies from a virtual repository in Artifactory, set the name of the repository. There's no 93 | # need to set this value, if it is set in the frogbot-config.yml file. 94 | # JF_DEPS_REPO: "" 95 | 96 | # [Optional] 97 | # Template for the branch name generated by Frogbot when creating pull requests with fixes. 98 | # The template must include ${BRANCH_NAME_HASH}, to ensure that the generated branch name is unique. 99 | # The template can optionally include the ${IMPACTED_PACKAGE} and ${FIX_VERSION} variables. 100 | # JF_BRANCH_NAME_TEMPLATE: "frogbot-${IMPACTED_PACKAGE}-${BRANCH_NAME_HASH}" 101 | 102 | # [Optional] 103 | # Template for the commit message generated by Frogbot when creating pull requests with fixes 104 | # The template can optionally include the ${IMPACTED_PACKAGE} and ${FIX_VERSION} variables. 105 | # JF_COMMIT_MESSAGE_TEMPLATE: "Upgrade ${IMPACTED_PACKAGE} to ${FIX_VERSION}" 106 | 107 | # [Optional] 108 | # Template for the pull request title generated by Frogbot when creating pull requests with fixes. 109 | # The template can optionally include the ${IMPACTED_PACKAGE} and ${FIX_VERSION} variables. 110 | # JF_PULL_REQUEST_TITLE_TEMPLATE: "[🐸 Frogbot] Upgrade ${IMPACTED_PACKAGE} to ${FIX_VERSION}" 111 | 112 | # [Optional, Default: "FALSE"] 113 | # If TRUE, Frogbot creates a single pull request with all the fixes. 114 | # If FALSE, Frogbot creates a separate pull request for each fix. 115 | # JF_GIT_AGGREGATE_FIXES: "FALSE" 116 | 117 | # [Optional, Default: "FALSE"] 118 | # Handle vulnerabilities with fix versions only 119 | # JF_FIXABLE_ONLY: "TRUE" 120 | 121 | # [Optional] 122 | # Set the minimum severity for vulnerabilities that should be fixed and commented on in pull requests 123 | # The following values are accepted: Low, Medium, High or Critical 124 | # JF_MIN_SEVERITY: "" 125 | 126 | # [Optional, Default: eco-system+frogbot@jfrog.com] 127 | # Set the email of the commit author 128 | # JF_GIT_EMAIL_AUTHOR: "" --------------------------------------------------------------------------------