From f01ac3f0a3dcb8f8df27d45c7b36426e939788eb Mon Sep 17 00:00:00 2001 From: Anbraten Date: Tue, 26 Dec 2023 19:22:52 +0100 Subject: [PATCH] Add pull request closed event (#2684) - [x] updates docs - [x] adjust UI - [x] show correct icon - [x] show correct link (to pr) - [x] add as option in secret edit - [x] parse webhook - [x] update tests - [x] github merged - [x] github closed - [x] gitea merged - [x] gitea closed - [x] bitbucket merged - [x] bitbucket closed - [x] gitlab merged - [x] gitlab closed closes #286 --- cmd/server/docs/docs.go | 2 + docs/docs/20-usage/15-terminiology/index.md | 9 + docs/docs/20-usage/20-workflow-syntax.md | 2 +- docs/docs/20-usage/50-environment.md | 14 +- pipeline/frontend/metadata/const.go | 13 +- .../frontend/yaml/linter/schema/schema.json | 3 +- server/forge/bitbucket/convert.go | 7 +- server/forge/bitbucket/fixtures/hooks.go | 581 ++++++++- server/forge/bitbucket/parse.go | 22 +- server/forge/bitbucket/parse_test.go | 57 +- server/forge/gitea/fixtures/hooks.go | 744 +++++++++++- server/forge/gitea/helper.go | 9 +- server/forge/gitea/helper_test.go | 4 +- server/forge/gitea/parse.go | 16 +- server/forge/gitea/parse_test.go | 83 +- server/forge/github/fixtures/hooks.go | 1039 +++++++++++++++++ server/forge/github/parse.go | 23 +- server/forge/github/parse_test.go | 36 +- server/forge/gitlab/convert.go | 3 + server/forge/gitlab/gitlab_test.go | 46 +- server/forge/gitlab/testdata/hooks.go | 297 ++++- server/model/const.go | 13 +- web/src/components/atomic/Icon.vue | 6 +- .../components/repo/pipeline/PipelineItem.vue | 3 +- .../repo/pipeline/PipelineStepList.vue | 4 +- web/src/compositions/usePipeline.ts | 2 +- web/src/lib/api/types/webhook.ts | 1 + web/src/views/repo/RepoBranch.vue | 5 +- web/src/views/repo/RepoPullRequest.vue | 2 +- .../views/repo/pipeline/PipelineWrapper.vue | 2 +- woodpecker-go/woodpecker/const.go | 11 +- 31 files changed, 2920 insertions(+), 139 deletions(-) diff --git a/cmd/server/docs/docs.go b/cmd/server/docs/docs.go index 1920cb7e7..6c7823a86 100644 --- a/cmd/server/docs/docs.go +++ b/cmd/server/docs/docs.go @@ -4396,6 +4396,7 @@ const docTemplate = `{ "enum": [ "push", "pull_request", + "pull_request_closed", "tag", "deployment", "cron", @@ -4404,6 +4405,7 @@ const docTemplate = `{ "x-enum-varnames": [ "EventPush", "EventPull", + "EventPullClosed", "EventTag", "EventDeploy", "EventCron", diff --git a/docs/docs/20-usage/15-terminiology/index.md b/docs/docs/20-usage/15-terminiology/index.md index 4640ede35..18e015d14 100644 --- a/docs/docs/20-usage/15-terminiology/index.md +++ b/docs/docs/20-usage/15-terminiology/index.md @@ -32,6 +32,15 @@ - **Dependency**: [Workflows][Workflow] can depend on each other, and if possible, they are executed in parallel. - **Status**: Status refers to the outcome of a step or [workflow][Workflow] after it has been executed, determined by the internal command exit code. At the end of a [workflow][Workflow], its status is sent to the [forge][Forge]. +## Pipeline events + +- `push`: A push event is triggered when a commit is pushed to a branch. +- `pull_request`: A pull request event is triggered when a pull request is opened or a new commit is pushed to it. +- `pull_request_closed`: A pull request closed event is triggered when a pull request is closed or merged. +- `tag`: A tag event is triggered when a tag is pushed. +- `manual`: A manual event is triggered when a user manually triggers a pipeline. +- `cron`: A cron event is triggered when a cron job is executed. + ## Conventions Sometimes there are multiple terms that can be used to describe something. This section lists the preferred terms to use in Woodpecker: diff --git a/docs/docs/20-usage/20-workflow-syntax.md b/docs/docs/20-usage/20-workflow-syntax.md index 81baf4368..9efee6fbf 100644 --- a/docs/docs/20-usage/20-workflow-syntax.md +++ b/docs/docs/20-usage/20-workflow-syntax.md @@ -263,7 +263,7 @@ when: #### `event` -Available events: `push`, `pull_request`, `tag`, `deployment`, `cron`, `manual` +Available events: `push`, `pull_request`, `pull_request_closed`, `tag`, `deployment`, `cron`, `manual` Execute a step if the build event is a `tag`: diff --git a/docs/docs/20-usage/50-environment.md b/docs/docs/20-usage/50-environment.md index 8deebc715..cf3352791 100644 --- a/docs/docs/20-usage/50-environment.md +++ b/docs/docs/20-usage/50-environment.md @@ -66,11 +66,11 @@ This is the reference list of all environment variables available to your pipeli | `CI_COMMIT_REF` | commit ref | | `CI_COMMIT_REFSPEC` | commit ref spec | | `CI_COMMIT_BRANCH` | commit branch (equals target branch for pull requests) | -| `CI_COMMIT_SOURCE_BRANCH` | commit source branch (empty if event is not `pull_request`) | -| `CI_COMMIT_TARGET_BRANCH` | commit target branch (empty if event is not `pull_request`) | +| `CI_COMMIT_SOURCE_BRANCH` | commit source branch (empty if event is not `pull_request` or `pull_request_closed`) | +| `CI_COMMIT_TARGET_BRANCH` | commit target branch (empty if event is not `pull_request` or `pull_request_closed`) | | `CI_COMMIT_TAG` | commit tag name (empty if event is not `tag`) | -| `CI_COMMIT_PULL_REQUEST` | commit pull request number (empty if event is not `pull_request`) | -| `CI_COMMIT_PULL_REQUEST_LABELS` | labels assigned to pull request (empty if event is not `pull_request`) | +| `CI_COMMIT_PULL_REQUEST` | commit pull request number (empty if event is not `pull_request` or `pull_request_closed`) | +| `CI_COMMIT_PULL_REQUEST_LABELS` | labels assigned to pull request (empty if event is not `pull_request` or `pull_request_closed`) | | `CI_COMMIT_MESSAGE` | commit message | | `CI_COMMIT_AUTHOR` | commit author username | | `CI_COMMIT_AUTHOR_EMAIL` | commit author email address | @@ -78,10 +78,10 @@ This is the reference list of all environment variables available to your pipeli | | **Current pipeline** | | `CI_PIPELINE_NUMBER` | pipeline number | | `CI_PIPELINE_PARENT` | number of parent pipeline | -| `CI_PIPELINE_EVENT` | pipeline event (push, pull_request, tag, deployment, cron, manual) | +| `CI_PIPELINE_EVENT` | pipeline event (see [pipeline events](../20-usage/15-terminiology/index.md#pipeline-events)) | | `CI_PIPELINE_URL` | link to the web UI for the pipeline | | `CI_PIPELINE_FORGE_URL` | link to the forge's web UI for the commit(s) or tag that triggered the pipeline | -| `CI_PIPELINE_DEPLOY_TARGET` | pipeline deploy target for `deployment` events (ie production) | +| `CI_PIPELINE_DEPLOY_TARGET` | pipeline deploy target for `deployment` events (i.e. production) | | `CI_PIPELINE_STATUS` | pipeline status (success, failure) | | `CI_PIPELINE_CREATED` | pipeline created UNIX timestamp | | `CI_PIPELINE_STARTED` | pipeline started UNIX timestamp | @@ -111,7 +111,7 @@ This is the reference list of all environment variables available to your pipeli | | **Previous pipeline** | | `CI_PREV_PIPELINE_NUMBER` | previous pipeline number | | `CI_PREV_PIPELINE_PARENT` | previous pipeline number of parent pipeline | -| `CI_PREV_PIPELINE_EVENT` | previous pipeline event (push, pull_request, tag, deployment) | +| `CI_PREV_PIPELINE_EVENT` | previous pipeline event (see [pipeline events](../20-usage/15-terminiology/index.md#pipeline-events)) | | `CI_PREV_PIPELINE_URL` | previous pipeline link in CI | | `CI_PREV_PIPELINE_FORGE_URL` | previous pipeline link to event in forge | | `CI_PREV_PIPELINE_DEPLOY_TARGET` | previous pipeline deploy target for `deployment` events (ie production) | diff --git a/pipeline/frontend/metadata/const.go b/pipeline/frontend/metadata/const.go index 75742cf8d..545fe5eca 100644 --- a/pipeline/frontend/metadata/const.go +++ b/pipeline/frontend/metadata/const.go @@ -16,12 +16,13 @@ package metadata // Event types corresponding to scm hooks. const ( - EventPush = "push" - EventPull = "pull_request" - EventTag = "tag" - EventDeploy = "deployment" - EventCron = "cron" - EventManual = "manual" + EventPush = "push" + EventPull = "pull_request" + EventPullClosed = "pull_request_closed" + EventTag = "tag" + EventDeploy = "deployment" + EventCron = "cron" + EventManual = "manual" ) // Different ways to handle failure states diff --git a/pipeline/frontend/yaml/linter/schema/schema.json b/pipeline/frontend/yaml/linter/schema/schema.json index c361cf26f..d1b9d97ad 100644 --- a/pipeline/frontend/yaml/linter/schema/schema.json +++ b/pipeline/frontend/yaml/linter/schema/schema.json @@ -394,7 +394,6 @@ }, "event": { "description": "Read more: https://woodpecker-ci.org/docs/usage/pipeline-syntax#event", - "default": ["push", "pull_request", "tag", "deployment"], "oneOf": [ { "type": "array", @@ -494,7 +493,7 @@ } }, "event_enum": { - "enum": ["push", "pull_request", "tag", "deployment", "cron", "manual"] + "enum": ["push", "pull_request", "pull_request_closed", "tag", "deployment", "cron", "manual"] }, "constraint_list": { "oneOf": [ diff --git a/server/forge/bitbucket/convert.go b/server/forge/bitbucket/convert.go index 7fb8cb6b5..700b3c32c 100644 --- a/server/forge/bitbucket/convert.go +++ b/server/forge/bitbucket/convert.go @@ -163,8 +163,13 @@ func convertWorkspace(from *internal.Workspace) *model.Team { // convertPullHook is a helper function used to convert a Bitbucket pull request // hook to the Woodpecker pipeline struct holding commit information. func convertPullHook(from *internal.PullRequestHook) *model.Pipeline { + event := model.EventPull + if from.PullRequest.State == stateClosed || from.PullRequest.State == stateDeclined { + event = model.EventPullClosed + } + return &model.Pipeline{ - Event: model.EventPull, + Event: event, Commit: from.PullRequest.Dest.Commit.Hash, Ref: fmt.Sprintf("refs/heads/%s", from.PullRequest.Dest.Branch.Name), Refspec: fmt.Sprintf("%s:%s", diff --git a/server/forge/bitbucket/fixtures/hooks.go b/server/forge/bitbucket/fixtures/hooks.go index b9358a8fa..dbf66da6b 100644 --- a/server/forge/bitbucket/fixtures/hooks.go +++ b/server/forge/bitbucket/fixtures/hooks.go @@ -456,10 +456,587 @@ const HookPull = ` } ` -const HookMerged = ` +const HookPullRequestMerged = ` { + "repository": { + "type": "repository", + "full_name": "anbraten/test-2", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2" + }, + "html": { + "href": "https://bitbucket.org/anbraten/test-2" + }, + "avatar": { + "href": "https://bytebucket.org/ravatar/%7B26554729-595f-47d1-aedd-302625cb4a97%7D?ts=default" + } + }, + "name": "test-2", + "scm": "git", + "website": null, + "owner": { + "display_name": "Anbraten", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/users/%7Bb1b7beef-77ca-452d-b059-fa092504ebd7%7D" + }, + "avatar": { + "href": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/70121:3046ad5f-946f-48fa-bcb4-a399eef48f0e/784add1f-95cc-42a5-a562-38a0e12de4fa/128" + }, + "html": { + "href": "https://bitbucket.org/%7Bb1b7beef-77ca-452d-b059-fa092504ebd7%7D/" + } + }, + "type": "user", + "uuid": "{b1b7beef-77ca-452d-b059-fa092504ebd7}", + "account_id": "70121:3046ad5f-946f-48fa-bcb4-a399eef48f0e", + "nickname": "Anbraten" + }, + "workspace": { + "type": "workspace", + "uuid": "{b1b7beef-77ca-452d-b059-fa092504ebd7}", + "name": "Anbraten", + "slug": "anbraten", + "links": { + "avatar": { + "href": "https://bitbucket.org/workspaces/anbraten/avatar/?ts=1651865281" + }, + "html": { + "href": "https://bitbucket.org/anbraten/" + }, + "self": { + "href": "https://api.bitbucket.org/2.0/workspaces/anbraten" + } + } + }, + "is_private": true, + "project": { + "type": "project", + "key": "TEST", + "uuid": "{3fa6429f-95e1-4c5a-875c-1753abcd8ace}", + "name": "test", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/workspaces/anbraten/projects/TEST" + }, + "html": { + "href": "https://bitbucket.org/anbraten/workspace/projects/TEST" + }, + "avatar": { + "href": "https://bitbucket.org/account/user/anbraten/projects/TEST/avatar/32?ts=1690725373" + } + } + }, + "uuid": "{26554729-595f-47d1-aedd-302625cb4a97}", + "parent": null + }, + "actor": { + "display_name": "Anbraten", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/users/%7Bb1b7beef-77ca-452d-b059-fa092504ebd7%7D" + }, + "avatar": { + "href": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/70121:3046ad5f-946f-48fa-bcb4-a399eef48f0e/784add1f-95cc-42a5-a562-38a0e12de4fa/128" + }, + "html": { + "href": "https://bitbucket.org/%7Bb1b7beef-77ca-452d-b059-fa092504ebd7%7D/" + } + }, + "type": "user", + "uuid": "{b1b7beef-77ca-452d-b059-fa092504ebd7}", + "account_id": "70121:3046ad5f-946f-48fa-bcb4-a399eef48f0e", + "nickname": "Anbraten" + }, "pullrequest": { - "state": "MERGED" + "comment_count": 0, + "task_count": 0, + "type": "pullrequest", + "id": 1, + "title": "README.md created online with Bitbucket", + "description": "README.md created online with Bitbucket", + "rendered": { + "title": { + "type": "rendered", + "raw": "README.md created online with Bitbucket", + "markup": "markdown", + "html": "

README.md created online with Bitbucket

" + }, + "description": { + "type": "rendered", + "raw": "README.md created online with Bitbucket", + "markup": "markdown", + "html": "

README.md created online with Bitbucket

" + } + }, + "state": "MERGED", + "merge_commit": { + "type": "commit", + "hash": "006704dbeab2", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2/commit/006704dbeab2" + }, + "html": { + "href": "https://bitbucket.org/anbraten/test-2/commits/006704dbeab2" + } + } + }, + "close_source_branch": true, + "closed_by": { + "display_name": "Anbraten", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/users/%7Bb1b7beef-77ca-452d-b059-fa092504ebd7%7D" + }, + "avatar": { + "href": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/70121:3046ad5f-946f-48fa-bcb4-a399eef48f0e/784add1f-95cc-42a5-a562-38a0e12de4fa/128" + }, + "html": { + "href": "https://bitbucket.org/%7Bb1b7beef-77ca-452d-b059-fa092504ebd7%7D/" + } + }, + "type": "user", + "uuid": "{b1b7beef-77ca-452d-b059-fa092504ebd7}", + "account_id": "70121:3046ad5f-946f-48fa-bcb4-a399eef48f0e", + "nickname": "Anbraten" + }, + "author": { + "display_name": "Anbraten", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/users/%7Bb1b7beef-77ca-452d-b059-fa092504ebd7%7D" + }, + "avatar": { + "href": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/70121:3046ad5f-946f-48fa-bcb4-a399eef48f0e/784add1f-95cc-42a5-a562-38a0e12de4fa/128" + }, + "html": { + "href": "https://bitbucket.org/%7Bb1b7beef-77ca-452d-b059-fa092504ebd7%7D/" + } + }, + "type": "user", + "uuid": "{b1b7beef-77ca-452d-b059-fa092504ebd7}", + "account_id": "70121:3046ad5f-946f-48fa-bcb4-a399eef48f0e", + "nickname": "Anbraten" + }, + "reason": "", + "created_on": "2023-12-05T18:28:16.861881+00:00", + "updated_on": "2023-12-05T18:29:44.785393+00:00", + "destination": { + "branch": { + "name": "main" + }, + "commit": { + "type": "commit", + "hash": "6c5f0bc9b2aa", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2/commit/6c5f0bc9b2aa" + }, + "html": { + "href": "https://bitbucket.org/anbraten/test-2/commits/6c5f0bc9b2aa" + } + } + }, + "repository": { + "type": "repository", + "full_name": "anbraten/test-2", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2" + }, + "html": { + "href": "https://bitbucket.org/anbraten/test-2" + }, + "avatar": { + "href": "https://bytebucket.org/ravatar/%7B26554729-595f-47d1-aedd-302625cb4a97%7D?ts=default" + } + }, + "name": "test-2", + "uuid": "{26554729-595f-47d1-aedd-302625cb4a97}" + } + }, + "source": { + "branch": { + "name": "patch-2" + }, + "commit": { + "type": "commit", + "hash": "668218c13e04", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2/commit/668218c13e04" + }, + "html": { + "href": "https://bitbucket.org/anbraten/test-2/commits/668218c13e04" + } + } + }, + "repository": { + "type": "repository", + "full_name": "anbraten/test-2", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2" + }, + "html": { + "href": "https://bitbucket.org/anbraten/test-2" + }, + "avatar": { + "href": "https://bytebucket.org/ravatar/%7B26554729-595f-47d1-aedd-302625cb4a97%7D?ts=default" + } + }, + "name": "test-2", + "uuid": "{26554729-595f-47d1-aedd-302625cb4a97}" + } + }, + "reviewers": [], + "participants": [ + { + "type": "participant", + "user": { + "display_name": "Anbraten", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/users/%7Bb1b7beef-77ca-452d-b059-fa092504ebd7%7D" + }, + "avatar": { + "href": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/70121:3046ad5f-946f-48fa-bcb4-a399eef48f0e/784add1f-95cc-42a5-a562-38a0e12de4fa/128" + }, + "html": { + "href": "https://bitbucket.org/%7Bb1b7beef-77ca-452d-b059-fa092504ebd7%7D/" + } + }, + "type": "user", + "uuid": "{b1b7beef-77ca-452d-b059-fa092504ebd7}", + "account_id": "70121:3046ad5f-946f-48fa-bcb4-a399eef48f0e", + "nickname": "Anbraten" + }, + "role": "PARTICIPANT", + "approved": true, + "state": "approved", + "participated_on": "2023-12-05T18:29:25.611876+00:00" + } + ], + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2/pullrequests/1" + }, + "html": { + "href": "https://bitbucket.org/anbraten/test-2/pull-requests/1" + }, + "commits": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2/pullrequests/1/commits" + }, + "approve": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2/pullrequests/1/approve" + }, + "request-changes": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2/pullrequests/1/request-changes" + }, + "diff": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2/diff/anbraten/test-2:668218c13e04%0D6c5f0bc9b2aa?from_pullrequest_id=1&topic=true" + }, + "diffstat": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2/diffstat/anbraten/test-2:668218c13e04%0D6c5f0bc9b2aa?from_pullrequest_id=1&topic=true" + }, + "comments": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2/pullrequests/1/comments" + }, + "activity": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2/pullrequests/1/activity" + }, + "merge": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2/pullrequests/1/merge" + }, + "decline": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2/pullrequests/1/decline" + }, + "statuses": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2/pullrequests/1/statuses" + } + }, + "summary": { + "type": "rendered", + "raw": "README.md created online with Bitbucket", + "markup": "markdown", + "html": "

README.md created online with Bitbucket

" + } + } +} +` + +const HookPullRequestDeclined = ` +{ + "repository": { + "type": "repository", + "full_name": "anbraten/test-2", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2" + }, + "html": { + "href": "https://bitbucket.org/anbraten/test-2" + }, + "avatar": { + "href": "https://bytebucket.org/ravatar/%7B26554729-595f-47d1-aedd-302625cb4a97%7D?ts=default" + } + }, + "name": "test-2", + "scm": "git", + "website": null, + "owner": { + "display_name": "Anbraten", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/users/%7Bb1b7beef-77ca-452d-b059-fa092504ebd7%7D" + }, + "avatar": { + "href": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/70121:3046ad5f-946f-48fa-bcb4-a399eef48f0e/784add1f-95cc-42a5-a562-38a0e12de4fa/128" + }, + "html": { + "href": "https://bitbucket.org/%7Bb1b7beef-77ca-452d-b059-fa092504ebd7%7D/" + } + }, + "type": "user", + "uuid": "{b1b7beef-77ca-452d-b059-fa092504ebd7}", + "account_id": "70121:3046ad5f-946f-48fa-bcb4-a399eef48f0e", + "nickname": "Anbraten" + }, + "workspace": { + "type": "workspace", + "uuid": "{b1b7beef-77ca-452d-b059-fa092504ebd7}", + "name": "Anbraten", + "slug": "anbraten", + "links": { + "avatar": { + "href": "https://bitbucket.org/workspaces/anbraten/avatar/?ts=1651865281" + }, + "html": { + "href": "https://bitbucket.org/anbraten/" + }, + "self": { + "href": "https://api.bitbucket.org/2.0/workspaces/anbraten" + } + } + }, + "is_private": true, + "project": { + "type": "project", + "key": "TEST", + "uuid": "{3fa6429f-95e1-4c5a-875c-1753abcd8ace}", + "name": "test", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/workspaces/anbraten/projects/TEST" + }, + "html": { + "href": "https://bitbucket.org/anbraten/workspace/projects/TEST" + }, + "avatar": { + "href": "https://bitbucket.org/account/user/anbraten/projects/TEST/avatar/32?ts=1690725373" + } + } + }, + "uuid": "{26554729-595f-47d1-aedd-302625cb4a97}", + "parent": null + }, + "actor": { + "display_name": "Anbraten", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/users/%7Bb1b7beef-77ca-452d-b059-fa092504ebd7%7D" + }, + "avatar": { + "href": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/70121:3046ad5f-946f-48fa-bcb4-a399eef48f0e/784add1f-95cc-42a5-a562-38a0e12de4fa/128" + }, + "html": { + "href": "https://bitbucket.org/%7Bb1b7beef-77ca-452d-b059-fa092504ebd7%7D/" + } + }, + "type": "user", + "uuid": "{b1b7beef-77ca-452d-b059-fa092504ebd7}", + "account_id": "70121:3046ad5f-946f-48fa-bcb4-a399eef48f0e", + "nickname": "Anbraten" + }, + "pullrequest": { + "comment_count": 0, + "task_count": 0, + "type": "pullrequest", + "id": 2, + "title": "CHANGELOG.md created online with Bitbucket", + "description": "CHANGELOG.md created online with Bitbucket", + "rendered": { + "title": { + "type": "rendered", + "raw": "CHANGELOG.md created online with Bitbucket", + "markup": "markdown", + "html": "

CHANGELOG.md created online with Bitbucket

" + }, + "description": { + "type": "rendered", + "raw": "CHANGELOG.md created online with Bitbucket", + "markup": "markdown", + "html": "

CHANGELOG.md created online with Bitbucket

" + } + }, + "state": "DECLINED", + "merge_commit": null, + "close_source_branch": false, + "closed_by": { + "display_name": "Anbraten", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/users/%7Bb1b7beef-77ca-452d-b059-fa092504ebd7%7D" + }, + "avatar": { + "href": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/70121:3046ad5f-946f-48fa-bcb4-a399eef48f0e/784add1f-95cc-42a5-a562-38a0e12de4fa/128" + }, + "html": { + "href": "https://bitbucket.org/%7Bb1b7beef-77ca-452d-b059-fa092504ebd7%7D/" + } + }, + "type": "user", + "uuid": "{b1b7beef-77ca-452d-b059-fa092504ebd7}", + "account_id": "70121:3046ad5f-946f-48fa-bcb4-a399eef48f0e", + "nickname": "Anbraten" + }, + "author": { + "display_name": "Anbraten", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/users/%7Bb1b7beef-77ca-452d-b059-fa092504ebd7%7D" + }, + "avatar": { + "href": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/70121:3046ad5f-946f-48fa-bcb4-a399eef48f0e/784add1f-95cc-42a5-a562-38a0e12de4fa/128" + }, + "html": { + "href": "https://bitbucket.org/%7Bb1b7beef-77ca-452d-b059-fa092504ebd7%7D/" + } + }, + "type": "user", + "uuid": "{b1b7beef-77ca-452d-b059-fa092504ebd7}", + "account_id": "70121:3046ad5f-946f-48fa-bcb4-a399eef48f0e", + "nickname": "Anbraten" + }, + "reason": "", + "created_on": "2023-12-05T18:36:27.667680+00:00", + "updated_on": "2023-12-05T18:36:57.260672+00:00", + "destination": { + "branch": { + "name": "main" + }, + "commit": { + "type": "commit", + "hash": "006704dbeab2", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2/commit/006704dbeab2" + }, + "html": { + "href": "https://bitbucket.org/anbraten/test-2/commits/006704dbeab2" + } + } + }, + "repository": { + "type": "repository", + "full_name": "anbraten/test-2", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2" + }, + "html": { + "href": "https://bitbucket.org/anbraten/test-2" + }, + "avatar": { + "href": "https://bytebucket.org/ravatar/%7B26554729-595f-47d1-aedd-302625cb4a97%7D?ts=default" + } + }, + "name": "test-2", + "uuid": "{26554729-595f-47d1-aedd-302625cb4a97}" + } + }, + "source": { + "branch": { + "name": "patch-2" + }, + "commit": { + "type": "commit", + "hash": "f90e18fc9d45", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2/commit/f90e18fc9d45" + }, + "html": { + "href": "https://bitbucket.org/anbraten/test-2/commits/f90e18fc9d45" + } + } + }, + "repository": { + "type": "repository", + "full_name": "anbraten/test-2", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2" + }, + "html": { + "href": "https://bitbucket.org/anbraten/test-2" + }, + "avatar": { + "href": "https://bytebucket.org/ravatar/%7B26554729-595f-47d1-aedd-302625cb4a97%7D?ts=default" + } + }, + "name": "test-2", + "uuid": "{26554729-595f-47d1-aedd-302625cb4a97}" + } + }, + "reviewers": [], + "participants": [], + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2/pullrequests/2" + }, + "html": { + "href": "https://bitbucket.org/anbraten/test-2/pull-requests/2" + }, + "commits": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2/pullrequests/2/commits" + }, + "approve": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2/pullrequests/2/approve" + }, + "request-changes": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2/pullrequests/2/request-changes" + }, + "diff": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2/diff/anbraten/test-2:f90e18fc9d45%0D006704dbeab2?from_pullrequest_id=2&topic=true" + }, + "diffstat": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2/diffstat/anbraten/test-2:f90e18fc9d45%0D006704dbeab2?from_pullrequest_id=2&topic=true" + }, + "comments": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2/pullrequests/2/comments" + }, + "activity": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2/pullrequests/2/activity" + }, + "merge": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2/pullrequests/2/merge" + }, + "decline": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2/pullrequests/2/decline" + }, + "statuses": { + "href": "https://api.bitbucket.org/2.0/repositories/anbraten/test-2/pullrequests/2/statuses" + } + }, + "summary": { + "type": "rendered", + "raw": "CHANGELOG.md created online with Bitbucket", + "markup": "markdown", + "html": "

CHANGELOG.md created online with Bitbucket

" + } } } ` diff --git a/server/forge/bitbucket/parse.go b/server/forge/bitbucket/parse.go index 7b22f345a..82cf8d5cc 100644 --- a/server/forge/bitbucket/parse.go +++ b/server/forge/bitbucket/parse.go @@ -25,11 +25,15 @@ import ( ) const ( - hookEvent = "X-Event-Key" - hookPush = "repo:push" - hookPullCreated = "pullrequest:created" - hookPullUpdated = "pullrequest:updated" - stateOpen = "OPEN" + hookEvent = "X-Event-Key" + hookPush = "repo:push" + hookPullCreated = "pullrequest:created" + hookPullUpdated = "pullrequest:updated" + hookPullMerged = "pullrequest:fulfilled" + hookPullDeclined = "pullrequest:rejected" + stateOpen = "OPEN" + stateClosed = "MERGED" + stateDeclined = "DECLINED" ) // parseHook parses a Bitbucket hook from an http.Request request and returns @@ -44,7 +48,7 @@ func parseHook(r *http.Request) (*model.Repo, *model.Pipeline, error) { switch hookType { case hookPush: return parsePushHook(payload) - case hookPullCreated, hookPullUpdated: + case hookPullCreated, hookPullUpdated, hookPullMerged, hookPullDeclined: return parsePullHook(payload) default: return nil, nil, &types.ErrIgnoreEvent{Event: hookType} @@ -71,15 +75,13 @@ func parsePushHook(payload []byte) (*model.Repo, *model.Pipeline, error) { } // parsePullHook parses a pull request hook and returns the Repo and Pipeline -// details. If the pull request is closed nil values are returned. +// details. func parsePullHook(payload []byte) (*model.Repo, *model.Pipeline, error) { hook := internal.PullRequestHook{} if err := json.Unmarshal(payload, &hook); err != nil { return nil, nil, err } - if hook.PullRequest.State != stateOpen { - return nil, nil, nil - } + return convertRepo(&hook.Repo, &internal.RepoPerm{}), convertPullHook(&hook), nil } diff --git a/server/forge/bitbucket/parse_test.go b/server/forge/bitbucket/parse_test.go index 915b2f685..efe6bda64 100644 --- a/server/forge/bitbucket/parse_test.go +++ b/server/forge/bitbucket/parse_test.go @@ -30,7 +30,7 @@ import ( func Test_parser(t *testing.T) { g := goblin.Goblin(t) g.Describe("Bitbucket parser", func() { - g.It("Should ignore unsupported hook", func() { + g.It("should ignore unsupported hook", func() { buf := bytes.NewBufferString(fixtures.HookPush) req, _ := http.NewRequest("POST", "/hook", buf) req.Header = http.Header{} @@ -42,8 +42,8 @@ func Test_parser(t *testing.T) { assert.ErrorIs(t, err, &types.ErrIgnoreEvent{}) }) - g.Describe("Given a pull request hook payload", func() { - g.It("Should return err when malformed", func() { + g.Describe("Given a pull-request hook payload", func() { + g.It("should return err when malformed", func() { buf := bytes.NewBufferString("[]") req, _ := http.NewRequest("POST", "/hook", buf) req.Header = http.Header{} @@ -53,19 +53,7 @@ func Test_parser(t *testing.T) { g.Assert(err).IsNotNil() }) - g.It("Should return nil if not open", func() { - buf := bytes.NewBufferString(fixtures.HookMerged) - req, _ := http.NewRequest("POST", "/hook", buf) - req.Header = http.Header{} - req.Header.Set(hookEvent, hookPullCreated) - - r, b, err := parseHook(req) - g.Assert(r).IsNil() - g.Assert(b).IsNil() - g.Assert(err).IsNil() - }) - - g.It("Should return pull request details", func() { + g.It("should return pull-request details", func() { buf := bytes.NewBufferString(fixtures.HookPull) req, _ := http.NewRequest("POST", "/hook", buf) req.Header = http.Header{} @@ -74,12 +62,39 @@ func Test_parser(t *testing.T) { r, b, err := parseHook(req) g.Assert(err).IsNil() g.Assert(r.FullName).Equal("user_name/repo_name") + g.Assert(b.Event).Equal(model.EventPull) g.Assert(b.Commit).Equal("ce5965ddd289") }) + + g.It("should return pull-request details for a pull-request merged payload", func() { + buf := bytes.NewBufferString(fixtures.HookPullRequestMerged) + req, _ := http.NewRequest("POST", "/hook", buf) + req.Header = http.Header{} + req.Header.Set(hookEvent, hookPullMerged) + + r, b, err := parseHook(req) + g.Assert(err).IsNil() + g.Assert(r.FullName).Equal("anbraten/test-2") + g.Assert(b.Event).Equal(model.EventPullClosed) + g.Assert(b.Commit).Equal("6c5f0bc9b2aa") + }) + + g.It("should return pull-request details for a pull-request closed payload", func() { + buf := bytes.NewBufferString(fixtures.HookPullRequestDeclined) + req, _ := http.NewRequest("POST", "/hook", buf) + req.Header = http.Header{} + req.Header.Set(hookEvent, hookPullDeclined) + + r, b, err := parseHook(req) + g.Assert(err).IsNil() + g.Assert(r.FullName).Equal("anbraten/test-2") + g.Assert(b.Event).Equal(model.EventPullClosed) + g.Assert(b.Commit).Equal("006704dbeab2") + }) }) g.Describe("Given a push hook payload", func() { - g.It("Should return err when malformed", func() { + g.It("should return err when malformed", func() { buf := bytes.NewBufferString("[]") req, _ := http.NewRequest("POST", "/hook", buf) req.Header = http.Header{} @@ -89,7 +104,7 @@ func Test_parser(t *testing.T) { g.Assert(err).IsNotNil() }) - g.It("Should return nil if missing commit sha", func() { + g.It("should return nil if missing commit sha", func() { buf := bytes.NewBufferString(fixtures.HookPushEmptyHash) req, _ := http.NewRequest("POST", "/hook", buf) req.Header = http.Header{} @@ -101,7 +116,7 @@ func Test_parser(t *testing.T) { g.Assert(err).IsNil() }) - g.It("Should return push details", func() { + g.It("should return push details", func() { buf := bytes.NewBufferString(fixtures.HookPush) req, _ := http.NewRequest("POST", "/hook", buf) req.Header = http.Header{} @@ -116,5 +131,9 @@ func Test_parser(t *testing.T) { g.Assert(b.Message).Equal("a\n") }) }) + + g.Describe("Given a tag hook payload", func() { + // TODO + }) }) } diff --git a/server/forge/gitea/fixtures/hooks.go b/server/forge/gitea/fixtures/hooks.go index 5140a8396..397c9b40b 100644 --- a/server/forge/gitea/fixtures/hooks.go +++ b/server/forge/gitea/fixtures/hooks.go @@ -229,8 +229,8 @@ const HookPushBranch = ` } ` -// HookPushTag is a sample Gitea tag hook -const HookPushTag = `{ +// HookTag is a sample Gitea tag hook +const HookTag = `{ "sha": "ef98532add3b2feb7a137426bba1248724367df5", "secret": "l26Un7G7HXogLAvsyf2hOA4EMARSTsR3", "ref": "v1.0.0", @@ -331,3 +331,743 @@ const HookPullRequest = `{ "avatar_url": "https://secure.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87" } }` + +const HookPullRequestMerged = ` +{ + "action": "closed", + "number": 1, + "pull_request": { + "id": 62112, + "url": "https://gitea.com/anbraten/test-repo/pulls/1", + "number": 1, + "user": { + "id": 26907, + "login": "anbraten", + "login_name": "", + "full_name": "", + "email": "anbraten@noreply.gitea.com", + "avatar_url": "https://seccdn.libravatar.org/avatar/fc9b6fe77c6b732a02925a62a81f05a0?d=identicon", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2021-07-19T23:21:52Z", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 1, + "username": "anbraten" + }, + "title": "Adjust file", + "body": "", + "labels": [], + "milestone": null, + "assignee": null, + "assignees": null, + "requested_reviewers": null, + "state": "closed", + "is_locked": false, + "comments": 1, + "html_url": "https://gitea.com/anbraten/test-repo/pulls/1", + "diff_url": "https://gitea.com/anbraten/test-repo/pulls/1.diff", + "patch_url": "https://gitea.com/anbraten/test-repo/pulls/1.patch", + "mergeable": true, + "merged": true, + "merged_at": "2023-12-05T18:35:31Z", + "merge_commit_sha": "f2440f050054df0f8ecabcace648f1683509064c", + "merged_by": { + "id": 26907, + "login": "anbraten", + "login_name": "", + "full_name": "", + "email": "anbraten@noreply.gitea.com", + "avatar_url": "https://seccdn.libravatar.org/avatar/fc9b6fe77c6b732a02925a62a81f05a0?d=identicon", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2021-07-19T23:21:52Z", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 1, + "username": "anbraten" + }, + "allow_maintainer_edit": false, + "base": { + "label": "main", + "ref": "main", + "sha": "f2440f050054df0f8ecabcace648f1683509064c", + "repo_id": 46534, + "repo": { + "id": 46534, + "owner": { + "id": 26907, + "login": "anbraten", + "login_name": "", + "full_name": "", + "email": "anbraten@noreply.gitea.com", + "avatar_url": "https://seccdn.libravatar.org/avatar/fc9b6fe77c6b732a02925a62a81f05a0?d=identicon", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2021-07-19T23:21:52Z", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 1, + "username": "anbraten" + }, + "name": "test-repo", + "full_name": "anbraten/test-repo", + "description": "", + "empty": false, + "private": false, + "fork": false, + "template": false, + "parent": null, + "mirror": false, + "size": 26, + "language": "", + "languages_url": "https://gitea.com/api/v1/repos/anbraten/test-repo/languages", + "html_url": "https://gitea.com/anbraten/test-repo", + "url": "https://gitea.com/api/v1/repos/anbraten/test-repo", + "link": "", + "ssh_url": "git@gitea.com:anbraten/test-repo.git", + "clone_url": "https://gitea.com/anbraten/test-repo.git", + "original_url": "", + "website": "", + "stars_count": 0, + "forks_count": 0, + "watchers_count": 1, + "open_issues_count": 0, + "open_pr_counter": 1, + "release_counter": 0, + "default_branch": "main", + "archived": false, + "created_at": "2023-12-05T18:03:55Z", + "updated_at": "2023-12-05T18:06:29Z", + "archived_at": "1970-01-01T00:00:00Z", + "permissions": { + "admin": false, + "push": false, + "pull": true + }, + "has_issues": true, + "internal_tracker": { + "enable_time_tracker": true, + "allow_only_contributors_to_track_time": true, + "enable_issue_dependencies": true + }, + "has_wiki": true, + "has_pull_requests": true, + "has_projects": true, + "has_releases": true, + "has_packages": false, + "has_actions": true, + "ignore_whitespace_conflicts": false, + "allow_merge_commits": true, + "allow_rebase": true, + "allow_rebase_explicit": true, + "allow_squash_merge": true, + "allow_rebase_update": true, + "default_delete_branch_after_merge": false, + "default_merge_style": "merge", + "default_allow_maintainer_edit": false, + "avatar_url": "", + "internal": false, + "mirror_interval": "", + "mirror_updated": "0001-01-01T00:00:00Z", + "repo_transfer": null + } + }, + "head": { + "label": "anbraten-patch-1", + "ref": "anbraten-patch-1", + "sha": "d555a5dd07f4d0148a58d4686ec381502ae6a2d4", + "repo_id": 46534, + "repo": { + "id": 46534, + "owner": { + "id": 26907, + "login": "anbraten", + "login_name": "", + "full_name": "", + "email": "anbraten@noreply.gitea.com", + "avatar_url": "https://seccdn.libravatar.org/avatar/fc9b6fe77c6b732a02925a62a81f05a0?d=identicon", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2021-07-19T23:21:52Z", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 1, + "username": "anbraten" + }, + "name": "test-repo", + "full_name": "anbraten/test-repo", + "description": "", + "empty": false, + "private": false, + "fork": false, + "template": false, + "parent": null, + "mirror": false, + "size": 26, + "language": "", + "languages_url": "https://gitea.com/api/v1/repos/anbraten/test-repo/languages", + "html_url": "https://gitea.com/anbraten/test-repo", + "url": "https://gitea.com/api/v1/repos/anbraten/test-repo", + "link": "", + "ssh_url": "git@gitea.com:anbraten/test-repo.git", + "clone_url": "https://gitea.com/anbraten/test-repo.git", + "original_url": "", + "website": "", + "stars_count": 0, + "forks_count": 0, + "watchers_count": 1, + "open_issues_count": 0, + "open_pr_counter": 1, + "release_counter": 0, + "default_branch": "main", + "archived": false, + "created_at": "2023-12-05T18:03:55Z", + "updated_at": "2023-12-05T18:06:29Z", + "archived_at": "1970-01-01T00:00:00Z", + "permissions": { + "admin": false, + "push": false, + "pull": true + }, + "has_issues": true, + "internal_tracker": { + "enable_time_tracker": true, + "allow_only_contributors_to_track_time": true, + "enable_issue_dependencies": true + }, + "has_wiki": true, + "has_pull_requests": true, + "has_projects": true, + "has_releases": true, + "has_packages": false, + "has_actions": true, + "ignore_whitespace_conflicts": false, + "allow_merge_commits": true, + "allow_rebase": true, + "allow_rebase_explicit": true, + "allow_squash_merge": true, + "allow_rebase_update": true, + "default_delete_branch_after_merge": false, + "default_merge_style": "merge", + "default_allow_maintainer_edit": false, + "avatar_url": "", + "internal": false, + "mirror_interval": "", + "mirror_updated": "0001-01-01T00:00:00Z", + "repo_transfer": null + } + }, + "merge_base": "068aee163ffd44eef28a7f9ebd43e2c01774f0fa", + "due_date": null, + "created_at": "2023-12-05T18:06:38Z", + "updated_at": "2023-12-05T18:35:31Z", + "closed_at": "2023-12-05T18:35:31Z", + "pin_order": 0 + }, + "requested_reviewer": null, + "repository": { + "id": 46534, + "owner": { + "id": 26907, + "login": "anbraten", + "login_name": "", + "full_name": "", + "email": "anbraten@noreply.gitea.com", + "avatar_url": "https://seccdn.libravatar.org/avatar/fc9b6fe77c6b732a02925a62a81f05a0?d=identicon", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2021-07-19T23:21:52Z", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 1, + "username": "anbraten" + }, + "name": "test-repo", + "full_name": "anbraten/test-repo", + "description": "", + "empty": false, + "private": false, + "fork": false, + "template": false, + "parent": null, + "mirror": false, + "size": 26, + "language": "", + "languages_url": "https://gitea.com/api/v1/repos/anbraten/test-repo/languages", + "html_url": "https://gitea.com/anbraten/test-repo", + "url": "https://gitea.com/api/v1/repos/anbraten/test-repo", + "link": "", + "ssh_url": "git@gitea.com:anbraten/test-repo.git", + "clone_url": "https://gitea.com/anbraten/test-repo.git", + "original_url": "", + "website": "", + "stars_count": 0, + "forks_count": 0, + "watchers_count": 1, + "open_issues_count": 0, + "open_pr_counter": 1, + "release_counter": 0, + "default_branch": "main", + "archived": false, + "created_at": "2023-12-05T18:03:55Z", + "updated_at": "2023-12-05T18:06:29Z", + "archived_at": "1970-01-01T00:00:00Z", + "permissions": { + "admin": true, + "push": true, + "pull": true + }, + "has_issues": true, + "internal_tracker": { + "enable_time_tracker": true, + "allow_only_contributors_to_track_time": true, + "enable_issue_dependencies": true + }, + "has_wiki": true, + "has_pull_requests": true, + "has_projects": true, + "has_releases": true, + "has_packages": false, + "has_actions": true, + "ignore_whitespace_conflicts": false, + "allow_merge_commits": true, + "allow_rebase": true, + "allow_rebase_explicit": true, + "allow_squash_merge": true, + "allow_rebase_update": true, + "default_delete_branch_after_merge": false, + "default_merge_style": "merge", + "default_allow_maintainer_edit": false, + "avatar_url": "", + "internal": false, + "mirror_interval": "", + "mirror_updated": "0001-01-01T00:00:00Z", + "repo_transfer": null + }, + "sender": { + "id": 26907, + "login": "anbraten", + "login_name": "", + "full_name": "", + "email": "anbraten@noreply.gitea.com", + "avatar_url": "https://seccdn.libravatar.org/avatar/fc9b6fe77c6b732a02925a62a81f05a0?d=identicon", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2021-07-19T23:21:52Z", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 1, + "username": "anbraten" + }, + "commit_id": "", + "review": null +} +` + +const HookPullRequestClosed = ` +{ + "action": "closed", + "number": 1, + "pull_request": { + "id": 62112, + "url": "https://gitea.com/anbraten/test-repo/pulls/1", + "number": 1, + "user": { + "id": 26907, + "login": "anbraten", + "login_name": "", + "full_name": "", + "email": "anbraten@noreply.gitea.com", + "avatar_url": "https://seccdn.libravatar.org/avatar/fc9b6fe77c6b732a02925a62a81f05a0?d=identicon", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2021-07-19T23:21:52Z", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 1, + "username": "anbraten" + }, + "title": "Adjust file", + "body": "", + "labels": [], + "milestone": null, + "assignee": null, + "assignees": null, + "requested_reviewers": null, + "state": "closed", + "is_locked": false, + "comments": 0, + "html_url": "https://gitea.com/anbraten/test-repo/pulls/1", + "diff_url": "https://gitea.com/anbraten/test-repo/pulls/1.diff", + "patch_url": "https://gitea.com/anbraten/test-repo/pulls/1.patch", + "mergeable": true, + "merged": false, + "merged_at": null, + "merge_commit_sha": null, + "merged_by": null, + "allow_maintainer_edit": false, + "base": { + "label": "main", + "ref": "main", + "sha": "068aee163ffd44eef28a7f9ebd43e2c01774f0fa", + "repo_id": 46534, + "repo": { + "id": 46534, + "owner": { + "id": 26907, + "login": "anbraten", + "login_name": "", + "full_name": "", + "email": "anbraten@noreply.gitea.com", + "avatar_url": "https://seccdn.libravatar.org/avatar/fc9b6fe77c6b732a02925a62a81f05a0?d=identicon", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2021-07-19T23:21:52Z", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 1, + "username": "anbraten" + }, + "name": "test-repo", + "full_name": "anbraten/test-repo", + "description": "", + "empty": false, + "private": false, + "fork": false, + "template": false, + "parent": null, + "mirror": false, + "size": 26, + "language": "", + "languages_url": "https://gitea.com/api/v1/repos/anbraten/test-repo/languages", + "html_url": "https://gitea.com/anbraten/test-repo", + "url": "https://gitea.com/api/v1/repos/anbraten/test-repo", + "link": "", + "ssh_url": "git@gitea.com:anbraten/test-repo.git", + "clone_url": "https://gitea.com/anbraten/test-repo.git", + "original_url": "", + "website": "", + "stars_count": 0, + "forks_count": 0, + "watchers_count": 1, + "open_issues_count": 0, + "open_pr_counter": 1, + "release_counter": 0, + "default_branch": "main", + "archived": false, + "created_at": "2023-12-05T18:03:55Z", + "updated_at": "2023-12-05T18:06:29Z", + "archived_at": "1970-01-01T00:00:00Z", + "permissions": { + "admin": false, + "push": false, + "pull": true + }, + "has_issues": true, + "internal_tracker": { + "enable_time_tracker": true, + "allow_only_contributors_to_track_time": true, + "enable_issue_dependencies": true + }, + "has_wiki": true, + "has_pull_requests": true, + "has_projects": true, + "has_releases": true, + "has_packages": false, + "has_actions": true, + "ignore_whitespace_conflicts": false, + "allow_merge_commits": true, + "allow_rebase": true, + "allow_rebase_explicit": true, + "allow_squash_merge": true, + "allow_rebase_update": true, + "default_delete_branch_after_merge": false, + "default_merge_style": "merge", + "default_allow_maintainer_edit": false, + "avatar_url": "", + "internal": false, + "mirror_interval": "", + "mirror_updated": "0001-01-01T00:00:00Z", + "repo_transfer": null + } + }, + "head": { + "label": "anbraten-patch-1", + "ref": "anbraten-patch-1", + "sha": "d555a5dd07f4d0148a58d4686ec381502ae6a2d4", + "repo_id": 46534, + "repo": { + "id": 46534, + "owner": { + "id": 26907, + "login": "anbraten", + "login_name": "", + "full_name": "", + "email": "anbraten@noreply.gitea.com", + "avatar_url": "https://seccdn.libravatar.org/avatar/fc9b6fe77c6b732a02925a62a81f05a0?d=identicon", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2021-07-19T23:21:52Z", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 1, + "username": "anbraten" + }, + "name": "test-repo", + "full_name": "anbraten/test-repo", + "description": "", + "empty": false, + "private": false, + "fork": false, + "template": false, + "parent": null, + "mirror": false, + "size": 26, + "language": "", + "languages_url": "https://gitea.com/api/v1/repos/anbraten/test-repo/languages", + "html_url": "https://gitea.com/anbraten/test-repo", + "url": "https://gitea.com/api/v1/repos/anbraten/test-repo", + "link": "", + "ssh_url": "git@gitea.com:anbraten/test-repo.git", + "clone_url": "https://gitea.com/anbraten/test-repo.git", + "original_url": "", + "website": "", + "stars_count": 0, + "forks_count": 0, + "watchers_count": 1, + "open_issues_count": 0, + "open_pr_counter": 1, + "release_counter": 0, + "default_branch": "main", + "archived": false, + "created_at": "2023-12-05T18:03:55Z", + "updated_at": "2023-12-05T18:06:29Z", + "archived_at": "1970-01-01T00:00:00Z", + "permissions": { + "admin": false, + "push": false, + "pull": true + }, + "has_issues": true, + "internal_tracker": { + "enable_time_tracker": true, + "allow_only_contributors_to_track_time": true, + "enable_issue_dependencies": true + }, + "has_wiki": true, + "has_pull_requests": true, + "has_projects": true, + "has_releases": true, + "has_packages": false, + "has_actions": true, + "ignore_whitespace_conflicts": false, + "allow_merge_commits": true, + "allow_rebase": true, + "allow_rebase_explicit": true, + "allow_squash_merge": true, + "allow_rebase_update": true, + "default_delete_branch_after_merge": false, + "default_merge_style": "merge", + "default_allow_maintainer_edit": false, + "avatar_url": "", + "internal": false, + "mirror_interval": "", + "mirror_updated": "0001-01-01T00:00:00Z", + "repo_transfer": null + } + }, + "merge_base": "068aee163ffd44eef28a7f9ebd43e2c01774f0fa", + "due_date": null, + "created_at": "2023-12-05T18:06:38Z", + "updated_at": "2023-12-05T18:06:43Z", + "closed_at": "2023-12-05T18:06:43Z", + "pin_order": 0 + }, + "requested_reviewer": null, + "repository": { + "id": 46534, + "owner": { + "id": 26907, + "login": "anbraten", + "login_name": "", + "full_name": "", + "email": "anbraten@noreply.gitea.com", + "avatar_url": "https://seccdn.libravatar.org/avatar/fc9b6fe77c6b732a02925a62a81f05a0?d=identicon", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2021-07-19T23:21:52Z", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 1, + "username": "anbraten" + }, + "name": "test-repo", + "full_name": "anbraten/test-repo", + "description": "", + "empty": false, + "private": false, + "fork": false, + "template": false, + "parent": null, + "mirror": false, + "size": 26, + "language": "", + "languages_url": "https://gitea.com/api/v1/repos/anbraten/test-repo/languages", + "html_url": "https://gitea.com/anbraten/test-repo", + "url": "https://gitea.com/api/v1/repos/anbraten/test-repo", + "link": "", + "ssh_url": "git@gitea.com:anbraten/test-repo.git", + "clone_url": "https://gitea.com/anbraten/test-repo.git", + "original_url": "", + "website": "", + "stars_count": 0, + "forks_count": 0, + "watchers_count": 1, + "open_issues_count": 0, + "open_pr_counter": 1, + "release_counter": 0, + "default_branch": "main", + "archived": false, + "created_at": "2023-12-05T18:03:55Z", + "updated_at": "2023-12-05T18:06:29Z", + "archived_at": "1970-01-01T00:00:00Z", + "permissions": { + "admin": true, + "push": true, + "pull": true + }, + "has_issues": true, + "internal_tracker": { + "enable_time_tracker": true, + "allow_only_contributors_to_track_time": true, + "enable_issue_dependencies": true + }, + "has_wiki": true, + "has_pull_requests": true, + "has_projects": true, + "has_releases": true, + "has_packages": false, + "has_actions": true, + "ignore_whitespace_conflicts": false, + "allow_merge_commits": true, + "allow_rebase": true, + "allow_rebase_explicit": true, + "allow_squash_merge": true, + "allow_rebase_update": true, + "default_delete_branch_after_merge": false, + "default_merge_style": "merge", + "default_allow_maintainer_edit": false, + "avatar_url": "", + "internal": false, + "mirror_interval": "", + "mirror_updated": "0001-01-01T00:00:00Z", + "repo_transfer": null + }, + "sender": { + "id": 26907, + "login": "anbraten", + "login_name": "", + "full_name": "", + "email": "anbraten@noreply.gitea.com", + "avatar_url": "https://seccdn.libravatar.org/avatar/fc9b6fe77c6b732a02925a62a81f05a0?d=identicon", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2021-07-19T23:21:52Z", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 1, + "username": "anbraten" + }, + "commit_id": "", + "review": null +} +` diff --git a/server/forge/gitea/helper.go b/server/forge/gitea/helper.go index 7d00d78a8..6972224a7 100644 --- a/server/forge/gitea/helper.go +++ b/server/forge/gitea/helper.go @@ -148,8 +148,14 @@ func pipelineFromPullRequest(hook *pullRequestHook) *model.Pipeline { hook.Repo.HTMLURL, fixMalformedAvatar(hook.PullRequest.Poster.AvatarURL), ) + + event := model.EventPull + if hook.Action == actionClose { + event = model.EventPullClosed + } + pipeline := &model.Pipeline{ - Event: model.EventPull, + Event: event, Commit: hook.PullRequest.Head.Sha, ForgeURL: hook.PullRequest.URL, Ref: fmt.Sprintf("refs/pull/%d/head", hook.Number), @@ -165,6 +171,7 @@ func pipelineFromPullRequest(hook *pullRequestHook) *model.Pipeline { ), PullRequestLabels: convertLabels(hook.PullRequest.Labels), } + return pipeline } diff --git a/server/forge/gitea/helper_test.go b/server/forge/gitea/helper_test.go index e2972f8d2..77f74091a 100644 --- a/server/forge/gitea/helper_test.go +++ b/server/forge/gitea/helper_test.go @@ -51,7 +51,7 @@ func Test_parse(t *testing.T) { }) g.It("Should parse tag hook payload", func() { - buf := bytes.NewBufferString(fixtures.HookPushTag) + buf := bytes.NewBufferString(fixtures.HookTag) hook, err := parsePush(buf) g.Assert(err).IsNil() g.Assert(hook.Ref).Equal("v1.0.0") @@ -118,7 +118,7 @@ func Test_parse(t *testing.T) { }) g.It("Should return a Pipeline struct from a tag hook", func() { - buf := bytes.NewBufferString(fixtures.HookPushTag) + buf := bytes.NewBufferString(fixtures.HookTag) hook, _ := parsePush(buf) pipeline := pipelineFromTag(hook) g.Assert(pipeline.Event).Equal(model.EventTag) diff --git a/server/forge/gitea/parse.go b/server/forge/gitea/parse.go index fc4f42e9d..e007ab012 100644 --- a/server/forge/gitea/parse.go +++ b/server/forge/gitea/parse.go @@ -32,10 +32,9 @@ const ( hookCreated = "create" hookPullRequest = "pull_request" - actionOpen = "opened" - actionSync = "synchronized" - - stateOpen = "open" + actionOpen = "opened" + actionSync = "synchronized" + actionClose = "closed" refBranch = "branch" refTag = "tag" @@ -53,7 +52,7 @@ func parseHook(r *http.Request) (*model.Repo, *model.Pipeline, error) { case hookPullRequest: return parsePullRequestHook(r.Body) } - log.Debug().Msgf("unsuported hook type: '%s'", hookType) + log.Debug().Msgf("unsupported hook type: '%s'", hookType) return nil, nil, &types.ErrIgnoreEvent{Event: hookType} } @@ -110,15 +109,10 @@ func parsePullRequestHook(payload io.Reader) (*model.Repo, *model.Pipeline, erro } // Don't trigger pipelines for non-code changes ... - if pr.Action != actionOpen && pr.Action != actionSync { + if pr.Action != actionOpen && pr.Action != actionSync && pr.Action != actionClose { log.Debug().Msgf("pull_request action is '%s' and no open or sync", pr.Action) return nil, nil, nil } - // ... or if PR is not open - if pr.PullRequest.State != stateOpen { - log.Debug().Msg("pull_request is closed") - return nil, nil, nil - } repo = toRepo(pr.Repo) pipeline = pipelineFromPullRequest(pr) diff --git a/server/forge/gitea/parse_test.go b/server/forge/gitea/parse_test.go index 1945b9508..6bca466e7 100644 --- a/server/forge/gitea/parse_test.go +++ b/server/forge/gitea/parse_test.go @@ -42,18 +42,22 @@ func Test_parser(t *testing.T) { g.Assert(b).IsNil() assert.ErrorIs(t, err, &types.ErrIgnoreEvent{}) }) - g.It("given a PR hook", func() { - buf := bytes.NewBufferString(fixtures.HookPullRequest) - req, _ := http.NewRequest("POST", "/hook", buf) - req.Header = http.Header{} - req.Header.Set(hookEvent, hookPullRequest) - r, b, err := parseHook(req) - g.Assert(r).IsNotNil() - g.Assert(b).IsNotNil() - g.Assert(err).IsNil() - g.Assert(b.Event).Equal(model.EventPull) - }) - g.Describe("given a push hook", func() { + + g.Describe("push event", func() { + g.It("should handle a push hook", func() { + buf := bytes.NewBufferString(fixtures.HookPushBranch) + req, _ := http.NewRequest("POST", "/hook", buf) + req.Header = http.Header{} + req.Header.Set(hookEvent, hookPush) + r, b, err := parseHook(req) + g.Assert(err).IsNil() + g.Assert(r).IsNotNil() + g.Assert(b).IsNotNil() + g.Assert(b.Event).Equal(model.EventPush) + g.Assert(b.Message).Equal("Delete '.woodpecker/.check.yml'\n") + g.Assert(b.ChangedFiles).Equal([]string{".woodpecker/.check.yml"}) + }) + g.It("should extract repository and pipeline details", func() { buf := bytes.NewBufferString(fixtures.HookPush) req, _ := http.NewRequest("POST", "/hook", buf) @@ -67,19 +71,58 @@ func Test_parser(t *testing.T) { g.Assert(utils.EqualSliceValues(b.ChangedFiles, []string{"CHANGELOG.md", "app/controller/application.rb"})).IsTrue() }) }) - g.Describe("given a push hook from an branch creation", func() { - g.It("should extract repository and pipeline details", func() { - buf := bytes.NewBufferString(fixtures.HookPushBranch) + + g.Describe("tag event", func() { + g.It("should handle a tag hook", func() { + buf := bytes.NewBufferString(fixtures.HookTag) req, _ := http.NewRequest("POST", "/hook", buf) req.Header = http.Header{} - req.Header.Set(hookEvent, hookPush) + req.Header.Set(hookEvent, hookCreated) r, b, err := parseHook(req) - g.Assert(err).IsNil() g.Assert(r).IsNotNil() g.Assert(b).IsNotNil() - g.Assert(b.Event).Equal(model.EventPush) - g.Assert(b.Message).Equal("Delete '.woodpecker/.check.yml'\n") - g.Assert(b.ChangedFiles).Equal([]string{".woodpecker/.check.yml"}) + g.Assert(err).IsNil() + g.Assert(b.Event).Equal(model.EventTag) + }) + }) + + g.Describe("pull-request events", func() { + // g.It("should handle a PR hook when PR got created") + + g.It("should handle a PR hook when PR got updated", func() { + buf := bytes.NewBufferString(fixtures.HookPullRequest) + req, _ := http.NewRequest("POST", "/hook", buf) + req.Header = http.Header{} + req.Header.Set(hookEvent, hookPullRequest) + r, b, err := parseHook(req) + g.Assert(r).IsNotNil() + g.Assert(b).IsNotNil() + g.Assert(err).IsNil() + g.Assert(b.Event).Equal(model.EventPull) + }) + + g.It("should handle a PR closed hook when PR got closed", func() { + buf := bytes.NewBufferString(fixtures.HookPullRequestClosed) + req, _ := http.NewRequest("POST", "/hook", buf) + req.Header = http.Header{} + req.Header.Set(hookEvent, hookPullRequest) + r, b, err := parseHook(req) + g.Assert(r).IsNotNil() + g.Assert(b).IsNotNil() + g.Assert(err).IsNil() + g.Assert(b.Event).Equal(model.EventPullClosed) + }) + + g.It("should handle a PR closed hook when PR was merged", func() { + buf := bytes.NewBufferString(fixtures.HookPullRequestMerged) + req, _ := http.NewRequest("POST", "/hook", buf) + req.Header = http.Header{} + req.Header.Set(hookEvent, hookPullRequest) + r, b, err := parseHook(req) + g.Assert(r).IsNotNil() + g.Assert(b).IsNotNil() + g.Assert(err).IsNil() + g.Assert(b.Event).Equal(model.EventPullClosed) }) }) }) diff --git a/server/forge/github/fixtures/hooks.go b/server/forge/github/fixtures/hooks.go index 3ca322632..1c6403597 100644 --- a/server/forge/github/fixtures/hooks.go +++ b/server/forge/github/fixtures/hooks.go @@ -352,3 +352,1042 @@ const HookDeploy = ` } } ` + +const HookPullRequestMerged = ` +{ + "action": "closed", + "number": 62, + "pull_request": { + "url": "https://api.github.com/repos/anbraten/test-ready-release-go/pulls/62", + "id": 1630965956, + "node_id": "PR_kwDOIl-VNc5hNpDE", + "html_url": "https://github.com/anbraten/test-ready-release-go/pull/62", + "diff_url": "https://github.com/anbraten/test-ready-release-go/pull/62.diff", + "patch_url": "https://github.com/anbraten/test-ready-release-go/pull/62.patch", + "issue_url": "https://api.github.com/repos/anbraten/test-ready-release-go/issues/62", + "number": 62, + "state": "closed", + "locked": false, + "title": "Change file", + "user": { + "login": "anbraten", + "id": 6918444, + "node_id": "MDQ6VXNlcjY5MTg0NDQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/6918444?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/anbraten", + "html_url": "https://github.com/anbraten", + "followers_url": "https://api.github.com/users/anbraten/followers", + "following_url": "https://api.github.com/users/anbraten/following{/other_user}", + "gists_url": "https://api.github.com/users/anbraten/gists{/gist_id}", + "starred_url": "https://api.github.com/users/anbraten/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/anbraten/subscriptions", + "organizations_url": "https://api.github.com/users/anbraten/orgs", + "repos_url": "https://api.github.com/users/anbraten/repos", + "events_url": "https://api.github.com/users/anbraten/events{/privacy}", + "received_events_url": "https://api.github.com/users/anbraten/received_events", + "type": "User", + "site_admin": false + }, + "body": null, + "created_at": "2023-12-05T18:13:16Z", + "updated_at": "2023-12-05T18:34:19Z", + "closed_at": "2023-12-05T18:34:19Z", + "merged_at": "2023-12-05T18:34:19Z", + "merge_commit_sha": "473d70eb7c50a54ae62bf9b124efa1c3eb245be8", + "assignee": null, + "assignees": [], + "requested_reviewers": [], + "requested_teams": [], + "labels": [], + "milestone": null, + "draft": false, + "commits_url": "https://api.github.com/repos/anbraten/test-ready-release-go/pulls/62/commits", + "review_comments_url": "https://api.github.com/repos/anbraten/test-ready-release-go/pulls/62/comments", + "review_comment_url": "https://api.github.com/repos/anbraten/test-ready-release-go/pulls/comments{/number}", + "comments_url": "https://api.github.com/repos/anbraten/test-ready-release-go/issues/62/comments", + "statuses_url": "https://api.github.com/repos/anbraten/test-ready-release-go/statuses/c88b9ee719285134957cbc698c9b7ef9b78007bf", + "head": { + "label": "anbraten:anbraten-patch-3", + "ref": "anbraten-patch-3", + "sha": "c88b9ee719285134957cbc698c9b7ef9b78007bf", + "user": { + "login": "anbraten", + "id": 6918444, + "node_id": "MDQ6VXNlcjY5MTg0NDQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/6918444?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/anbraten", + "html_url": "https://github.com/anbraten", + "followers_url": "https://api.github.com/users/anbraten/followers", + "following_url": "https://api.github.com/users/anbraten/following{/other_user}", + "gists_url": "https://api.github.com/users/anbraten/gists{/gist_id}", + "starred_url": "https://api.github.com/users/anbraten/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/anbraten/subscriptions", + "organizations_url": "https://api.github.com/users/anbraten/orgs", + "repos_url": "https://api.github.com/users/anbraten/repos", + "events_url": "https://api.github.com/users/anbraten/events{/privacy}", + "received_events_url": "https://api.github.com/users/anbraten/received_events", + "type": "User", + "site_admin": false + }, + "repo": { + "id": 576689461, + "node_id": "R_kgDOIl-VNQ", + "name": "test-ready-release-go", + "full_name": "anbraten/test-ready-release-go", + "private": false, + "owner": { + "login": "anbraten", + "id": 6918444, + "node_id": "MDQ6VXNlcjY5MTg0NDQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/6918444?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/anbraten", + "html_url": "https://github.com/anbraten", + "followers_url": "https://api.github.com/users/anbraten/followers", + "following_url": "https://api.github.com/users/anbraten/following{/other_user}", + "gists_url": "https://api.github.com/users/anbraten/gists{/gist_id}", + "starred_url": "https://api.github.com/users/anbraten/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/anbraten/subscriptions", + "organizations_url": "https://api.github.com/users/anbraten/orgs", + "repos_url": "https://api.github.com/users/anbraten/repos", + "events_url": "https://api.github.com/users/anbraten/events{/privacy}", + "received_events_url": "https://api.github.com/users/anbraten/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://github.com/anbraten/test-ready-release-go", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/anbraten/test-ready-release-go", + "forks_url": "https://api.github.com/repos/anbraten/test-ready-release-go/forks", + "keys_url": "https://api.github.com/repos/anbraten/test-ready-release-go/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/anbraten/test-ready-release-go/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/anbraten/test-ready-release-go/teams", + "hooks_url": "https://api.github.com/repos/anbraten/test-ready-release-go/hooks", + "issue_events_url": "https://api.github.com/repos/anbraten/test-ready-release-go/issues/events{/number}", + "events_url": "https://api.github.com/repos/anbraten/test-ready-release-go/events", + "assignees_url": "https://api.github.com/repos/anbraten/test-ready-release-go/assignees{/user}", + "branches_url": "https://api.github.com/repos/anbraten/test-ready-release-go/branches{/branch}", + "tags_url": "https://api.github.com/repos/anbraten/test-ready-release-go/tags", + "blobs_url": "https://api.github.com/repos/anbraten/test-ready-release-go/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/anbraten/test-ready-release-go/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/anbraten/test-ready-release-go/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/anbraten/test-ready-release-go/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/anbraten/test-ready-release-go/statuses/{sha}", + "languages_url": "https://api.github.com/repos/anbraten/test-ready-release-go/languages", + "stargazers_url": "https://api.github.com/repos/anbraten/test-ready-release-go/stargazers", + "contributors_url": "https://api.github.com/repos/anbraten/test-ready-release-go/contributors", + "subscribers_url": "https://api.github.com/repos/anbraten/test-ready-release-go/subscribers", + "subscription_url": "https://api.github.com/repos/anbraten/test-ready-release-go/subscription", + "commits_url": "https://api.github.com/repos/anbraten/test-ready-release-go/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/anbraten/test-ready-release-go/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/anbraten/test-ready-release-go/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/anbraten/test-ready-release-go/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/anbraten/test-ready-release-go/contents/{+path}", + "compare_url": "https://api.github.com/repos/anbraten/test-ready-release-go/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/anbraten/test-ready-release-go/merges", + "archive_url": "https://api.github.com/repos/anbraten/test-ready-release-go/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/anbraten/test-ready-release-go/downloads", + "issues_url": "https://api.github.com/repos/anbraten/test-ready-release-go/issues{/number}", + "pulls_url": "https://api.github.com/repos/anbraten/test-ready-release-go/pulls{/number}", + "milestones_url": "https://api.github.com/repos/anbraten/test-ready-release-go/milestones{/number}", + "notifications_url": "https://api.github.com/repos/anbraten/test-ready-release-go/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/anbraten/test-ready-release-go/labels{/name}", + "releases_url": "https://api.github.com/repos/anbraten/test-ready-release-go/releases{/id}", + "deployments_url": "https://api.github.com/repos/anbraten/test-ready-release-go/deployments", + "created_at": "2022-12-10T16:59:42Z", + "updated_at": "2023-07-11T17:00:26Z", + "pushed_at": "2023-12-05T18:34:19Z", + "git_url": "git://github.com/anbraten/test-ready-release-go.git", + "ssh_url": "git@github.com:anbraten/test-ready-release-go.git", + "clone_url": "https://github.com/anbraten/test-ready-release-go.git", + "svn_url": "https://github.com/anbraten/test-ready-release-go", + "homepage": null, + "size": 11198, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Go", + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "has_discussions": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 0, + "license": { + "key": "apache-2.0", + "name": "Apache License 2.0", + "spdx_id": "Apache-2.0", + "url": "https://api.github.com/licenses/apache-2.0", + "node_id": "MDc6TGljZW5zZTI=" + }, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [], + "visibility": "public", + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "main", + "allow_squash_merge": true, + "allow_merge_commit": true, + "allow_rebase_merge": true, + "allow_auto_merge": false, + "delete_branch_on_merge": false, + "allow_update_branch": false, + "use_squash_pr_title_as_default": false, + "squash_merge_commit_message": "COMMIT_MESSAGES", + "squash_merge_commit_title": "COMMIT_OR_PR_TITLE", + "merge_commit_message": "PR_TITLE", + "merge_commit_title": "MERGE_MESSAGE" + } + }, + "base": { + "label": "anbraten:main", + "ref": "main", + "sha": "26fd46e0d1237cdabfe84ec6a0f37466fc716952", + "user": { + "login": "anbraten", + "id": 6918444, + "node_id": "MDQ6VXNlcjY5MTg0NDQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/6918444?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/anbraten", + "html_url": "https://github.com/anbraten", + "followers_url": "https://api.github.com/users/anbraten/followers", + "following_url": "https://api.github.com/users/anbraten/following{/other_user}", + "gists_url": "https://api.github.com/users/anbraten/gists{/gist_id}", + "starred_url": "https://api.github.com/users/anbraten/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/anbraten/subscriptions", + "organizations_url": "https://api.github.com/users/anbraten/orgs", + "repos_url": "https://api.github.com/users/anbraten/repos", + "events_url": "https://api.github.com/users/anbraten/events{/privacy}", + "received_events_url": "https://api.github.com/users/anbraten/received_events", + "type": "User", + "site_admin": false + }, + "repo": { + "id": 576689461, + "node_id": "R_kgDOIl-VNQ", + "name": "test-ready-release-go", + "full_name": "anbraten/test-ready-release-go", + "private": false, + "owner": { + "login": "anbraten", + "id": 6918444, + "node_id": "MDQ6VXNlcjY5MTg0NDQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/6918444?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/anbraten", + "html_url": "https://github.com/anbraten", + "followers_url": "https://api.github.com/users/anbraten/followers", + "following_url": "https://api.github.com/users/anbraten/following{/other_user}", + "gists_url": "https://api.github.com/users/anbraten/gists{/gist_id}", + "starred_url": "https://api.github.com/users/anbraten/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/anbraten/subscriptions", + "organizations_url": "https://api.github.com/users/anbraten/orgs", + "repos_url": "https://api.github.com/users/anbraten/repos", + "events_url": "https://api.github.com/users/anbraten/events{/privacy}", + "received_events_url": "https://api.github.com/users/anbraten/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://github.com/anbraten/test-ready-release-go", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/anbraten/test-ready-release-go", + "forks_url": "https://api.github.com/repos/anbraten/test-ready-release-go/forks", + "keys_url": "https://api.github.com/repos/anbraten/test-ready-release-go/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/anbraten/test-ready-release-go/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/anbraten/test-ready-release-go/teams", + "hooks_url": "https://api.github.com/repos/anbraten/test-ready-release-go/hooks", + "issue_events_url": "https://api.github.com/repos/anbraten/test-ready-release-go/issues/events{/number}", + "events_url": "https://api.github.com/repos/anbraten/test-ready-release-go/events", + "assignees_url": "https://api.github.com/repos/anbraten/test-ready-release-go/assignees{/user}", + "branches_url": "https://api.github.com/repos/anbraten/test-ready-release-go/branches{/branch}", + "tags_url": "https://api.github.com/repos/anbraten/test-ready-release-go/tags", + "blobs_url": "https://api.github.com/repos/anbraten/test-ready-release-go/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/anbraten/test-ready-release-go/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/anbraten/test-ready-release-go/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/anbraten/test-ready-release-go/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/anbraten/test-ready-release-go/statuses/{sha}", + "languages_url": "https://api.github.com/repos/anbraten/test-ready-release-go/languages", + "stargazers_url": "https://api.github.com/repos/anbraten/test-ready-release-go/stargazers", + "contributors_url": "https://api.github.com/repos/anbraten/test-ready-release-go/contributors", + "subscribers_url": "https://api.github.com/repos/anbraten/test-ready-release-go/subscribers", + "subscription_url": "https://api.github.com/repos/anbraten/test-ready-release-go/subscription", + "commits_url": "https://api.github.com/repos/anbraten/test-ready-release-go/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/anbraten/test-ready-release-go/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/anbraten/test-ready-release-go/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/anbraten/test-ready-release-go/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/anbraten/test-ready-release-go/contents/{+path}", + "compare_url": "https://api.github.com/repos/anbraten/test-ready-release-go/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/anbraten/test-ready-release-go/merges", + "archive_url": "https://api.github.com/repos/anbraten/test-ready-release-go/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/anbraten/test-ready-release-go/downloads", + "issues_url": "https://api.github.com/repos/anbraten/test-ready-release-go/issues{/number}", + "pulls_url": "https://api.github.com/repos/anbraten/test-ready-release-go/pulls{/number}", + "milestones_url": "https://api.github.com/repos/anbraten/test-ready-release-go/milestones{/number}", + "notifications_url": "https://api.github.com/repos/anbraten/test-ready-release-go/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/anbraten/test-ready-release-go/labels{/name}", + "releases_url": "https://api.github.com/repos/anbraten/test-ready-release-go/releases{/id}", + "deployments_url": "https://api.github.com/repos/anbraten/test-ready-release-go/deployments", + "created_at": "2022-12-10T16:59:42Z", + "updated_at": "2023-07-11T17:00:26Z", + "pushed_at": "2023-12-05T18:34:19Z", + "git_url": "git://github.com/anbraten/test-ready-release-go.git", + "ssh_url": "git@github.com:anbraten/test-ready-release-go.git", + "clone_url": "https://github.com/anbraten/test-ready-release-go.git", + "svn_url": "https://github.com/anbraten/test-ready-release-go", + "homepage": null, + "size": 11198, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Go", + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "has_discussions": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 0, + "license": { + "key": "apache-2.0", + "name": "Apache License 2.0", + "spdx_id": "Apache-2.0", + "url": "https://api.github.com/licenses/apache-2.0", + "node_id": "MDc6TGljZW5zZTI=" + }, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [], + "visibility": "public", + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "main", + "allow_squash_merge": true, + "allow_merge_commit": true, + "allow_rebase_merge": true, + "allow_auto_merge": false, + "delete_branch_on_merge": false, + "allow_update_branch": false, + "use_squash_pr_title_as_default": false, + "squash_merge_commit_message": "COMMIT_MESSAGES", + "squash_merge_commit_title": "COMMIT_OR_PR_TITLE", + "merge_commit_message": "PR_TITLE", + "merge_commit_title": "MERGE_MESSAGE" + } + }, + "_links": { + "self": { + "href": "https://api.github.com/repos/anbraten/test-ready-release-go/pulls/62" + }, + "html": { + "href": "https://github.com/anbraten/test-ready-release-go/pull/62" + }, + "issue": { + "href": "https://api.github.com/repos/anbraten/test-ready-release-go/issues/62" + }, + "comments": { + "href": "https://api.github.com/repos/anbraten/test-ready-release-go/issues/62/comments" + }, + "review_comments": { + "href": "https://api.github.com/repos/anbraten/test-ready-release-go/pulls/62/comments" + }, + "review_comment": { + "href": "https://api.github.com/repos/anbraten/test-ready-release-go/pulls/comments{/number}" + }, + "commits": { + "href": "https://api.github.com/repos/anbraten/test-ready-release-go/pulls/62/commits" + }, + "statuses": { + "href": "https://api.github.com/repos/anbraten/test-ready-release-go/statuses/c88b9ee719285134957cbc698c9b7ef9b78007bf" + } + }, + "author_association": "OWNER", + "auto_merge": null, + "active_lock_reason": null, + "merged": true, + "mergeable": null, + "rebaseable": null, + "mergeable_state": "unknown", + "merged_by": { + "login": "anbraten", + "id": 6918444, + "node_id": "MDQ6VXNlcjY5MTg0NDQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/6918444?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/anbraten", + "html_url": "https://github.com/anbraten", + "followers_url": "https://api.github.com/users/anbraten/followers", + "following_url": "https://api.github.com/users/anbraten/following{/other_user}", + "gists_url": "https://api.github.com/users/anbraten/gists{/gist_id}", + "starred_url": "https://api.github.com/users/anbraten/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/anbraten/subscriptions", + "organizations_url": "https://api.github.com/users/anbraten/orgs", + "repos_url": "https://api.github.com/users/anbraten/repos", + "events_url": "https://api.github.com/users/anbraten/events{/privacy}", + "received_events_url": "https://api.github.com/users/anbraten/received_events", + "type": "User", + "site_admin": false + }, + "comments": 0, + "review_comments": 0, + "maintainer_can_modify": false, + "commits": 1, + "additions": 1, + "deletions": 0, + "changed_files": 1 + }, + "repository": { + "id": 576689461, + "node_id": "R_kgDOIl-VNQ", + "name": "test-ready-release-go", + "full_name": "anbraten/test-ready-release-go", + "private": false, + "owner": { + "login": "anbraten", + "id": 6918444, + "node_id": "MDQ6VXNlcjY5MTg0NDQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/6918444?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/anbraten", + "html_url": "https://github.com/anbraten", + "followers_url": "https://api.github.com/users/anbraten/followers", + "following_url": "https://api.github.com/users/anbraten/following{/other_user}", + "gists_url": "https://api.github.com/users/anbraten/gists{/gist_id}", + "starred_url": "https://api.github.com/users/anbraten/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/anbraten/subscriptions", + "organizations_url": "https://api.github.com/users/anbraten/orgs", + "repos_url": "https://api.github.com/users/anbraten/repos", + "events_url": "https://api.github.com/users/anbraten/events{/privacy}", + "received_events_url": "https://api.github.com/users/anbraten/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://github.com/anbraten/test-ready-release-go", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/anbraten/test-ready-release-go", + "forks_url": "https://api.github.com/repos/anbraten/test-ready-release-go/forks", + "keys_url": "https://api.github.com/repos/anbraten/test-ready-release-go/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/anbraten/test-ready-release-go/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/anbraten/test-ready-release-go/teams", + "hooks_url": "https://api.github.com/repos/anbraten/test-ready-release-go/hooks", + "issue_events_url": "https://api.github.com/repos/anbraten/test-ready-release-go/issues/events{/number}", + "events_url": "https://api.github.com/repos/anbraten/test-ready-release-go/events", + "assignees_url": "https://api.github.com/repos/anbraten/test-ready-release-go/assignees{/user}", + "branches_url": "https://api.github.com/repos/anbraten/test-ready-release-go/branches{/branch}", + "tags_url": "https://api.github.com/repos/anbraten/test-ready-release-go/tags", + "blobs_url": "https://api.github.com/repos/anbraten/test-ready-release-go/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/anbraten/test-ready-release-go/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/anbraten/test-ready-release-go/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/anbraten/test-ready-release-go/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/anbraten/test-ready-release-go/statuses/{sha}", + "languages_url": "https://api.github.com/repos/anbraten/test-ready-release-go/languages", + "stargazers_url": "https://api.github.com/repos/anbraten/test-ready-release-go/stargazers", + "contributors_url": "https://api.github.com/repos/anbraten/test-ready-release-go/contributors", + "subscribers_url": "https://api.github.com/repos/anbraten/test-ready-release-go/subscribers", + "subscription_url": "https://api.github.com/repos/anbraten/test-ready-release-go/subscription", + "commits_url": "https://api.github.com/repos/anbraten/test-ready-release-go/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/anbraten/test-ready-release-go/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/anbraten/test-ready-release-go/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/anbraten/test-ready-release-go/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/anbraten/test-ready-release-go/contents/{+path}", + "compare_url": "https://api.github.com/repos/anbraten/test-ready-release-go/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/anbraten/test-ready-release-go/merges", + "archive_url": "https://api.github.com/repos/anbraten/test-ready-release-go/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/anbraten/test-ready-release-go/downloads", + "issues_url": "https://api.github.com/repos/anbraten/test-ready-release-go/issues{/number}", + "pulls_url": "https://api.github.com/repos/anbraten/test-ready-release-go/pulls{/number}", + "milestones_url": "https://api.github.com/repos/anbraten/test-ready-release-go/milestones{/number}", + "notifications_url": "https://api.github.com/repos/anbraten/test-ready-release-go/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/anbraten/test-ready-release-go/labels{/name}", + "releases_url": "https://api.github.com/repos/anbraten/test-ready-release-go/releases{/id}", + "deployments_url": "https://api.github.com/repos/anbraten/test-ready-release-go/deployments", + "created_at": "2022-12-10T16:59:42Z", + "updated_at": "2023-07-11T17:00:26Z", + "pushed_at": "2023-12-05T18:34:19Z", + "git_url": "git://github.com/anbraten/test-ready-release-go.git", + "ssh_url": "git@github.com:anbraten/test-ready-release-go.git", + "clone_url": "https://github.com/anbraten/test-ready-release-go.git", + "svn_url": "https://github.com/anbraten/test-ready-release-go", + "homepage": null, + "size": 11198, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Go", + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "has_discussions": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 0, + "license": { + "key": "apache-2.0", + "name": "Apache License 2.0", + "spdx_id": "Apache-2.0", + "url": "https://api.github.com/licenses/apache-2.0", + "node_id": "MDc6TGljZW5zZTI=" + }, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [], + "visibility": "public", + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "main" + }, + "sender": { + "login": "anbraten", + "id": 6918444, + "node_id": "MDQ6VXNlcjY5MTg0NDQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/6918444?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/anbraten", + "html_url": "https://github.com/anbraten", + "followers_url": "https://api.github.com/users/anbraten/followers", + "following_url": "https://api.github.com/users/anbraten/following{/other_user}", + "gists_url": "https://api.github.com/users/anbraten/gists{/gist_id}", + "starred_url": "https://api.github.com/users/anbraten/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/anbraten/subscriptions", + "organizations_url": "https://api.github.com/users/anbraten/orgs", + "repos_url": "https://api.github.com/users/anbraten/repos", + "events_url": "https://api.github.com/users/anbraten/events{/privacy}", + "received_events_url": "https://api.github.com/users/anbraten/received_events", + "type": "User", + "site_admin": false + } +} +` + +// HookPullRequest is a sample hook pull request +// https://developer.github.com/v3/activity/events/types/#pullrequestevent +const HookPullRequestClosed = ` +{ + "action": "closed", + "number": 62, + "pull_request": { + "url": "https://api.github.com/repos/anbraten/test-ready-release-go/pulls/62", + "id": 1630965956, + "node_id": "PR_kwDOIl-VNc5hNpDE", + "html_url": "https://github.com/anbraten/test-ready-release-go/pull/62", + "diff_url": "https://github.com/anbraten/test-ready-release-go/pull/62.diff", + "patch_url": "https://github.com/anbraten/test-ready-release-go/pull/62.patch", + "issue_url": "https://api.github.com/repos/anbraten/test-ready-release-go/issues/62", + "number": 62, + "state": "closed", + "locked": false, + "title": "Change file", + "user": { + "login": "anbraten", + "id": 6918444, + "node_id": "MDQ6VXNlcjY5MTg0NDQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/6918444?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/anbraten", + "html_url": "https://github.com/anbraten", + "followers_url": "https://api.github.com/users/anbraten/followers", + "following_url": "https://api.github.com/users/anbraten/following{/other_user}", + "gists_url": "https://api.github.com/users/anbraten/gists{/gist_id}", + "starred_url": "https://api.github.com/users/anbraten/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/anbraten/subscriptions", + "organizations_url": "https://api.github.com/users/anbraten/orgs", + "repos_url": "https://api.github.com/users/anbraten/repos", + "events_url": "https://api.github.com/users/anbraten/events{/privacy}", + "received_events_url": "https://api.github.com/users/anbraten/received_events", + "type": "User", + "site_admin": false + }, + "body": null, + "created_at": "2023-12-05T18:13:16Z", + "updated_at": "2023-12-05T18:14:13Z", + "closed_at": "2023-12-05T18:14:13Z", + "merged_at": null, + "merge_commit_sha": "79fd3b2a13c462ef9b3169b9dee9cb39605fda1b", + "assignee": null, + "assignees": [], + "requested_reviewers": [], + "requested_teams": [], + "labels": [], + "milestone": null, + "draft": false, + "commits_url": "https://api.github.com/repos/anbraten/test-ready-release-go/pulls/62/commits", + "review_comments_url": "https://api.github.com/repos/anbraten/test-ready-release-go/pulls/62/comments", + "review_comment_url": "https://api.github.com/repos/anbraten/test-ready-release-go/pulls/comments{/number}", + "comments_url": "https://api.github.com/repos/anbraten/test-ready-release-go/issues/62/comments", + "statuses_url": "https://api.github.com/repos/anbraten/test-ready-release-go/statuses/c88b9ee719285134957cbc698c9b7ef9b78007bf", + "head": { + "label": "anbraten:anbraten-patch-3", + "ref": "anbraten-patch-3", + "sha": "c88b9ee719285134957cbc698c9b7ef9b78007bf", + "user": { + "login": "anbraten", + "id": 6918444, + "node_id": "MDQ6VXNlcjY5MTg0NDQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/6918444?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/anbraten", + "html_url": "https://github.com/anbraten", + "followers_url": "https://api.github.com/users/anbraten/followers", + "following_url": "https://api.github.com/users/anbraten/following{/other_user}", + "gists_url": "https://api.github.com/users/anbraten/gists{/gist_id}", + "starred_url": "https://api.github.com/users/anbraten/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/anbraten/subscriptions", + "organizations_url": "https://api.github.com/users/anbraten/orgs", + "repos_url": "https://api.github.com/users/anbraten/repos", + "events_url": "https://api.github.com/users/anbraten/events{/privacy}", + "received_events_url": "https://api.github.com/users/anbraten/received_events", + "type": "User", + "site_admin": false + }, + "repo": { + "id": 576689461, + "node_id": "R_kgDOIl-VNQ", + "name": "test-ready-release-go", + "full_name": "anbraten/test-ready-release-go", + "private": false, + "owner": { + "login": "anbraten", + "id": 6918444, + "node_id": "MDQ6VXNlcjY5MTg0NDQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/6918444?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/anbraten", + "html_url": "https://github.com/anbraten", + "followers_url": "https://api.github.com/users/anbraten/followers", + "following_url": "https://api.github.com/users/anbraten/following{/other_user}", + "gists_url": "https://api.github.com/users/anbraten/gists{/gist_id}", + "starred_url": "https://api.github.com/users/anbraten/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/anbraten/subscriptions", + "organizations_url": "https://api.github.com/users/anbraten/orgs", + "repos_url": "https://api.github.com/users/anbraten/repos", + "events_url": "https://api.github.com/users/anbraten/events{/privacy}", + "received_events_url": "https://api.github.com/users/anbraten/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://github.com/anbraten/test-ready-release-go", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/anbraten/test-ready-release-go", + "forks_url": "https://api.github.com/repos/anbraten/test-ready-release-go/forks", + "keys_url": "https://api.github.com/repos/anbraten/test-ready-release-go/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/anbraten/test-ready-release-go/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/anbraten/test-ready-release-go/teams", + "hooks_url": "https://api.github.com/repos/anbraten/test-ready-release-go/hooks", + "issue_events_url": "https://api.github.com/repos/anbraten/test-ready-release-go/issues/events{/number}", + "events_url": "https://api.github.com/repos/anbraten/test-ready-release-go/events", + "assignees_url": "https://api.github.com/repos/anbraten/test-ready-release-go/assignees{/user}", + "branches_url": "https://api.github.com/repos/anbraten/test-ready-release-go/branches{/branch}", + "tags_url": "https://api.github.com/repos/anbraten/test-ready-release-go/tags", + "blobs_url": "https://api.github.com/repos/anbraten/test-ready-release-go/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/anbraten/test-ready-release-go/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/anbraten/test-ready-release-go/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/anbraten/test-ready-release-go/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/anbraten/test-ready-release-go/statuses/{sha}", + "languages_url": "https://api.github.com/repos/anbraten/test-ready-release-go/languages", + "stargazers_url": "https://api.github.com/repos/anbraten/test-ready-release-go/stargazers", + "contributors_url": "https://api.github.com/repos/anbraten/test-ready-release-go/contributors", + "subscribers_url": "https://api.github.com/repos/anbraten/test-ready-release-go/subscribers", + "subscription_url": "https://api.github.com/repos/anbraten/test-ready-release-go/subscription", + "commits_url": "https://api.github.com/repos/anbraten/test-ready-release-go/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/anbraten/test-ready-release-go/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/anbraten/test-ready-release-go/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/anbraten/test-ready-release-go/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/anbraten/test-ready-release-go/contents/{+path}", + "compare_url": "https://api.github.com/repos/anbraten/test-ready-release-go/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/anbraten/test-ready-release-go/merges", + "archive_url": "https://api.github.com/repos/anbraten/test-ready-release-go/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/anbraten/test-ready-release-go/downloads", + "issues_url": "https://api.github.com/repos/anbraten/test-ready-release-go/issues{/number}", + "pulls_url": "https://api.github.com/repos/anbraten/test-ready-release-go/pulls{/number}", + "milestones_url": "https://api.github.com/repos/anbraten/test-ready-release-go/milestones{/number}", + "notifications_url": "https://api.github.com/repos/anbraten/test-ready-release-go/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/anbraten/test-ready-release-go/labels{/name}", + "releases_url": "https://api.github.com/repos/anbraten/test-ready-release-go/releases{/id}", + "deployments_url": "https://api.github.com/repos/anbraten/test-ready-release-go/deployments", + "created_at": "2022-12-10T16:59:42Z", + "updated_at": "2023-07-11T17:00:26Z", + "pushed_at": "2023-12-05T18:13:17Z", + "git_url": "git://github.com/anbraten/test-ready-release-go.git", + "ssh_url": "git@github.com:anbraten/test-ready-release-go.git", + "clone_url": "https://github.com/anbraten/test-ready-release-go.git", + "svn_url": "https://github.com/anbraten/test-ready-release-go", + "homepage": null, + "size": 11198, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Go", + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "has_discussions": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 0, + "license": { + "key": "apache-2.0", + "name": "Apache License 2.0", + "spdx_id": "Apache-2.0", + "url": "https://api.github.com/licenses/apache-2.0", + "node_id": "MDc6TGljZW5zZTI=" + }, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [], + "visibility": "public", + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "main", + "allow_squash_merge": true, + "allow_merge_commit": true, + "allow_rebase_merge": true, + "allow_auto_merge": false, + "delete_branch_on_merge": false, + "allow_update_branch": false, + "use_squash_pr_title_as_default": false, + "squash_merge_commit_message": "COMMIT_MESSAGES", + "squash_merge_commit_title": "COMMIT_OR_PR_TITLE", + "merge_commit_message": "PR_TITLE", + "merge_commit_title": "MERGE_MESSAGE" + } + }, + "base": { + "label": "anbraten:main", + "ref": "main", + "sha": "26fd46e0d1237cdabfe84ec6a0f37466fc716952", + "user": { + "login": "anbraten", + "id": 6918444, + "node_id": "MDQ6VXNlcjY5MTg0NDQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/6918444?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/anbraten", + "html_url": "https://github.com/anbraten", + "followers_url": "https://api.github.com/users/anbraten/followers", + "following_url": "https://api.github.com/users/anbraten/following{/other_user}", + "gists_url": "https://api.github.com/users/anbraten/gists{/gist_id}", + "starred_url": "https://api.github.com/users/anbraten/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/anbraten/subscriptions", + "organizations_url": "https://api.github.com/users/anbraten/orgs", + "repos_url": "https://api.github.com/users/anbraten/repos", + "events_url": "https://api.github.com/users/anbraten/events{/privacy}", + "received_events_url": "https://api.github.com/users/anbraten/received_events", + "type": "User", + "site_admin": false + }, + "repo": { + "id": 576689461, + "node_id": "R_kgDOIl-VNQ", + "name": "test-ready-release-go", + "full_name": "anbraten/test-ready-release-go", + "private": false, + "owner": { + "login": "anbraten", + "id": 6918444, + "node_id": "MDQ6VXNlcjY5MTg0NDQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/6918444?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/anbraten", + "html_url": "https://github.com/anbraten", + "followers_url": "https://api.github.com/users/anbraten/followers", + "following_url": "https://api.github.com/users/anbraten/following{/other_user}", + "gists_url": "https://api.github.com/users/anbraten/gists{/gist_id}", + "starred_url": "https://api.github.com/users/anbraten/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/anbraten/subscriptions", + "organizations_url": "https://api.github.com/users/anbraten/orgs", + "repos_url": "https://api.github.com/users/anbraten/repos", + "events_url": "https://api.github.com/users/anbraten/events{/privacy}", + "received_events_url": "https://api.github.com/users/anbraten/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://github.com/anbraten/test-ready-release-go", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/anbraten/test-ready-release-go", + "forks_url": "https://api.github.com/repos/anbraten/test-ready-release-go/forks", + "keys_url": "https://api.github.com/repos/anbraten/test-ready-release-go/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/anbraten/test-ready-release-go/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/anbraten/test-ready-release-go/teams", + "hooks_url": "https://api.github.com/repos/anbraten/test-ready-release-go/hooks", + "issue_events_url": "https://api.github.com/repos/anbraten/test-ready-release-go/issues/events{/number}", + "events_url": "https://api.github.com/repos/anbraten/test-ready-release-go/events", + "assignees_url": "https://api.github.com/repos/anbraten/test-ready-release-go/assignees{/user}", + "branches_url": "https://api.github.com/repos/anbraten/test-ready-release-go/branches{/branch}", + "tags_url": "https://api.github.com/repos/anbraten/test-ready-release-go/tags", + "blobs_url": "https://api.github.com/repos/anbraten/test-ready-release-go/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/anbraten/test-ready-release-go/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/anbraten/test-ready-release-go/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/anbraten/test-ready-release-go/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/anbraten/test-ready-release-go/statuses/{sha}", + "languages_url": "https://api.github.com/repos/anbraten/test-ready-release-go/languages", + "stargazers_url": "https://api.github.com/repos/anbraten/test-ready-release-go/stargazers", + "contributors_url": "https://api.github.com/repos/anbraten/test-ready-release-go/contributors", + "subscribers_url": "https://api.github.com/repos/anbraten/test-ready-release-go/subscribers", + "subscription_url": "https://api.github.com/repos/anbraten/test-ready-release-go/subscription", + "commits_url": "https://api.github.com/repos/anbraten/test-ready-release-go/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/anbraten/test-ready-release-go/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/anbraten/test-ready-release-go/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/anbraten/test-ready-release-go/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/anbraten/test-ready-release-go/contents/{+path}", + "compare_url": "https://api.github.com/repos/anbraten/test-ready-release-go/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/anbraten/test-ready-release-go/merges", + "archive_url": "https://api.github.com/repos/anbraten/test-ready-release-go/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/anbraten/test-ready-release-go/downloads", + "issues_url": "https://api.github.com/repos/anbraten/test-ready-release-go/issues{/number}", + "pulls_url": "https://api.github.com/repos/anbraten/test-ready-release-go/pulls{/number}", + "milestones_url": "https://api.github.com/repos/anbraten/test-ready-release-go/milestones{/number}", + "notifications_url": "https://api.github.com/repos/anbraten/test-ready-release-go/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/anbraten/test-ready-release-go/labels{/name}", + "releases_url": "https://api.github.com/repos/anbraten/test-ready-release-go/releases{/id}", + "deployments_url": "https://api.github.com/repos/anbraten/test-ready-release-go/deployments", + "created_at": "2022-12-10T16:59:42Z", + "updated_at": "2023-07-11T17:00:26Z", + "pushed_at": "2023-12-05T18:13:17Z", + "git_url": "git://github.com/anbraten/test-ready-release-go.git", + "ssh_url": "git@github.com:anbraten/test-ready-release-go.git", + "clone_url": "https://github.com/anbraten/test-ready-release-go.git", + "svn_url": "https://github.com/anbraten/test-ready-release-go", + "homepage": null, + "size": 11198, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Go", + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "has_discussions": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 0, + "license": { + "key": "apache-2.0", + "name": "Apache License 2.0", + "spdx_id": "Apache-2.0", + "url": "https://api.github.com/licenses/apache-2.0", + "node_id": "MDc6TGljZW5zZTI=" + }, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [], + "visibility": "public", + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "main", + "allow_squash_merge": true, + "allow_merge_commit": true, + "allow_rebase_merge": true, + "allow_auto_merge": false, + "delete_branch_on_merge": false, + "allow_update_branch": false, + "use_squash_pr_title_as_default": false, + "squash_merge_commit_message": "COMMIT_MESSAGES", + "squash_merge_commit_title": "COMMIT_OR_PR_TITLE", + "merge_commit_message": "PR_TITLE", + "merge_commit_title": "MERGE_MESSAGE" + } + }, + "_links": { + "self": { + "href": "https://api.github.com/repos/anbraten/test-ready-release-go/pulls/62" + }, + "html": { + "href": "https://github.com/anbraten/test-ready-release-go/pull/62" + }, + "issue": { + "href": "https://api.github.com/repos/anbraten/test-ready-release-go/issues/62" + }, + "comments": { + "href": "https://api.github.com/repos/anbraten/test-ready-release-go/issues/62/comments" + }, + "review_comments": { + "href": "https://api.github.com/repos/anbraten/test-ready-release-go/pulls/62/comments" + }, + "review_comment": { + "href": "https://api.github.com/repos/anbraten/test-ready-release-go/pulls/comments{/number}" + }, + "commits": { + "href": "https://api.github.com/repos/anbraten/test-ready-release-go/pulls/62/commits" + }, + "statuses": { + "href": "https://api.github.com/repos/anbraten/test-ready-release-go/statuses/c88b9ee719285134957cbc698c9b7ef9b78007bf" + } + }, + "author_association": "OWNER", + "auto_merge": null, + "active_lock_reason": null, + "merged": false, + "mergeable": true, + "rebaseable": false, + "mergeable_state": "clean", + "merged_by": null, + "comments": 0, + "review_comments": 0, + "maintainer_can_modify": false, + "commits": 1, + "additions": 1, + "deletions": 0, + "changed_files": 1 + }, + "repository": { + "id": 576689461, + "node_id": "R_kgDOIl-VNQ", + "name": "test-ready-release-go", + "full_name": "anbraten/test-ready-release-go", + "private": false, + "owner": { + "login": "anbraten", + "id": 6918444, + "node_id": "MDQ6VXNlcjY5MTg0NDQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/6918444?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/anbraten", + "html_url": "https://github.com/anbraten", + "followers_url": "https://api.github.com/users/anbraten/followers", + "following_url": "https://api.github.com/users/anbraten/following{/other_user}", + "gists_url": "https://api.github.com/users/anbraten/gists{/gist_id}", + "starred_url": "https://api.github.com/users/anbraten/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/anbraten/subscriptions", + "organizations_url": "https://api.github.com/users/anbraten/orgs", + "repos_url": "https://api.github.com/users/anbraten/repos", + "events_url": "https://api.github.com/users/anbraten/events{/privacy}", + "received_events_url": "https://api.github.com/users/anbraten/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://github.com/anbraten/test-ready-release-go", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/anbraten/test-ready-release-go", + "forks_url": "https://api.github.com/repos/anbraten/test-ready-release-go/forks", + "keys_url": "https://api.github.com/repos/anbraten/test-ready-release-go/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/anbraten/test-ready-release-go/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/anbraten/test-ready-release-go/teams", + "hooks_url": "https://api.github.com/repos/anbraten/test-ready-release-go/hooks", + "issue_events_url": "https://api.github.com/repos/anbraten/test-ready-release-go/issues/events{/number}", + "events_url": "https://api.github.com/repos/anbraten/test-ready-release-go/events", + "assignees_url": "https://api.github.com/repos/anbraten/test-ready-release-go/assignees{/user}", + "branches_url": "https://api.github.com/repos/anbraten/test-ready-release-go/branches{/branch}", + "tags_url": "https://api.github.com/repos/anbraten/test-ready-release-go/tags", + "blobs_url": "https://api.github.com/repos/anbraten/test-ready-release-go/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/anbraten/test-ready-release-go/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/anbraten/test-ready-release-go/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/anbraten/test-ready-release-go/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/anbraten/test-ready-release-go/statuses/{sha}", + "languages_url": "https://api.github.com/repos/anbraten/test-ready-release-go/languages", + "stargazers_url": "https://api.github.com/repos/anbraten/test-ready-release-go/stargazers", + "contributors_url": "https://api.github.com/repos/anbraten/test-ready-release-go/contributors", + "subscribers_url": "https://api.github.com/repos/anbraten/test-ready-release-go/subscribers", + "subscription_url": "https://api.github.com/repos/anbraten/test-ready-release-go/subscription", + "commits_url": "https://api.github.com/repos/anbraten/test-ready-release-go/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/anbraten/test-ready-release-go/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/anbraten/test-ready-release-go/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/anbraten/test-ready-release-go/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/anbraten/test-ready-release-go/contents/{+path}", + "compare_url": "https://api.github.com/repos/anbraten/test-ready-release-go/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/anbraten/test-ready-release-go/merges", + "archive_url": "https://api.github.com/repos/anbraten/test-ready-release-go/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/anbraten/test-ready-release-go/downloads", + "issues_url": "https://api.github.com/repos/anbraten/test-ready-release-go/issues{/number}", + "pulls_url": "https://api.github.com/repos/anbraten/test-ready-release-go/pulls{/number}", + "milestones_url": "https://api.github.com/repos/anbraten/test-ready-release-go/milestones{/number}", + "notifications_url": "https://api.github.com/repos/anbraten/test-ready-release-go/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/anbraten/test-ready-release-go/labels{/name}", + "releases_url": "https://api.github.com/repos/anbraten/test-ready-release-go/releases{/id}", + "deployments_url": "https://api.github.com/repos/anbraten/test-ready-release-go/deployments", + "created_at": "2022-12-10T16:59:42Z", + "updated_at": "2023-07-11T17:00:26Z", + "pushed_at": "2023-12-05T18:13:17Z", + "git_url": "git://github.com/anbraten/test-ready-release-go.git", + "ssh_url": "git@github.com:anbraten/test-ready-release-go.git", + "clone_url": "https://github.com/anbraten/test-ready-release-go.git", + "svn_url": "https://github.com/anbraten/test-ready-release-go", + "homepage": null, + "size": 11198, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Go", + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "has_discussions": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 0, + "license": { + "key": "apache-2.0", + "name": "Apache License 2.0", + "spdx_id": "Apache-2.0", + "url": "https://api.github.com/licenses/apache-2.0", + "node_id": "MDc6TGljZW5zZTI=" + }, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [], + "visibility": "public", + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "main" + }, + "sender": { + "login": "anbraten", + "id": 6918444, + "node_id": "MDQ6VXNlcjY5MTg0NDQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/6918444?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/anbraten", + "html_url": "https://github.com/anbraten", + "followers_url": "https://api.github.com/users/anbraten/followers", + "following_url": "https://api.github.com/users/anbraten/following{/other_user}", + "gists_url": "https://api.github.com/users/anbraten/gists{/gist_id}", + "starred_url": "https://api.github.com/users/anbraten/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/anbraten/subscriptions", + "organizations_url": "https://api.github.com/users/anbraten/orgs", + "repos_url": "https://api.github.com/users/anbraten/repos", + "events_url": "https://api.github.com/users/anbraten/events{/privacy}", + "received_events_url": "https://api.github.com/users/anbraten/received_events", + "type": "User", + "site_admin": false + } +} +` diff --git a/server/forge/github/parse.go b/server/forge/github/parse.go index e1937b4d3..293cab383 100644 --- a/server/forge/github/parse.go +++ b/server/forge/github/parse.go @@ -32,10 +32,12 @@ import ( const ( hookField = "payload" - actionOpen = "opened" - actionSync = "synchronize" + actionOpen = "opened" + actionClose = "closed" + actionSync = "synchronize" - stateOpen = "open" + stateOpen = "open" + stateClose = "closed" ) // parseHook parses a GitHub hook from an http.Request request and returns @@ -140,18 +142,19 @@ func parseDeployHook(hook *github.DeploymentEvent) (*model.Repo, *model.Pipeline } // parsePullHook parses a pull request hook and returns the Repo and Pipeline -// details. If the pull request is closed nil values are returned. +// details. func parsePullHook(hook *github.PullRequestEvent, merge bool) (*github.PullRequest, *model.Repo, *model.Pipeline, error) { - // only listen to new merge-requests and pushes to open ones - if hook.GetAction() != actionOpen && hook.GetAction() != actionSync { - return nil, nil, nil, nil - } - if hook.GetPullRequest().GetState() != stateOpen { + if hook.GetAction() != actionOpen && hook.GetAction() != actionSync && hook.GetAction() != actionClose { return nil, nil, nil, nil } + event := model.EventPull + if hook.GetPullRequest().GetState() == stateClose { + event = model.EventPullClosed + } + pipeline := &model.Pipeline{ - Event: model.EventPull, + Event: event, Commit: hook.GetPullRequest().GetHead().GetSHA(), ForgeURL: hook.GetPullRequest().GetHTMLURL(), Ref: fmt.Sprintf(headRefs, hook.GetPullRequest().GetNumber()), diff --git a/server/forge/github/parse_test.go b/server/forge/github/parse_test.go index d8208380c..e3625dbee 100644 --- a/server/forge/github/parse_test.go +++ b/server/forge/github/parse_test.go @@ -79,23 +79,7 @@ func Test_parser(t *testing.T) { }) g.Describe("given a pull request hook", func() { - g.It("should skip when action is not open or sync", func() { - req := testHookRequest([]byte(fixtures.HookPullRequestInvalidAction), hookPull) - p, r, b, err := parseHook(req, false) - g.Assert(r).IsNil() - g.Assert(b).IsNil() - g.Assert(err).IsNil() - g.Assert(p).IsNil() - }) - g.It("should skip when state is not open", func() { - req := testHookRequest([]byte(fixtures.HookPullRequestInvalidState), hookPull) - p, r, b, err := parseHook(req, false) - g.Assert(r).IsNil() - g.Assert(b).IsNil() - g.Assert(err).IsNil() - g.Assert(p).IsNil() - }) - g.It("should extract repository and pipeline details", func() { + g.It("should handle a PR hook when PR got opened or pushed to", func() { req := testHookRequest([]byte(fixtures.HookPullRequest), hookPull) p, r, b, err := parseHook(req, false) g.Assert(err).IsNil() @@ -104,6 +88,24 @@ func Test_parser(t *testing.T) { g.Assert(p).IsNotNil() g.Assert(b.Event).Equal(model.EventPull) }) + g.It("should handle a PR closed hook when PR got closed", func() { + req := testHookRequest([]byte(fixtures.HookPullRequestClosed), hookPull) + p, r, b, err := parseHook(req, false) + g.Assert(err).IsNil() + g.Assert(r).IsNotNil() + g.Assert(b).IsNotNil() + g.Assert(p).IsNotNil() + g.Assert(b.Event).Equal(model.EventPullClosed) + }) + g.It("should handle a PR closed hook when PR got merged", func() { + req := testHookRequest([]byte(fixtures.HookPullRequestMerged), hookPull) + p, r, b, err := parseHook(req, false) + g.Assert(err).IsNil() + g.Assert(r).IsNotNil() + g.Assert(b).IsNotNil() + g.Assert(p).IsNotNil() + g.Assert(b.Event).Equal(model.EventPullClosed) + }) }) g.Describe("given a deployment hook", func() { diff --git a/server/forge/gitlab/convert.go b/server/forge/gitlab/convert.go index 5ab015b63..0641d43d4 100644 --- a/server/forge/gitlab/convert.go +++ b/server/forge/gitlab/convert.go @@ -111,6 +111,9 @@ func convertMergeRequestHook(hook *gitlab.MergeEvent, req *http.Request) (int, * } pipeline.Event = model.EventPull + if obj.State == "closed" { + pipeline.Event = model.EventPullClosed + } lastCommit := obj.LastCommit diff --git a/server/forge/gitlab/gitlab_test.go b/server/forge/gitlab/gitlab_test.go index c5c671fb6..11b865975 100644 --- a/server/forge/gitlab/gitlab_test.go +++ b/server/forge/gitlab/gitlab_test.go @@ -137,7 +137,7 @@ func Test_GitLab(t *testing.T) { req, _ := http.NewRequest( testdata.ServiceHookMethod, testdata.ServiceHookURL.String(), - bytes.NewReader(testdata.ServiceHookPushBody), + bytes.NewReader(testdata.HookPush), ) req.Header = testdata.ServiceHookHeaders @@ -160,7 +160,7 @@ func Test_GitLab(t *testing.T) { req, _ := http.NewRequest( testdata.ServiceHookMethod, testdata.ServiceHookURL.String(), - bytes.NewReader(testdata.ServiceHookTagPushBody), + bytes.NewReader(testdata.HookTag), ) req.Header = testdata.ServiceHookHeaders @@ -182,7 +182,7 @@ func Test_GitLab(t *testing.T) { req, _ := http.NewRequest( testdata.ServiceHookMethod, testdata.ServiceHookURL.String(), - bytes.NewReader(testdata.WebhookMergeRequestBody), + bytes.NewReader(testdata.HookPullRequest), ) req.Header = testdata.ServiceHookHeaders @@ -198,6 +198,46 @@ func Test_GitLab(t *testing.T) { assert.Len(t, pipeline.ChangedFiles, 0) // see L217 } }) + + g.It("Should parse merge request hook when MR closed", func() { + req, _ := http.NewRequest( + testdata.ServiceHookMethod, + testdata.ServiceHookURL.String(), + bytes.NewReader(testdata.HookPullRequestClosed), + ) + req.Header = testdata.ServiceHookHeaders + + // TODO: insert fake store into context to retrieve user & repo, this will activate fetching of ChangedFiles + hookRepo, pipeline, err := client.Hook(ctx, req) + assert.NoError(t, err) + if assert.NotNil(t, hookRepo) && assert.NotNil(t, pipeline) { + assert.Equal(t, "main", hookRepo.Branch) + assert.Equal(t, "anbraten", hookRepo.Owner) + assert.Equal(t, "woodpecker-test", hookRepo.Name) + assert.Equal(t, "Add new file", pipeline.Title) + assert.Len(t, pipeline.ChangedFiles, 0) // see L217 + } + }) + + g.It("Should parse merge request hook when merged", func() { + req, _ := http.NewRequest( + testdata.ServiceHookMethod, + testdata.ServiceHookURL.String(), + bytes.NewReader(testdata.HookPullRequestMerged), + ) + req.Header = testdata.ServiceHookHeaders + + // TODO: insert fake store into context to retrieve user & repo, this will activate fetching of ChangedFiles + hookRepo, pipeline, err := client.Hook(ctx, req) + assert.NoError(t, err) + if assert.NotNil(t, hookRepo) && assert.NotNil(t, pipeline) { + assert.Equal(t, "main", hookRepo.Branch) + assert.Equal(t, "anbraten", hookRepo.Owner) + assert.Equal(t, "woodpecker-test", hookRepo.Name) + assert.Equal(t, "Add new file", pipeline.Title) + assert.Len(t, pipeline.ChangedFiles, 0) // see L217 + } + }) }) }) }) diff --git a/server/forge/gitlab/testdata/hooks.go b/server/forge/gitlab/testdata/hooks.go index 2d1a1bb14..715c666a5 100644 --- a/server/forge/gitlab/testdata/hooks.go +++ b/server/forge/gitlab/testdata/hooks.go @@ -31,8 +31,9 @@ var ( } ) -// ServiceHookPushBody is payload of ServiceHook: Push -var ServiceHookPushBody = []byte(`{ +// HookPush is payload of a push event +var HookPush = []byte(` +{ "object_kind": "push", "event_name": "push", "before": "ffe8eb4f91d1fe6bc49f1e610e50e4b5767f0104", @@ -100,8 +101,9 @@ var ServiceHookPushBody = []byte(`{ } }`) -// ServiceHookTagPushBody is payload of ServiceHook: TagPush -var ServiceHookTagPushBody = []byte(`{ +// HookTag is payload of a TAG event +var HookTag = []byte(` +{ "object_kind": "tag_push", "event_name": "tag_push", "before": "0000000000000000000000000000000000000000", @@ -169,8 +171,9 @@ var ServiceHookTagPushBody = []byte(`{ } }`) -// WebhookMergeRequestBody is payload of MergeEvent -var WebhookMergeRequestBody = []byte(`{ +// HookPullRequest is payload of a PULL_REQUEST event +var HookPullRequest = []byte(` +{ "object_kind": "merge_request", "event_type": "merge_request", "user": { @@ -314,3 +317,285 @@ var WebhookMergeRequestBody = []byte(`{ ] } `) + +var HookPullRequestClosed = []byte(` +{ + "object_kind": "merge_request", + "event_type": "merge_request", + "user": { + "id": 2251488, + "name": "Anbraten", + "username": "anbraten", + "avatar_url": "https://secure.gravatar.com/avatar/fc9b6fe77c6b732a02925a62a81f05a0?s=80&d=identicon", + "email": "[REDACTED]" + }, + "project": { + "id": 32059612, + "name": "woodpecker-test", + "description": "", + "web_url": "https://gitlab.com/anbraten/woodpecker-test", + "avatar_url": null, + "git_ssh_url": "git@gitlab.com:anbraten/woodpecker-test.git", + "git_http_url": "https://gitlab.com/anbraten/woodpecker-test.git", + "namespace": "Anbraten", + "visibility_level": 20, + "path_with_namespace": "anbraten/woodpecker-test", + "default_branch": "main", + "ci_config_path": "", + "homepage": "https://gitlab.com/anbraten/woodpecker-test", + "url": "git@gitlab.com:anbraten/woodpecker-test.git", + "ssh_url": "git@gitlab.com:anbraten/woodpecker-test.git", + "http_url": "https://gitlab.com/anbraten/woodpecker-test.git" + }, + "object_attributes": { + "assignee_id": null, + "author_id": 2251488, + "created_at": "2023-12-05 18:40:22 UTC", + "description": "", + "draft": false, + "head_pipeline_id": null, + "id": 268189426, + "iid": 4, + "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": "patch-1", + "source_project_id": 32059612, + "state_id": 2, + "target_branch": "main", + "target_project_id": 32059612, + "time_estimate": 0, + "title": "Add new file", + "updated_at": "2023-12-05 18:40:34 UTC", + "updated_by_id": null, + "url": "https://gitlab.com/anbraten/woodpecker-test/-/merge_requests/4", + "source": { + "id": 32059612, + "name": "woodpecker-test", + "description": "", + "web_url": "https://gitlab.com/anbraten/woodpecker-test", + "avatar_url": null, + "git_ssh_url": "git@gitlab.com:anbraten/woodpecker-test.git", + "git_http_url": "https://gitlab.com/anbraten/woodpecker-test.git", + "namespace": "Anbraten", + "visibility_level": 20, + "path_with_namespace": "anbraten/woodpecker-test", + "default_branch": "main", + "ci_config_path": "", + "homepage": "https://gitlab.com/anbraten/woodpecker-test", + "url": "git@gitlab.com:anbraten/woodpecker-test.git", + "ssh_url": "git@gitlab.com:anbraten/woodpecker-test.git", + "http_url": "https://gitlab.com/anbraten/woodpecker-test.git" + }, + "target": { + "id": 32059612, + "name": "woodpecker-test", + "description": "", + "web_url": "https://gitlab.com/anbraten/woodpecker-test", + "avatar_url": null, + "git_ssh_url": "git@gitlab.com:anbraten/woodpecker-test.git", + "git_http_url": "https://gitlab.com/anbraten/woodpecker-test.git", + "namespace": "Anbraten", + "visibility_level": 20, + "path_with_namespace": "anbraten/woodpecker-test", + "default_branch": "main", + "ci_config_path": "", + "homepage": "https://gitlab.com/anbraten/woodpecker-test", + "url": "git@gitlab.com:anbraten/woodpecker-test.git", + "ssh_url": "git@gitlab.com:anbraten/woodpecker-test.git", + "http_url": "https://gitlab.com/anbraten/woodpecker-test.git" + }, + "last_commit": { + "id": "3e4db3586b65dd401de8c77b3ac343fd24cbf89b", + "message": "Add new file", + "title": "Add new file", + "timestamp": "2023-12-05T18:39:57+00:00", + "url": "https://gitlab.com/anbraten/woodpecker-test/-/commit/3e4db3586b65dd401de8c77b3ac343fd24cbf89b", + "author": { + "name": "Anbraten", + "email": "[redacted]" + } + }, + "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": [], + "reviewer_ids": [], + "labels": [], + "state": "closed", + "blocking_discussions_resolved": true, + "first_contribution": false, + "detailed_merge_status": "not_open", + "action": "close" + }, + "labels": [], + "changes": { + "state_id": { + "previous": 1, + "current": 2 + }, + "updated_at": { + "previous": "2023-12-05 18:40:28 UTC", + "current": "2023-12-05 18:40:34 UTC" + } + }, + "repository": { + "name": "woodpecker-test", + "url": "git@gitlab.com:anbraten/woodpecker-test.git", + "description": "", + "homepage": "https://gitlab.com/anbraten/woodpecker-test" + } +} +`) + +var HookPullRequestMerged = []byte(` +{ + "object_kind": "merge_request", + "event_type": "merge_request", + "user": { + "id": 2251488, + "name": "Anbraten", + "username": "anbraten", + "avatar_url": "https://secure.gravatar.com/avatar/fc9b6fe77c6b732a02925a62a81f05a0?s=80&d=identicon", + "email": "[REDACTED]" + }, + "project": { + "id": 32059612, + "name": "woodpecker-test", + "description": "", + "web_url": "https://gitlab.com/anbraten/woodpecker-test", + "avatar_url": null, + "git_ssh_url": "git@gitlab.com:anbraten/woodpecker-test.git", + "git_http_url": "https://gitlab.com/anbraten/woodpecker-test.git", + "namespace": "Anbraten", + "visibility_level": 20, + "path_with_namespace": "anbraten/woodpecker-test", + "default_branch": "main", + "ci_config_path": "", + "homepage": "https://gitlab.com/anbraten/woodpecker-test", + "url": "git@gitlab.com:anbraten/woodpecker-test.git", + "ssh_url": "git@gitlab.com:anbraten/woodpecker-test.git", + "http_url": "https://gitlab.com/anbraten/woodpecker-test.git" + }, + "object_attributes": { + "assignee_id": null, + "author_id": 2251488, + "created_at": "2023-12-05 18:40:22 UTC", + "description": "", + "draft": false, + "head_pipeline_id": null, + "id": 268189426, + "iid": 4, + "last_edited_at": null, + "last_edited_by_id": null, + "merge_commit_sha": "43411b53d670203e887c4985c4e58e8e6b7c109e", + "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": "patch-1", + "source_project_id": 32059612, + "state_id": 3, + "target_branch": "main", + "target_project_id": 32059612, + "time_estimate": 0, + "title": "Add new file", + "updated_at": "2023-12-05 18:43:00 UTC", + "updated_by_id": null, + "url": "https://gitlab.com/anbraten/woodpecker-test/-/merge_requests/4", + "source": { + "id": 32059612, + "name": "woodpecker-test", + "description": "", + "web_url": "https://gitlab.com/anbraten/woodpecker-test", + "avatar_url": null, + "git_ssh_url": "git@gitlab.com:anbraten/woodpecker-test.git", + "git_http_url": "https://gitlab.com/anbraten/woodpecker-test.git", + "namespace": "Anbraten", + "visibility_level": 20, + "path_with_namespace": "anbraten/woodpecker-test", + "default_branch": "main", + "ci_config_path": "", + "homepage": "https://gitlab.com/anbraten/woodpecker-test", + "url": "git@gitlab.com:anbraten/woodpecker-test.git", + "ssh_url": "git@gitlab.com:anbraten/woodpecker-test.git", + "http_url": "https://gitlab.com/anbraten/woodpecker-test.git" + }, + "target": { + "id": 32059612, + "name": "woodpecker-test", + "description": "", + "web_url": "https://gitlab.com/anbraten/woodpecker-test", + "avatar_url": null, + "git_ssh_url": "git@gitlab.com:anbraten/woodpecker-test.git", + "git_http_url": "https://gitlab.com/anbraten/woodpecker-test.git", + "namespace": "Anbraten", + "visibility_level": 20, + "path_with_namespace": "anbraten/woodpecker-test", + "default_branch": "main", + "ci_config_path": "", + "homepage": "https://gitlab.com/anbraten/woodpecker-test", + "url": "git@gitlab.com:anbraten/woodpecker-test.git", + "ssh_url": "git@gitlab.com:anbraten/woodpecker-test.git", + "http_url": "https://gitlab.com/anbraten/woodpecker-test.git" + }, + "last_commit": { + "id": "3e4db3586b65dd401de8c77b3ac343fd24cbf89b", + "message": "Add new file", + "title": "Add new file", + "timestamp": "2023-12-05T18:39:57+00:00", + "url": "https://gitlab.com/anbraten/woodpecker-test/-/commit/3e4db3586b65dd401de8c77b3ac343fd24cbf89b", + "author": { + "name": "Anbraten", + "email": "[redacted]" + } + }, + "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": [], + "reviewer_ids": [], + "labels": [], + "state": "merged", + "blocking_discussions_resolved": true, + "first_contribution": false, + "detailed_merge_status": "not_open", + "action": "merge" + }, + "labels": [], + "changes": { + "state_id": { + "previous": 4, + "current": 3 + }, + "updated_at": { + "previous": "2023-12-05 18:43:00 UTC", + "current": "2023-12-05 18:43:00 UTC" + } + }, + "repository": { + "name": "woodpecker-test", + "url": "git@gitlab.com:anbraten/woodpecker-test.git", + "description": "", + "homepage": "https://gitlab.com/anbraten/woodpecker-test" + } +} +`) diff --git a/server/model/const.go b/server/model/const.go index 89760d730..c2084ce9d 100644 --- a/server/model/const.go +++ b/server/model/const.go @@ -23,12 +23,13 @@ import ( type WebhookEvent string // @name WebhookEvent const ( - EventPush WebhookEvent = "push" - EventPull WebhookEvent = "pull_request" - EventTag WebhookEvent = "tag" - EventDeploy WebhookEvent = "deployment" - EventCron WebhookEvent = "cron" - EventManual WebhookEvent = "manual" + EventPush WebhookEvent = "push" + EventPull WebhookEvent = "pull_request" + EventPullClosed WebhookEvent = "pull_request_closed" + EventTag WebhookEvent = "tag" + EventDeploy WebhookEvent = "deployment" + EventCron WebhookEvent = "cron" + EventManual WebhookEvent = "manual" ) type WebhookEventList []WebhookEvent diff --git a/web/src/components/atomic/Icon.vue b/web/src/components/atomic/Icon.vue index 129d911d0..70c22c84d 100644 --- a/web/src/components/atomic/Icon.vue +++ b/web/src/components/atomic/Icon.vue @@ -2,7 +2,8 @@ - + + @@ -58,7 +59,8 @@ export type IconNames = | 'duration' | 'since' | 'push' - | 'pull_request' + | 'pull-request' + | 'pull-request-closed' | 'manual-pipeline' | 'tag' | 'deployment' diff --git a/web/src/components/repo/pipeline/PipelineItem.vue b/web/src/components/repo/pipeline/PipelineItem.vue index 81dfde87d..dd3fb6bfc 100644 --- a/web/src/components/repo/pipeline/PipelineItem.vue +++ b/web/src/components/repo/pipeline/PipelineItem.vue @@ -37,7 +37,8 @@ class="grid grid-rows-2 grid-flow-col w-full md:ml-auto md:w-96 py-2 gap-x-4 gap-y-2 flex-shrink-0 text-wp-text-100" >
- + + diff --git a/web/src/components/repo/pipeline/PipelineStepList.vue b/web/src/components/repo/pipeline/PipelineStepList.vue index 2e71a60e7..c49865295 100644 --- a/web/src/components/repo/pipeline/PipelineStepList.vue +++ b/web/src/components/repo/pipeline/PipelineStepList.vue @@ -11,11 +11,11 @@ {{ pipeline.author }}
- + {{ prettyRef }} ) => { return pipeline.value.ref.replaceAll('refs/tags/', ''); } - if (pipeline.value?.event === 'pull_request') { + if (pipeline.value?.event === 'pull_request' || pipeline.value?.event === 'pull_request_closed') { return `#${pipeline.value.ref .replaceAll('refs/pull/', '') .replaceAll('refs/merge-requests/', '') diff --git a/web/src/lib/api/types/webhook.ts b/web/src/lib/api/types/webhook.ts index e7a369835..33aa24c7c 100644 --- a/web/src/lib/api/types/webhook.ts +++ b/web/src/lib/api/types/webhook.ts @@ -2,6 +2,7 @@ export enum WebhookEvents { Push = 'push', Tag = 'tag', PullRequest = 'pull_request', + PullRequestClosed = 'pull_request_closed', Deploy = 'deployment', Cron = 'cron', Manual = 'manual', diff --git a/web/src/views/repo/RepoBranch.vue b/web/src/views/repo/RepoBranch.vue index 785451506..de834c0fa 100644 --- a/web/src/views/repo/RepoBranch.vue +++ b/web/src/views/repo/RepoBranch.vue @@ -24,6 +24,9 @@ if (!repo || !repoPermissions) { const allPipelines = inject>('pipelines'); const pipelines = computed( - () => allPipelines?.value.filter((b) => b.branch === branch.value && b.event !== 'pull_request'), + () => + allPipelines?.value.filter( + (b) => b.branch === branch.value && b.event !== 'pull_request' && b.event !== 'pull_request_closed', + ), ); diff --git a/web/src/views/repo/RepoPullRequest.vue b/web/src/views/repo/RepoPullRequest.vue index 5aa014167..d08b306c1 100644 --- a/web/src/views/repo/RepoPullRequest.vue +++ b/web/src/views/repo/RepoPullRequest.vue @@ -29,7 +29,7 @@ const pipelines = computed( () => allPipelines?.value.filter( (b) => - b.event === 'pull_request' && + (b.event === 'pull_request' || b.event === 'pull_request_closed') && b.ref .replaceAll('refs/pull/', '') .replaceAll('refs/merge-requests/', '') diff --git a/web/src/views/repo/pipeline/PipelineWrapper.vue b/web/src/views/repo/pipeline/PipelineWrapper.vue index 4f367a17b..535b1d04f 100644 --- a/web/src/views/repo/pipeline/PipelineWrapper.vue +++ b/web/src/views/repo/pipeline/PipelineWrapper.vue @@ -88,7 +88,7 @@