Browse Source

webhook: add Release event (#2387)

pull/4280/head
Unknwon 8 years ago
parent
commit
b615d670b3
No known key found for this signature in database
GPG Key ID: 25B575AE3213B2B3
  1. 2
      conf/locale/locale_en-US.ini
  2. 3
      models/issue.go
  3. 73
      models/release.go
  4. 9
      models/webhook.go
  5. 18
      models/webhook_discord.go
  6. 11
      models/webhook_slack.go
  7. 20
      modules/bindata/bindata.go
  8. 1
      modules/form/repo.go
  9. 34
      public/css/gogs.css
  10. 4
      public/less/_admin.less
  11. 4
      public/less/_repository.less
  12. 4
      routers/repo/release.go
  13. 1
      routers/repo/webhook.go
  14. 10
      templates/repo/settings/webhook_settings.tmpl
  15. 2
      vendor/github.com/gogits/go-gogs-client/gogs.go
  16. 22
      vendor/github.com/gogits/go-gogs-client/release.go
  17. 27
      vendor/github.com/gogits/go-gogs-client/repo_hook.go
  18. 6
      vendor/vendor.json

2
conf/locale/locale_en-US.ini

@ -776,6 +776,8 @@ settings.event_issue_comment = Issue Comment
settings.event_issue_comment_desc = Issue comment created, edited, or deleted.
settings.event_pull_request = Pull Request
settings.event_pull_request_desc = Pull request opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared, milestoned, demilestoned, or synchronized.
settings.event_release = Release
settings.event_release_desc = Release published in a repository.
settings.active = Active
settings.active_helper = Details regarding the event which triggered the hook will be delivered as well.
settings.add_hook_success = New webhook has been added.

3
models/issue.go

@ -12,9 +12,10 @@ import (
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
api "github.com/gogits/go-gogs-client"
log "gopkg.in/clog.v1"
api "github.com/gogits/go-gogs-client"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/setting"
)

73
models/release.go

@ -11,8 +11,10 @@ import (
"time"
"github.com/go-xorm/xorm"
log "gopkg.in/clog.v1"
"github.com/gogits/git-module"
api "github.com/gogits/go-gogs-client"
"github.com/gogits/gogs/modules/process"
)
@ -21,6 +23,7 @@ import (
type Release struct {
ID int64 `xorm:"pk autoincr"`
RepoID int64
Repo *Repository `xorm:"-"`
PublisherID int64
Publisher *User `xorm:"-"`
TagName string
@ -52,6 +55,13 @@ func (r *Release) AfterSet(colName string, _ xorm.Cell) {
}
func (r *Release) loadAttributes(e Engine) (err error) {
if r.Repo == nil {
r.Repo, err = getRepositoryByID(e, r.RepoID)
if err != nil {
return fmt.Errorf("getRepositoryByID [repo_id: %d]: %v", r.RepoID, err)
}
}
if r.Publisher == nil {
r.Publisher, err = getUserByID(e, r.PublisherID)
if err != nil {
@ -59,7 +69,7 @@ func (r *Release) loadAttributes(e Engine) (err error) {
r.PublisherID = -1
r.Publisher = NewGhostUser()
} else {
return fmt.Errorf("getUserByID.(Publisher) [%d]: %v", r.PublisherID, err)
return fmt.Errorf("getUserByID.(Publisher) [publisher_id: %d]: %v", r.PublisherID, err)
}
}
}
@ -71,6 +81,22 @@ func (r *Release) LoadAttributes() error {
return r.loadAttributes(x)
}
// This method assumes some fields assigned with values:
// Required - Publisher
func (r *Release) APIFormat() *api.Release {
return &api.Release{
ID: r.ID,
TagName: r.TagName,
TargetCommitish: r.Target,
Name: r.Title,
Body: r.Note,
Draft: r.IsDraft,
Prerelease: r.IsPrerelease,
Author: r.Publisher.APIFormat(),
Created: r.Created,
}
}
// IsReleaseExist returns true if release with given tag name already exists.
func IsReleaseExist(repoID int64, tagName string) (bool, error) {
if len(tagName) == 0 {
@ -113,6 +139,17 @@ func createTag(gitRepo *git.Repository, r *Release) error {
return nil
}
func (r *Release) preparePublishWebhooks() {
if err := PrepareWebhooks(r.Repo, HOOK_EVENT_RELEASE, &api.ReleasePayload{
Action: api.HOOK_RELEASE_PUBLISHED,
Release: r.APIFormat(),
Repository: r.Repo.APIFormat(nil),
Sender: r.Publisher.APIFormat(),
}); err != nil {
log.Error(2, "PrepareWebhooks: %v", err)
}
}
// CreateRelease creates a new release of repository.
func CreateRelease(gitRepo *git.Repository, r *Release) error {
isExist, err := IsReleaseExist(r.RepoID, r.TagName)
@ -126,8 +163,20 @@ func CreateRelease(gitRepo *git.Repository, r *Release) error {
return err
}
r.LowerTagName = strings.ToLower(r.TagName)
_, err = x.InsertOne(r)
return err
if _, err = x.Insert(r); err != nil {
return fmt.Errorf("Insert: %v", err)
}
// Only send webhook when actually published, skip drafts
if r.IsDraft {
return nil
}
r, err = GetReleaseByID(r.ID)
if err != nil {
return fmt.Errorf("GetReleaseByID: %v", err)
}
r.preparePublishWebhooks()
return nil
}
// GetRelease returns release by given ID.
@ -205,12 +254,22 @@ func SortReleases(rels []*Release) {
}
// UpdateRelease updates information of a release.
func UpdateRelease(gitRepo *git.Repository, rel *Release) (err error) {
if err = createTag(gitRepo, rel); err != nil {
func UpdateRelease(doer *User, gitRepo *git.Repository, r *Release, isPublish bool) (err error) {
if err = createTag(gitRepo, r); err != nil {
return fmt.Errorf("createTag: %v", err)
}
r.PublisherID = doer.ID
if _, err = x.Id(r.ID).AllCols().Update(r); err != nil {
return err
}
_, err = x.Id(rel.ID).AllCols().Update(rel)
return err
if !isPublish {
return nil
}
r.Publisher = doer
r.preparePublishWebhooks()
return nil
}
// DeleteReleaseOfRepoByID deletes a release and corresponding Git tag by given ID.

9
models/webhook.go

@ -69,6 +69,7 @@ type HookEvents struct {
Issues bool `json:"issues"`
IssueComment bool `json:"issue_comment"`
PullRequest bool `json:"pull_request"`
Release bool `json:"release"`
}
// HookEvent represents events that will delivery hook.
@ -196,6 +197,12 @@ func (w *Webhook) HasPullRequestEvent() bool {
(w.ChooseEvents && w.HookEvents.PullRequest)
}
// HasReleaseEvent returns true if hook enabled release event.
func (w *Webhook) HasReleaseEvent() bool {
return w.SendEverything ||
(w.ChooseEvents && w.HookEvents.Release)
}
type eventChecker struct {
checker func() bool
typ HookEventType
@ -211,6 +218,7 @@ func (w *Webhook) EventsArray() []string {
{w.HasIssuesEvent, HOOK_EVENT_ISSUES},
{w.HasIssueCommentEvent, HOOK_EVENT_ISSUE_COMMENT},
{w.HasPullRequestEvent, HOOK_EVENT_PULL_REQUEST},
{w.HasReleaseEvent, HOOK_EVENT_RELEASE},
}
for _, c := range eventCheckers {
if c.checker() {
@ -381,6 +389,7 @@ const (
HOOK_EVENT_ISSUES HookEventType = "issues"
HOOK_EVENT_ISSUE_COMMENT HookEventType = "issue_comment"
HOOK_EVENT_PULL_REQUEST HookEventType = "pull_request"
HOOK_EVENT_RELEASE HookEventType = "release"
)
// HookRequest represents hook task request information.

18
models/webhook_discord.go

@ -353,6 +353,22 @@ func getDiscordPullRequestPayload(p *api.PullRequestPayload, slack *SlackMeta) (
}, nil
}
func getDiscordReleasePayload(p *api.ReleasePayload) (*DiscordPayload, error) {
repoLink := DiscordLinkFormatter(p.Repository.HTMLURL, p.Repository.Name)
refLink := DiscordLinkFormatter(p.Repository.HTMLURL+"/src/"+p.Release.TagName, p.Release.TagName)
content := fmt.Sprintf("Published new release %s of %s", refLink, repoLink)
return &DiscordPayload{
Embeds: []*DiscordEmbedObject{{
Description: content,
URL: setting.AppUrl + p.Sender.UserName,
Author: &DiscordEmbedAuthorObject{
Name: p.Sender.UserName,
IconURL: p.Sender.AvatarUrl,
},
}},
}, nil
}
func GetDiscordPayload(p api.Payloader, event HookEventType, meta string) (payload *DiscordPayload, err error) {
slack := &SlackMeta{}
if err := json.Unmarshal([]byte(meta), &slack); err != nil {
@ -374,6 +390,8 @@ func GetDiscordPayload(p api.Payloader, event HookEventType, meta string) (paylo
payload, err = getDiscordIssueCommentPayload(p.(*api.IssueCommentPayload), slack)
case HOOK_EVENT_PULL_REQUEST:
payload, err = getDiscordPullRequestPayload(p.(*api.PullRequestPayload), slack)
case HOOK_EVENT_RELEASE:
payload, err = getDiscordReleasePayload(p.(*api.ReleasePayload))
}
if err != nil {
return nil, fmt.Errorf("event '%s': %v", event, err)

11
models/webhook_slack.go

@ -277,6 +277,15 @@ func getSlackPullRequestPayload(p *api.PullRequestPayload, slack *SlackMeta) (*S
}, nil
}
func getSlackReleasePayload(p *api.ReleasePayload) (*SlackPayload, error) {
repoLink := SlackLinkFormatter(p.Repository.HTMLURL, p.Repository.Name)
refLink := SlackLinkFormatter(p.Repository.HTMLURL+"/src/"+p.Release.TagName, p.Release.TagName)
text := fmt.Sprintf("[%s] new release %s published by %s", repoLink, refLink, p.Sender.UserName)
return &SlackPayload{
Text: text,
}, nil
}
func GetSlackPayload(p api.Payloader, event HookEventType, meta string) (payload *SlackPayload, err error) {
slack := &SlackMeta{}
if err := json.Unmarshal([]byte(meta), &slack); err != nil {
@ -298,6 +307,8 @@ func GetSlackPayload(p api.Payloader, event HookEventType, meta string) (payload
payload, err = getSlackIssueCommentPayload(p.(*api.IssueCommentPayload), slack)
case HOOK_EVENT_PULL_REQUEST:
payload, err = getSlackPullRequestPayload(p.(*api.PullRequestPayload), slack)
case HOOK_EVENT_RELEASE:
payload, err = getSlackReleasePayload(p.(*api.ReleasePayload))
}
if err != nil {
return nil, fmt.Errorf("event '%s': %v", event, err)

20
modules/bindata/bindata.go

File diff suppressed because one or more lines are too long

1
modules/form/repo.go

@ -141,6 +141,7 @@ type Webhook struct {
Issues bool
IssueComment bool
PullRequest bool
Release bool
Active bool
}

34
public/css/gogs.css

@ -1227,30 +1227,30 @@ footer .ui.language .menu {
right: 0!important;
left: auto!important;
}
.repository.branches .ui.list {
.repository.branches:not(.settings) .ui.list {
padding: 0;
}
.repository.branches .ui.list > .item {
.repository.branches:not(.settings) .ui.list > .item {
margin: 0;
line-height: 31px;
}
.repository.branches .ui.list > .item:not(:last-child) {
.repository.branches:not(.settings) .ui.list > .item:not(:last-child) {
border-bottom: 1px solid #DDD;
}
.repository.branches .ui.list > .item .column {
.repository.branches:not(.settings) .ui.list > .item .column {
padding: 5px 15px;
}
.repository.branches .ui.list > .item .column .octicon {
.repository.branches:not(.settings) .ui.list > .item .column .octicon {
vertical-align: text-bottom;
}
.repository.branches .ui.list > .item .column code {
.repository.branches:not(.settings) .ui.list > .item .column code {
padding: 4px 0;
font-size: 12px;
}
.repository.branches .ui.list > .item .column .ui.text:not(i) {
.repository.branches:not(.settings) .ui.list > .item .column .ui.text:not(i) {
font-size: 12px;
}
.repository.branches .ui.list > .item .column .ui.button {
.repository.branches:not(.settings) .ui.list > .item .column .ui.button {
font-size: 12px;
padding: 8px 10px;
}
@ -2338,28 +2338,28 @@ footer .ui.language .menu {
margin-left: 5px;
margin-top: -3px;
}
.repository.settings.branches .protected-branches .selection.dropdown {
.repository.settings.settings.branches .protected-branches .selection.dropdown {
width: 300px;
}
.repository.settings.branches .protected-branches .item {
.repository.settings.settings.branches .protected-branches .item {
border: 1px solid #eaeaea;
padding: 10px 15px;
}
.repository.settings.branches .protected-branches .item:not(:last-child) {
.repository.settings.settings.branches .protected-branches .item:not(:last-child) {
border-bottom: 0;
}
.repository.settings.branches .branch-protection .help {
.repository.settings.settings.branches .branch-protection .help {
margin-left: 26px;
padding-top: 0;
}
.repository.settings.branches .branch-protection .fields {
.repository.settings.settings.branches .branch-protection .fields {
margin-left: 20px;
display: block;
}
.repository.settings.branches .branch-protection .whitelist {
.repository.settings.settings.branches .branch-protection .whitelist {
margin-left: 26px;
}
.repository.settings.branches .branch-protection .whitelist .dropdown img {
.repository.settings.settings.branches .branch-protection .whitelist .dropdown img {
display: inline-block;
}
.repository.settings.webhooks .types .menu .item {
@ -3035,10 +3035,6 @@ footer .ui.language .menu {
.admin .table.segment:not(.select) td:first-of-type {
padding-left: 15px !important;
}
.admin .ui.header,
.admin .ui.segment {
box-shadow: 0 1px 2px 0 rgba(34, 36, 38, 0.15);
}
.admin.user .email {
max-width: 200px;
}

4
public/less/_admin.less

@ -29,10 +29,6 @@
}
}
}
.ui.header,
.ui.segment {
box-shadow: 0 1px 2px 0 rgba(34,36,38,.15);
}
&.user {
.email {

4
public/less/_repository.less

@ -150,7 +150,7 @@
}
}
&.branches {
&.branches:not(.settings) {
.ui.list {
padding: 0;
>.item {
@ -1351,7 +1351,7 @@
}
}
&.branches {
&.settings.branches {
.protected-branches {
.selection.dropdown {
width: 300px;

4
routers/repo/release.go

@ -203,7 +203,6 @@ func NewReleasePost(ctx *context.Context, f form.NewRelease) {
IsPrerelease: f.Prerelease,
CreatedUnix: tagCreatedUnix,
}
if err = models.CreateRelease(ctx.Repo.GitRepo, rel); err != nil {
ctx.Data["Err_TagName"] = true
switch {
@ -274,11 +273,12 @@ func EditReleasePost(ctx *context.Context, f form.EditRelease) {
return
}
isPublish := rel.IsDraft && len(f.Draft) == 0
rel.Title = f.Title
rel.Note = f.Content
rel.IsDraft = len(f.Draft) > 0
rel.IsPrerelease = f.Prerelease
if err = models.UpdateRelease(ctx.Repo.GitRepo, rel); err != nil {
if err = models.UpdateRelease(ctx.User, ctx.Repo.GitRepo, rel, isPublish); err != nil {
ctx.Handle(500, "UpdateRelease", err)
return
}

1
routers/repo/webhook.go

@ -116,6 +116,7 @@ func ParseHookEvent(f form.Webhook) *models.HookEvent {
Issues: f.Issues,
IssueComment: f.IssueComment,
PullRequest: f.PullRequest,
Release: f.Release,
},
}
}

10
templates/repo/settings/webhook_settings.tmpl

@ -92,6 +92,16 @@
</div>
</div>
</div>
<!-- Release -->
<div class="seven wide column">
<div class="field">
<div class="ui checkbox">
<input class="hidden" name="release" type="checkbox" tabindex="0" {{if .Webhook.Release}}checked{{end}}>
<label>{{.i18n.Tr "repo.settings.event_release"}}</label>
<span class="help">{{.i18n.Tr "repo.settings.event_release_desc"}}</span>
</div>
</div>
</div>
</div>
</div>

2
vendor/github.com/gogits/go-gogs-client/gogs.go generated vendored

@ -14,7 +14,7 @@ import (
)
func Version() string {
return "0.12.9"
return "0.12.10"
}
// Client represents a Gogs API client.

22
vendor/github.com/gogits/go-gogs-client/release.go generated vendored

@ -0,0 +1,22 @@
// Copyright 2017 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package gogs
import (
"time"
)
// Release represents a release API object.
type Release struct {
ID int64 `json:"id"`
TagName string `json:"tag_name"`
TargetCommitish string `json:"target_commitish"`
Name string `json:"name"`
Body string `json:"body"`
Draft bool `json:"draft"`
Prerelease bool `json:"prerelease"`
Author *User `json:"author"`
Created time.Time `json:"created_at"`
}

27
vendor/github.com/gogits/go-gogs-client/repo_hook.go generated vendored

@ -256,6 +256,7 @@ type ChangesPayload struct {
Body *ChangesFromPayload `json:"body,omitempty"`
}
// IssuesPayload represents a payload information of issues event.
type IssuesPayload struct {
Action HookIssueAction `json:"action"`
Index int64 `json:"number"`
@ -277,6 +278,7 @@ const (
HOOK_ISSUE_COMMENT_DELETED HookIssueCommentAction = "deleted"
)
// IssueCommentPayload represents a payload information of issue comment event.
type IssueCommentPayload struct {
Action HookIssueCommentAction `json:"action"`
Issue *Issue `json:"issue"`
@ -310,3 +312,28 @@ type PullRequestPayload struct {
func (p *PullRequestPayload) JSONPayload() ([]byte, error) {
return json.MarshalIndent(p, "", " ")
}
// __________ .__
// \______ \ ____ | | ____ _____ ______ ____
// | _// __ \| | _/ __ \\__ \ / ___// __ \
// | | \ ___/| |_\ ___/ / __ \_\___ \\ ___/
// |____|_ /\___ >____/\___ >____ /____ >\___ >
// \/ \/ \/ \/ \/ \/
type HookReleaseAction string
const (
HOOK_RELEASE_PUBLISHED HookReleaseAction = "published"
)
// ReleasePayload represents a payload information of release event.
type ReleasePayload struct {
Action HookReleaseAction `json:"action"`
Release *Release `json:"release"`
Repository *Repository `json:"repository"`
Sender *User `json:"sender"`
}
func (p *ReleasePayload) JSONPayload() ([]byte, error) {
return json.MarshalIndent(p, "", " ")
}

6
vendor/vendor.json vendored

@ -165,10 +165,10 @@
"revisionTime": "2017-03-10T19:06:55Z"
},
{
"checksumSHA1": "Rvj0LCHGhFQyIM7MzBPt1iRP89c=",
"checksumSHA1": "1p1/OSDPORWbSBCD791BbGh2vVc=",
"path": "github.com/gogits/go-gogs-client",
"revision": "8e438478f71b840fcd0b3e810684ea4f6bf476bb",
"revisionTime": "2017-03-09T09:10:09Z"
"revision": "08824b5ad7408bc38f2b9287c94be2f059c9966a",
"revisionTime": "2017-03-11T23:40:19Z"
},
{
"checksumSHA1": "p4yoFWgDiTfpu1JYgh26t6+VDTk=",

Loading…
Cancel
Save