mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-02-12 00:45:17 +00:00
Merge branch 'master' into refactor_issues-subscription
This commit is contained in:
commit
90c36e37d3
68 changed files with 5437 additions and 512 deletions
11
README.md
11
README.md
|
@ -1,4 +1,4 @@
|
||||||
[简体中文](https://github.com/go-gitea/gitea/blob/master/README_ZH.md)
|
[简体中文](README_ZH.md)
|
||||||
|
|
||||||
<h1> <img src="https://raw.githubusercontent.com/go-gitea/gitea/master/public/img/gitea-192.png" alt="logo" width="30" height="30"> Gitea - Git with a cup of tea</h1>
|
<h1> <img src="https://raw.githubusercontent.com/go-gitea/gitea/master/public/img/gitea-192.png" alt="logo" width="30" height="30"> Gitea - Git with a cup of tea</h1>
|
||||||
|
|
||||||
|
@ -105,9 +105,8 @@ for the full license text.
|
||||||
## Screenshots
|
## Screenshots
|
||||||
Looking for an overview of the interface? Check it out!
|
Looking for an overview of the interface? Check it out!
|
||||||
|
|
||||||
| | | |
|
|![Dashboard](https://dl.gitea.io/screenshots/home_timeline.png)|![User Profile](https://dl.gitea.io/screenshots/user_profile.png)|![Global Issues](https://dl.gitea.io/screenshots/global_issues.png)|
|
||||||
|:---:|:---:|:---:|
|
|:---:|:---:|:---:|
|
||||||
|![Dashboard](https://image.ibb.co/dms6DG/1.png)|![Repository](https://image.ibb.co/m6MSLw/2.png)|![Commits History](https://image.ibb.co/cjrSLw/3.png)|
|
|![Branches](https://dl.gitea.io/screenshots/branches.png)|![Web Editor](https://dl.gitea.io/screenshots/web_editor.png)|![Activity](https://dl.gitea.io/screenshots/activity.png)|
|
||||||
|![Branches](https://image.ibb.co/e6vbDG/4.png)|![Issues](https://image.ibb.co/bJTJSb/5.png)|![Pull Request View](https://image.ibb.co/e02dSb/6.png)|
|
|![New Migration](https://dl.gitea.io/screenshots/migration.png)|![Migrating](https://dl.gitea.io/screenshots/migration.gif)|![Pull Request View](https://image.ibb.co/e02dSb/6.png)
|
||||||
|![Releases](https://image.ibb.co/cUzgfw/7.png)|![Activity](https://image.ibb.co/eZgGDG/8.png)|![Wiki](https://image.ibb.co/dYV9YG/9.png)|
|
![Pull Request Dark](https://dl.gitea.io/screenshots/pull_requests_dark.png)|![Diff Review Dark](https://dl.gitea.io/screenshots/review_dark.png)|![Diff Dark](https://dl.gitea.io/screenshots/diff_dark.png)|
|
||||||
|![Diff](https://image.ibb.co/ewA9YG/10.png)|![Organization](https://image.ibb.co/ceOwDG/11.png)|![Profile](https://image.ibb.co/c44Q7b/12.png)|
|
|
||||||
|
|
16
README_ZH.md
16
README_ZH.md
|
@ -1,14 +1,15 @@
|
||||||
[English](https://github.com/go-gitea/gitea/blob/master/README.md)
|
[English](README.md)
|
||||||
|
|
||||||
# Gitea - Git with a cup of tea
|
<h1> <img src="https://raw.githubusercontent.com/go-gitea/gitea/master/public/img/gitea-192.png" alt="logo" width="30" height="30"> Gitea - Git with a cup of tea</h1>
|
||||||
|
|
||||||
[![Build Status](https://drone.gitea.io/api/badges/go-gitea/gitea/status.svg)](https://drone.gitea.io/go-gitea/gitea)
|
[![Build Status](https://drone.gitea.io/api/badges/go-gitea/gitea/status.svg)](https://drone.gitea.io/go-gitea/gitea)
|
||||||
[![Join the chat at https://img.shields.io/discord/322538954119184384.svg](https://img.shields.io/discord/322538954119184384.svg)](https://discord.gg/gitea)
|
[![Join the Discord chat at https://discord.gg/NsatcWJ](https://img.shields.io/discord/322538954119184384.svg)](https://discord.gg/NsatcWJ)
|
||||||
[![](https://images.microbadger.com/badges/image/gitea/gitea.svg)](https://microbadger.com/images/gitea/gitea "Get your own image badge on microbadger.com")
|
[![](https://images.microbadger.com/badges/image/gitea/gitea.svg)](https://microbadger.com/images/gitea/gitea "Get your own image badge on microbadger.com")
|
||||||
[![codecov](https://codecov.io/gh/go-gitea/gitea/branch/master/graph/badge.svg)](https://codecov.io/gh/go-gitea/gitea)
|
[![codecov](https://codecov.io/gh/go-gitea/gitea/branch/master/graph/badge.svg)](https://codecov.io/gh/go-gitea/gitea)
|
||||||
[![Go Report Card](https://goreportcard.com/badge/code.gitea.io/gitea)](https://goreportcard.com/report/code.gitea.io/gitea)
|
[![Go Report Card](https://goreportcard.com/badge/code.gitea.io/gitea)](https://goreportcard.com/report/code.gitea.io/gitea)
|
||||||
[![GoDoc](https://godoc.org/code.gitea.io/gitea?status.svg)](https://godoc.org/code.gitea.io/gitea)
|
[![GoDoc](https://godoc.org/code.gitea.io/gitea?status.svg)](https://godoc.org/code.gitea.io/gitea)
|
||||||
[![GitHub release](https://img.shields.io/github/release/go-gitea/gitea.svg)](https://github.com/go-gitea/gitea/releases/latest)
|
[![GitHub release](https://img.shields.io/github/release/go-gitea/gitea.svg)](https://github.com/go-gitea/gitea/releases/latest)
|
||||||
|
[![Help Contribute to Open Source](https://www.codetriage.com/go-gitea/gitea/badges/users.svg)](https://www.codetriage.com/go-gitea/gitea)
|
||||||
[![Become a backer/sponsor of gitea](https://opencollective.com/gitea/tiers/backers/badge.svg?label=backers&color=brightgreen)](https://opencollective.com/gitea)
|
[![Become a backer/sponsor of gitea](https://opencollective.com/gitea/tiers/backers/badge.svg?label=backers&color=brightgreen)](https://opencollective.com/gitea)
|
||||||
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
|
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
|
||||||
[![Crowdin](https://badges.crowdin.net/gitea/localized.svg)](https://crowdin.com/project/gitea)
|
[![Crowdin](https://badges.crowdin.net/gitea/localized.svg)](https://crowdin.com/project/gitea)
|
||||||
|
@ -45,9 +46,8 @@ Fork -> Patch -> Push -> Pull Request
|
||||||
|
|
||||||
## 截图
|
## 截图
|
||||||
|
|
||||||
| | | |
|
|![Dashboard](https://dl.gitea.io/screenshots/home_timeline.png)|![User Profile](https://dl.gitea.io/screenshots/user_profile.png)|![Global Issues](https://dl.gitea.io/screenshots/global_issues.png)|
|
||||||
|:---:|:---:|:---:|
|
|:---:|:---:|:---:|
|
||||||
|![Dashboard](https://image.ibb.co/dms6DG/1.png)|![Repository](https://image.ibb.co/m6MSLw/2.png)|![Commits History](https://image.ibb.co/cjrSLw/3.png)|
|
|![Branches](https://dl.gitea.io/screenshots/branches.png)|![Web Editor](https://dl.gitea.io/screenshots/web_editor.png)|![Activity](https://dl.gitea.io/screenshots/activity.png)|
|
||||||
|![Branches](https://image.ibb.co/e6vbDG/4.png)|![Issues](https://image.ibb.co/bJTJSb/5.png)|![Pull Request View](https://image.ibb.co/e02dSb/6.png)|
|
|![New Migration](https://dl.gitea.io/screenshots/migration.png)|![Migrating](https://dl.gitea.io/screenshots/migration.gif)|![Pull Request View](https://image.ibb.co/e02dSb/6.png)
|
||||||
|![Releases](https://image.ibb.co/cUzgfw/7.png)|![Activity](https://image.ibb.co/eZgGDG/8.png)|![Wiki](https://image.ibb.co/dYV9YG/9.png)|
|
![Pull Request Dark](https://dl.gitea.io/screenshots/pull_requests_dark.png)|![Diff Review Dark](https://dl.gitea.io/screenshots/review_dark.png)|![Diff Dark](https://dl.gitea.io/screenshots/diff_dark.png)|
|
||||||
|![Diff](https://image.ibb.co/ewA9YG/10.png)|![Organization](https://image.ibb.co/ceOwDG/11.png)|![Profile](https://image.ibb.co/c44Q7b/12.png)|
|
|
||||||
|
|
|
@ -30,7 +30,8 @@ After=network.target
|
||||||
## PartOf=gitea.service
|
## PartOf=gitea.service
|
||||||
##
|
##
|
||||||
## [Socket]
|
## [Socket]
|
||||||
## ListenStream=
|
## Service=gitea.service
|
||||||
|
## ListenStream=<some_port>
|
||||||
## NoDelay=true
|
## NoDelay=true
|
||||||
##
|
##
|
||||||
## [Install]
|
## [Install]
|
||||||
|
@ -53,7 +54,7 @@ WorkingDirectory=/var/lib/gitea/
|
||||||
# If using unix socket: Tells Systemd to create /run/gitea folder to home gitea.sock
|
# If using unix socket: Tells Systemd to create /run/gitea folder to home gitea.sock
|
||||||
# Manual cration would vanish after reboot.
|
# Manual cration would vanish after reboot.
|
||||||
#RuntimeDirectory=gitea
|
#RuntimeDirectory=gitea
|
||||||
ExecStart=/usr/local/bin/gitea web -c /etc/gitea/app.ini
|
ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini
|
||||||
Restart=always
|
Restart=always
|
||||||
Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/gitea
|
Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/gitea
|
||||||
# If you want to bind Gitea to a port below 1024, uncomment
|
# If you want to bind Gitea to a port below 1024, uncomment
|
||||||
|
|
|
@ -18,7 +18,7 @@ params:
|
||||||
description: Git with a cup of tea
|
description: Git with a cup of tea
|
||||||
author: The Gitea Authors
|
author: The Gitea Authors
|
||||||
website: https://docs.gitea.io
|
website: https://docs.gitea.io
|
||||||
version: 1.9.3
|
version: 1.9.5
|
||||||
|
|
||||||
menu:
|
menu:
|
||||||
page:
|
page:
|
||||||
|
|
|
@ -42,6 +42,7 @@ Also see [Support Options]({{< relref "doc/help/seek-help.en-us.md" >}})
|
||||||
* [SSH Common Errors](#ssh-common-errors)
|
* [SSH Common Errors](#ssh-common-errors)
|
||||||
* [Missing releases after migration repository with tags](#missing-releases-after-migrating-repository-with-tags)
|
* [Missing releases after migration repository with tags](#missing-releases-after-migrating-repository-with-tags)
|
||||||
* [LFS Issues](#lfs-issues)
|
* [LFS Issues](#lfs-issues)
|
||||||
|
* [How can I create users before starting Gitea](#how-can-i-create-users-before-starting-gitea)
|
||||||
|
|
||||||
|
|
||||||
## Difference between 1.x and 1.x.x downloads
|
## Difference between 1.x and 1.x.x downloads
|
||||||
|
@ -272,3 +273,6 @@ Check the value of `LFS_HTTP_AUTH_EXPIRY` in your `app.ini` file.
|
||||||
By default, your LFS token will expire after 20 minutes. If you have a slow connection or a large file (or both), it may not finish uploading within the time limit.
|
By default, your LFS token will expire after 20 minutes. If you have a slow connection or a large file (or both), it may not finish uploading within the time limit.
|
||||||
|
|
||||||
You may want to set this value to `60m` or `120m`.
|
You may want to set this value to `60m` or `120m`.
|
||||||
|
|
||||||
|
## How can I create users before starting Gitea
|
||||||
|
Gitea provides a sub-command `gitea migrate` to initialize the database, after which you can use the [admin CLI commands]({{< relref "doc/usage/command-line.en-us.md" >}}) to add users like normal.
|
||||||
|
|
|
@ -281,3 +281,10 @@ provided key. You should also set the value
|
||||||
NB: opensshd requires the gitea program to be owned by root and not
|
NB: opensshd requires the gitea program to be owned by root and not
|
||||||
writable by group or others. The program must be specified by an absolute
|
writable by group or others. The program must be specified by an absolute
|
||||||
path.
|
path.
|
||||||
|
|
||||||
|
#### migrate
|
||||||
|
Migrates the database. This command can be used to run other commands before starting the server for the first time.
|
||||||
|
This command is idempotent.
|
||||||
|
|
||||||
|
#### convert
|
||||||
|
Converts an existing MySQL database from utf8 to utf8mb4.
|
||||||
|
|
6
go.mod
6
go.mod
|
@ -69,12 +69,10 @@ require (
|
||||||
github.com/mattn/go-sqlite3 v1.11.0
|
github.com/mattn/go-sqlite3 v1.11.0
|
||||||
github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75
|
github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75
|
||||||
github.com/microcosm-cc/bluemonday v0.0.0-20161012083705-f77f16ffc87a
|
github.com/microcosm-cc/bluemonday v0.0.0-20161012083705-f77f16ffc87a
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
|
||||||
github.com/modern-go/reflect2 v1.0.1 // indirect
|
|
||||||
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae // indirect
|
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae // indirect
|
||||||
github.com/msteinert/pam v0.0.0-20151204160544-02ccfbfaf0cc
|
github.com/msteinert/pam v0.0.0-20151204160544-02ccfbfaf0cc
|
||||||
github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5
|
github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5
|
||||||
github.com/niklasfasching/go-org v0.1.7
|
github.com/niklasfasching/go-org v0.1.8
|
||||||
github.com/oliamb/cutter v0.2.2
|
github.com/oliamb/cutter v0.2.2
|
||||||
github.com/philhofer/fwd v1.0.0 // indirect
|
github.com/philhofer/fwd v1.0.0 // indirect
|
||||||
github.com/pkg/errors v0.8.1
|
github.com/pkg/errors v0.8.1
|
||||||
|
@ -103,7 +101,7 @@ require (
|
||||||
github.com/willf/bitset v0.0.0-20180426185212-8ce1146b8621 // indirect
|
github.com/willf/bitset v0.0.0-20180426185212-8ce1146b8621 // indirect
|
||||||
github.com/yohcop/openid-go v0.0.0-20160914080427-2c050d2dae53
|
github.com/yohcop/openid-go v0.0.0-20160914080427-2c050d2dae53
|
||||||
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad
|
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad
|
||||||
golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271
|
golang.org/x/net v0.0.0-20191101175033-0deb6923b6d9
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
||||||
golang.org/x/sys v0.0.0-20190910064555-bbd175535a8b
|
golang.org/x/sys v0.0.0-20190910064555-bbd175535a8b
|
||||||
golang.org/x/text v0.3.2
|
golang.org/x/text v0.3.2
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -427,6 +427,8 @@ github.com/niklasfasching/go-org v0.1.6 h1:F521WcqRNl8OJumlgAnekZgERaTA2HpfOYYfV
|
||||||
github.com/niklasfasching/go-org v0.1.6/go.mod h1:AsLD6X7djzRIz4/RFZu8vwRL0VGjUvGZCCH1Nz0VdrU=
|
github.com/niklasfasching/go-org v0.1.6/go.mod h1:AsLD6X7djzRIz4/RFZu8vwRL0VGjUvGZCCH1Nz0VdrU=
|
||||||
github.com/niklasfasching/go-org v0.1.7 h1:t3V+3XnS/7BhKv/7SlMUa8FvAiq577/a1T3D7mLIRXE=
|
github.com/niklasfasching/go-org v0.1.7 h1:t3V+3XnS/7BhKv/7SlMUa8FvAiq577/a1T3D7mLIRXE=
|
||||||
github.com/niklasfasching/go-org v0.1.7/go.mod h1:AsLD6X7djzRIz4/RFZu8vwRL0VGjUvGZCCH1Nz0VdrU=
|
github.com/niklasfasching/go-org v0.1.7/go.mod h1:AsLD6X7djzRIz4/RFZu8vwRL0VGjUvGZCCH1Nz0VdrU=
|
||||||
|
github.com/niklasfasching/go-org v0.1.8 h1:Kjvs6lP+LIILHhc9zIJ4Gu90a/pVY483if2Qmu8v4Fg=
|
||||||
|
github.com/niklasfasching/go-org v0.1.8/go.mod h1:AsLD6X7djzRIz4/RFZu8vwRL0VGjUvGZCCH1Nz0VdrU=
|
||||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||||
github.com/oliamb/cutter v0.2.2 h1:Lfwkya0HHNU1YLnGv2hTkzHfasrSMkgv4Dn+5rmlk3k=
|
github.com/oliamb/cutter v0.2.2 h1:Lfwkya0HHNU1YLnGv2hTkzHfasrSMkgv4Dn+5rmlk3k=
|
||||||
github.com/oliamb/cutter v0.2.2/go.mod h1:4BenG2/4GuRBDbVm/OPahDVqbrOemzpPiG5mi1iryBU=
|
github.com/oliamb/cutter v0.2.2/go.mod h1:4BenG2/4GuRBDbVm/OPahDVqbrOemzpPiG5mi1iryBU=
|
||||||
|
@ -658,6 +660,8 @@ golang.org/x/net v0.0.0-20190909003024-a7b16738d86b h1:XfVGCX+0T4WOStkaOsJRllbsi
|
||||||
golang.org/x/net v0.0.0-20190909003024-a7b16738d86b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190909003024-a7b16738d86b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271 h1:N66aaryRB3Ax92gH0v3hp1QYZ3zWWCCUR/j8Ifh45Ss=
|
golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271 h1:N66aaryRB3Ax92gH0v3hp1QYZ3zWWCCUR/j8Ifh45Ss=
|
||||||
golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20191101175033-0deb6923b6d9 h1:DPz9iiH3YoKiKhX/ijjoZvT0VFwK2c6CWYWQ7Zyr8TU=
|
||||||
|
golang.org/x/net v0.0.0-20191101175033-0deb6923b6d9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 h1:Wo7BWFiOk0QRFMLYMqJGFMd9CgUAcGx7V+qEg/h5IBI=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 h1:Wo7BWFiOk0QRFMLYMqJGFMd9CgUAcGx7V+qEg/h5IBI=
|
||||||
|
|
|
@ -1293,8 +1293,12 @@ func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) {
|
||||||
log.Warn("Malformed Labels argument: %s", opts.Labels)
|
log.Warn("Malformed Labels argument: %s", opts.Labels)
|
||||||
} else {
|
} else {
|
||||||
for i, labelID := range labelIDs {
|
for i, labelID := range labelIDs {
|
||||||
|
if labelID > 0 {
|
||||||
sess.Join("INNER", fmt.Sprintf("issue_label il%d", i),
|
sess.Join("INNER", fmt.Sprintf("issue_label il%d", i),
|
||||||
fmt.Sprintf("issue.id = il%[1]d.issue_id AND il%[1]d.label_id = %[2]d", i, labelID))
|
fmt.Sprintf("issue.id = il%[1]d.issue_id AND il%[1]d.label_id = %[2]d", i, labelID))
|
||||||
|
} else {
|
||||||
|
sess.Where("issue.id NOT IN (SELECT issue_id FROM issue_label WHERE label_id = ?)", -labelID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,7 +107,7 @@ func parseKeyString(content string) (string, error) {
|
||||||
|
|
||||||
var keyType, keyContent, keyComment string
|
var keyType, keyContent, keyComment string
|
||||||
|
|
||||||
if content[:len(ssh2keyStart)] == ssh2keyStart {
|
if strings.HasPrefix(content, ssh2keyStart) {
|
||||||
// Parse SSH2 file format.
|
// Parse SSH2 file format.
|
||||||
|
|
||||||
// Transform all legal line endings to a single "\n".
|
// Transform all legal line endings to a single "\n".
|
||||||
|
|
|
@ -131,6 +131,19 @@ AAAAC3NzaC1lZDI1NTE5AAAAICV0MGX/W9IvLA4FXpIuUcdDcbj5KX4syHgsTy7soVgf
|
||||||
_, err := CheckPublicKeyString(test.content)
|
_, err := CheckPublicKeyString(test.content)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, invalidKeys := range []struct {
|
||||||
|
content string
|
||||||
|
}{
|
||||||
|
{"test"},
|
||||||
|
{"---- NOT A REAL KEY ----"},
|
||||||
|
{"bad\nkey"},
|
||||||
|
{"\t\t:)\t\r\n"},
|
||||||
|
{"\r\ntest \r\ngitea\r\n\r\n"},
|
||||||
|
} {
|
||||||
|
_, err := CheckPublicKeyString(invalidKeys.content)
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_calcFingerprint(t *testing.T) {
|
func Test_calcFingerprint(t *testing.T) {
|
||||||
|
|
|
@ -118,33 +118,6 @@ func (w *Webhook) AfterLoad() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSlackHook returns slack metadata
|
|
||||||
func (w *Webhook) GetSlackHook() *SlackMeta {
|
|
||||||
s := &SlackMeta{}
|
|
||||||
if err := json.Unmarshal([]byte(w.Meta), s); err != nil {
|
|
||||||
log.Error("webhook.GetSlackHook(%d): %v", w.ID, err)
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetDiscordHook returns discord metadata
|
|
||||||
func (w *Webhook) GetDiscordHook() *DiscordMeta {
|
|
||||||
s := &DiscordMeta{}
|
|
||||||
if err := json.Unmarshal([]byte(w.Meta), s); err != nil {
|
|
||||||
log.Error("webhook.GetDiscordHook(%d): %v", w.ID, err)
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetTelegramHook returns telegram metadata
|
|
||||||
func (w *Webhook) GetTelegramHook() *TelegramMeta {
|
|
||||||
s := &TelegramMeta{}
|
|
||||||
if err := json.Unmarshal([]byte(w.Meta), s); err != nil {
|
|
||||||
log.Error("webhook.GetTelegramHook(%d): %v", w.ID, err)
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
// History returns history of webhook by given conditions.
|
// History returns history of webhook by given conditions.
|
||||||
func (w *Webhook) History(page int) ([]*HookTask, error) {
|
func (w *Webhook) History(page int) ([]*HookTask, error) {
|
||||||
return HookTasks(w.ID, page)
|
return HookTasks(w.ID, page)
|
||||||
|
|
|
@ -24,18 +24,6 @@ func TestIsValidHookContentType(t *testing.T) {
|
||||||
assert.False(t, IsValidHookContentType("invalid"))
|
assert.False(t, IsValidHookContentType("invalid"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWebhook_GetSlackHook(t *testing.T) {
|
|
||||||
w := &Webhook{
|
|
||||||
Meta: `{"channel": "foo", "username": "username", "color": "blue"}`,
|
|
||||||
}
|
|
||||||
slackHook := w.GetSlackHook()
|
|
||||||
assert.Equal(t, *slackHook, SlackMeta{
|
|
||||||
Channel: "foo",
|
|
||||||
Username: "username",
|
|
||||||
Color: "blue",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWebhook_History(t *testing.T) {
|
func TestWebhook_History(t *testing.T) {
|
||||||
assert.NoError(t, PrepareTestDatabase())
|
assert.NoError(t, PrepareTestDatabase())
|
||||||
webhook := AssertExistsAndLoadBean(t, &Webhook{ID: 1}).(*Webhook)
|
webhook := AssertExistsAndLoadBean(t, &Webhook{ID: 1}).(*Webhook)
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html"
|
"html"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/markup"
|
"code.gitea.io/gitea/modules/markup"
|
||||||
|
@ -91,7 +90,7 @@ func (r *Renderer) WriteRegularLink(l org.RegularLink) {
|
||||||
|
|
||||||
description := string(link)
|
description := string(link)
|
||||||
if l.Description != nil {
|
if l.Description != nil {
|
||||||
description = r.nodesAsString(l.Description...)
|
description = r.WriteNodesAsString(l.Description...)
|
||||||
}
|
}
|
||||||
switch l.Kind() {
|
switch l.Kind() {
|
||||||
case "image":
|
case "image":
|
||||||
|
@ -102,21 +101,3 @@ func (r *Renderer) WriteRegularLink(l org.RegularLink) {
|
||||||
r.WriteString(fmt.Sprintf(`<a href="%s" title="%s">%s</a>`, link, description, description))
|
r.WriteString(fmt.Sprintf(`<a href="%s" title="%s">%s</a>`, link, description, description))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Renderer) emptyClone() *Renderer {
|
|
||||||
wcopy := *(r.HTMLWriter)
|
|
||||||
wcopy.Builder = strings.Builder{}
|
|
||||||
|
|
||||||
rcopy := *r
|
|
||||||
rcopy.HTMLWriter = &wcopy
|
|
||||||
|
|
||||||
wcopy.ExtendingWriter = &rcopy
|
|
||||||
|
|
||||||
return &rcopy
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Renderer) nodesAsString(nodes ...org.Node) string {
|
|
||||||
tmp := r.emptyClone()
|
|
||||||
org.WriteNodes(tmp, nodes...)
|
|
||||||
return tmp.String()
|
|
||||||
}
|
|
||||||
|
|
|
@ -252,6 +252,7 @@ func (g *GiteaLocalUploader) CreateReleases(releases ...*base.Release) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// download attachment
|
// download attachment
|
||||||
|
err = func() error {
|
||||||
resp, err := http.Get(asset.URL)
|
resp, err := http.Get(asset.URL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -269,10 +270,12 @@ func (g *GiteaLocalUploader) CreateReleases(releases ...*base.Release) error {
|
||||||
}
|
}
|
||||||
defer fw.Close()
|
defer fw.Close()
|
||||||
|
|
||||||
if _, err := io.Copy(fw, resp.Body); err != nil {
|
_, err = io.Copy(fw, resp.Body)
|
||||||
|
return err
|
||||||
|
}()
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
rel.Attachments = append(rel.Attachments, &attach)
|
rel.Attachments = append(rel.Attachments, &attach)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -468,21 +471,24 @@ func (g *GiteaLocalUploader) newPullRequest(pr *base.PullRequest) (*models.PullR
|
||||||
}
|
}
|
||||||
|
|
||||||
// download patch file
|
// download patch file
|
||||||
|
err := func() error {
|
||||||
resp, err := http.Get(pr.PatchURL)
|
resp, err := http.Get(pr.PatchURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
pullDir := filepath.Join(g.repo.RepoPath(), "pulls")
|
pullDir := filepath.Join(g.repo.RepoPath(), "pulls")
|
||||||
if err = os.MkdirAll(pullDir, os.ModePerm); err != nil {
|
if err = os.MkdirAll(pullDir, os.ModePerm); err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
f, err := os.Create(filepath.Join(pullDir, fmt.Sprintf("%d.patch", pr.Number)))
|
f, err := os.Create(filepath.Join(pullDir, fmt.Sprintf("%d.patch", pr.Number)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
_, err = io.Copy(f, resp.Body)
|
_, err = io.Copy(f, resp.Body)
|
||||||
|
return err
|
||||||
|
}()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -496,8 +502,8 @@ func (g *GiteaLocalUploader) newPullRequest(pr *base.PullRequest) (*models.PullR
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer p.Close()
|
|
||||||
_, err = p.WriteString(pr.Head.SHA)
|
_, err = p.WriteString(pr.Head.SHA)
|
||||||
|
p.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -531,8 +537,8 @@ func (g *GiteaLocalUploader) newPullRequest(pr *base.PullRequest) (*models.PullR
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer b.Close()
|
|
||||||
_, err = b.WriteString(pr.Head.SHA)
|
_, err = b.WriteString(pr.Head.SHA)
|
||||||
|
b.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
77
modules/notification/action/action.go
Normal file
77
modules/notification/action/action.go
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
// Copyright 2019 The Gitea 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 action
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models"
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/notification/base"
|
||||||
|
)
|
||||||
|
|
||||||
|
type actionNotifier struct {
|
||||||
|
base.NullNotifier
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ base.Notifier = &actionNotifier{}
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewNotifier create a new webhookNotifier notifier
|
||||||
|
func NewNotifier() base.Notifier {
|
||||||
|
return &actionNotifier{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *actionNotifier) NotifyNewIssue(issue *models.Issue) {
|
||||||
|
if err := issue.LoadPoster(); err != nil {
|
||||||
|
log.Error("issue.LoadPoster: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := issue.LoadRepo(); err != nil {
|
||||||
|
log.Error("issue.LoadRepo: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
repo := issue.Repo
|
||||||
|
|
||||||
|
if err := models.NotifyWatchers(&models.Action{
|
||||||
|
ActUserID: issue.Poster.ID,
|
||||||
|
ActUser: issue.Poster,
|
||||||
|
OpType: models.ActionCreateIssue,
|
||||||
|
Content: fmt.Sprintf("%d|%s", issue.Index, issue.Title),
|
||||||
|
RepoID: repo.ID,
|
||||||
|
Repo: repo,
|
||||||
|
IsPrivate: repo.IsPrivate,
|
||||||
|
}); err != nil {
|
||||||
|
log.Error("NotifyWatchers: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *actionNotifier) NotifyNewPullRequest(pull *models.PullRequest) {
|
||||||
|
if err := pull.LoadIssue(); err != nil {
|
||||||
|
log.Error("pull.LoadIssue: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := pull.Issue.LoadRepo(); err != nil {
|
||||||
|
log.Error("pull.Issue.LoadRepo: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := pull.Issue.LoadPoster(); err != nil {
|
||||||
|
log.Error("pull.Issue.LoadPoster: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := models.NotifyWatchers(&models.Action{
|
||||||
|
ActUserID: pull.Issue.Poster.ID,
|
||||||
|
ActUser: pull.Issue.Poster,
|
||||||
|
OpType: models.ActionCreatePullRequest,
|
||||||
|
Content: fmt.Sprintf("%d|%s", pull.Issue.Index, pull.Issue.Title),
|
||||||
|
RepoID: pull.Issue.Repo.ID,
|
||||||
|
Repo: pull.Issue.Repo,
|
||||||
|
IsPrivate: pull.Issue.Repo.IsPrivate,
|
||||||
|
}); err != nil {
|
||||||
|
log.Error("NotifyWatchers: %v", err)
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,6 +30,7 @@ type Notifier interface {
|
||||||
|
|
||||||
NotifyNewPullRequest(*models.PullRequest)
|
NotifyNewPullRequest(*models.PullRequest)
|
||||||
NotifyMergePullRequest(*models.PullRequest, *models.User, *git.Repository)
|
NotifyMergePullRequest(*models.PullRequest, *models.User, *git.Repository)
|
||||||
|
NotifyPullRequestSynchronized(doer *models.User, pr *models.PullRequest)
|
||||||
NotifyPullRequestReview(*models.PullRequest, *models.Review, *models.Comment)
|
NotifyPullRequestReview(*models.PullRequest, *models.Review, *models.Comment)
|
||||||
|
|
||||||
NotifyCreateIssueComment(*models.User, *models.Repository,
|
NotifyCreateIssueComment(*models.User, *models.Repository,
|
||||||
|
@ -40,4 +41,6 @@ type Notifier interface {
|
||||||
NotifyNewRelease(rel *models.Release)
|
NotifyNewRelease(rel *models.Release)
|
||||||
NotifyUpdateRelease(doer *models.User, rel *models.Release)
|
NotifyUpdateRelease(doer *models.User, rel *models.Release)
|
||||||
NotifyDeleteRelease(doer *models.User, rel *models.Release)
|
NotifyDeleteRelease(doer *models.User, rel *models.Release)
|
||||||
|
|
||||||
|
NotifyPushCommits(pusher *models.User, repo *models.Repository, refName, oldCommitID, newCommitID string, commits *models.PushCommits)
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,10 @@ func (*NullNotifier) NotifyPullRequestReview(pr *models.PullRequest, r *models.R
|
||||||
func (*NullNotifier) NotifyMergePullRequest(pr *models.PullRequest, doer *models.User, baseRepo *git.Repository) {
|
func (*NullNotifier) NotifyMergePullRequest(pr *models.PullRequest, doer *models.User, baseRepo *git.Repository) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NotifyPullRequestSynchronized places a place holder function
|
||||||
|
func (*NullNotifier) NotifyPullRequestSynchronized(doer *models.User, pr *models.PullRequest) {
|
||||||
|
}
|
||||||
|
|
||||||
// NotifyUpdateComment places a place holder function
|
// NotifyUpdateComment places a place holder function
|
||||||
func (*NullNotifier) NotifyUpdateComment(doer *models.User, c *models.Comment, oldContent string) {
|
func (*NullNotifier) NotifyUpdateComment(doer *models.User, c *models.Comment, oldContent string) {
|
||||||
}
|
}
|
||||||
|
@ -106,3 +110,7 @@ func (*NullNotifier) NotifyCreateRepository(doer *models.User, u *models.User, r
|
||||||
// NotifyMigrateRepository places a place holder function
|
// NotifyMigrateRepository places a place holder function
|
||||||
func (*NullNotifier) NotifyMigrateRepository(doer *models.User, u *models.User, repo *models.Repository) {
|
func (*NullNotifier) NotifyMigrateRepository(doer *models.User, u *models.User, repo *models.Repository) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NotifyPushCommits notifies commits pushed to notifiers
|
||||||
|
func (*NullNotifier) NotifyPushCommits(pusher *models.User, repo *models.Repository, refName, oldCommitID, newCommitID string, commits *models.PushCommits) {
|
||||||
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ package notification
|
||||||
import (
|
import (
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
"code.gitea.io/gitea/modules/notification/action"
|
||||||
"code.gitea.io/gitea/modules/notification/base"
|
"code.gitea.io/gitea/modules/notification/base"
|
||||||
"code.gitea.io/gitea/modules/notification/indexer"
|
"code.gitea.io/gitea/modules/notification/indexer"
|
||||||
"code.gitea.io/gitea/modules/notification/mail"
|
"code.gitea.io/gitea/modules/notification/mail"
|
||||||
|
@ -33,6 +34,7 @@ func NewContext() {
|
||||||
}
|
}
|
||||||
RegisterNotifier(indexer.NewNotifier())
|
RegisterNotifier(indexer.NewNotifier())
|
||||||
RegisterNotifier(webhook.NewNotifier())
|
RegisterNotifier(webhook.NewNotifier())
|
||||||
|
RegisterNotifier(action.NewNotifier())
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyCreateIssueComment notifies issue comment related message to notifiers
|
// NotifyCreateIssueComment notifies issue comment related message to notifiers
|
||||||
|
@ -71,6 +73,13 @@ func NotifyNewPullRequest(pr *models.PullRequest) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NotifyPullRequestSynchronized notifies Synchronized pull request
|
||||||
|
func NotifyPullRequestSynchronized(doer *models.User, pr *models.PullRequest) {
|
||||||
|
for _, notifier := range notifiers {
|
||||||
|
notifier.NotifyPullRequestSynchronized(doer, pr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NotifyPullRequestReview notifies new pull request review
|
// NotifyPullRequestReview notifies new pull request review
|
||||||
func NotifyPullRequestReview(pr *models.PullRequest, review *models.Review, comment *models.Comment) {
|
func NotifyPullRequestReview(pr *models.PullRequest, review *models.Review, comment *models.Comment) {
|
||||||
for _, notifier := range notifiers {
|
for _, notifier := range notifiers {
|
||||||
|
@ -183,3 +192,10 @@ func NotifyMigrateRepository(doer *models.User, u *models.User, repo *models.Rep
|
||||||
notifier.NotifyMigrateRepository(doer, u, repo)
|
notifier.NotifyMigrateRepository(doer, u, repo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NotifyPushCommits notifies commits pushed to notifiers
|
||||||
|
func NotifyPushCommits(pusher *models.User, repo *models.Repository, refName, oldCommitID, newCommitID string, commits *models.PushCommits) {
|
||||||
|
for _, notifier := range notifiers {
|
||||||
|
notifier.NotifyPushCommits(pusher, repo, refName, oldCommitID, newCommitID, commits)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -8,7 +8,9 @@ import (
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/notification/base"
|
"code.gitea.io/gitea/modules/notification/base"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
"code.gitea.io/gitea/modules/webhook"
|
||||||
webhook_module "code.gitea.io/gitea/modules/webhook"
|
webhook_module "code.gitea.io/gitea/modules/webhook"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -250,6 +252,15 @@ func (m *webhookNotifier) NotifyIssueChangeStatus(doer *models.User, issue *mode
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *webhookNotifier) NotifyNewIssue(issue *models.Issue) {
|
func (m *webhookNotifier) NotifyNewIssue(issue *models.Issue) {
|
||||||
|
if err := issue.LoadRepo(); err != nil {
|
||||||
|
log.Error("issue.LoadRepo: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := issue.LoadPoster(); err != nil {
|
||||||
|
log.Error("issue.LoadPoster: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
mode, _ := models.AccessLevel(issue.Poster, issue.Repo)
|
mode, _ := models.AccessLevel(issue.Poster, issue.Repo)
|
||||||
if err := webhook_module.PrepareWebhooks(issue.Repo, models.HookEventIssues, &api.IssuePayload{
|
if err := webhook_module.PrepareWebhooks(issue.Repo, models.HookEventIssues, &api.IssuePayload{
|
||||||
Action: api.HookIssueOpened,
|
Action: api.HookIssueOpened,
|
||||||
|
@ -262,6 +273,32 @@ func (m *webhookNotifier) NotifyNewIssue(issue *models.Issue) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *webhookNotifier) NotifyNewPullRequest(pull *models.PullRequest) {
|
||||||
|
if err := pull.LoadIssue(); err != nil {
|
||||||
|
log.Error("pull.LoadIssue: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := pull.Issue.LoadRepo(); err != nil {
|
||||||
|
log.Error("pull.Issue.LoadRepo: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := pull.Issue.LoadPoster(); err != nil {
|
||||||
|
log.Error("pull.Issue.LoadPoster: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mode, _ := models.AccessLevel(pull.Issue.Poster, pull.Issue.Repo)
|
||||||
|
if err := webhook.PrepareWebhooks(pull.Issue.Repo, models.HookEventPullRequest, &api.PullRequestPayload{
|
||||||
|
Action: api.HookIssueOpened,
|
||||||
|
Index: pull.Issue.Index,
|
||||||
|
PullRequest: pull.APIFormat(),
|
||||||
|
Repository: pull.Issue.Repo.APIFormat(mode),
|
||||||
|
Sender: pull.Issue.Poster.APIFormat(),
|
||||||
|
}); err != nil {
|
||||||
|
log.Error("PrepareWebhooks: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (m *webhookNotifier) NotifyIssueChangeContent(doer *models.User, issue *models.Issue, oldContent string) {
|
func (m *webhookNotifier) NotifyIssueChangeContent(doer *models.User, issue *models.Issue, oldContent string) {
|
||||||
mode, _ := models.AccessLevel(issue.Poster, issue.Repo)
|
mode, _ := models.AccessLevel(issue.Poster, issue.Repo)
|
||||||
var err error
|
var err error
|
||||||
|
@ -461,3 +498,87 @@ func (m *webhookNotifier) NotifyIssueChangeMilestone(doer *models.User, issue *m
|
||||||
log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
|
log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *webhookNotifier) NotifyPushCommits(pusher *models.User, repo *models.Repository, refName, oldCommitID, newCommitID string, commits *models.PushCommits) {
|
||||||
|
apiPusher := pusher.APIFormat()
|
||||||
|
apiCommits, err := commits.ToAPIPayloadCommits(repo.RepoPath(), repo.HTMLURL())
|
||||||
|
if err != nil {
|
||||||
|
log.Error("commits.ToAPIPayloadCommits failed: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := webhook_module.PrepareWebhooks(repo, models.HookEventPush, &api.PushPayload{
|
||||||
|
Ref: refName,
|
||||||
|
Before: oldCommitID,
|
||||||
|
After: newCommitID,
|
||||||
|
CompareURL: setting.AppURL + commits.CompareURL,
|
||||||
|
Commits: apiCommits,
|
||||||
|
Repo: repo.APIFormat(models.AccessModeOwner),
|
||||||
|
Pusher: apiPusher,
|
||||||
|
Sender: apiPusher,
|
||||||
|
}); err != nil {
|
||||||
|
log.Error("PrepareWebhooks: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *webhookNotifier) NotifyPullRequestReview(pr *models.PullRequest, review *models.Review, comment *models.Comment) {
|
||||||
|
var reviewHookType models.HookEventType
|
||||||
|
|
||||||
|
switch review.Type {
|
||||||
|
case models.ReviewTypeApprove:
|
||||||
|
reviewHookType = models.HookEventPullRequestApproved
|
||||||
|
case models.ReviewTypeComment:
|
||||||
|
reviewHookType = models.HookEventPullRequestComment
|
||||||
|
case models.ReviewTypeReject:
|
||||||
|
reviewHookType = models.HookEventPullRequestRejected
|
||||||
|
default:
|
||||||
|
// unsupported review webhook type here
|
||||||
|
log.Error("Unsupported review webhook type")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := pr.LoadIssue(); err != nil {
|
||||||
|
log.Error("pr.LoadIssue: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mode, err := models.AccessLevel(review.Issue.Poster, review.Issue.Repo)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("models.AccessLevel: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := webhook.PrepareWebhooks(review.Issue.Repo, reviewHookType, &api.PullRequestPayload{
|
||||||
|
Action: api.HookIssueSynchronized,
|
||||||
|
Index: review.Issue.Index,
|
||||||
|
PullRequest: pr.APIFormat(),
|
||||||
|
Repository: review.Issue.Repo.APIFormat(mode),
|
||||||
|
Sender: review.Reviewer.APIFormat(),
|
||||||
|
Review: &api.ReviewPayload{
|
||||||
|
Type: string(reviewHookType),
|
||||||
|
Content: review.Content,
|
||||||
|
},
|
||||||
|
}); err != nil {
|
||||||
|
log.Error("PrepareWebhooks: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *webhookNotifier) NotifyPullRequestSynchronized(doer *models.User, pr *models.PullRequest) {
|
||||||
|
if err := pr.LoadIssue(); err != nil {
|
||||||
|
log.Error("pr.LoadIssue: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := pr.Issue.LoadAttributes(); err != nil {
|
||||||
|
log.Error("LoadAttributes: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := webhook.PrepareWebhooks(pr.Issue.Repo, models.HookEventPullRequest, &api.PullRequestPayload{
|
||||||
|
Action: api.HookIssueSynchronized,
|
||||||
|
Index: pr.Issue.Index,
|
||||||
|
PullRequest: pr.Issue.PullRequest.APIFormat(),
|
||||||
|
Repository: pr.Issue.Repo.APIFormat(models.AccessModeNone),
|
||||||
|
Sender: doer.APIFormat(),
|
||||||
|
}); err != nil {
|
||||||
|
log.Error("PrepareWebhooks [pull_id: %v]: %v", pr.ID, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/notification"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/webhook"
|
"code.gitea.io/gitea/modules/webhook"
|
||||||
|
@ -190,22 +191,7 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if isHookEventPush {
|
if isHookEventPush {
|
||||||
commits, err := opts.Commits.ToAPIPayloadCommits(repo.RepoPath(), repo.HTMLURL())
|
notification.NotifyPushCommits(pusher, repo, opts.RefFullName, opts.OldCommitID, opts.NewCommitID, opts.Commits)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err = webhook.PrepareWebhooks(repo, models.HookEventPush, &api.PushPayload{
|
|
||||||
Ref: opts.RefFullName,
|
|
||||||
Before: opts.OldCommitID,
|
|
||||||
After: opts.NewCommitID,
|
|
||||||
CompareURL: setting.AppURL + opts.Commits.CompareURL,
|
|
||||||
Commits: commits,
|
|
||||||
Repo: apiRepo,
|
|
||||||
Pusher: apiPusher,
|
|
||||||
Sender: apiPusher,
|
|
||||||
}); err != nil {
|
|
||||||
return fmt.Errorf("PrepareWebhooks: %v", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -100,6 +100,7 @@ type EditIssueOption struct {
|
||||||
State *string `json:"state"`
|
State *string `json:"state"`
|
||||||
// swagger:strfmt date-time
|
// swagger:strfmt date-time
|
||||||
Deadline *time.Time `json:"due_date"`
|
Deadline *time.Time `json:"due_date"`
|
||||||
|
RemoveDeadline *bool `json:"unset_due_date"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// EditDeadlineOption options for creating a deadline
|
// EditDeadlineOption options for creating a deadline
|
||||||
|
|
|
@ -89,4 +89,5 @@ type EditPullRequestOption struct {
|
||||||
State *string `json:"state"`
|
State *string `json:"state"`
|
||||||
// swagger:strfmt date-time
|
// swagger:strfmt date-time
|
||||||
Deadline *time.Time `json:"due_date"`
|
Deadline *time.Time `json:"due_date"`
|
||||||
|
RemoveDeadline *bool `json:"unset_due_date"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,14 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package webhook
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
|
||||||
|
@ -184,7 +185,7 @@ func getDingtalkIssuesPayload(p *api.IssuePayload) (*DingtalkPayload, error) {
|
||||||
|
|
||||||
func getDingtalkIssueCommentPayload(p *api.IssueCommentPayload) (*DingtalkPayload, error) {
|
func getDingtalkIssueCommentPayload(p *api.IssueCommentPayload) (*DingtalkPayload, error) {
|
||||||
title := fmt.Sprintf("#%d: %s", p.Issue.Index, p.Issue.Title)
|
title := fmt.Sprintf("#%d: %s", p.Issue.Index, p.Issue.Title)
|
||||||
url := fmt.Sprintf("%s/issues/%d#%s", p.Repository.HTMLURL, p.Issue.Index, CommentHashTag(p.Comment.ID))
|
url := fmt.Sprintf("%s/issues/%d#%s", p.Repository.HTMLURL, p.Issue.Index, models.CommentHashTag(p.Comment.ID))
|
||||||
var content string
|
var content string
|
||||||
switch p.Action {
|
switch p.Action {
|
||||||
case api.HookIssueCommentCreated:
|
case api.HookIssueCommentCreated:
|
||||||
|
@ -286,7 +287,7 @@ func getDingtalkPullRequestPayload(p *api.PullRequestPayload) (*DingtalkPayload,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDingtalkPullRequestApprovalPayload(p *api.PullRequestPayload, event HookEventType) (*DingtalkPayload, error) {
|
func getDingtalkPullRequestApprovalPayload(p *api.PullRequestPayload, event models.HookEventType) (*DingtalkPayload, error) {
|
||||||
var text, title string
|
var text, title string
|
||||||
switch p.Action {
|
switch p.Action {
|
||||||
case api.HookIssueSynchronized:
|
case api.HookIssueSynchronized:
|
||||||
|
@ -392,29 +393,29 @@ func getDingtalkReleasePayload(p *api.ReleasePayload) (*DingtalkPayload, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDingtalkPayload converts a ding talk webhook into a DingtalkPayload
|
// GetDingtalkPayload converts a ding talk webhook into a DingtalkPayload
|
||||||
func GetDingtalkPayload(p api.Payloader, event HookEventType, meta string) (*DingtalkPayload, error) {
|
func GetDingtalkPayload(p api.Payloader, event models.HookEventType, meta string) (*DingtalkPayload, error) {
|
||||||
s := new(DingtalkPayload)
|
s := new(DingtalkPayload)
|
||||||
|
|
||||||
switch event {
|
switch event {
|
||||||
case HookEventCreate:
|
case models.HookEventCreate:
|
||||||
return getDingtalkCreatePayload(p.(*api.CreatePayload))
|
return getDingtalkCreatePayload(p.(*api.CreatePayload))
|
||||||
case HookEventDelete:
|
case models.HookEventDelete:
|
||||||
return getDingtalkDeletePayload(p.(*api.DeletePayload))
|
return getDingtalkDeletePayload(p.(*api.DeletePayload))
|
||||||
case HookEventFork:
|
case models.HookEventFork:
|
||||||
return getDingtalkForkPayload(p.(*api.ForkPayload))
|
return getDingtalkForkPayload(p.(*api.ForkPayload))
|
||||||
case HookEventIssues:
|
case models.HookEventIssues:
|
||||||
return getDingtalkIssuesPayload(p.(*api.IssuePayload))
|
return getDingtalkIssuesPayload(p.(*api.IssuePayload))
|
||||||
case HookEventIssueComment:
|
case models.HookEventIssueComment:
|
||||||
return getDingtalkIssueCommentPayload(p.(*api.IssueCommentPayload))
|
return getDingtalkIssueCommentPayload(p.(*api.IssueCommentPayload))
|
||||||
case HookEventPush:
|
case models.HookEventPush:
|
||||||
return getDingtalkPushPayload(p.(*api.PushPayload))
|
return getDingtalkPushPayload(p.(*api.PushPayload))
|
||||||
case HookEventPullRequest:
|
case models.HookEventPullRequest:
|
||||||
return getDingtalkPullRequestPayload(p.(*api.PullRequestPayload))
|
return getDingtalkPullRequestPayload(p.(*api.PullRequestPayload))
|
||||||
case HookEventPullRequestApproved, HookEventPullRequestRejected, HookEventPullRequestComment:
|
case models.HookEventPullRequestApproved, models.HookEventPullRequestRejected, models.HookEventPullRequestComment:
|
||||||
return getDingtalkPullRequestApprovalPayload(p.(*api.PullRequestPayload), event)
|
return getDingtalkPullRequestApprovalPayload(p.(*api.PullRequestPayload), event)
|
||||||
case HookEventRepository:
|
case models.HookEventRepository:
|
||||||
return getDingtalkRepositoryPayload(p.(*api.RepositoryPayload))
|
return getDingtalkRepositoryPayload(p.(*api.RepositoryPayload))
|
||||||
case HookEventRelease:
|
case models.HookEventRelease:
|
||||||
return getDingtalkReleasePayload(p.(*api.ReleasePayload))
|
return getDingtalkReleasePayload(p.(*api.ReleasePayload))
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package webhook
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
@ -11,7 +11,9 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
)
|
)
|
||||||
|
@ -63,6 +65,15 @@ type (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// GetDiscordHook returns discord metadata
|
||||||
|
func GetDiscordHook(w *models.Webhook) *DiscordMeta {
|
||||||
|
s := &DiscordMeta{}
|
||||||
|
if err := json.Unmarshal([]byte(w.Meta), s); err != nil {
|
||||||
|
log.Error("webhook.GetDiscordHook(%d): %v", w.ID, err)
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
func color(clr string) int {
|
func color(clr string) int {
|
||||||
if clr != "" {
|
if clr != "" {
|
||||||
clr = strings.TrimLeft(clr, "#")
|
clr = strings.TrimLeft(clr, "#")
|
||||||
|
@ -288,7 +299,7 @@ func getDiscordIssuesPayload(p *api.IssuePayload, meta *DiscordMeta) (*DiscordPa
|
||||||
|
|
||||||
func getDiscordIssueCommentPayload(p *api.IssueCommentPayload, discord *DiscordMeta) (*DiscordPayload, error) {
|
func getDiscordIssueCommentPayload(p *api.IssueCommentPayload, discord *DiscordMeta) (*DiscordPayload, error) {
|
||||||
title := fmt.Sprintf("#%d: %s", p.Issue.Index, p.Issue.Title)
|
title := fmt.Sprintf("#%d: %s", p.Issue.Index, p.Issue.Title)
|
||||||
url := fmt.Sprintf("%s/issues/%d#%s", p.Repository.HTMLURL, p.Issue.Index, CommentHashTag(p.Comment.ID))
|
url := fmt.Sprintf("%s/issues/%d#%s", p.Repository.HTMLURL, p.Issue.Index, models.CommentHashTag(p.Comment.ID))
|
||||||
content := ""
|
content := ""
|
||||||
var color int
|
var color int
|
||||||
switch p.Action {
|
switch p.Action {
|
||||||
|
@ -421,7 +432,7 @@ func getDiscordPullRequestPayload(p *api.PullRequestPayload, meta *DiscordMeta)
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDiscordPullRequestApprovalPayload(p *api.PullRequestPayload, meta *DiscordMeta, event HookEventType) (*DiscordPayload, error) {
|
func getDiscordPullRequestApprovalPayload(p *api.PullRequestPayload, meta *DiscordMeta, event models.HookEventType) (*DiscordPayload, error) {
|
||||||
var text, title string
|
var text, title string
|
||||||
var color int
|
var color int
|
||||||
switch p.Action {
|
switch p.Action {
|
||||||
|
@ -435,11 +446,11 @@ func getDiscordPullRequestApprovalPayload(p *api.PullRequestPayload, meta *Disco
|
||||||
text = p.Review.Content
|
text = p.Review.Content
|
||||||
|
|
||||||
switch event {
|
switch event {
|
||||||
case HookEventPullRequestApproved:
|
case models.HookEventPullRequestApproved:
|
||||||
color = greenColor
|
color = greenColor
|
||||||
case HookEventPullRequestRejected:
|
case models.HookEventPullRequestRejected:
|
||||||
color = redColor
|
color = redColor
|
||||||
case HookEventPullRequestComment:
|
case models.HookEventPullRequestComment:
|
||||||
color = greyColor
|
color = greyColor
|
||||||
default:
|
default:
|
||||||
color = yellowColor
|
color = yellowColor
|
||||||
|
@ -534,7 +545,7 @@ func getDiscordReleasePayload(p *api.ReleasePayload, meta *DiscordMeta) (*Discor
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDiscordPayload converts a discord webhook into a DiscordPayload
|
// GetDiscordPayload converts a discord webhook into a DiscordPayload
|
||||||
func GetDiscordPayload(p api.Payloader, event HookEventType, meta string) (*DiscordPayload, error) {
|
func GetDiscordPayload(p api.Payloader, event models.HookEventType, meta string) (*DiscordPayload, error) {
|
||||||
s := new(DiscordPayload)
|
s := new(DiscordPayload)
|
||||||
|
|
||||||
discord := &DiscordMeta{}
|
discord := &DiscordMeta{}
|
||||||
|
@ -543,40 +554,40 @@ func GetDiscordPayload(p api.Payloader, event HookEventType, meta string) (*Disc
|
||||||
}
|
}
|
||||||
|
|
||||||
switch event {
|
switch event {
|
||||||
case HookEventCreate:
|
case models.HookEventCreate:
|
||||||
return getDiscordCreatePayload(p.(*api.CreatePayload), discord)
|
return getDiscordCreatePayload(p.(*api.CreatePayload), discord)
|
||||||
case HookEventDelete:
|
case models.HookEventDelete:
|
||||||
return getDiscordDeletePayload(p.(*api.DeletePayload), discord)
|
return getDiscordDeletePayload(p.(*api.DeletePayload), discord)
|
||||||
case HookEventFork:
|
case models.HookEventFork:
|
||||||
return getDiscordForkPayload(p.(*api.ForkPayload), discord)
|
return getDiscordForkPayload(p.(*api.ForkPayload), discord)
|
||||||
case HookEventIssues:
|
case models.HookEventIssues:
|
||||||
return getDiscordIssuesPayload(p.(*api.IssuePayload), discord)
|
return getDiscordIssuesPayload(p.(*api.IssuePayload), discord)
|
||||||
case HookEventIssueComment:
|
case models.HookEventIssueComment:
|
||||||
return getDiscordIssueCommentPayload(p.(*api.IssueCommentPayload), discord)
|
return getDiscordIssueCommentPayload(p.(*api.IssueCommentPayload), discord)
|
||||||
case HookEventPush:
|
case models.HookEventPush:
|
||||||
return getDiscordPushPayload(p.(*api.PushPayload), discord)
|
return getDiscordPushPayload(p.(*api.PushPayload), discord)
|
||||||
case HookEventPullRequest:
|
case models.HookEventPullRequest:
|
||||||
return getDiscordPullRequestPayload(p.(*api.PullRequestPayload), discord)
|
return getDiscordPullRequestPayload(p.(*api.PullRequestPayload), discord)
|
||||||
case HookEventPullRequestRejected, HookEventPullRequestApproved, HookEventPullRequestComment:
|
case models.HookEventPullRequestRejected, models.HookEventPullRequestApproved, models.HookEventPullRequestComment:
|
||||||
return getDiscordPullRequestApprovalPayload(p.(*api.PullRequestPayload), discord, event)
|
return getDiscordPullRequestApprovalPayload(p.(*api.PullRequestPayload), discord, event)
|
||||||
case HookEventRepository:
|
case models.HookEventRepository:
|
||||||
return getDiscordRepositoryPayload(p.(*api.RepositoryPayload), discord)
|
return getDiscordRepositoryPayload(p.(*api.RepositoryPayload), discord)
|
||||||
case HookEventRelease:
|
case models.HookEventRelease:
|
||||||
return getDiscordReleasePayload(p.(*api.ReleasePayload), discord)
|
return getDiscordReleasePayload(p.(*api.ReleasePayload), discord)
|
||||||
}
|
}
|
||||||
|
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseHookPullRequestEventType(event HookEventType) (string, error) {
|
func parseHookPullRequestEventType(event models.HookEventType) (string, error) {
|
||||||
|
|
||||||
switch event {
|
switch event {
|
||||||
|
|
||||||
case HookEventPullRequestApproved:
|
case models.HookEventPullRequestApproved:
|
||||||
return "approved", nil
|
return "approved", nil
|
||||||
case HookEventPullRequestRejected:
|
case models.HookEventPullRequestRejected:
|
||||||
return "rejected", nil
|
return "rejected", nil
|
||||||
case HookEventPullRequestComment:
|
case models.HookEventPullRequestComment:
|
||||||
return "comment", nil
|
return "comment", nil
|
||||||
|
|
||||||
default:
|
default:
|
|
@ -2,13 +2,14 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package webhook
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
)
|
)
|
||||||
|
@ -357,7 +358,7 @@ func getMSTeamsIssuesPayload(p *api.IssuePayload) (*MSTeamsPayload, error) {
|
||||||
|
|
||||||
func getMSTeamsIssueCommentPayload(p *api.IssueCommentPayload) (*MSTeamsPayload, error) {
|
func getMSTeamsIssueCommentPayload(p *api.IssueCommentPayload) (*MSTeamsPayload, error) {
|
||||||
title := fmt.Sprintf("#%d: %s", p.Issue.Index, p.Issue.Title)
|
title := fmt.Sprintf("#%d: %s", p.Issue.Index, p.Issue.Title)
|
||||||
url := fmt.Sprintf("%s/issues/%d#%s", p.Repository.HTMLURL, p.Issue.Index, CommentHashTag(p.Comment.ID))
|
url := fmt.Sprintf("%s/issues/%d#%s", p.Repository.HTMLURL, p.Issue.Index, models.CommentHashTag(p.Comment.ID))
|
||||||
content := ""
|
content := ""
|
||||||
var color int
|
var color int
|
||||||
switch p.Action {
|
switch p.Action {
|
||||||
|
@ -530,7 +531,7 @@ func getMSTeamsPullRequestPayload(p *api.PullRequestPayload) (*MSTeamsPayload, e
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMSTeamsPullRequestApprovalPayload(p *api.PullRequestPayload, event HookEventType) (*MSTeamsPayload, error) {
|
func getMSTeamsPullRequestApprovalPayload(p *api.PullRequestPayload, event models.HookEventType) (*MSTeamsPayload, error) {
|
||||||
var text, title string
|
var text, title string
|
||||||
var color int
|
var color int
|
||||||
switch p.Action {
|
switch p.Action {
|
||||||
|
@ -544,11 +545,11 @@ func getMSTeamsPullRequestApprovalPayload(p *api.PullRequestPayload, event HookE
|
||||||
text = p.Review.Content
|
text = p.Review.Content
|
||||||
|
|
||||||
switch event {
|
switch event {
|
||||||
case HookEventPullRequestApproved:
|
case models.HookEventPullRequestApproved:
|
||||||
color = greenColor
|
color = greenColor
|
||||||
case HookEventPullRequestRejected:
|
case models.HookEventPullRequestRejected:
|
||||||
color = redColor
|
color = redColor
|
||||||
case HookEventPullRequestComment:
|
case models.HookEventPullRequestComment:
|
||||||
color = greyColor
|
color = greyColor
|
||||||
default:
|
default:
|
||||||
color = yellowColor
|
color = yellowColor
|
||||||
|
@ -699,29 +700,29 @@ func getMSTeamsReleasePayload(p *api.ReleasePayload) (*MSTeamsPayload, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMSTeamsPayload converts a MSTeams webhook into a MSTeamsPayload
|
// GetMSTeamsPayload converts a MSTeams webhook into a MSTeamsPayload
|
||||||
func GetMSTeamsPayload(p api.Payloader, event HookEventType, meta string) (*MSTeamsPayload, error) {
|
func GetMSTeamsPayload(p api.Payloader, event models.HookEventType, meta string) (*MSTeamsPayload, error) {
|
||||||
s := new(MSTeamsPayload)
|
s := new(MSTeamsPayload)
|
||||||
|
|
||||||
switch event {
|
switch event {
|
||||||
case HookEventCreate:
|
case models.HookEventCreate:
|
||||||
return getMSTeamsCreatePayload(p.(*api.CreatePayload))
|
return getMSTeamsCreatePayload(p.(*api.CreatePayload))
|
||||||
case HookEventDelete:
|
case models.HookEventDelete:
|
||||||
return getMSTeamsDeletePayload(p.(*api.DeletePayload))
|
return getMSTeamsDeletePayload(p.(*api.DeletePayload))
|
||||||
case HookEventFork:
|
case models.HookEventFork:
|
||||||
return getMSTeamsForkPayload(p.(*api.ForkPayload))
|
return getMSTeamsForkPayload(p.(*api.ForkPayload))
|
||||||
case HookEventIssues:
|
case models.HookEventIssues:
|
||||||
return getMSTeamsIssuesPayload(p.(*api.IssuePayload))
|
return getMSTeamsIssuesPayload(p.(*api.IssuePayload))
|
||||||
case HookEventIssueComment:
|
case models.HookEventIssueComment:
|
||||||
return getMSTeamsIssueCommentPayload(p.(*api.IssueCommentPayload))
|
return getMSTeamsIssueCommentPayload(p.(*api.IssueCommentPayload))
|
||||||
case HookEventPush:
|
case models.HookEventPush:
|
||||||
return getMSTeamsPushPayload(p.(*api.PushPayload))
|
return getMSTeamsPushPayload(p.(*api.PushPayload))
|
||||||
case HookEventPullRequest:
|
case models.HookEventPullRequest:
|
||||||
return getMSTeamsPullRequestPayload(p.(*api.PullRequestPayload))
|
return getMSTeamsPullRequestPayload(p.(*api.PullRequestPayload))
|
||||||
case HookEventPullRequestRejected, HookEventPullRequestApproved, HookEventPullRequestComment:
|
case models.HookEventPullRequestRejected, models.HookEventPullRequestApproved, models.HookEventPullRequestComment:
|
||||||
return getMSTeamsPullRequestApprovalPayload(p.(*api.PullRequestPayload), event)
|
return getMSTeamsPullRequestApprovalPayload(p.(*api.PullRequestPayload), event)
|
||||||
case HookEventRepository:
|
case models.HookEventRepository:
|
||||||
return getMSTeamsRepositoryPayload(p.(*api.RepositoryPayload))
|
return getMSTeamsRepositoryPayload(p.(*api.RepositoryPayload))
|
||||||
case HookEventRelease:
|
case models.HookEventRelease:
|
||||||
return getMSTeamsReleasePayload(p.(*api.ReleasePayload))
|
return getMSTeamsReleasePayload(p.(*api.ReleasePayload))
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package webhook
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
@ -10,7 +10,9 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
)
|
)
|
||||||
|
@ -23,6 +25,15 @@ type SlackMeta struct {
|
||||||
Color string `json:"color"`
|
Color string `json:"color"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetSlackHook returns slack metadata
|
||||||
|
func GetSlackHook(w *models.Webhook) *SlackMeta {
|
||||||
|
s := &SlackMeta{}
|
||||||
|
if err := json.Unmarshal([]byte(w.Meta), s); err != nil {
|
||||||
|
log.Error("webhook.GetSlackHook(%d): %v", w.ID, err)
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
// SlackPayload contains the information about the slack channel
|
// SlackPayload contains the information about the slack channel
|
||||||
type SlackPayload struct {
|
type SlackPayload struct {
|
||||||
Channel string `json:"channel"`
|
Channel string `json:"channel"`
|
||||||
|
@ -181,7 +192,7 @@ func getSlackIssuesPayload(p *api.IssuePayload, slack *SlackMeta) (*SlackPayload
|
||||||
|
|
||||||
func getSlackIssueCommentPayload(p *api.IssueCommentPayload, slack *SlackMeta) (*SlackPayload, error) {
|
func getSlackIssueCommentPayload(p *api.IssueCommentPayload, slack *SlackMeta) (*SlackPayload, error) {
|
||||||
senderLink := SlackLinkFormatter(setting.AppURL+p.Sender.UserName, p.Sender.UserName)
|
senderLink := SlackLinkFormatter(setting.AppURL+p.Sender.UserName, p.Sender.UserName)
|
||||||
titleLink := SlackLinkFormatter(fmt.Sprintf("%s/issues/%d#%s", p.Repository.HTMLURL, p.Issue.Index, CommentHashTag(p.Comment.ID)),
|
titleLink := SlackLinkFormatter(fmt.Sprintf("%s/issues/%d#%s", p.Repository.HTMLURL, p.Issue.Index, models.CommentHashTag(p.Comment.ID)),
|
||||||
fmt.Sprintf("#%d %s", p.Issue.Index, p.Issue.Title))
|
fmt.Sprintf("#%d %s", p.Issue.Index, p.Issue.Title))
|
||||||
var text, title, attachmentText string
|
var text, title, attachmentText string
|
||||||
switch p.Action {
|
switch p.Action {
|
||||||
|
@ -335,7 +346,7 @@ func getSlackPullRequestPayload(p *api.PullRequestPayload, slack *SlackMeta) (*S
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSlackPullRequestApprovalPayload(p *api.PullRequestPayload, slack *SlackMeta, event HookEventType) (*SlackPayload, error) {
|
func getSlackPullRequestApprovalPayload(p *api.PullRequestPayload, slack *SlackMeta, event models.HookEventType) (*SlackPayload, error) {
|
||||||
senderLink := SlackLinkFormatter(setting.AppURL+p.Sender.UserName, p.Sender.UserName)
|
senderLink := SlackLinkFormatter(setting.AppURL+p.Sender.UserName, p.Sender.UserName)
|
||||||
titleLink := SlackLinkFormatter(fmt.Sprintf("%s/pulls/%d", p.Repository.HTMLURL, p.Index),
|
titleLink := SlackLinkFormatter(fmt.Sprintf("%s/pulls/%d", p.Repository.HTMLURL, p.Index),
|
||||||
fmt.Sprintf("#%d %s", p.Index, p.PullRequest.Title))
|
fmt.Sprintf("#%d %s", p.Index, p.PullRequest.Title))
|
||||||
|
@ -388,7 +399,7 @@ func getSlackRepositoryPayload(p *api.RepositoryPayload, slack *SlackMeta) (*Sla
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSlackPayload converts a slack webhook into a SlackPayload
|
// GetSlackPayload converts a slack webhook into a SlackPayload
|
||||||
func GetSlackPayload(p api.Payloader, event HookEventType, meta string) (*SlackPayload, error) {
|
func GetSlackPayload(p api.Payloader, event models.HookEventType, meta string) (*SlackPayload, error) {
|
||||||
s := new(SlackPayload)
|
s := new(SlackPayload)
|
||||||
|
|
||||||
slack := &SlackMeta{}
|
slack := &SlackMeta{}
|
||||||
|
@ -397,25 +408,25 @@ func GetSlackPayload(p api.Payloader, event HookEventType, meta string) (*SlackP
|
||||||
}
|
}
|
||||||
|
|
||||||
switch event {
|
switch event {
|
||||||
case HookEventCreate:
|
case models.HookEventCreate:
|
||||||
return getSlackCreatePayload(p.(*api.CreatePayload), slack)
|
return getSlackCreatePayload(p.(*api.CreatePayload), slack)
|
||||||
case HookEventDelete:
|
case models.HookEventDelete:
|
||||||
return getSlackDeletePayload(p.(*api.DeletePayload), slack)
|
return getSlackDeletePayload(p.(*api.DeletePayload), slack)
|
||||||
case HookEventFork:
|
case models.HookEventFork:
|
||||||
return getSlackForkPayload(p.(*api.ForkPayload), slack)
|
return getSlackForkPayload(p.(*api.ForkPayload), slack)
|
||||||
case HookEventIssues:
|
case models.HookEventIssues:
|
||||||
return getSlackIssuesPayload(p.(*api.IssuePayload), slack)
|
return getSlackIssuesPayload(p.(*api.IssuePayload), slack)
|
||||||
case HookEventIssueComment:
|
case models.HookEventIssueComment:
|
||||||
return getSlackIssueCommentPayload(p.(*api.IssueCommentPayload), slack)
|
return getSlackIssueCommentPayload(p.(*api.IssueCommentPayload), slack)
|
||||||
case HookEventPush:
|
case models.HookEventPush:
|
||||||
return getSlackPushPayload(p.(*api.PushPayload), slack)
|
return getSlackPushPayload(p.(*api.PushPayload), slack)
|
||||||
case HookEventPullRequest:
|
case models.HookEventPullRequest:
|
||||||
return getSlackPullRequestPayload(p.(*api.PullRequestPayload), slack)
|
return getSlackPullRequestPayload(p.(*api.PullRequestPayload), slack)
|
||||||
case HookEventPullRequestRejected, HookEventPullRequestApproved, HookEventPullRequestComment:
|
case models.HookEventPullRequestRejected, models.HookEventPullRequestApproved, models.HookEventPullRequestComment:
|
||||||
return getSlackPullRequestApprovalPayload(p.(*api.PullRequestPayload), slack, event)
|
return getSlackPullRequestApprovalPayload(p.(*api.PullRequestPayload), slack, event)
|
||||||
case HookEventRepository:
|
case models.HookEventRepository:
|
||||||
return getSlackRepositoryPayload(p.(*api.RepositoryPayload), slack)
|
return getSlackRepositoryPayload(p.(*api.RepositoryPayload), slack)
|
||||||
case HookEventRelease:
|
case models.HookEventRelease:
|
||||||
return getSlackReleasePayload(p.(*api.ReleasePayload), slack)
|
return getSlackReleasePayload(p.(*api.ReleasePayload), slack)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package webhook
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
@ -10,7 +10,9 @@ import (
|
||||||
"html"
|
"html"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/markup"
|
"code.gitea.io/gitea/modules/markup"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
)
|
)
|
||||||
|
@ -30,6 +32,15 @@ type (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// GetTelegramHook returns telegram metadata
|
||||||
|
func GetTelegramHook(w *models.Webhook) *TelegramMeta {
|
||||||
|
s := &TelegramMeta{}
|
||||||
|
if err := json.Unmarshal([]byte(w.Meta), s); err != nil {
|
||||||
|
log.Error("webhook.GetTelegramHook(%d): %v", w.ID, err)
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
// SetSecret sets the telegram secret
|
// SetSecret sets the telegram secret
|
||||||
func (p *TelegramPayload) SetSecret(_ string) {}
|
func (p *TelegramPayload) SetSecret(_ string) {}
|
||||||
|
|
||||||
|
@ -169,7 +180,7 @@ func getTelegramIssuesPayload(p *api.IssuePayload) (*TelegramPayload, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTelegramIssueCommentPayload(p *api.IssueCommentPayload) (*TelegramPayload, error) {
|
func getTelegramIssueCommentPayload(p *api.IssueCommentPayload) (*TelegramPayload, error) {
|
||||||
url := fmt.Sprintf("%s/issues/%d#%s", p.Repository.HTMLURL, p.Issue.Index, CommentHashTag(p.Comment.ID))
|
url := fmt.Sprintf("%s/issues/%d#%s", p.Repository.HTMLURL, p.Issue.Index, models.CommentHashTag(p.Comment.ID))
|
||||||
title := fmt.Sprintf(`<a href="%s">#%d %s</a>`, url, p.Issue.Index, html.EscapeString(p.Issue.Title))
|
title := fmt.Sprintf(`<a href="%s">#%d %s</a>`, url, p.Issue.Index, html.EscapeString(p.Issue.Title))
|
||||||
var text string
|
var text string
|
||||||
switch p.Action {
|
switch p.Action {
|
||||||
|
@ -214,7 +225,7 @@ func getTelegramPullRequestPayload(p *api.PullRequestPayload) (*TelegramPayload,
|
||||||
p.PullRequest.HTMLURL, p.Index, p.PullRequest.Title)
|
p.PullRequest.HTMLURL, p.Index, p.PullRequest.Title)
|
||||||
text = p.PullRequest.Body
|
text = p.PullRequest.Body
|
||||||
case api.HookIssueAssigned:
|
case api.HookIssueAssigned:
|
||||||
list, err := MakeAssigneeList(&Issue{ID: p.PullRequest.ID})
|
list, err := models.MakeAssigneeList(&models.Issue{ID: p.PullRequest.ID})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &TelegramPayload{}, err
|
return &TelegramPayload{}, err
|
||||||
}
|
}
|
||||||
|
@ -297,27 +308,27 @@ func getTelegramReleasePayload(p *api.ReleasePayload) (*TelegramPayload, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTelegramPayload converts a telegram webhook into a TelegramPayload
|
// GetTelegramPayload converts a telegram webhook into a TelegramPayload
|
||||||
func GetTelegramPayload(p api.Payloader, event HookEventType, meta string) (*TelegramPayload, error) {
|
func GetTelegramPayload(p api.Payloader, event models.HookEventType, meta string) (*TelegramPayload, error) {
|
||||||
s := new(TelegramPayload)
|
s := new(TelegramPayload)
|
||||||
|
|
||||||
switch event {
|
switch event {
|
||||||
case HookEventCreate:
|
case models.HookEventCreate:
|
||||||
return getTelegramCreatePayload(p.(*api.CreatePayload))
|
return getTelegramCreatePayload(p.(*api.CreatePayload))
|
||||||
case HookEventDelete:
|
case models.HookEventDelete:
|
||||||
return getTelegramDeletePayload(p.(*api.DeletePayload))
|
return getTelegramDeletePayload(p.(*api.DeletePayload))
|
||||||
case HookEventFork:
|
case models.HookEventFork:
|
||||||
return getTelegramForkPayload(p.(*api.ForkPayload))
|
return getTelegramForkPayload(p.(*api.ForkPayload))
|
||||||
case HookEventIssues:
|
case models.HookEventIssues:
|
||||||
return getTelegramIssuesPayload(p.(*api.IssuePayload))
|
return getTelegramIssuesPayload(p.(*api.IssuePayload))
|
||||||
case HookEventIssueComment:
|
case models.HookEventIssueComment:
|
||||||
return getTelegramIssueCommentPayload(p.(*api.IssueCommentPayload))
|
return getTelegramIssueCommentPayload(p.(*api.IssueCommentPayload))
|
||||||
case HookEventPush:
|
case models.HookEventPush:
|
||||||
return getTelegramPushPayload(p.(*api.PushPayload))
|
return getTelegramPushPayload(p.(*api.PushPayload))
|
||||||
case HookEventPullRequest:
|
case models.HookEventPullRequest:
|
||||||
return getTelegramPullRequestPayload(p.(*api.PullRequestPayload))
|
return getTelegramPullRequestPayload(p.(*api.PullRequestPayload))
|
||||||
case HookEventRepository:
|
case models.HookEventRepository:
|
||||||
return getTelegramRepositoryPayload(p.(*api.RepositoryPayload))
|
return getTelegramRepositoryPayload(p.(*api.RepositoryPayload))
|
||||||
case HookEventRelease:
|
case models.HookEventRelease:
|
||||||
return getTelegramReleasePayload(p.(*api.ReleasePayload))
|
return getTelegramReleasePayload(p.(*api.ReleasePayload))
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,27 +90,27 @@ func prepareWebhook(w *models.Webhook, repo *models.Repository, event models.Hoo
|
||||||
// Use separate objects so modifications won't be made on payload on non-Gogs/Gitea type hooks.
|
// Use separate objects so modifications won't be made on payload on non-Gogs/Gitea type hooks.
|
||||||
switch w.HookTaskType {
|
switch w.HookTaskType {
|
||||||
case models.SLACK:
|
case models.SLACK:
|
||||||
payloader, err = models.GetSlackPayload(p, event, w.Meta)
|
payloader, err = GetSlackPayload(p, event, w.Meta)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("GetSlackPayload: %v", err)
|
return fmt.Errorf("GetSlackPayload: %v", err)
|
||||||
}
|
}
|
||||||
case models.DISCORD:
|
case models.DISCORD:
|
||||||
payloader, err = models.GetDiscordPayload(p, event, w.Meta)
|
payloader, err = GetDiscordPayload(p, event, w.Meta)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("GetDiscordPayload: %v", err)
|
return fmt.Errorf("GetDiscordPayload: %v", err)
|
||||||
}
|
}
|
||||||
case models.DINGTALK:
|
case models.DINGTALK:
|
||||||
payloader, err = models.GetDingtalkPayload(p, event, w.Meta)
|
payloader, err = GetDingtalkPayload(p, event, w.Meta)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("GetDingtalkPayload: %v", err)
|
return fmt.Errorf("GetDingtalkPayload: %v", err)
|
||||||
}
|
}
|
||||||
case models.TELEGRAM:
|
case models.TELEGRAM:
|
||||||
payloader, err = models.GetTelegramPayload(p, event, w.Meta)
|
payloader, err = GetTelegramPayload(p, event, w.Meta)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("GetTelegramPayload: %v", err)
|
return fmt.Errorf("GetTelegramPayload: %v", err)
|
||||||
}
|
}
|
||||||
case models.MSTEAMS:
|
case models.MSTEAMS:
|
||||||
payloader, err = models.GetMSTeamsPayload(p, event, w.Meta)
|
payloader, err = GetMSTeamsPayload(p, event, w.Meta)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("GetMSTeamsPayload: %v", err)
|
return fmt.Errorf("GetMSTeamsPayload: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,18 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestWebhook_GetSlackHook(t *testing.T) {
|
||||||
|
w := &models.Webhook{
|
||||||
|
Meta: `{"channel": "foo", "username": "username", "color": "blue"}`,
|
||||||
|
}
|
||||||
|
slackHook := GetSlackHook(w)
|
||||||
|
assert.Equal(t, *slackHook, SlackMeta{
|
||||||
|
Channel: "foo",
|
||||||
|
Username: "username",
|
||||||
|
Color: "blue",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestPrepareWebhooks(t *testing.T) {
|
func TestPrepareWebhooks(t *testing.T) {
|
||||||
assert.NoError(t, models.PrepareTestDatabase())
|
assert.NoError(t, models.PrepareTestDatabase())
|
||||||
|
|
||||||
|
|
|
@ -1090,6 +1090,9 @@ activity.period.daily = 1 day
|
||||||
activity.period.halfweekly = 3 days
|
activity.period.halfweekly = 3 days
|
||||||
activity.period.weekly = 1 week
|
activity.period.weekly = 1 week
|
||||||
activity.period.monthly = 1 month
|
activity.period.monthly = 1 month
|
||||||
|
activity.period.quarterly = 3 months
|
||||||
|
activity.period.semiyearly = 6 months
|
||||||
|
activity.period.yearly = 1 year
|
||||||
activity.overview = Overview
|
activity.overview = Overview
|
||||||
activity.active_prs_count_1 = <strong>%d</strong> Active Pull Request
|
activity.active_prs_count_1 = <strong>%d</strong> Active Pull Request
|
||||||
activity.active_prs_count_n = <strong>%d</strong> Active Pull Requests
|
activity.active_prs_count_n = <strong>%d</strong> Active Pull Requests
|
||||||
|
|
|
@ -741,6 +741,7 @@ editor.no_changes_to_show=表示する変更箇所はありません。
|
||||||
editor.fail_to_update_file=ファイル '%s' を作成または変更できませんでした: %v
|
editor.fail_to_update_file=ファイル '%s' を作成または変更できませんでした: %v
|
||||||
editor.add_subdir=ディレクトリを追加…
|
editor.add_subdir=ディレクトリを追加…
|
||||||
editor.unable_to_upload_files='%s' へファイルをアップロードすることができませんでした: %v
|
editor.unable_to_upload_files='%s' へファイルをアップロードすることができませんでした: %v
|
||||||
|
editor.upload_file_is_locked=ファイル '%[1]s' は %[2]s がロックしています。
|
||||||
editor.upload_files_to_dir='%s' にファイルをアップロード
|
editor.upload_files_to_dir='%s' にファイルをアップロード
|
||||||
editor.cannot_commit_to_protected_branch=保護されたブランチ '%s' にコミットすることはできません。
|
editor.cannot_commit_to_protected_branch=保護されたブランチ '%s' にコミットすることはできません。
|
||||||
|
|
||||||
|
@ -1088,6 +1089,9 @@ activity.period.daily=1日
|
||||||
activity.period.halfweekly=3日
|
activity.period.halfweekly=3日
|
||||||
activity.period.weekly=1週間
|
activity.period.weekly=1週間
|
||||||
activity.period.monthly=1ヶ月
|
activity.period.monthly=1ヶ月
|
||||||
|
activity.period.quarterly=3ヶ月
|
||||||
|
activity.period.semiyearly=6ヶ月
|
||||||
|
activity.period.yearly=1年
|
||||||
activity.overview=概要
|
activity.overview=概要
|
||||||
activity.active_prs_count_1=<strong>%d</strong>件のアクティブなプルリクエスト
|
activity.active_prs_count_1=<strong>%d</strong>件のアクティブなプルリクエスト
|
||||||
activity.active_prs_count_n=<strong>%d</strong>件のアクティブなプルリクエスト
|
activity.active_prs_count_n=<strong>%d</strong>件のアクティブなプルリクエスト
|
||||||
|
@ -1379,8 +1383,20 @@ settings.unarchive.success=リポジトリのアーカイブを解除しまし
|
||||||
settings.unarchive.error=リポジトリのアーカイブ解除でエラーが発生しました。 詳細はログを確認してください。
|
settings.unarchive.error=リポジトリのアーカイブ解除でエラーが発生しました。 詳細はログを確認してください。
|
||||||
settings.update_avatar_success=リポジトリのアバターを更新しました。
|
settings.update_avatar_success=リポジトリのアバターを更新しました。
|
||||||
settings.lfs=LFS
|
settings.lfs=LFS
|
||||||
|
settings.lfs_filelist=このリポジトリに含まれているLFSファイル
|
||||||
|
settings.lfs_no_lfs_files=このリポジトリにLFSファイルはありません
|
||||||
|
settings.lfs_findcommits=コミットを検索
|
||||||
|
settings.lfs_lfs_file_no_commits=このLFSファイルに関するコミットはありません
|
||||||
settings.lfs_delete=LFSファイル(OID %s)の削除
|
settings.lfs_delete=LFSファイル(OID %s)の削除
|
||||||
settings.lfs_delete_warning=LFSファイルを削除すると、チェックアウトのときに 'object does not exist' エラーが発生するかもしれません。 よろしいですか?
|
settings.lfs_delete_warning=LFSファイルを削除すると、チェックアウトのときに 'object does not exist' エラーが発生するかもしれません。 よろしいですか?
|
||||||
|
settings.lfs_findpointerfiles=ポインタファイルを検索
|
||||||
|
settings.lfs_pointers.found=%d件のblobポインタ - 登録済 %d件、未登録 %d件 (実体ファイルなし %d件)
|
||||||
|
settings.lfs_pointers.sha=Blob SHA
|
||||||
|
settings.lfs_pointers.oid=OID
|
||||||
|
settings.lfs_pointers.inRepo=Repo内
|
||||||
|
settings.lfs_pointers.exists=実体ファイルあり
|
||||||
|
settings.lfs_pointers.accessible=ユーザーがアクセス可
|
||||||
|
settings.lfs_pointers.associateAccessible=アクセス可能な%d件のOIDを登録
|
||||||
|
|
||||||
diff.browse_source=ソースを参照
|
diff.browse_source=ソースを参照
|
||||||
diff.parent=親
|
diff.parent=親
|
||||||
|
|
|
@ -1089,6 +1089,9 @@ activity.period.daily=1 dia
|
||||||
activity.period.halfweekly=3 dias
|
activity.period.halfweekly=3 dias
|
||||||
activity.period.weekly=1 semana
|
activity.period.weekly=1 semana
|
||||||
activity.period.monthly=1 mês
|
activity.period.monthly=1 mês
|
||||||
|
activity.period.quarterly=3 meses
|
||||||
|
activity.period.semiyearly=6 meses
|
||||||
|
activity.period.yearly=1 ano
|
||||||
activity.overview=Visão geral
|
activity.overview=Visão geral
|
||||||
activity.active_prs_count_1=<strong>%d</strong> Pull request ativo
|
activity.active_prs_count_1=<strong>%d</strong> Pull request ativo
|
||||||
activity.active_prs_count_n=<strong>%d</strong> Pull requests ativos
|
activity.active_prs_count_n=<strong>%d</strong> Pull requests ativos
|
||||||
|
|
|
@ -701,6 +701,7 @@ editor.no_changes_to_show=Gösterilecek değişiklik yok.
|
||||||
editor.fail_to_update_file=Şu hata ile '%s' dosyasını güncelleme/oluşturma başarısız oldu: %v
|
editor.fail_to_update_file=Şu hata ile '%s' dosyasını güncelleme/oluşturma başarısız oldu: %v
|
||||||
editor.add_subdir=Bir dizin ekle…
|
editor.add_subdir=Bir dizin ekle…
|
||||||
editor.unable_to_upload_files=Şu hata ile dosyalar '%s' 'a yüklenemedi: %v
|
editor.unable_to_upload_files=Şu hata ile dosyalar '%s' 'a yüklenemedi: %v
|
||||||
|
editor.upload_file_is_locked='%s' dosyası %s tarafından kilitlendi.
|
||||||
editor.upload_files_to_dir=Dosyaları '%s' 'a yükle
|
editor.upload_files_to_dir=Dosyaları '%s' 'a yükle
|
||||||
editor.cannot_commit_to_protected_branch=Korunan '%s' dalına işleme yapılamıyor.
|
editor.cannot_commit_to_protected_branch=Korunan '%s' dalına işleme yapılamıyor.
|
||||||
|
|
||||||
|
@ -1046,17 +1047,20 @@ activity.period.daily=1 gün
|
||||||
activity.period.halfweekly=3 gün
|
activity.period.halfweekly=3 gün
|
||||||
activity.period.weekly=1 hafta
|
activity.period.weekly=1 hafta
|
||||||
activity.period.monthly=1 ay
|
activity.period.monthly=1 ay
|
||||||
|
activity.period.quarterly=3 ay
|
||||||
|
activity.period.semiyearly=6 ay
|
||||||
|
activity.period.yearly=1 yıl
|
||||||
activity.overview=Genel Bakış
|
activity.overview=Genel Bakış
|
||||||
activity.active_prs_count_1=<strong>%d</strong> Aktif Çekme İsteği
|
activity.active_prs_count_1=<strong>%d</strong> Aktif Çekme İsteği
|
||||||
activity.active_prs_count_n=<strong>%d</strong> Aktif Çekme İsteği
|
activity.active_prs_count_n=<strong>%d</strong> Aktif Çekme İsteği
|
||||||
activity.merged_prs_count_1=Birleştirilmiş Çekme İsteği
|
activity.merged_prs_count_1=Birleştirilmiş Çekme İsteği
|
||||||
activity.merged_prs_count_n=Birleştirilmiş Çekme İstekleri
|
activity.merged_prs_count_n=Birleştirilmiş Çekme İsteği
|
||||||
activity.opened_prs_count_1=Önerilen Çekme İsteği
|
activity.opened_prs_count_1=Önerilen Çekme İsteği
|
||||||
activity.opened_prs_count_n=Önerilen Çekme İstekleri
|
activity.opened_prs_count_n=Önerilen Çekme İsteği
|
||||||
activity.title.user_1=%d kullanıcı
|
activity.title.user_1=%d kullanıcı
|
||||||
activity.title.user_n=%d kullanıcı
|
activity.title.user_n=%d kullanıcı
|
||||||
activity.title.prs_1=%d Çekme isteği
|
activity.title.prs_1=%d Çekme isteği
|
||||||
activity.title.prs_n=%d Çekme istekleri
|
activity.title.prs_n=%d Çekme isteği
|
||||||
activity.title.prs_merged_by=%s tarafından %s birleştirildi
|
activity.title.prs_merged_by=%s tarafından %s birleştirildi
|
||||||
activity.title.prs_opened_by=%s tarafından %s önerildi
|
activity.title.prs_opened_by=%s tarafından %s önerildi
|
||||||
activity.merged_prs_label=Birleştirilen
|
activity.merged_prs_label=Birleştirilen
|
||||||
|
@ -1064,20 +1068,21 @@ activity.opened_prs_label=Önerilen
|
||||||
activity.active_issues_count_1=<strong>%d</strong> Aktif Konu
|
activity.active_issues_count_1=<strong>%d</strong> Aktif Konu
|
||||||
activity.active_issues_count_n=<strong>%d</strong> Aktif Konu
|
activity.active_issues_count_n=<strong>%d</strong> Aktif Konu
|
||||||
activity.closed_issues_count_1=Kapalı Konu
|
activity.closed_issues_count_1=Kapalı Konu
|
||||||
activity.closed_issues_count_n=Kapalı Konular
|
activity.closed_issues_count_n=Kapalı Konu
|
||||||
activity.title.issues_1=%d Konu
|
activity.title.issues_1=%d Konu
|
||||||
activity.title.issues_n=%d Konu
|
activity.title.issues_n=%d Konu
|
||||||
activity.title.issues_closed_by=%s %s tarafından kapatıldı
|
activity.title.issues_closed_by=%s %s tarafından kapatıldı
|
||||||
activity.title.issues_created_by=%s %s tarafından oluşturuldu
|
activity.title.issues_created_by=%s %s tarafından oluşturuldu
|
||||||
activity.closed_issue_label=Kapalı
|
activity.closed_issue_label=Kapalı
|
||||||
activity.new_issues_count_1=Yeni Konu
|
activity.new_issues_count_1=Yeni Konu
|
||||||
activity.new_issues_count_n=Yeni Konular
|
activity.new_issues_count_n=Yeni Konu
|
||||||
activity.new_issue_label=Açıldı
|
activity.new_issue_label=Açıldı
|
||||||
activity.title.unresolved_conv_1=%d Çözümlenmemiş Konuşma
|
activity.title.unresolved_conv_1=%d Çözümlenmemiş Konuşma
|
||||||
activity.title.unresolved_conv_n=%d Çözümlenmemiş Konuşma
|
activity.title.unresolved_conv_n=%d Çözümlenmemiş Konuşma
|
||||||
|
activity.unresolved_conv_desc=Son zamanlarda değişen bu konu ve değişiklik istekleri henüz çözümlenmedi.
|
||||||
activity.unresolved_conv_label=Açık
|
activity.unresolved_conv_label=Açık
|
||||||
activity.title.releases_1=%d Serbest bırak
|
activity.title.releases_1=%d Sürüm
|
||||||
activity.title.releases_n=%d Serbest bırakmalar
|
activity.title.releases_n=%d Sürüm
|
||||||
activity.title.releases_published_by=%s tarafından %s yayınlandı
|
activity.title.releases_published_by=%s tarafından %s yayınlandı
|
||||||
activity.published_release_label=Yayınlandı
|
activity.published_release_label=Yayınlandı
|
||||||
activity.no_git_activity=Bu dönemde herhangi bir işleme yapılmamıştır.
|
activity.no_git_activity=Bu dönemde herhangi bir işleme yapılmamıştır.
|
||||||
|
@ -1095,6 +1100,7 @@ activity.git_stats_file_1=%d dosya
|
||||||
activity.git_stats_file_n=%d dosya
|
activity.git_stats_file_n=%d dosya
|
||||||
activity.git_stats_files_changed_1=değişti
|
activity.git_stats_files_changed_1=değişti
|
||||||
activity.git_stats_files_changed_n=değişti
|
activity.git_stats_files_changed_n=değişti
|
||||||
|
activity.git_stats_additions=ve oldu
|
||||||
activity.git_stats_addition_1=%d ekleme
|
activity.git_stats_addition_1=%d ekleme
|
||||||
activity.git_stats_addition_n=%d ekleme
|
activity.git_stats_addition_n=%d ekleme
|
||||||
activity.git_stats_and_deletions=ve
|
activity.git_stats_and_deletions=ve
|
||||||
|
|
|
@ -84,7 +84,6 @@ func NewUserPost(ctx *context.Context, form auth.AdminCreateUserForm) {
|
||||||
Passwd: form.Password,
|
Passwd: form.Password,
|
||||||
IsActive: true,
|
IsActive: true,
|
||||||
LoginType: models.LoginPlain,
|
LoginType: models.LoginPlain,
|
||||||
MustChangePassword: form.MustChangePassword,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(form.LoginType) > 0 {
|
if len(form.LoginType) > 0 {
|
||||||
|
@ -95,10 +94,13 @@ func NewUserPost(ctx *context.Context, form auth.AdminCreateUserForm) {
|
||||||
u.LoginName = form.LoginName
|
u.LoginName = form.LoginName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if u.LoginType == models.LoginPlain {
|
||||||
if !password.IsComplexEnough(form.Password) {
|
if !password.IsComplexEnough(form.Password) {
|
||||||
ctx.RenderWithErr(ctx.Tr("form.password_complexity"), tplUserNew, &form)
|
ctx.RenderWithErr(ctx.Tr("form.password_complexity"), tplUserNew, &form)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
u.MustChangePassword = form.MustChangePassword
|
||||||
|
}
|
||||||
if err := models.CreateUser(u); err != nil {
|
if err := models.CreateUser(u); err != nil {
|
||||||
switch {
|
switch {
|
||||||
case models.IsErrUserAlreadyExist(err):
|
case models.IsErrUserAlreadyExist(err):
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"code.gitea.io/gitea/modules/structs"
|
"code.gitea.io/gitea/modules/structs"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
"code.gitea.io/gitea/modules/webhook"
|
||||||
|
|
||||||
"github.com/unknwon/com"
|
"github.com/unknwon/com"
|
||||||
)
|
)
|
||||||
|
@ -166,7 +167,7 @@ func ToHook(repoLink string, w *models.Webhook) *api.Hook {
|
||||||
"content_type": w.ContentType.Name(),
|
"content_type": w.ContentType.Name(),
|
||||||
}
|
}
|
||||||
if w.HookTaskType == models.SLACK {
|
if w.HookTaskType == models.SLACK {
|
||||||
s := w.GetSlackHook()
|
s := webhook.GetSlackHook(w)
|
||||||
config["channel"] = s.Channel
|
config["channel"] = s.Channel
|
||||||
config["username"] = s.Username
|
config["username"] = s.Username
|
||||||
config["icon_url"] = s.IconURL
|
config["icon_url"] = s.IconURL
|
||||||
|
|
|
@ -458,9 +458,16 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
|
||||||
issue.Content = *form.Body
|
issue.Content = *form.Body
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the deadline
|
// Update or remove the deadline, only if set and allowed
|
||||||
if form.Deadline != nil && ctx.Repo.CanWrite(models.UnitTypeIssues) {
|
if (form.Deadline != nil || form.RemoveDeadline != nil) && ctx.Repo.CanWrite(models.UnitTypeIssues) {
|
||||||
deadlineUnix := timeutil.TimeStamp(form.Deadline.Unix())
|
var deadlineUnix timeutil.TimeStamp
|
||||||
|
|
||||||
|
if (form.RemoveDeadline == nil || !*form.RemoveDeadline) && !form.Deadline.IsZero() {
|
||||||
|
deadline := time.Date(form.Deadline.Year(), form.Deadline.Month(), form.Deadline.Day(),
|
||||||
|
23, 59, 59, 0, form.Deadline.Location())
|
||||||
|
deadlineUnix = timeutil.TimeStamp(deadline.Unix())
|
||||||
|
}
|
||||||
|
|
||||||
if err := models.UpdateIssueDeadline(issue, deadlineUnix, ctx.User); err != nil {
|
if err := models.UpdateIssueDeadline(issue, deadlineUnix, ctx.User); err != nil {
|
||||||
ctx.Error(500, "UpdateIssueDeadline", err)
|
ctx.Error(500, "UpdateIssueDeadline", err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/modules/auth"
|
"code.gitea.io/gitea/modules/auth"
|
||||||
|
@ -326,7 +327,7 @@ func CreatePullRequest(ctx *context.APIContext, form api.CreatePullRequestOption
|
||||||
func EditPullRequest(ctx *context.APIContext, form api.EditPullRequestOption) {
|
func EditPullRequest(ctx *context.APIContext, form api.EditPullRequestOption) {
|
||||||
// swagger:operation PATCH /repos/{owner}/{repo}/pulls/{index} repository repoEditPullRequest
|
// swagger:operation PATCH /repos/{owner}/{repo}/pulls/{index} repository repoEditPullRequest
|
||||||
// ---
|
// ---
|
||||||
// summary: Update a pull request
|
// summary: Update a pull request. If using deadline only the date will be taken into account, and time of day ignored.
|
||||||
// consumes:
|
// consumes:
|
||||||
// - application/json
|
// - application/json
|
||||||
// produces:
|
// produces:
|
||||||
|
@ -385,9 +386,15 @@ func EditPullRequest(ctx *context.APIContext, form api.EditPullRequestOption) {
|
||||||
issue.Content = form.Body
|
issue.Content = form.Body
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update Deadline
|
// Update or remove deadline if set
|
||||||
if form.Deadline != nil {
|
if form.Deadline != nil || form.RemoveDeadline != nil {
|
||||||
deadlineUnix := timeutil.TimeStamp(form.Deadline.Unix())
|
var deadlineUnix timeutil.TimeStamp
|
||||||
|
if (form.RemoveDeadline == nil || !*form.RemoveDeadline) && !form.Deadline.IsZero() {
|
||||||
|
deadline := time.Date(form.Deadline.Year(), form.Deadline.Month(), form.Deadline.Day(),
|
||||||
|
23, 59, 59, 0, form.Deadline.Location())
|
||||||
|
deadlineUnix = timeutil.TimeStamp(deadline.Unix())
|
||||||
|
}
|
||||||
|
|
||||||
if err := models.UpdateIssueDeadline(issue, deadlineUnix, ctx.User); err != nil {
|
if err := models.UpdateIssueDeadline(issue, deadlineUnix, ctx.User); err != nil {
|
||||||
ctx.Error(500, "UpdateIssueDeadline", err)
|
ctx.Error(500, "UpdateIssueDeadline", err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
"code.gitea.io/gitea/modules/webhook"
|
||||||
"code.gitea.io/gitea/routers/api/v1/convert"
|
"code.gitea.io/gitea/routers/api/v1/convert"
|
||||||
"code.gitea.io/gitea/routers/utils"
|
"code.gitea.io/gitea/routers/utils"
|
||||||
|
|
||||||
|
@ -129,7 +130,7 @@ func addHook(ctx *context.APIContext, form *api.CreateHookOption, orgID, repoID
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
meta, err := json.Marshal(&models.SlackMeta{
|
meta, err := json.Marshal(&webhook.SlackMeta{
|
||||||
Channel: strings.TrimSpace(channel),
|
Channel: strings.TrimSpace(channel),
|
||||||
Username: form.Config["username"],
|
Username: form.Config["username"],
|
||||||
IconURL: form.Config["icon_url"],
|
IconURL: form.Config["icon_url"],
|
||||||
|
@ -203,7 +204,7 @@ func editHook(ctx *context.APIContext, form *api.EditHookOption, w *models.Webho
|
||||||
|
|
||||||
if w.HookTaskType == models.SLACK {
|
if w.HookTaskType == models.SLACK {
|
||||||
if channel, ok := form.Config["channel"]; ok {
|
if channel, ok := form.Config["channel"]; ok {
|
||||||
meta, err := json.Marshal(&models.SlackMeta{
|
meta, err := json.Marshal(&webhook.SlackMeta{
|
||||||
Channel: channel,
|
Channel: channel,
|
||||||
Username: form.Config["username"],
|
Username: form.Config["username"],
|
||||||
IconURL: form.Config["icon_url"],
|
IconURL: form.Config["icon_url"],
|
||||||
|
|
|
@ -35,6 +35,12 @@ func Activity(ctx *context.Context) {
|
||||||
timeFrom = timeUntil.Add(-time.Hour * 168)
|
timeFrom = timeUntil.Add(-time.Hour * 168)
|
||||||
case "monthly":
|
case "monthly":
|
||||||
timeFrom = timeUntil.AddDate(0, -1, 0)
|
timeFrom = timeUntil.AddDate(0, -1, 0)
|
||||||
|
case "quarterly":
|
||||||
|
timeFrom = timeUntil.AddDate(0, -3, 0)
|
||||||
|
case "semiyearly":
|
||||||
|
timeFrom = timeUntil.AddDate(0, -6, 0)
|
||||||
|
case "yearly":
|
||||||
|
timeFrom = timeUntil.AddDate(-1, 0, 0)
|
||||||
default:
|
default:
|
||||||
ctx.Data["Period"] = "weekly"
|
ctx.Data["Period"] = "weekly"
|
||||||
timeFrom = timeUntil.Add(-time.Hour * 168)
|
timeFrom = timeUntil.Add(-time.Hour * 168)
|
||||||
|
@ -70,6 +76,12 @@ func ActivityAuthors(ctx *context.Context) {
|
||||||
timeFrom = timeUntil.Add(-time.Hour * 168)
|
timeFrom = timeUntil.Add(-time.Hour * 168)
|
||||||
case "monthly":
|
case "monthly":
|
||||||
timeFrom = timeUntil.AddDate(0, -1, 0)
|
timeFrom = timeUntil.AddDate(0, -1, 0)
|
||||||
|
case "quarterly":
|
||||||
|
timeFrom = timeUntil.AddDate(0, -3, 0)
|
||||||
|
case "semiyearly":
|
||||||
|
timeFrom = timeUntil.AddDate(0, -6, 0)
|
||||||
|
case "yearly":
|
||||||
|
timeFrom = timeUntil.AddDate(-1, 0, 0)
|
||||||
default:
|
default:
|
||||||
timeFrom = timeUntil.Add(-time.Hour * 168)
|
timeFrom = timeUntil.Add(-time.Hour * 168)
|
||||||
}
|
}
|
||||||
|
|
|
@ -268,7 +268,7 @@ func DiscordHooksNewPost(ctx *context.Context, form auth.NewDiscordHookForm) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
meta, err := json.Marshal(&models.DiscordMeta{
|
meta, err := json.Marshal(&webhook.DiscordMeta{
|
||||||
Username: form.Username,
|
Username: form.Username,
|
||||||
IconURL: form.IconURL,
|
IconURL: form.IconURL,
|
||||||
})
|
})
|
||||||
|
@ -357,7 +357,7 @@ func TelegramHooksNewPost(ctx *context.Context, form auth.NewTelegramHookForm) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
meta, err := json.Marshal(&models.TelegramMeta{
|
meta, err := json.Marshal(&webhook.TelegramMeta{
|
||||||
BotToken: form.BotToken,
|
BotToken: form.BotToken,
|
||||||
ChatID: form.ChatID,
|
ChatID: form.ChatID,
|
||||||
})
|
})
|
||||||
|
@ -452,7 +452,7 @@ func SlackHooksNewPost(ctx *context.Context, form auth.NewSlackHookForm) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
meta, err := json.Marshal(&models.SlackMeta{
|
meta, err := json.Marshal(&webhook.SlackMeta{
|
||||||
Channel: strings.TrimSpace(form.Channel),
|
Channel: strings.TrimSpace(form.Channel),
|
||||||
Username: form.Username,
|
Username: form.Username,
|
||||||
IconURL: form.IconURL,
|
IconURL: form.IconURL,
|
||||||
|
@ -515,11 +515,11 @@ func checkWebhook(ctx *context.Context) (*orgRepoCtx, *models.Webhook) {
|
||||||
ctx.Data["HookType"] = w.HookTaskType.Name()
|
ctx.Data["HookType"] = w.HookTaskType.Name()
|
||||||
switch w.HookTaskType {
|
switch w.HookTaskType {
|
||||||
case models.SLACK:
|
case models.SLACK:
|
||||||
ctx.Data["SlackHook"] = w.GetSlackHook()
|
ctx.Data["SlackHook"] = webhook.GetSlackHook(w)
|
||||||
case models.DISCORD:
|
case models.DISCORD:
|
||||||
ctx.Data["DiscordHook"] = w.GetDiscordHook()
|
ctx.Data["DiscordHook"] = webhook.GetDiscordHook(w)
|
||||||
case models.TELEGRAM:
|
case models.TELEGRAM:
|
||||||
ctx.Data["TelegramHook"] = w.GetTelegramHook()
|
ctx.Data["TelegramHook"] = webhook.GetTelegramHook(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Data["History"], err = w.History(1)
|
ctx.Data["History"], err = w.History(1)
|
||||||
|
@ -646,7 +646,7 @@ func SlackHooksEditPost(ctx *context.Context, form auth.NewSlackHookForm) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
meta, err := json.Marshal(&models.SlackMeta{
|
meta, err := json.Marshal(&webhook.SlackMeta{
|
||||||
Channel: strings.TrimSpace(form.Channel),
|
Channel: strings.TrimSpace(form.Channel),
|
||||||
Username: form.Username,
|
Username: form.Username,
|
||||||
IconURL: form.IconURL,
|
IconURL: form.IconURL,
|
||||||
|
@ -690,7 +690,7 @@ func DiscordHooksEditPost(ctx *context.Context, form auth.NewDiscordHookForm) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
meta, err := json.Marshal(&models.DiscordMeta{
|
meta, err := json.Marshal(&webhook.DiscordMeta{
|
||||||
Username: form.Username,
|
Username: form.Username,
|
||||||
IconURL: form.IconURL,
|
IconURL: form.IconURL,
|
||||||
})
|
})
|
||||||
|
@ -763,7 +763,7 @@ func TelegramHooksEditPost(ctx *context.Context, form auth.NewTelegramHookForm)
|
||||||
ctx.HTML(200, orCtx.NewTemplate)
|
ctx.HTML(200, orCtx.NewTemplate)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
meta, err := json.Marshal(&models.TelegramMeta{
|
meta, err := json.Marshal(&webhook.TelegramMeta{
|
||||||
BotToken: form.BotToken,
|
BotToken: form.BotToken,
|
||||||
ChatID: form.ChatID,
|
ChatID: form.ChatID,
|
||||||
})
|
})
|
||||||
|
|
|
@ -5,10 +5,7 @@
|
||||||
package issue
|
package issue
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/modules/log"
|
|
||||||
"code.gitea.io/gitea/modules/notification"
|
"code.gitea.io/gitea/modules/notification"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -24,18 +21,6 @@ func NewIssue(repo *models.Repository, issue *models.Issue, labelIDs []int64, uu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := models.NotifyWatchers(&models.Action{
|
|
||||||
ActUserID: issue.Poster.ID,
|
|
||||||
ActUser: issue.Poster,
|
|
||||||
OpType: models.ActionCreateIssue,
|
|
||||||
Content: fmt.Sprintf("%d|%s", issue.Index, issue.Title),
|
|
||||||
RepoID: repo.ID,
|
|
||||||
Repo: repo,
|
|
||||||
IsPrivate: repo.IsPrivate,
|
|
||||||
}); err != nil {
|
|
||||||
log.Error("NotifyWatchers: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
notification.NotifyNewIssue(issue)
|
notification.NotifyNewIssue(issue)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -9,9 +9,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
|
"code.gitea.io/gitea/modules/notification"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
|
||||||
"code.gitea.io/gitea/modules/webhook"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func syncAction(opType models.ActionType, repo *models.Repository, refName string, data []byte) error {
|
func syncAction(opType models.ActionType, repo *models.Repository, refName string, data []byte) error {
|
||||||
|
@ -45,25 +44,9 @@ func SyncPushAction(repo *models.Repository, opts SyncPushActionOptions) error {
|
||||||
opts.Commits.Commits = opts.Commits.Commits[:setting.UI.FeedMaxCommitNum]
|
opts.Commits.Commits = opts.Commits.Commits[:setting.UI.FeedMaxCommitNum]
|
||||||
}
|
}
|
||||||
|
|
||||||
apiCommits, err := opts.Commits.ToAPIPayloadCommits(repo.RepoPath(), repo.HTMLURL())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
opts.Commits.CompareURL = repo.ComposeCompareURL(opts.OldCommitID, opts.NewCommitID)
|
opts.Commits.CompareURL = repo.ComposeCompareURL(opts.OldCommitID, opts.NewCommitID)
|
||||||
apiPusher := repo.MustOwner().APIFormat()
|
|
||||||
if err := webhook.PrepareWebhooks(repo, models.HookEventPush, &api.PushPayload{
|
notification.NotifyPushCommits(repo.MustOwner(), repo, opts.RefName, opts.OldCommitID, opts.NewCommitID, opts.Commits)
|
||||||
Ref: opts.RefName,
|
|
||||||
Before: opts.OldCommitID,
|
|
||||||
After: opts.NewCommitID,
|
|
||||||
CompareURL: setting.AppURL + opts.Commits.CompareURL,
|
|
||||||
Commits: apiCommits,
|
|
||||||
Repo: repo.APIFormat(models.AccessModeOwner),
|
|
||||||
Pusher: apiPusher,
|
|
||||||
Sender: apiPusher,
|
|
||||||
}); err != nil {
|
|
||||||
return fmt.Errorf("PrepareWebhooks: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := json.Marshal(opts.Commits)
|
data, err := json.Marshal(opts.Commits)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -20,10 +20,9 @@ import (
|
||||||
"code.gitea.io/gitea/modules/cache"
|
"code.gitea.io/gitea/modules/cache"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/notification"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
"code.gitea.io/gitea/modules/webhook"
|
|
||||||
|
|
||||||
"github.com/mcuadros/go-version"
|
"github.com/mcuadros/go-version"
|
||||||
)
|
)
|
||||||
|
@ -360,16 +359,7 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
mode, _ := models.AccessLevel(doer, pr.Issue.Repo)
|
notification.NotifyIssueChangeStatus(doer, pr.Issue, true)
|
||||||
if err = webhook.PrepareWebhooks(pr.Issue.Repo, models.HookEventPullRequest, &api.PullRequestPayload{
|
|
||||||
Action: api.HookIssueClosed,
|
|
||||||
Index: pr.Index,
|
|
||||||
PullRequest: pr.APIFormat(),
|
|
||||||
Repository: pr.Issue.Repo.APIFormat(mode),
|
|
||||||
Sender: doer.APIFormat(),
|
|
||||||
}); err != nil {
|
|
||||||
log.Error("PrepareWebhooks: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,7 @@ import (
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
"code.gitea.io/gitea/modules/notification"
|
||||||
"code.gitea.io/gitea/modules/webhook"
|
|
||||||
issue_service "code.gitea.io/gitea/services/issue"
|
issue_service "code.gitea.io/gitea/services/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -27,30 +26,10 @@ func NewPullRequest(repo *models.Repository, pull *models.Issue, labelIDs []int6
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := models.NotifyWatchers(&models.Action{
|
|
||||||
ActUserID: pull.Poster.ID,
|
|
||||||
ActUser: pull.Poster,
|
|
||||||
OpType: models.ActionCreatePullRequest,
|
|
||||||
Content: fmt.Sprintf("%d|%s", pull.Index, pull.Title),
|
|
||||||
RepoID: repo.ID,
|
|
||||||
Repo: repo,
|
|
||||||
IsPrivate: repo.IsPrivate,
|
|
||||||
}); err != nil {
|
|
||||||
log.Error("NotifyWatchers: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
pr.Issue = pull
|
pr.Issue = pull
|
||||||
pull.PullRequest = pr
|
pull.PullRequest = pr
|
||||||
mode, _ := models.AccessLevel(pull.Poster, repo)
|
|
||||||
if err := webhook.PrepareWebhooks(repo, models.HookEventPullRequest, &api.PullRequestPayload{
|
notification.NotifyNewPullRequest(pr)
|
||||||
Action: api.HookIssueOpened,
|
|
||||||
Index: pull.Index,
|
|
||||||
PullRequest: pr.APIFormat(),
|
|
||||||
Repository: repo.APIFormat(mode),
|
|
||||||
Sender: pull.Poster.APIFormat(),
|
|
||||||
}); err != nil {
|
|
||||||
log.Error("PrepareWebhooks: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -109,25 +88,11 @@ func AddTestPullRequestTask(doer *models.User, repoID int64, branch string, isSy
|
||||||
if err == nil {
|
if err == nil {
|
||||||
for _, pr := range prs {
|
for _, pr := range prs {
|
||||||
pr.Issue.PullRequest = pr
|
pr.Issue.PullRequest = pr
|
||||||
if err = pr.Issue.LoadAttributes(); err != nil {
|
notification.NotifyPullRequestSynchronized(doer, pr)
|
||||||
log.Error("LoadAttributes: %v", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err = webhook.PrepareWebhooks(pr.Issue.Repo, models.HookEventPullRequest, &api.PullRequestPayload{
|
|
||||||
Action: api.HookIssueSynchronized,
|
|
||||||
Index: pr.Issue.Index,
|
|
||||||
PullRequest: pr.Issue.PullRequest.APIFormat(),
|
|
||||||
Repository: pr.Issue.Repo.APIFormat(models.AccessModeNone),
|
|
||||||
Sender: doer.APIFormat(),
|
|
||||||
}); err != nil {
|
|
||||||
log.Error("PrepareWebhooks [pull_id: %v]: %v", pr.ID, err)
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
addHeadRepoTasks(prs)
|
addHeadRepoTasks(prs)
|
||||||
|
|
||||||
log.Trace("AddTestPullRequestTask [base_repo_id: %d, base_branch: %s]: finding pull requests", repoID, branch)
|
log.Trace("AddTestPullRequestTask [base_repo_id: %d, base_branch: %s]: finding pull requests", repoID, branch)
|
||||||
|
|
|
@ -7,8 +7,7 @@ package pull
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
"code.gitea.io/gitea/modules/notification"
|
||||||
"code.gitea.io/gitea/modules/webhook"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// CreateReview creates a new review based on opts
|
// CreateReview creates a new review based on opts
|
||||||
|
@ -18,7 +17,9 @@ func CreateReview(opts models.CreateReviewOptions) (*models.Review, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return review, reviewHook(review)
|
notification.NotifyPullRequestReview(review.Issue.PullRequest, review, nil)
|
||||||
|
|
||||||
|
return review, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateReview updates a review
|
// UpdateReview updates a review
|
||||||
|
@ -28,43 +29,7 @@ func UpdateReview(review *models.Review) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return reviewHook(review)
|
notification.NotifyPullRequestReview(review.Issue.PullRequest, review, nil)
|
||||||
}
|
|
||||||
|
|
||||||
func reviewHook(review *models.Review) error {
|
|
||||||
var reviewHookType models.HookEventType
|
|
||||||
|
|
||||||
switch review.Type {
|
|
||||||
case models.ReviewTypeApprove:
|
|
||||||
reviewHookType = models.HookEventPullRequestApproved
|
|
||||||
case models.ReviewTypeComment:
|
|
||||||
reviewHookType = models.HookEventPullRequestComment
|
|
||||||
case models.ReviewTypeReject:
|
|
||||||
reviewHookType = models.HookEventPullRequestRejected
|
|
||||||
default:
|
|
||||||
// unsupported review webhook type here
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
pr := review.Issue.PullRequest
|
|
||||||
|
|
||||||
if err := pr.LoadIssue(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
mode, err := models.AccessLevel(review.Issue.Poster, review.Issue.Repo)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return webhook.PrepareWebhooks(review.Issue.Repo, reviewHookType, &api.PullRequestPayload{
|
|
||||||
Action: api.HookIssueSynchronized,
|
|
||||||
Index: review.Issue.Index,
|
|
||||||
PullRequest: pr.APIFormat(),
|
|
||||||
Repository: review.Issue.Repo.APIFormat(mode),
|
|
||||||
Sender: review.Reviewer.APIFormat(),
|
|
||||||
Review: &api.ReviewPayload{
|
|
||||||
Type: string(reviewHookType),
|
|
||||||
Content: review.Content,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
<input id="password" name="password" type="password" value="{{.password}}" {{if eq .login_type "0-0"}}required{{end}}>
|
<input id="password" name="password" type="password" value="{{.password}}" {{if eq .login_type "0-0"}}required{{end}}>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="inline field">
|
<div class="inline field local{{if ne .login_type "0-0"}} hide{{end}}">
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<label><strong>{{.i18n.Tr "auth.allow_password_change" }}</strong></label>
|
<label><strong>{{.i18n.Tr "auth.allow_password_change" }}</strong></label>
|
||||||
<input name="must_change_password" type="checkbox" checked>
|
<input name="must_change_password" type="checkbox" checked>
|
||||||
|
|
|
@ -17,6 +17,9 @@
|
||||||
<a class="{{if eq .Period "halfweekly"}}active {{end}}item" href="{{$.RepoLink}}/activity/halfweekly">{{.i18n.Tr "repo.activity.period.halfweekly"}}</a>
|
<a class="{{if eq .Period "halfweekly"}}active {{end}}item" href="{{$.RepoLink}}/activity/halfweekly">{{.i18n.Tr "repo.activity.period.halfweekly"}}</a>
|
||||||
<a class="{{if eq .Period "weekly"}}active {{end}}item" href="{{$.RepoLink}}/activity/weekly">{{.i18n.Tr "repo.activity.period.weekly"}}</a>
|
<a class="{{if eq .Period "weekly"}}active {{end}}item" href="{{$.RepoLink}}/activity/weekly">{{.i18n.Tr "repo.activity.period.weekly"}}</a>
|
||||||
<a class="{{if eq .Period "monthly"}}active {{end}}item" href="{{$.RepoLink}}/activity/monthly">{{.i18n.Tr "repo.activity.period.monthly"}}</a>
|
<a class="{{if eq .Period "monthly"}}active {{end}}item" href="{{$.RepoLink}}/activity/monthly">{{.i18n.Tr "repo.activity.period.monthly"}}</a>
|
||||||
|
<a class="{{if eq .Period "quarterly"}}active {{end}}item" href="{{$.RepoLink}}/activity/quarterly">{{.i18n.Tr "repo.activity.period.quarterly"}}</a>
|
||||||
|
<a class="{{if eq .Period "semiyearly"}}active {{end}}item" href="{{$.RepoLink}}/activity/semiyearly">{{.i18n.Tr "repo.activity.period.semiyearly"}}</a>
|
||||||
|
<a class="{{if eq .Period "yearly"}}active {{end}}item" href="{{$.RepoLink}}/activity/yearly">{{.i18n.Tr "repo.activity.period.yearly"}}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -42,7 +42,6 @@
|
||||||
{{if .Signature}}
|
{{if .Signature}}
|
||||||
<div class="ui detail icon button">
|
<div class="ui detail icon button">
|
||||||
{{if .Verification.Verified}}
|
{{if .Verification.Verified}}
|
||||||
<i title="{{.Verification.Reason}}" class="lock green icon"></i>
|
|
||||||
{{if ne .Verification.SigningUser.ID 0}}
|
{{if ne .Verification.SigningUser.ID 0}}
|
||||||
<i title="{{.Verification.Reason}}" class="lock green icon"></i>
|
<i title="{{.Verification.Reason}}" class="lock green icon"></i>
|
||||||
{{else}}
|
{{else}}
|
||||||
|
|
|
@ -3,7 +3,12 @@
|
||||||
<i class="dropdown icon"></i>
|
<i class="dropdown icon"></i>
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<a class="item tiny basic toggle button" data-target="#diff-files">{{.i18n.Tr "repo.diff.show_diff_stats"}}</a>
|
<a class="item tiny basic toggle button" data-target="#diff-files">{{.i18n.Tr "repo.diff.show_diff_stats"}}</a>
|
||||||
|
{{if .Issue.Index}}
|
||||||
<a class="item" href="{{$.RepoLink}}/pulls/{{.Issue.Index}}.patch" download="{{.Issue.Index}}.patch">{{.i18n.Tr "repo.diff.download_patch"}}</a>
|
<a class="item" href="{{$.RepoLink}}/pulls/{{.Issue.Index}}.patch" download="{{.Issue.Index}}.patch">{{.i18n.Tr "repo.diff.download_patch"}}</a>
|
||||||
<a class="item" href="{{$.RepoLink}}/pulls/{{.Issue.Index}}.diff" download="{{.Issue.Index}}.diff">{{.i18n.Tr "repo.diff.download_diff"}}</a>
|
<a class="item" href="{{$.RepoLink}}/pulls/{{.Issue.Index}}.diff" download="{{.Issue.Index}}.diff">{{.i18n.Tr "repo.diff.download_diff"}}</a>
|
||||||
|
{{else if .Commit.ID.String}}
|
||||||
|
<a class="item" href="{{$.RepoLink}}/commit/{{.Commit.ID.String}}.patch" download="{{ShortSha .Commit.ID.String}}.patch">{{.i18n.Tr "repo.diff.download_patch"}}</a>
|
||||||
|
<a class="item" href="{{$.RepoLink}}/commit/{{.Commit.ID.String}}.diff" download="{{ShortSha .Commit.ID.String}}.diff">{{.i18n.Tr "repo.diff.download_diff"}}</a>
|
||||||
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -132,7 +132,7 @@
|
||||||
{{range $.branch_status_check_contexts}}
|
{{range $.branch_status_check_contexts}}
|
||||||
<tr><td>
|
<tr><td>
|
||||||
<span class="ui checkbox">
|
<span class="ui checkbox">
|
||||||
<input class="enable-whitelist" name="status_check_contexts" value="{{.}}" type="checkbox" {{if $.is_context_require}}{{if call $.is_context_required .}}checked{{end}}{{end}}>
|
<input class="enable-whitelist" name="status_check_contexts" value="{{.}}" type="checkbox" {{if $.is_context_required}}{{if call $.is_context_required .}}checked{{end}}{{end}}>
|
||||||
</span>
|
</span>
|
||||||
{{.}}
|
{{.}}
|
||||||
{{if $.is_context_required}}{{if call $.is_context_required .}}<div class="ui label right">Required</div>{{end}}{{end}}
|
{{if $.is_context_required}}{{if call $.is_context_required .}}<div class="ui label right">Required</div>{{end}}{{end}}
|
||||||
|
|
|
@ -4715,7 +4715,7 @@
|
||||||
"tags": [
|
"tags": [
|
||||||
"repository"
|
"repository"
|
||||||
],
|
],
|
||||||
"summary": "Update a pull request",
|
"summary": "Update a pull request. If using deadline only the date will be taken into account, and time of day ignored.",
|
||||||
"operationId": "repoEditPullRequest",
|
"operationId": "repoEditPullRequest",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
|
@ -8532,6 +8532,10 @@
|
||||||
"title": {
|
"title": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"x-go-name": "Title"
|
"x-go-name": "Title"
|
||||||
|
},
|
||||||
|
"unset_due_date": {
|
||||||
|
"type": "boolean",
|
||||||
|
"x-go-name": "RemoveDeadline"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
||||||
|
@ -8660,6 +8664,10 @@
|
||||||
"title": {
|
"title": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"x-go-name": "Title"
|
"x-go-name": "Title"
|
||||||
|
},
|
||||||
|
"unset_due_date": {
|
||||||
|
"type": "boolean",
|
||||||
|
"x-go-name": "RemoveDeadline"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
||||||
|
|
4
vendor/github.com/niklasfasching/go-org/org/block.go
generated
vendored
4
vendor/github.com/niklasfasching/go-org/org/block.go
generated
vendored
|
@ -80,5 +80,5 @@ func trimIndentUpTo(max int) func(string) string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n Example) String() string { return orgWriter.nodesAsString(n) }
|
func (n Example) String() string { return orgWriter.WriteNodesAsString(n) }
|
||||||
func (n Block) String() string { return orgWriter.nodesAsString(n) }
|
func (n Block) String() string { return orgWriter.WriteNodesAsString(n) }
|
||||||
|
|
2
vendor/github.com/niklasfasching/go-org/org/document.go
generated
vendored
2
vendor/github.com/niklasfasching/go-org/org/document.go
generated
vendored
|
@ -90,7 +90,7 @@ func New() *Configuration {
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns the pretty printed Org mode string for the given nodes (see OrgWriter).
|
// String returns the pretty printed Org mode string for the given nodes (see OrgWriter).
|
||||||
func String(nodes []Node) string { return orgWriter.nodesAsString(nodes...) }
|
func String(nodes []Node) string { return orgWriter.WriteNodesAsString(nodes...) }
|
||||||
|
|
||||||
// Write is called after with an instance of the Writer interface to export a parsed Document into another format.
|
// Write is called after with an instance of the Writer interface to export a parsed Document into another format.
|
||||||
func (d *Document) Write(w Writer) (out string, err error) {
|
func (d *Document) Write(w Writer) (out string, err error) {
|
||||||
|
|
4
vendor/github.com/niklasfasching/go-org/org/drawer.go
generated
vendored
4
vendor/github.com/niklasfasching/go-org/org/drawer.go
generated
vendored
|
@ -93,5 +93,5 @@ func (d *PropertyDrawer) Get(key string) (string, bool) {
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n Drawer) String() string { return orgWriter.nodesAsString(n) }
|
func (n Drawer) String() string { return orgWriter.WriteNodesAsString(n) }
|
||||||
func (n PropertyDrawer) String() string { return orgWriter.nodesAsString(n) }
|
func (n PropertyDrawer) String() string { return orgWriter.WriteNodesAsString(n) }
|
||||||
|
|
2
vendor/github.com/niklasfasching/go-org/org/footnote.go
generated
vendored
2
vendor/github.com/niklasfasching/go-org/org/footnote.go
generated
vendored
|
@ -32,4 +32,4 @@ func (d *Document) parseFootnoteDefinition(i int, parentStop stopFn) (int, Node)
|
||||||
return consumed, definition
|
return consumed, definition
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n FootnoteDefinition) String() string { return orgWriter.nodesAsString(n) }
|
func (n FootnoteDefinition) String() string { return orgWriter.WriteNodesAsString(n) }
|
||||||
|
|
2
vendor/github.com/niklasfasching/go-org/org/headline.go
generated
vendored
2
vendor/github.com/niklasfasching/go-org/org/headline.go
generated
vendored
|
@ -98,4 +98,4 @@ func (parent *Section) add(current *Section) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n Headline) String() string { return orgWriter.nodesAsString(n) }
|
func (n Headline) String() string { return orgWriter.WriteNodesAsString(n) }
|
||||||
|
|
39
vendor/github.com/niklasfasching/go-org/org/html_writer.go
generated
vendored
39
vendor/github.com/niklasfasching/go-org/org/html_writer.go
generated
vendored
|
@ -69,16 +69,13 @@ func NewHTMLWriter() *HTMLWriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *HTMLWriter) emptyClone() *HTMLWriter {
|
func (w *HTMLWriter) WriteNodesAsString(nodes ...Node) string {
|
||||||
wcopy := *w
|
original := w.Builder
|
||||||
wcopy.Builder = strings.Builder{}
|
w.Builder = strings.Builder{}
|
||||||
return &wcopy
|
WriteNodes(w, nodes...)
|
||||||
}
|
out := w.String()
|
||||||
|
w.Builder = original
|
||||||
func (w *HTMLWriter) nodesAsString(nodes ...Node) string {
|
return out
|
||||||
tmp := w.emptyClone()
|
|
||||||
WriteNodes(tmp, nodes...)
|
|
||||||
return tmp.String()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *HTMLWriter) WriterWithExtensions() Writer {
|
func (w *HTMLWriter) WriterWithExtensions() Writer {
|
||||||
|
@ -104,12 +101,14 @@ func (w *HTMLWriter) WritePropertyDrawer(PropertyDrawer) {}
|
||||||
func (w *HTMLWriter) WriteBlock(b Block) {
|
func (w *HTMLWriter) WriteBlock(b Block) {
|
||||||
content := ""
|
content := ""
|
||||||
if isRawTextBlock(b.Name) {
|
if isRawTextBlock(b.Name) {
|
||||||
exportWriter := w.emptyClone()
|
builder, htmlEscape := w.Builder, w.htmlEscape
|
||||||
exportWriter.htmlEscape = false
|
w.Builder, w.htmlEscape = strings.Builder{}, false
|
||||||
WriteNodes(exportWriter, b.Children...)
|
WriteNodes(w, b.Children...)
|
||||||
content = strings.TrimRightFunc(exportWriter.String(), unicode.IsSpace)
|
out := w.String()
|
||||||
|
w.Builder, w.htmlEscape = builder, htmlEscape
|
||||||
|
content = strings.TrimRightFunc(out, unicode.IsSpace)
|
||||||
} else {
|
} else {
|
||||||
content = w.nodesAsString(b.Children...)
|
content = w.WriteNodesAsString(b.Children...)
|
||||||
}
|
}
|
||||||
switch name := b.Name; {
|
switch name := b.Name; {
|
||||||
case name == "SRC":
|
case name == "SRC":
|
||||||
|
@ -194,7 +193,7 @@ func (w *HTMLWriter) writeSection(section *Section) {
|
||||||
// NOTE: To satisfy hugo ExtractTOC() check we cannot use `<li>\n` here. Doesn't really matter, just a note.
|
// NOTE: To satisfy hugo ExtractTOC() check we cannot use `<li>\n` here. Doesn't really matter, just a note.
|
||||||
w.WriteString("<li>")
|
w.WriteString("<li>")
|
||||||
h := section.Headline
|
h := section.Headline
|
||||||
title := cleanHeadlineTitleForHTMLAnchorRegexp.ReplaceAllString(w.nodesAsString(h.Title...), "")
|
title := cleanHeadlineTitleForHTMLAnchorRegexp.ReplaceAllString(w.WriteNodesAsString(h.Title...), "")
|
||||||
w.WriteString(fmt.Sprintf("<a href=\"#%s\">%s</a>\n", h.ID(), title))
|
w.WriteString(fmt.Sprintf("<a href=\"#%s\">%s</a>\n", h.ID(), title))
|
||||||
if len(section.Children) != 0 {
|
if len(section.Children) != 0 {
|
||||||
w.WriteString("<ul>\n")
|
w.WriteString("<ul>\n")
|
||||||
|
@ -306,7 +305,7 @@ func (w *HTMLWriter) WriteRegularLink(l RegularLink) {
|
||||||
}
|
}
|
||||||
description := url
|
description := url
|
||||||
if l.Description != nil {
|
if l.Description != nil {
|
||||||
description = w.nodesAsString(l.Description...)
|
description = w.WriteNodesAsString(l.Description...)
|
||||||
}
|
}
|
||||||
switch l.Kind() {
|
switch l.Kind() {
|
||||||
case "image":
|
case "image":
|
||||||
|
@ -384,10 +383,10 @@ func (w *HTMLWriter) WriteHorizontalRule(h HorizontalRule) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *HTMLWriter) WriteNodeWithMeta(n NodeWithMeta) {
|
func (w *HTMLWriter) WriteNodeWithMeta(n NodeWithMeta) {
|
||||||
out := w.nodesAsString(n.Node)
|
out := w.WriteNodesAsString(n.Node)
|
||||||
if p, ok := n.Node.(Paragraph); ok {
|
if p, ok := n.Node.(Paragraph); ok {
|
||||||
if len(p.Children) == 1 && isImageOrVideoLink(p.Children[0]) {
|
if len(p.Children) == 1 && isImageOrVideoLink(p.Children[0]) {
|
||||||
out = w.nodesAsString(p.Children[0])
|
out = w.WriteNodesAsString(p.Children[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, attributes := range n.Meta.HTMLAttributes {
|
for _, attributes := range n.Meta.HTMLAttributes {
|
||||||
|
@ -399,7 +398,7 @@ func (w *HTMLWriter) WriteNodeWithMeta(n NodeWithMeta) {
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
caption += " "
|
caption += " "
|
||||||
}
|
}
|
||||||
caption += w.nodesAsString(ns...)
|
caption += w.WriteNodesAsString(ns...)
|
||||||
}
|
}
|
||||||
out = fmt.Sprintf("<figure>\n%s<figcaption>\n%s\n</figcaption>\n</figure>\n", out, caption)
|
out = fmt.Sprintf("<figure>\n%s<figcaption>\n%s\n</figcaption>\n</figure>\n", out, caption)
|
||||||
}
|
}
|
||||||
|
|
22
vendor/github.com/niklasfasching/go-org/org/inline.go
generated
vendored
22
vendor/github.com/niklasfasching/go-org/org/inline.go
generated
vendored
|
@ -147,8 +147,8 @@ func (d *Document) parseExplicitLineBreakOrLatexFragment(input string, start int
|
||||||
switch {
|
switch {
|
||||||
case start+2 >= len(input):
|
case start+2 >= len(input):
|
||||||
case input[start+1] == '\\' && start != 0 && input[start-1] != '\n':
|
case input[start+1] == '\\' && start != 0 && input[start-1] != '\n':
|
||||||
for i := start + 2; unicode.IsSpace(rune(input[i])); i++ {
|
for i := start + 2; i <= len(input)-1 && unicode.IsSpace(rune(input[i])); i++ {
|
||||||
if i >= len(input) || input[i] == '\n' {
|
if input[i] == '\n' {
|
||||||
return i + 1 - start, ExplicitLineBreak{}
|
return i + 1 - start, ExplicitLineBreak{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -346,12 +346,12 @@ func (l RegularLink) Kind() string {
|
||||||
return "regular"
|
return "regular"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n Text) String() string { return orgWriter.nodesAsString(n) }
|
func (n Text) String() string { return orgWriter.WriteNodesAsString(n) }
|
||||||
func (n LineBreak) String() string { return orgWriter.nodesAsString(n) }
|
func (n LineBreak) String() string { return orgWriter.WriteNodesAsString(n) }
|
||||||
func (n ExplicitLineBreak) String() string { return orgWriter.nodesAsString(n) }
|
func (n ExplicitLineBreak) String() string { return orgWriter.WriteNodesAsString(n) }
|
||||||
func (n StatisticToken) String() string { return orgWriter.nodesAsString(n) }
|
func (n StatisticToken) String() string { return orgWriter.WriteNodesAsString(n) }
|
||||||
func (n Emphasis) String() string { return orgWriter.nodesAsString(n) }
|
func (n Emphasis) String() string { return orgWriter.WriteNodesAsString(n) }
|
||||||
func (n LatexFragment) String() string { return orgWriter.nodesAsString(n) }
|
func (n LatexFragment) String() string { return orgWriter.WriteNodesAsString(n) }
|
||||||
func (n FootnoteLink) String() string { return orgWriter.nodesAsString(n) }
|
func (n FootnoteLink) String() string { return orgWriter.WriteNodesAsString(n) }
|
||||||
func (n RegularLink) String() string { return orgWriter.nodesAsString(n) }
|
func (n RegularLink) String() string { return orgWriter.WriteNodesAsString(n) }
|
||||||
func (n Timestamp) String() string { return orgWriter.nodesAsString(n) }
|
func (n Timestamp) String() string { return orgWriter.WriteNodesAsString(n) }
|
||||||
|
|
10
vendor/github.com/niklasfasching/go-org/org/keyword.go
generated
vendored
10
vendor/github.com/niklasfasching/go-org/org/keyword.go
generated
vendored
|
@ -177,8 +177,8 @@ func (d *Document) loadSetupFile(k Keyword) (int, Node) {
|
||||||
return 1, k
|
return 1, k
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n Comment) String() string { return orgWriter.nodesAsString(n) }
|
func (n Comment) String() string { return orgWriter.WriteNodesAsString(n) }
|
||||||
func (n Keyword) String() string { return orgWriter.nodesAsString(n) }
|
func (n Keyword) String() string { return orgWriter.WriteNodesAsString(n) }
|
||||||
func (n NodeWithMeta) String() string { return orgWriter.nodesAsString(n) }
|
func (n NodeWithMeta) String() string { return orgWriter.WriteNodesAsString(n) }
|
||||||
func (n NodeWithName) String() string { return orgWriter.nodesAsString(n) }
|
func (n NodeWithName) String() string { return orgWriter.WriteNodesAsString(n) }
|
||||||
func (n Include) String() string { return orgWriter.nodesAsString(n) }
|
func (n Include) String() string { return orgWriter.WriteNodesAsString(n) }
|
||||||
|
|
6
vendor/github.com/niklasfasching/go-org/org/list.go
generated
vendored
6
vendor/github.com/niklasfasching/go-org/org/list.go
generated
vendored
|
@ -109,6 +109,6 @@ func (d *Document) parseListItem(l List, i int, parentStop stopFn) (int, Node) {
|
||||||
return i - start, ListItem{bullet, status, nodes}
|
return i - start, ListItem{bullet, status, nodes}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n List) String() string { return orgWriter.nodesAsString(n) }
|
func (n List) String() string { return orgWriter.WriteNodesAsString(n) }
|
||||||
func (n ListItem) String() string { return orgWriter.nodesAsString(n) }
|
func (n ListItem) String() string { return orgWriter.WriteNodesAsString(n) }
|
||||||
func (n DescriptiveListItem) String() string { return orgWriter.nodesAsString(n) }
|
func (n DescriptiveListItem) String() string { return orgWriter.WriteNodesAsString(n) }
|
||||||
|
|
71
vendor/github.com/niklasfasching/go-org/org/org_writer.go
generated
vendored
71
vendor/github.com/niklasfasching/go-org/org/org_writer.go
generated
vendored
|
@ -43,39 +43,33 @@ func (w *OrgWriter) WriterWithExtensions() Writer {
|
||||||
func (w *OrgWriter) Before(d *Document) {}
|
func (w *OrgWriter) Before(d *Document) {}
|
||||||
func (w *OrgWriter) After(d *Document) {}
|
func (w *OrgWriter) After(d *Document) {}
|
||||||
|
|
||||||
func (w *OrgWriter) emptyClone() *OrgWriter {
|
func (w *OrgWriter) WriteNodesAsString(nodes ...Node) string {
|
||||||
wcopy := *w
|
builder := w.Builder
|
||||||
wcopy.Builder = strings.Builder{}
|
w.Builder = strings.Builder{}
|
||||||
return &wcopy
|
WriteNodes(w, nodes...)
|
||||||
}
|
out := w.String()
|
||||||
|
w.Builder = builder
|
||||||
func (w *OrgWriter) nodesAsString(nodes ...Node) string {
|
return out
|
||||||
tmp := w.emptyClone()
|
|
||||||
WriteNodes(tmp, nodes...)
|
|
||||||
return tmp.String()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *OrgWriter) WriteHeadline(h Headline) {
|
func (w *OrgWriter) WriteHeadline(h Headline) {
|
||||||
tmp := w.emptyClone()
|
start := w.Len()
|
||||||
tmp.WriteString(strings.Repeat("*", h.Lvl))
|
w.WriteString(strings.Repeat("*", h.Lvl))
|
||||||
if h.Status != "" {
|
if h.Status != "" {
|
||||||
tmp.WriteString(" " + h.Status)
|
w.WriteString(" " + h.Status)
|
||||||
}
|
}
|
||||||
if h.Priority != "" {
|
if h.Priority != "" {
|
||||||
tmp.WriteString(" [#" + h.Priority + "]")
|
w.WriteString(" [#" + h.Priority + "]")
|
||||||
}
|
}
|
||||||
tmp.WriteString(" ")
|
w.WriteString(" ")
|
||||||
WriteNodes(tmp, h.Title...)
|
WriteNodes(w, h.Title...)
|
||||||
hString := tmp.String()
|
|
||||||
if len(h.Tags) != 0 {
|
if len(h.Tags) != 0 {
|
||||||
tString := ":" + strings.Join(h.Tags, ":") + ":"
|
tString := ":" + strings.Join(h.Tags, ":") + ":"
|
||||||
if n := w.TagsColumn - len(tString) - len(hString); n > 0 {
|
if n := w.TagsColumn - len(tString) - (w.Len() - start); n > 0 {
|
||||||
w.WriteString(hString + strings.Repeat(" ", n) + tString)
|
w.WriteString(strings.Repeat(" ", n) + tString)
|
||||||
} else {
|
} else {
|
||||||
w.WriteString(hString + " " + tString)
|
w.WriteString(" " + tString)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
w.WriteString(hString)
|
|
||||||
}
|
}
|
||||||
w.WriteString("\n")
|
w.WriteString("\n")
|
||||||
if len(h.Children) != 0 {
|
if len(h.Children) != 0 {
|
||||||
|
@ -123,7 +117,7 @@ func (w *OrgWriter) WritePropertyDrawer(d PropertyDrawer) {
|
||||||
|
|
||||||
func (w *OrgWriter) WriteFootnoteDefinition(f FootnoteDefinition) {
|
func (w *OrgWriter) WriteFootnoteDefinition(f FootnoteDefinition) {
|
||||||
w.WriteString(fmt.Sprintf("[fn:%s]", f.Name))
|
w.WriteString(fmt.Sprintf("[fn:%s]", f.Name))
|
||||||
content := w.nodesAsString(f.Children...)
|
content := w.WriteNodesAsString(f.Children...)
|
||||||
if content != "" && !unicode.IsSpace(rune(content[0])) {
|
if content != "" && !unicode.IsSpace(rune(content[0])) {
|
||||||
w.WriteString(" ")
|
w.WriteString(" ")
|
||||||
}
|
}
|
||||||
|
@ -131,7 +125,7 @@ func (w *OrgWriter) WriteFootnoteDefinition(f FootnoteDefinition) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *OrgWriter) WriteParagraph(p Paragraph) {
|
func (w *OrgWriter) WriteParagraph(p Paragraph) {
|
||||||
content := w.nodesAsString(p.Children...)
|
content := w.WriteNodesAsString(p.Children...)
|
||||||
if len(content) > 0 && content[0] != '\n' {
|
if len(content) > 0 && content[0] != '\n' {
|
||||||
w.WriteString(w.indent)
|
w.WriteString(w.indent)
|
||||||
}
|
}
|
||||||
|
@ -141,7 +135,7 @@ func (w *OrgWriter) WriteParagraph(p Paragraph) {
|
||||||
func (w *OrgWriter) WriteExample(e Example) {
|
func (w *OrgWriter) WriteExample(e Example) {
|
||||||
for _, n := range e.Children {
|
for _, n := range e.Children {
|
||||||
w.WriteString(w.indent + ":")
|
w.WriteString(w.indent + ":")
|
||||||
if content := w.nodesAsString(n); content != "" {
|
if content := w.WriteNodesAsString(n); content != "" {
|
||||||
w.WriteString(" " + content)
|
w.WriteString(" " + content)
|
||||||
}
|
}
|
||||||
w.WriteString("\n")
|
w.WriteString("\n")
|
||||||
|
@ -185,10 +179,11 @@ func (w *OrgWriter) WriteComment(c Comment) {
|
||||||
func (w *OrgWriter) WriteList(l List) { WriteNodes(w, l.Items...) }
|
func (w *OrgWriter) WriteList(l List) { WriteNodes(w, l.Items...) }
|
||||||
|
|
||||||
func (w *OrgWriter) WriteListItem(li ListItem) {
|
func (w *OrgWriter) WriteListItem(li ListItem) {
|
||||||
liWriter := w.emptyClone()
|
originalBuilder, originalIndent := w.Builder, w.indent
|
||||||
liWriter.indent = w.indent + strings.Repeat(" ", len(li.Bullet)+1)
|
w.Builder, w.indent = strings.Builder{}, w.indent+strings.Repeat(" ", len(li.Bullet)+1)
|
||||||
WriteNodes(liWriter, li.Children...)
|
WriteNodes(w, li.Children...)
|
||||||
content := strings.TrimPrefix(liWriter.String(), liWriter.indent)
|
content := strings.TrimPrefix(w.String(), w.indent)
|
||||||
|
w.Builder, w.indent = originalBuilder, originalIndent
|
||||||
w.WriteString(w.indent + li.Bullet)
|
w.WriteString(w.indent + li.Bullet)
|
||||||
if li.Status != "" {
|
if li.Status != "" {
|
||||||
w.WriteString(fmt.Sprintf(" [%s]", li.Status))
|
w.WriteString(fmt.Sprintf(" [%s]", li.Status))
|
||||||
|
@ -207,14 +202,15 @@ func (w *OrgWriter) WriteDescriptiveListItem(di DescriptiveListItem) {
|
||||||
}
|
}
|
||||||
indent := w.indent + strings.Repeat(" ", len(di.Bullet)+1)
|
indent := w.indent + strings.Repeat(" ", len(di.Bullet)+1)
|
||||||
if len(di.Term) != 0 {
|
if len(di.Term) != 0 {
|
||||||
term := w.nodesAsString(di.Term...)
|
term := w.WriteNodesAsString(di.Term...)
|
||||||
w.WriteString(" " + term + " ::")
|
w.WriteString(" " + term + " ::")
|
||||||
indent = indent + strings.Repeat(" ", len(term)+4)
|
indent = indent + strings.Repeat(" ", len(term)+4)
|
||||||
}
|
}
|
||||||
diWriter := w.emptyClone()
|
originalBuilder, originalIndent := w.Builder, w.indent
|
||||||
diWriter.indent = indent
|
w.Builder, w.indent = strings.Builder{}, indent
|
||||||
WriteNodes(diWriter, di.Details...)
|
WriteNodes(w, di.Details...)
|
||||||
details := strings.TrimPrefix(diWriter.String(), diWriter.indent)
|
details := strings.TrimPrefix(w.String(), w.indent)
|
||||||
|
w.Builder, w.indent = originalBuilder, originalIndent
|
||||||
if len(details) > 0 && details[0] == '\n' {
|
if len(details) > 0 && details[0] == '\n' {
|
||||||
w.WriteString(details)
|
w.WriteString(details)
|
||||||
} else {
|
} else {
|
||||||
|
@ -239,7 +235,7 @@ func (w *OrgWriter) WriteTable(t Table) {
|
||||||
w.WriteString(`|`)
|
w.WriteString(`|`)
|
||||||
for _, column := range row.Columns {
|
for _, column := range row.Columns {
|
||||||
w.WriteString(` `)
|
w.WriteString(` `)
|
||||||
content := w.nodesAsString(column.Children...)
|
content := w.WriteNodesAsString(column.Children...)
|
||||||
if content == "" {
|
if content == "" {
|
||||||
content = " "
|
content = " "
|
||||||
}
|
}
|
||||||
|
@ -326,9 +322,6 @@ func (w *OrgWriter) WriteRegularLink(l RegularLink) {
|
||||||
} else if l.Description == nil {
|
} else if l.Description == nil {
|
||||||
w.WriteString(fmt.Sprintf("[[%s]]", l.URL))
|
w.WriteString(fmt.Sprintf("[[%s]]", l.URL))
|
||||||
} else {
|
} else {
|
||||||
descriptionWriter := w.emptyClone()
|
w.WriteString(fmt.Sprintf("[[%s][%s]]", l.URL, w.WriteNodesAsString(l.Description...)))
|
||||||
WriteNodes(descriptionWriter, l.Description...)
|
|
||||||
description := descriptionWriter.String()
|
|
||||||
w.WriteString(fmt.Sprintf("[[%s][%s]]", l.URL, description))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
4
vendor/github.com/niklasfasching/go-org/org/paragraph.go
generated
vendored
4
vendor/github.com/niklasfasching/go-org/org/paragraph.go
generated
vendored
|
@ -42,5 +42,5 @@ func (d *Document) parseHorizontalRule(i int, parentStop stopFn) (int, Node) {
|
||||||
return 1, HorizontalRule{}
|
return 1, HorizontalRule{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n Paragraph) String() string { return orgWriter.nodesAsString(n) }
|
func (n Paragraph) String() string { return orgWriter.WriteNodesAsString(n) }
|
||||||
func (n HorizontalRule) String() string { return orgWriter.nodesAsString(n) }
|
func (n HorizontalRule) String() string { return orgWriter.WriteNodesAsString(n) }
|
||||||
|
|
2
vendor/github.com/niklasfasching/go-org/org/table.go
generated
vendored
2
vendor/github.com/niklasfasching/go-org/org/table.go
generated
vendored
|
@ -127,4 +127,4 @@ func isSpecialRow(rawColumns []string) bool {
|
||||||
return isAlignRow
|
return isAlignRow
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n Table) String() string { return orgWriter.nodesAsString(n) }
|
func (n Table) String() string { return orgWriter.WriteNodesAsString(n) }
|
||||||
|
|
1
vendor/github.com/niklasfasching/go-org/org/writer.go
generated
vendored
1
vendor/github.com/niklasfasching/go-org/org/writer.go
generated
vendored
|
@ -9,6 +9,7 @@ type Writer interface {
|
||||||
String() string // String is called at the very end to retrieve the final output.
|
String() string // String is called at the very end to retrieve the final output.
|
||||||
|
|
||||||
WriterWithExtensions() Writer
|
WriterWithExtensions() Writer
|
||||||
|
WriteNodesAsString(...Node) string
|
||||||
|
|
||||||
WriteKeyword(Keyword)
|
WriteKeyword(Keyword)
|
||||||
WriteInclude(Include)
|
WriteInclude(Include)
|
||||||
|
|
2
vendor/golang.org/x/net/idna/tables11.0.0.go
generated
vendored
2
vendor/golang.org/x/net/idna/tables11.0.0.go
generated
vendored
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
|
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
|
||||||
|
|
||||||
// +build go1.13
|
// +build go1.13,!go1.14
|
||||||
|
|
||||||
package idna
|
package idna
|
||||||
|
|
||||||
|
|
4733
vendor/golang.org/x/net/idna/tables12.00.go
generated
vendored
Normal file
4733
vendor/golang.org/x/net/idna/tables12.00.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
4
vendor/modules.txt
vendored
4
vendor/modules.txt
vendored
|
@ -330,7 +330,7 @@ github.com/mschoch/smat
|
||||||
github.com/msteinert/pam
|
github.com/msteinert/pam
|
||||||
# github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5
|
# github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5
|
||||||
github.com/nfnt/resize
|
github.com/nfnt/resize
|
||||||
# github.com/niklasfasching/go-org v0.1.7
|
# github.com/niklasfasching/go-org v0.1.8
|
||||||
github.com/niklasfasching/go-org/org
|
github.com/niklasfasching/go-org/org
|
||||||
# github.com/oliamb/cutter v0.2.2
|
# github.com/oliamb/cutter v0.2.2
|
||||||
github.com/oliamb/cutter
|
github.com/oliamb/cutter
|
||||||
|
@ -464,7 +464,7 @@ golang.org/x/crypto/scrypt
|
||||||
golang.org/x/crypto/ssh
|
golang.org/x/crypto/ssh
|
||||||
golang.org/x/crypto/ssh/agent
|
golang.org/x/crypto/ssh/agent
|
||||||
golang.org/x/crypto/ssh/knownhosts
|
golang.org/x/crypto/ssh/knownhosts
|
||||||
# golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271
|
# golang.org/x/net v0.0.0-20191101175033-0deb6923b6d9
|
||||||
golang.org/x/net/context
|
golang.org/x/net/context
|
||||||
golang.org/x/net/context/ctxhttp
|
golang.org/x/net/context/ctxhttp
|
||||||
golang.org/x/net/html
|
golang.org/x/net/html
|
||||||
|
|
Loading…
Reference in a new issue