Merge branch 'master' into refactor_issues-subscription

This commit is contained in:
6543 2019-11-15 11:06:59 +01:00 committed by GitHub
commit cd6f2bef54
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
92 changed files with 8159 additions and 4700 deletions

View File

@ -24,7 +24,7 @@ indent_size = 2
[*.js] [*.js]
indent_style = space indent_style = space
indent_size = 4 indent_size = 2
[Makefile] [Makefile]
indent_style = tab indent_style = tab

View File

@ -1,27 +1,51 @@
root: true root: true
extends: extends:
- eslint-config-airbnb-base
- eslint:recommended - eslint:recommended
parserOptions: parserOptions:
ecmaVersion: 2015 ecmaVersion: 2020
env: env:
browser: true browser: true
jquery: true
es6: true es6: true
jquery: true
node: true
globals: globals:
Clipboard: false Clipboard: false
CodeMirror: false CodeMirror: false
emojify: false
SimpleMDE: false
Vue: false
Dropzone: false Dropzone: false
u2fApi: false emojify: false
hljs: false hljs: false
SimpleMDE: false
u2fApi: false
Vue: false
rules: rules:
no-unused-vars: [error, {args: all, argsIgnorePattern: ^_, varsIgnorePattern: ^_, ignoreRestSiblings: true}] camelcase: [0]
prefer-const: [2, {destructuring: all}] comma-dangle: [2, only-multiline]
consistent-return: [0]
default-case: [0]
func-names: [0]
max-len: [0]
newline-per-chained-call: [0]
arrow-body-style: [0]
no-alert: [0]
no-continue: [0]
no-mixed-operators: [0]
no-multi-assign: [0]
no-new: [0]
no-param-reassign: [0]
no-plusplus: [0]
no-restricted-syntax: [0]
no-shadow: [0]
no-unused-vars: [2, {args: all, argsIgnorePattern: ^_, varsIgnorePattern: ^_, ignoreRestSiblings: true}]
no-use-before-define: [0]
no-var: [2] no-var: [2]
one-var-declaration-per-line: [0]
one-var: [0]
prefer-const: [2, {destructuring: all}]
prefer-destructuring: [0]
radix: [2, as-needed]

View File

@ -4,11 +4,44 @@ This changelog goes through all the changes that have been made in each release
without substantial changes to our git log; to see the highlights of what has without substantial changes to our git log; to see the highlights of what has
been added to each release, please refer to the [blog](https://blog.gitea.io). been added to each release, please refer to the [blog](https://blog.gitea.io).
## [1.10.0-RC2](https://github.com/go-gitea/gitea/releases/tag/v1.10.0-rc2) - 2019-10-30 ## [1.10.0](https://github.com/go-gitea/gitea/releases/tag/v1.10.0) - 2019-11-13
* BREAKING * BREAKING
* Fix deadline on update issue or PR via API (#8698) * Fix deadline on update issue or PR via API (#8698)
* Hide some user information via API if user doesn't have enough permission (#8655) (#8657) * Hide some user information via API if user doesn't have enough permission (#8655) (#8657)
* Remove legacy handling of drone token (#8191)
* Change repo search to use exact match for topic search. (#7941)
* Add pagination for admin api get orgs and fix only list public orgs bug (#7742)
* Implement the ability to change the ssh port to match what is in the gitea config (#7286)
* SECURITY
* Fix issue with user.fullname (#8903)
* Ignore mentions for users with no access (#8395)
* Be more strict with git arguments (#7715)
* Extract the username and password from the mirror url (#7651)
* reserve .well-known username (#7637)
* FEATURE
* Org/Members: display 2FA members states + optimize sql requests (#7621)
* SetDefaultBranch on pushing to empty repository (#7610)
* Adds side-by-side diff for images (#6784)
* API method to list all commits of a repository (#6408)
* Password Complexity Checks (#6230)
* Add option to initialize repository with labels (#6061)
* Add additional password hash algorithms (#6023)
* BUGFIXES * BUGFIXES
* Allow to merge if file path contains " or \ (#8629) (#8771)
* On windows set core.longpaths true (#8776) (#8786)
* Fix 500 when edit hook (#8782) (#8789)
* Fix Checkbox at RepoSettings Protected Branch (#8799) (#8801)
* Fix SSH2 conditional in key parsing code (#8806) (#8810)
* Fix commit expand button to not go to commit link (#8745) (#8825)
* Fix new user form for non-local users (#8826) (#8828)
* Fix to close opened io resources as soon as not needed (#8839) (#8846)
* Fix edit content button on migrated issue content (#8877) (#8884)
* Fix require external registration password (#8885) (#8890)
* Fix password complexity check on registration (#8887) (#8888)
* Update Github Migration Tests (#8896) (#8938) (#8945)
* Enable punctuations ending mentions (#8889) (#8894)
* Add Close() method to gogitRepository (#8901) (#8956)
* Hotfix for review actions and notifications (#8965)
* Expose db.SetMaxOpenConns and allow non MySQL dbs to set conn pool params (#8528) (#8618) * Expose db.SetMaxOpenConns and allow non MySQL dbs to set conn pool params (#8528) (#8618)
* Fix milestone close timestamp (#8728) (#8730) * Fix milestone close timestamp (#8728) (#8730)
* Fix 500 when getting user as unauthenticated user (#8653) (#8663) * Fix 500 when getting user as unauthenticated user (#8653) (#8663)
@ -29,22 +62,6 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
* Fix password complexity regex for special characters (#8524) * Fix password complexity regex for special characters (#8524)
* Prevent .code-view from overriding font on icon fonts (#8614) (#8627) * Prevent .code-view from overriding font on icon fonts (#8614) (#8627)
* Allow more than 255 characters for tokens in external_login_user table (#8554) * Allow more than 255 characters for tokens in external_login_user table (#8554)
## [1.10.0-RC1](https://github.com/go-gitea/gitea/releases/tag/v1.10.0-rc1) - 2019-10-14
* BREAKING
* Remove legacy handling of drone token (#8191)
* Change repo search to use exact match for topic search. (#7941)
* Add pagination for admin api get orgs and fix only list public orgs bug (#7742)
* Implement the ability to change the ssh port to match what is in the gitea config (#7286)
* FEATURE
* Org/Members: display 2FA members states + optimize sql requests (#7621)
* SetDefaultBranch on pushing to empty repository (#7610)
* Adds side-by-side diff for images (#6784)
* API method to list all commits of a repository (#6408)
* Password Complexity Checks (#6230)
* Add option to initialize repository with labels (#6061)
* Add additional password hash algorithms (#6023)
* BUGFIXES
* Fix errors in create org UI regarding team access permission (#8506) * Fix errors in create org UI regarding team access permission (#8506)
* Fix bug on FindExternalUsersByProvider (#8504) * Fix bug on FindExternalUsersByProvider (#8504)
* Create .ssh dir as necessary (#8486) * Create .ssh dir as necessary (#8486)
@ -244,10 +261,6 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
* Support setting cookie domain (#6288) * Support setting cookie domain (#6288)
* Move migrating repository from frontend to backend (#6200) * Move migrating repository from frontend to backend (#6200)
* Delete releases attachments if release is deleted (#6068) * Delete releases attachments if release is deleted (#6068)
* SECURITY
* Ignore mentions for users with no access (#8395)
* Be more strict with git arguments (#7715)
* reserve .well-known username (#7637)
* TRANSLATION * TRANSLATION
* Latvian translation for home page (#8468) * Latvian translation for home page (#8468)
* Add home template italian translation (#8352) * Add home template italian translation (#8352)
@ -276,7 +289,6 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
* Fix global search result CSS, misc CSS tweaks (#7789) * Fix global search result CSS, misc CSS tweaks (#7789)
* Tweak label border CSS (#7739) * Tweak label border CSS (#7739)
* Fix create menu item widths (#7708) * Fix create menu item widths (#7708)
* Extract the username and password from the mirror url (#7651)
* [Branch View] Delete duplicate protection symbol (#7624) * [Branch View] Delete duplicate protection symbol (#7624)
* [Branch View] Delete Table Header (#7622) * [Branch View] Delete Table Header (#7622)
* [Branch View] icons to buttons (#7602) * [Branch View] icons to buttons (#7602)
@ -289,6 +301,14 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
* wiki - editor - add buttons 'inline code', 'empty checkbox', 'checked checkbox' (#7243) * wiki - editor - add buttons 'inline code', 'empty checkbox', 'checked checkbox' (#7243)
* Fix Statuses API only shows first 10 statuses: Add paging and extend API GetCommitStatuses (#7141) * Fix Statuses API only shows first 10 statuses: Add paging and extend API GetCommitStatuses (#7141)
## [1.9.6](https://github.com/go-gitea/gitea/releases/tag/v1.9.6) - 2019-11-13
* BUGFIXES
* Allow to merge if file path contains " or \ (#8629) (#8772)
* Fix 500 when edit hook (#8782) (#8790)
* Fix issue with user.fullname (#8904)
* Update Github Migration Test (#8897) (#8946)
* Add Close() method to gogitRepository (#8901) (#8958)
## [1.9.5](https://github.com/go-gitea/gitea/releases/tag/v1.9.5) - 2019-10-30 ## [1.9.5](https://github.com/go-gitea/gitea/releases/tag/v1.9.5) - 2019-10-30
* BREAKING * BREAKING
* Hide some user information via API if user doesn't have enough permission (#8655) (#8658) * Hide some user information via API if user doesn't have enough permission (#8655) (#8658)

View File

@ -434,7 +434,8 @@ npm-update: npm-check
.PHONY: js .PHONY: js
js: npm js: npm
npx eslint public/js npx eslint web_src/js webpack.config.js
npx webpack
.PHONY: css .PHONY: css
css: npm css: npm

View File

@ -16,6 +16,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/private" "code.gitea.io/gitea/modules/private"
"code.gitea.io/gitea/modules/setting"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
@ -55,7 +56,13 @@ var (
func runHookPreReceive(c *cli.Context) error { func runHookPreReceive(c *cli.Context) error {
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 { if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
return nil if setting.OnlyAllowPushIfGiteaEnvironmentSet {
fail(`Rejecting changes as Gitea environment not set.
If you are pushing over SSH you must push with a key managed by
Gitea or set your environment appropriately.`, "")
} else {
return nil
}
} }
setup("hooks/pre-receive.log") setup("hooks/pre-receive.log")
@ -115,7 +122,13 @@ func runHookPreReceive(c *cli.Context) error {
func runHookUpdate(c *cli.Context) error { func runHookUpdate(c *cli.Context) error {
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 { if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
return nil if setting.OnlyAllowPushIfGiteaEnvironmentSet {
fail(`Rejecting changes as Gitea environment not set.
If you are pushing over SSH you must push with a key managed by
Gitea or set your environment appropriately.`, "")
} else {
return nil
}
} }
setup("hooks/update.log") setup("hooks/update.log")
@ -125,7 +138,13 @@ func runHookUpdate(c *cli.Context) error {
func runHookPostReceive(c *cli.Context) error { func runHookPostReceive(c *cli.Context) error {
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 { if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
return nil if setting.OnlyAllowPushIfGiteaEnvironmentSet {
fail(`Rejecting changes as Gitea environment not set.
If you are pushing over SSH you must push with a key managed by
Gitea or set your environment appropriately.`, "")
} else {
return nil
}
} }
setup("hooks/post-receive.log") setup("hooks/post-receive.log")

View File

@ -383,6 +383,8 @@ MIN_PASSWORD_LENGTH = 6
IMPORT_LOCAL_PATHS = false IMPORT_LOCAL_PATHS = false
; Set to true to prevent all users (including admin) from creating custom git hooks ; Set to true to prevent all users (including admin) from creating custom git hooks
DISABLE_GIT_HOOKS = false DISABLE_GIT_HOOKS = false
; Set to false to allow pushes to gitea repositories despite having an incomplete environment - NOT RECOMMENDED
ONLY_ALLOW_PUSH_IF_GITEA_ENVIRONMENT_SET = true
;Comma separated list of character classes required to pass minimum complexity. ;Comma separated list of character classes required to pass minimum complexity.
;If left empty or no valid values are specified, the default values ("lower,upper,digit,spec") will be used. ;If left empty or no valid values are specified, the default values ("lower,upper,digit,spec") will be used.
;Use "off" to disable checking. ;Use "off" to disable checking.

1
docs/.gitignore vendored
View File

@ -1,3 +1,4 @@
public/ public/
templates/swagger/v1_json.tmpl templates/swagger/v1_json.tmpl
themes/ themes/
resources/

176
docs/assets/js/search.js Normal file
View File

@ -0,0 +1,176 @@
function ready(fn) {
if (document.readyState != 'loading') {
fn();
} else {
document.addEventListener('DOMContentLoaded', fn);
}
}
ready(doSearch);
const summaryInclude = 60;
const fuseOptions = {
shouldSort: true,
includeMatches: true,
matchAllTokens: true,
threshold: 0.0, // for parsing diacritics
tokenize: true,
location: 0,
distance: 100,
maxPatternLength: 32,
minMatchCharLength: 1,
keys: [{
name: "title",
weight: 0.8
},
{
name: "contents",
weight: 0.5
},
{
name: "tags",
weight: 0.3
},
{
name: "categories",
weight: 0.3
}
]
};
function param(name) {
return decodeURIComponent((location.search.split(name + '=')[1] || '').split('&')[0]).replace(/\+/g, ' ');
}
let searchQuery = param("s");
function doSearch() {
if (searchQuery) {
document.getElementById("search-query").value = searchQuery;
executeSearch(searchQuery);
} else {
const para = document.createElement("P");
para.innerText = "Please enter a word or phrase above";
document.getElementById("search-results").appendChild(para);
}
}
function getJSON(url, fn) {
const request = new XMLHttpRequest();
request.open('GET', url, true);
request.onload = function () {
if (request.status >= 200 && request.status < 400) {
const data = JSON.parse(request.responseText);
fn(data);
} else {
console.log("Target reached on " + url + " with error " + request.status);
}
};
request.onerror = function () {
console.log("Connection error " + request.status);
};
request.send();
}
function executeSearch(searchQuery) {
getJSON("/" + document.LANG + "/index.json", function (data) {
const pages = data;
const fuse = new Fuse(pages, fuseOptions);
const result = fuse.search(searchQuery);
console.log({
"matches": result
});
document.getElementById("search-results").innerHTML = "";
if (result.length > 0) {
populateResults(result);
} else {
const para = document.createElement("P");
para.innerText = "No matches found";
document.getElementById("search-results").appendChild(para);
}
});
}
function populateResults(result) {
result.forEach(function (value, key) {
const content = value.item.contents;
let snippet = "";
const snippetHighlights = [];
if (fuseOptions.tokenize) {
snippetHighlights.push(searchQuery);
value.matches.forEach(function (mvalue) {
if (mvalue.key === "tags" || mvalue.key === "categories") {
snippetHighlights.push(mvalue.value);
} else if (mvalue.key === "contents") {
const ind = content.toLowerCase().indexOf(searchQuery.toLowerCase());
const start = ind - summaryInclude > 0 ? ind - summaryInclude : 0;
const end = ind + searchQuery.length + summaryInclude < content.length ? ind + searchQuery.length + summaryInclude : content.length;
snippet += content.substring(start, end);
if (ind > -1) {
snippetHighlights.push(content.substring(ind, ind + searchQuery.length))
} else {
snippetHighlights.push(mvalue.value.substring(mvalue.indices[0][0], mvalue.indices[0][1] - mvalue.indices[0][0] + 1));
}
}
});
}
if (snippet.length < 1) {
snippet += content.substring(0, summaryInclude * 2);
}
//pull template from hugo templarte definition
const templateDefinition = document.getElementById("search-result-template").innerHTML;
//replace values
const output = render(templateDefinition, {
key: key,
title: value.item.title,
link: value.item.permalink,
tags: value.item.tags,
categories: value.item.categories,
snippet: snippet
});
document.getElementById("search-results").appendChild(htmlToElement(output));
snippetHighlights.forEach(function (snipvalue) {
new Mark(document.getElementById("summary-" + key)).mark(snipvalue);
});
});
}
function render(templateString, data) {
let conditionalMatches, copy;
const conditionalPattern = /\$\{\s*isset ([a-zA-Z]*) \s*\}(.*)\$\{\s*end\s*}/g;
//since loop below depends on re.lastInxdex, we use a copy to capture any manipulations whilst inside the loop
copy = templateString;
while ((conditionalMatches = conditionalPattern.exec(templateString)) !== null) {
if (data[conditionalMatches[1]]) {
//valid key, remove conditionals, leave content.
copy = copy.replace(conditionalMatches[0], conditionalMatches[2]);
} else {
//not valid, remove entire section
copy = copy.replace(conditionalMatches[0], '');
}
}
templateString = copy;
//now any conditionals removed we can do simple substitution
let key, find, re;
for (key in data) {
find = '\\$\\{\\s*' + key + '\\s*\\}';
re = new RegExp(find, 'g');
templateString = templateString.replace(re, data[key]);
}
return templateString;
}
/**
* By Mark Amery: https://stackoverflow.com/a/35385518
* @param {String} HTML representing a single element
* @return {Element}
*/
function htmlToElement(html) {
const template = document.createElement('template');
html = html.trim(); // Never return a text node of whitespace as the result
template.innerHTML = html;
return template.content.firstChild;
}

View File

@ -18,7 +18,13 @@ 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.5 version: 1.10.0
outputs:
home:
- HTML
- RSS
- JSON
menu: menu:
page: page:

View File

@ -244,6 +244,7 @@ relation to port exhaustion.
authentication provided email. authentication provided email.
- `DISABLE_GIT_HOOKS`: **false**: Set to `true` to prevent all users (including admin) from creating custom - `DISABLE_GIT_HOOKS`: **false**: Set to `true` to prevent all users (including admin) from creating custom
git hooks. git hooks.
- `ONLY_ALLOW_PUSH_IF_GITEA_ENVIRONMENT_SET`: **true**: Set to `false` to allow local users to push to gitea-repositories without setting up the Gitea environment. This is not recommended and if you want local users to push to gitea repositories you should set the environment appropriately.
- `IMPORT_LOCAL_PATHS`: **false**: Set to `false` to prevent all users (including admin) from importing local path on server. - `IMPORT_LOCAL_PATHS`: **false**: Set to `false` to prevent all users (including admin) from importing local path on server.
- `INTERNAL_TOKEN`: **\<random at every install if no uri set\>**: Secret used to validate communication within Gitea binary. - `INTERNAL_TOKEN`: **\<random at every install if no uri set\>**: Secret used to validate communication within Gitea binary.
- `INTERNAL_TOKEN_URI`: **<empty>**: Instead of defining internal token in the configuration, this configuration option can be used to give Gitea a path to a file that contains the internal token (example value: `file:/etc/gitea/internal_token`) - `INTERNAL_TOKEN_URI`: **<empty>**: Instead of defining internal token in the configuration, this configuration option can be used to give Gitea a path to a file that contains the internal token (example value: `file:/etc/gitea/internal_token`)
@ -306,6 +307,7 @@ relation to port exhaustion.
- `AUTO_WATCH_ON_CHANGES`: **false**: Enable this to make users watch a repository after their first commit to it - `AUTO_WATCH_ON_CHANGES`: **false**: Enable this to make users watch a repository after their first commit to it
- `DEFAULT_ORG_VISIBILITY`: **public**: Set default visibility mode for organisations, either "public", "limited" or "private". - `DEFAULT_ORG_VISIBILITY`: **public**: Set default visibility mode for organisations, either "public", "limited" or "private".
- `DEFAULT_ORG_MEMBER_VISIBLE`: **false** True will make the membership of the users visible when added to the organisation. - `DEFAULT_ORG_MEMBER_VISIBLE`: **false** True will make the membership of the users visible when added to the organisation.
- `ALLOW_ONLY_EXTERNAL_REGISTRATION`: **false** Set to true to force registration only using third-party services.
## Webhook (`webhook`) ## Webhook (`webhook`)

View File

@ -2,12 +2,12 @@
date: "2017-01-20T15:00:00+08:00" date: "2017-01-20T15:00:00+08:00"
title: "Help" title: "Help"
slug: "help" slug: "help"
weight: 50 weight: 5
toc: false toc: false
draft: false draft: false
menu: menu:
sidebar: sidebar:
name: "Help" name: "Help"
weight: 50 weight: 5
identifier: "help" identifier: "help"
--- ---

View File

@ -0,0 +1,13 @@
---
date: "2017-01-20T15:00:00+08:00"
title: "Aide"
slug: "help"
weight: 5
toc: false
draft: false
menu:
sidebar:
name: "Aide"
weight: 5
identifier: "help"
---

View File

@ -2,12 +2,12 @@
date: "2017-01-20T15:00:00+08:00" date: "2017-01-20T15:00:00+08:00"
title: "帮助" title: "帮助"
slug: "help" slug: "help"
weight: 50 weight: 5
toc: false toc: false
draft: false draft: false
menu: menu:
sidebar: sidebar:
name: "帮助" name: "帮助"
weight: 50 weight: 5
identifier: "help" identifier: "help"
--- ---

View File

@ -0,0 +1,13 @@
---
date: "2017-01-20T15:00:00+08:00"
title: "救命"
slug: "help"
weight: 5
toc: false
draft: false
menu:
sidebar:
name: "救命"
weight: 5
identifier: "help"
---

View File

@ -0,0 +1,25 @@
---
date: "2019-11-12T16:00:00+02:00"
title: "Search"
slug: "search"
weight: 4
toc: true
draft: false
menu:
sidebar:
parent: "help"
name: "Search"
weight: 4
identifier: "search"
sitemap:
priority : 0.1
layout: "search"
---
This file exists solely to respond to /search URL with the related `search` layout template.
No content shown here is rendered, all content is based in the template layouts/doc/search.html
Setting a very low sitemap priority will tell search engines this is not important content.

View File

@ -0,0 +1,25 @@
---
date: "2019-11-12T16:00:00+02:00"
title: "Chercher"
slug: "search"
weight: 4
toc: true
draft: false
menu:
sidebar:
parent: "help"
name: "Chercher"
weight: 4
identifier: "search"
sitemap:
priority : 0.1
layout: "search"
---
This file exists solely to respond to /search URL with the related `search` layout template.
No content shown here is rendered, all content is based in the template layouts/doc/search.html
Setting a very low sitemap priority will tell search engines this is not important content.

View File

@ -0,0 +1,25 @@
---
date: "2019-11-12T16:00:00+02:00"
title: "搜索"
slug: "search"
weight: 4
toc: true
draft: false
menu:
sidebar:
parent: "help"
name: "搜索"
weight: 4
identifier: "search"
sitemap:
priority : 0.1
layout: "search"
---
This file exists solely to respond to /search URL with the related `search` layout template.
No content shown here is rendered, all content is based in the template layouts/doc/search.html
Setting a very low sitemap priority will tell search engines this is not important content.

View File

@ -0,0 +1,25 @@
---
date: "2019-11-12T16:00:00+02:00"
title: "搜索"
slug: "search"
weight: 4
toc: true
draft: false
menu:
sidebar:
parent: "help"
name: "搜索"
weight: 4
identifier: "search"
sitemap:
priority : 0.1
layout: "search"
---
This file exists solely to respond to /search URL with the related `search` layout template.
No content shown here is rendered, all content is based in the template layouts/doc/search.html
Setting a very low sitemap priority will tell search engines this is not important content.

View File

@ -40,7 +40,7 @@ To register Gitea as a Windows service, open a command prompt (cmd) as an Admini
then run the following command: then run the following command:
``` ```
sc create gitea start= auto binPath= ""C:\gitea\gitea.exe" web --config "C:\gitea\custom\conf\app.ini"" sc create gitea start= auto binPath= "\"C:\gitea\gitea.exe\" web --config \"C:\gitea\custom\conf\app.ini\""
``` ```
Do not forget to replace `C:\gitea` with the correct Gitea directory. Do not forget to replace `C:\gitea` with the correct Gitea directory.

View File

@ -18,7 +18,7 @@ menu:
Pour activer le service Windows Gitea, ouvrez une `cmd` en tant qu'Administrateur puis utilisez la commande suivante : Pour activer le service Windows Gitea, ouvrez une `cmd` en tant qu'Administrateur puis utilisez la commande suivante :
``` ```
sc create gitea start= auto binPath= ""C:\gitea\gitea.exe" web --config "C:\gitea\custom\conf\app.ini"" sc create gitea start= auto binPath= "\"C:\gitea\gitea.exe\" web --config \"C:\gitea\custom\conf\app.ini\""
``` ```
N'oubliez pas de remplacer `C:\gitea` par le chemin que vous avez utilisez pour votre installation. N'oubliez pas de remplacer `C:\gitea` par le chemin que vous avez utilisez pour votre installation.

View File

@ -18,7 +18,7 @@ menu:
要注册为Windows服务首先以Administrator身份运行 `cmd`,然后执行以下命令: 要注册为Windows服务首先以Administrator身份运行 `cmd`,然后执行以下命令:
``` ```
sc create gitea start= auto binPath= ""C:\gitea\gitea.exe" web --config "C:\gitea\custom\conf\app.ini"" sc create gitea start= auto binPath= "\"C:\gitea\gitea.exe\" web --config \"C:\gitea\custom\conf\app.ini\""
``` ```
别忘了将 `C:\gitea` 替换成你的 Gitea 安装目录。 别忘了将 `C:\gitea` 替换成你的 Gitea 安装目录。

View File

@ -18,7 +18,7 @@ menu:
要註冊為 Windows 服務,首先要以管理者身份執行 `cmd`,跳出命令列視窗後執行底下指令: 要註冊為 Windows 服務,首先要以管理者身份執行 `cmd`,跳出命令列視窗後執行底下指令:
``` ```
sc create gitea start= auto binPath= ""C:\gitea\gitea.exe" web --config "C:\gitea\custom\conf\app.ini"" sc create gitea start= auto binPath= "\"C:\gitea\gitea.exe\" web --config \"C:\gitea\custom\conf\app.ini\""
``` ```
別忘記將 `C:\gitea` 取代為您的 Gitea 安裝路徑。 別忘記將 `C:\gitea` 取代為您的 Gitea 安裝路徑。

View File

@ -51,6 +51,8 @@ services:
- gitea - gitea
volumes: volumes:
- ./gitea:/data - ./gitea:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports: ports:
- "3000:3000" - "3000:3000"
- "222:22" - "222:22"
@ -80,6 +82,8 @@ services:
- gitea - gitea
volumes: volumes:
- ./gitea:/data - ./gitea:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports: ports:
- - "3000:3000" - - "3000:3000"
- - "222:22" - - "222:22"
@ -115,6 +119,8 @@ services:
- gitea - gitea
volumes: volumes:
- ./gitea:/data - ./gitea:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports: ports:
- "3000:3000" - "3000:3000"
- "222:22" - "222:22"
@ -163,6 +169,8 @@ services:
- gitea - gitea
volumes: volumes:
- ./gitea:/data - ./gitea:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports: ports:
- "3000:3000" - "3000:3000"
- "222:22" - "222:22"
@ -209,6 +217,8 @@ services:
volumes: volumes:
- - ./gitea:/data - - ./gitea:/data
+ - gitea:/data + - gitea:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports: ports:
- "3000:3000" - "3000:3000"
- "222:22" - "222:22"
@ -306,6 +316,8 @@ UID/GID as the container values `USER_UID`/`USER_GID`. You should also create th
- gitea - gitea
volumes: volumes:
- /var/lib/gitea:/data - /var/lib/gitea:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports: ports:
- "3000:3000" - "3000:3000"
- "127.0.0.1:2222:22" - "127.0.0.1:2222:22"

View File

@ -0,0 +1,5 @@
{{- $.Scratch.Add "index" slice -}}
{{- range .Site.RegularPages -}}
{{- $.Scratch.Add "index" (dict "title" .Title "tags" .Params.tags "categories" .Params.categories "contents" .Plain "permalink" .Permalink) -}}
{{- end -}}
{{- $.Scratch.Get "index" | jsonify -}}

View File

@ -0,0 +1,44 @@
{{ partial "header.html" . }}
{{ partial "navbar.html" . }}
<section class="section">
<div class="container is-centered page">
<div class="columns">
<div class="column is-one-quarter">
{{ partial "menu" . }}
</div>
<div class="column">
<div class=" content">
<section class="resume-section p-3 p-lg-5 d-flex flex-column">
<div class="my-auto" >
<form action="{{ "search" | absLangURL }}">
<label>Search:
<input id="search-query" name="s"/>
</label>
</form>
<br/>
<div id="search-results"></div>
</div>
</section>
<!-- this template is sucked in by search.js and appended to the search-results div above. So editing here will adjust style -->
<script id="search-result-template" type="text/x-js-template">
<div id="summary-${key}">
<h4><a href="${link}">${title}</a></h4>
<p>${snippet}</p>
${ isset tags }<p>Tags: ${tags}</p>${ end }
${ isset categories }<p>Categories: ${categories}</p>${ end }
<hr/>
</div>
</script>
</div>
</div>
</div>
</div>
</section>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fuse.js/3.4.5/fuse.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mark.js/8.11.1/mark.min.js"></script>
<script>document.LANG = "{{ .Language.Lang }}";</script>
{{ $script := resources.Get "js/search.js" | minify | fingerprint -}}
<script src="{{ $script.Permalink }}" {{ printf "integrity=%q" $script.Data.Integrity | safeHTMLAttr }}></script>
{{ partial "footer.html" . }}

View File

@ -1,5 +1,5 @@
/* /*
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' https://fonts.googleapis.com https://cdnjs.cloudflare.com; font-src 'self' data: https://cdnjs.cloudflare.com https://fonts.gstatic.com Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' https://cdnjs.cloudflare.com; style-src 'self' https://fonts.googleapis.com https://cdnjs.cloudflare.com; font-src 'self' data: https://cdnjs.cloudflare.com https://fonts.gstatic.com
X-Frame-Options: DENY X-Frame-Options: DENY
X-Xss-Protection: 1; mode=block X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff X-Content-Type-Options: nosniff

1
go.mod
View File

@ -80,7 +80,6 @@ require (
github.com/prometheus/client_golang v1.1.0 github.com/prometheus/client_golang v1.1.0
github.com/prometheus/procfs v0.0.4 // indirect github.com/prometheus/procfs v0.0.4 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001 // indirect github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001 // indirect
github.com/russross/blackfriday v2.0.0+incompatible // indirect
github.com/russross/blackfriday/v2 v2.0.1 github.com/russross/blackfriday/v2 v2.0.1
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca // indirect github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca // indirect
github.com/satori/go.uuid v1.2.0 github.com/satori/go.uuid v1.2.0

45
go.sum
View File

@ -1,12 +1,10 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.30.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.30.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.37.4 h1:glPeL3BQJsbF6aIIYfZizMwc5LTYz250bDMjttbBGAU=
cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.44.3 h1:0sMegbmn/8uTwpNkB0q9cLEpZ2W5a6kl+wtBQgPWBJQ=
cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.0 h1:bALuGBSgE+BD4rxsopAYlqjcwqcQtye6pWG4bC3N/k0= cloud.google.com/go v0.45.0 h1:bALuGBSgE+BD4rxsopAYlqjcwqcQtye6pWG4bC3N/k0=
cloud.google.com/go v0.45.0/go.mod h1:452BcPOeI9AZfbvDw0Tbo7D32wA+WX9WME8AZwMEDZU= cloud.google.com/go v0.45.0/go.mod h1:452BcPOeI9AZfbvDw0Tbo7D32wA+WX9WME8AZwMEDZU=
@ -67,7 +65,6 @@ github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:l
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
@ -167,7 +164,6 @@ github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70t
github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
github.com/go-openapi/analysis v0.19.4 h1:1TjOzrWkj+9BrjnM1yPAICbaoC0FyfD49oVkTBrSSa0=
github.com/go-openapi/analysis v0.19.4/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= github.com/go-openapi/analysis v0.19.4/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
github.com/go-openapi/analysis v0.19.5 h1:8b2ZgKfKIUTVQpTb77MoRDIMEIwvDVw40o3aOXdfYzI= github.com/go-openapi/analysis v0.19.5 h1:8b2ZgKfKIUTVQpTb77MoRDIMEIwvDVw40o3aOXdfYzI=
github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU=
@ -179,39 +175,33 @@ github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNP
github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4= github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4=
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.19.2 h1:A9+F4Dc/MCNB5jibxf6rRvOvR/iFgQdyNx9eIhnGqq0=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w=
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o= github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o=
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.19.2 h1:rf5ArTHmIJxyV5Oiks+Su0mUens1+AjpkPoWr5xFRcI=
github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs=
github.com/go-openapi/loads v0.19.3 h1:jwIoahqCmaA5OBoc/B+1+Mu2L0Gr8xYQnbeyQEo/7b0= github.com/go-openapi/loads v0.19.3 h1:jwIoahqCmaA5OBoc/B+1+Mu2L0Gr8xYQnbeyQEo/7b0=
github.com/go-openapi/loads v0.19.3/go.mod h1:YVfqhUCdahYwR3f3iiwQLhicVRvLlU/WO5WPaZvcvSI= github.com/go-openapi/loads v0.19.3/go.mod h1:YVfqhUCdahYwR3f3iiwQLhicVRvLlU/WO5WPaZvcvSI=
github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA=
github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64=
github.com/go-openapi/runtime v0.19.4 h1:csnOgcgAiuGoM/Po7PEpKDoNulCcF3FGbSnbHfxgjMI=
github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4=
github.com/go-openapi/runtime v0.19.5 h1:h4Zk7oTfB3ZYM2oMNliQvL+3BrDstTIX8lqP7yaYCuI= github.com/go-openapi/runtime v0.19.5 h1:h4Zk7oTfB3ZYM2oMNliQvL+3BrDstTIX8lqP7yaYCuI=
github.com/go-openapi/runtime v0.19.5/go.mod h1:WIH6IYPXOrtgTClTV8xzdrD20jBlrK25D0aQbdSlqp8= github.com/go-openapi/runtime v0.19.5/go.mod h1:WIH6IYPXOrtgTClTV8xzdrD20jBlrK25D0aQbdSlqp8=
github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.19.2 h1:SStNd1jRcYtfKCN7R0laGNs80WYYvn5CbBjM2sOmCrE=
github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY=
github.com/go-openapi/spec v0.19.3 h1:0XRyw8kguri6Yw4SxhsQA/atC88yqrk0+G4YhI2wabc= github.com/go-openapi/spec v0.19.3 h1:0XRyw8kguri6Yw4SxhsQA/atC88yqrk0+G4YhI2wabc=
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY=
github.com/go-openapi/strfmt v0.19.2 h1:clPGfBnJohokno0e+d7hs6Yocrzjlgz6EsQSDncCRnE=
github.com/go-openapi/strfmt v0.19.2/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= github.com/go-openapi/strfmt v0.19.2/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
github.com/go-openapi/strfmt v0.19.3 h1:eRfyY5SkaNJCAwmmMcADjY31ow9+N7MCLW7oRkbsINA= github.com/go-openapi/strfmt v0.19.3 h1:eRfyY5SkaNJCAwmmMcADjY31ow9+N7MCLW7oRkbsINA=
github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
@ -221,7 +211,6 @@ github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
github.com/go-openapi/validate v0.19.2 h1:ky5l57HjyVRrsJfd2+Ro5Z9PjGuKbsmftwyMtk8H7js=
github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
github.com/go-openapi/validate v0.19.3 h1:PAH/2DylwWcIU1s0Y7k3yNmeAgWOcKrNE2Q7Ww/kCg4= github.com/go-openapi/validate v0.19.3 h1:PAH/2DylwWcIU1s0Y7k3yNmeAgWOcKrNE2Q7Ww/kCg4=
github.com/go-openapi/validate v0.19.3/go.mod h1:90Vh6jjkTn+OT1Eefm0ZixWNFjhtOH7vS9k0lo6zwJo= github.com/go-openapi/validate v0.19.3/go.mod h1:90Vh6jjkTn+OT1Eefm0ZixWNFjhtOH7vS9k0lo6zwJo=
@ -255,18 +244,15 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@ -288,7 +274,6 @@ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg=
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4= github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4=
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@ -302,7 +287,6 @@ github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1 h1:LqbZZ9sNMWVjeXS4NN5
github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1/go.mod h1:YeAe0gNeiNT5hoiZRI4yiOky6jVdNvfO2N6Kav/HmxY= github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1/go.mod h1:YeAe0gNeiNT5hoiZRI4yiOky6jVdNvfO2N6Kav/HmxY=
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.1.1 h1:YMDmfaK68mUixINzY/XjscuJ47uXFWSSHzFbBQM0PrE=
github.com/gorilla/sessions v1.1.1/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= github.com/gorilla/sessions v1.1.1/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ= github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ=
github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
@ -385,7 +369,6 @@ github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM= github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM=
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
@ -423,21 +406,15 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5 h1:BvoENQQU+fZ9uukda/RzCAL/191HHwJA5b13R6diVlY= github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5 h1:BvoENQQU+fZ9uukda/RzCAL/191HHwJA5b13R6diVlY=
github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/niklasfasching/go-org v0.1.6 h1:F521WcqRNl8OJumlgAnekZgERaTA2HpfOYYfVEKOeI8=
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/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 h1:Kjvs6lP+LIILHhc9zIJ4Gu90a/pVY483if2Qmu8v4Fg=
github.com/niklasfasching/go-org v0.1.8/go.mod h1:AsLD6X7djzRIz4/RFZu8vwRL0VGjUvGZCCH1Nz0VdrU= 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=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w=
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
@ -466,7 +443,6 @@ github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
@ -491,8 +467,6 @@ github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001/go.mod h1:qq
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v2.0.0+incompatible h1:cBXrhZNUf9C+La9/YpS+UHpUT8YD6Td9ZMSU9APFcsk=
github.com/russross/blackfriday v2.0.0+incompatible/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca h1:NugYot0LIVPxTvN8n+Kvkn6TrbMyxQiuvKdEwFdR9vI= github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca h1:NugYot0LIVPxTvN8n+Kvkn6TrbMyxQiuvKdEwFdR9vI=
@ -503,8 +477,6 @@ github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b h1:4kg1wyftSKxLtnPAvcRWakIPpokB9w780/KwrNLnfPA= github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b h1:4kg1wyftSKxLtnPAvcRWakIPpokB9w780/KwrNLnfPA=
github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/sanitized_anchor_name v0.0.0-20160918041101-1dba4b3954bc h1:3wIrJvFb3Pf6B/2mDBnN1G5IfUVev4X5apadQlWOczE=
github.com/shurcooL/sanitized_anchor_name v0.0.0-20160918041101-1dba4b3954bc/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd h1:ug7PpSOB5RBPK1Kg6qskGBoP3Vnj/aNYFTznWvlkGo0= github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd h1:ug7PpSOB5RBPK1Kg6qskGBoP3Vnj/aNYFTznWvlkGo0=
@ -517,7 +489,6 @@ github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY=
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w= github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w=
github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
@ -548,11 +519,9 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/syndtr/goleveldb v0.0.0-20190203031304-2f17a3356c66 h1:AwmkkZT+TucFotNCL+aNJ/0KCMsRtlXN9fs8uoOMSRk=
github.com/syndtr/goleveldb v0.0.0-20190203031304-2f17a3356c66/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/syndtr/goleveldb v0.0.0-20190203031304-2f17a3356c66/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
@ -594,7 +563,6 @@ go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk= go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.mongodb.org/mongo-driver v1.1.0 h1:aeOqSrhl9eDRAap/3T5pCfMBEBxZ0vuXBP+RMtp2KX8=
go.mongodb.org/mongo-driver v1.1.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.mongodb.org/mongo-driver v1.1.1 h1:Sq1fR+0c58RME5EoqKdjkiQAmPjmfHlZOoRI6fTUOcs= go.mongodb.org/mongo-driver v1.1.1 h1:Sq1fR+0c58RME5EoqKdjkiQAmPjmfHlZOoRI6fTUOcs=
go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
@ -614,7 +582,6 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad h1:5E5raQxcv+6CZ11RrBYQe5WRbUIWpScjh0kvHZkZIrQ= golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad h1:5E5raQxcv+6CZ11RrBYQe5WRbUIWpScjh0kvHZkZIrQ=
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@ -651,20 +618,13 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190909003024-a7b16738d86b h1:XfVGCX+0T4WOStkaOsJRllbsiImhB2jgVBGc9L0lPGc=
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/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 h1:DPz9iiH3YoKiKhX/ijjoZvT0VFwK2c6CWYWQ7Zyr8TU=
golang.org/x/net v0.0.0-20191101175033-0deb6923b6d9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 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/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -694,7 +654,6 @@ golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190730183949-1393eb018365/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190730183949-1393eb018365/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3 h1:4y9KwBHBgBNwDbtu44R5o1fdOCQUEXhbk/P4A9WmJq0=
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190910064555-bbd175535a8b h1:3S2h5FadpNr0zUUCVZjlKIEYF+KaX/OBplTGo89CYHI= golang.org/x/sys v0.0.0-20190910064555-bbd175535a8b h1:3S2h5FadpNr0zUUCVZjlKIEYF+KaX/OBplTGo89CYHI=
@ -738,9 +697,7 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.0 h1:Tfd7cKwKbFRsI8RMAD3oqqw7JPFRrvFlOsfbgVkjOOw=
google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.4 h1:WiKh4+/eMB2HaY7QhCfW/R7MuRAoA8QMCSJA6jP5/fo= google.golang.org/appengine v1.6.4 h1:WiKh4+/eMB2HaY7QhCfW/R7MuRAoA8QMCSJA6jP5/fo=
google.golang.org/appengine v1.6.4/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.4/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
@ -764,7 +721,6 @@ gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod
gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 h1:nn6Zav2sOQHCFJHEspya8KqxhFwKci30UxHy3HXPTyQ= gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 h1:nn6Zav2sOQHCFJHEspya8KqxhFwKci30UxHy3HXPTyQ=
gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@ -776,7 +732,6 @@ gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkp
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.44.2/go.mod h1:M3Cogqpuv0QCi3ExAY5V4uOt4qb/R3xZubo9m8lK5wg= gopkg.in/ini.v1 v1.44.2/go.mod h1:M3Cogqpuv0QCi3ExAY5V4uOt4qb/R3xZubo9m8lK5wg=
gopkg.in/ini.v1 v1.46.0 h1:VeDZbLYGaupuvIrsYCEOe/L/2Pcs5n7hdO1ZTjporag=
gopkg.in/ini.v1 v1.46.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.46.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.48.0 h1:URjZc+8ugRY5mL5uUeQH/a63JcHwdX9xZaWvmNWD7z8= gopkg.in/ini.v1 v1.48.0 h1:URjZc+8ugRY5mL5uUeQH/a63JcHwdX9xZaWvmNWD7z8=
gopkg.in/ini.v1 v1.48.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.48.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=

View File

@ -79,8 +79,10 @@ func allowLFSFilters() []string {
return globalArgs return globalArgs
} }
func onGiteaRun(t *testing.T, callback func(*testing.T, *url.URL)) { func onGiteaRun(t *testing.T, callback func(*testing.T, *url.URL), prepare ...bool) {
prepareTestEnv(t, 1) if len(prepare) == 0 || prepare[0] {
prepareTestEnv(t, 1)
}
s := http.Server{ s := http.Server{
Handler: mac, Handler: mac,
} }

View File

@ -23,14 +23,7 @@ import (
) )
func TestGPGGit(t *testing.T) { func TestGPGGit(t *testing.T) {
onGiteaRun(t, testGPGGit)
}
func testGPGGit(t *testing.T, u *url.URL) {
username := "user2" username := "user2"
baseAPITestContext := NewAPITestContext(t, username, "repo1")
u.Path = baseAPITestContext.GitPath()
// OK Set a new GPG home // OK Set a new GPG home
tmpDir, err := ioutil.TempDir("", "temp-gpg") tmpDir, err := ioutil.TempDir("", "temp-gpg")
@ -65,130 +58,218 @@ func testGPGGit(t *testing.T, u *url.URL) {
setting.Repository.Signing.SigningEmail = "gitea@fake.local" setting.Repository.Signing.SigningEmail = "gitea@fake.local"
user := models.AssertExistsAndLoadBean(t, &models.User{Name: username}).(*models.User) user := models.AssertExistsAndLoadBean(t, &models.User{Name: username}).(*models.User)
t.Run("Unsigned-Initial", func(t *testing.T) { setting.Repository.Signing.InitialCommit = []string{"never"}
PrintCurrentTest(t) setting.Repository.Signing.CRUDActions = []string{"never"}
setting.Repository.Signing.InitialCommit = []string{"never"}
testCtx := NewAPITestContext(t, username, "initial-unsigned") baseAPITestContext := NewAPITestContext(t, username, "repo1")
t.Run("CreateRepository", doAPICreateRepository(testCtx, false)) onGiteaRun(t, func(t *testing.T, u *url.URL) {
t.Run("CheckMasterBranchUnsigned", doAPIGetBranch(testCtx, "master", func(t *testing.T, branch api.Branch) { u.Path = baseAPITestContext.GitPath()
assert.NotNil(t, branch.Commit)
assert.NotNil(t, branch.Commit.Verification) t.Run("Unsigned-Initial", func(t *testing.T) {
assert.False(t, branch.Commit.Verification.Verified) PrintCurrentTest(t)
assert.Empty(t, branch.Commit.Verification.Signature) testCtx := NewAPITestContext(t, username, "initial-unsigned")
})) t.Run("CreateRepository", doAPICreateRepository(testCtx, false))
setting.Repository.Signing.CRUDActions = []string{"never"} t.Run("CheckMasterBranchUnsigned", doAPIGetBranch(testCtx, "master", func(t *testing.T, branch api.Branch) {
t.Run("CreateCRUDFile-Never", crudActionCreateFile( assert.NotNil(t, branch.Commit)
t, testCtx, user, "master", "never", "unsigned-never.txt", func(t *testing.T, response api.FileResponse) { assert.NotNil(t, branch.Commit.Verification)
assert.False(t, response.Verification.Verified) assert.False(t, branch.Commit.Verification.Verified)
assert.Empty(t, branch.Commit.Verification.Signature)
})) }))
t.Run("CreateCRUDFile-Never", crudActionCreateFile( t.Run("CreateCRUDFile-Never", crudActionCreateFile(
t, testCtx, user, "never", "never2", "unsigned-never2.txt", func(t *testing.T, response api.FileResponse) { t, testCtx, user, "master", "never", "unsigned-never.txt", func(t *testing.T, response api.FileResponse) {
assert.False(t, response.Verification.Verified) assert.False(t, response.Verification.Verified)
}))
t.Run("CreateCRUDFile-Never", crudActionCreateFile(
t, testCtx, user, "never", "never2", "unsigned-never2.txt", func(t *testing.T, response api.FileResponse) {
assert.False(t, response.Verification.Verified)
}))
})
}, false)
setting.Repository.Signing.CRUDActions = []string{"parentsigned"}
onGiteaRun(t, func(t *testing.T, u *url.URL) {
u.Path = baseAPITestContext.GitPath()
t.Run("Unsigned-Initial-CRUD-ParentSigned", func(t *testing.T) {
PrintCurrentTest(t)
testCtx := NewAPITestContext(t, username, "initial-unsigned")
t.Run("CreateCRUDFile-ParentSigned", crudActionCreateFile(
t, testCtx, user, "master", "parentsigned", "signed-parent.txt", func(t *testing.T, response api.FileResponse) {
assert.False(t, response.Verification.Verified)
}))
t.Run("CreateCRUDFile-ParentSigned", crudActionCreateFile(
t, testCtx, user, "parentsigned", "parentsigned2", "signed-parent2.txt", func(t *testing.T, response api.FileResponse) {
assert.False(t, response.Verification.Verified)
}))
})
}, false)
setting.Repository.Signing.CRUDActions = []string{"never"}
onGiteaRun(t, func(t *testing.T, u *url.URL) {
u.Path = baseAPITestContext.GitPath()
t.Run("Unsigned-Initial-CRUD-Never", func(t *testing.T) {
PrintCurrentTest(t)
testCtx := NewAPITestContext(t, username, "initial-unsigned")
t.Run("CreateCRUDFile-Never", crudActionCreateFile(
t, testCtx, user, "parentsigned", "parentsigned-never", "unsigned-never2.txt", func(t *testing.T, response api.FileResponse) {
assert.False(t, response.Verification.Verified)
}))
})
}, false)
setting.Repository.Signing.CRUDActions = []string{"always"}
onGiteaRun(t, func(t *testing.T, u *url.URL) {
u.Path = baseAPITestContext.GitPath()
t.Run("Unsigned-Initial-CRUD-Always", func(t *testing.T) {
PrintCurrentTest(t)
testCtx := NewAPITestContext(t, username, "initial-unsigned")
t.Run("CreateCRUDFile-Always", crudActionCreateFile(
t, testCtx, user, "master", "always", "signed-always.txt", func(t *testing.T, response api.FileResponse) {
assert.True(t, response.Verification.Verified)
assert.Equal(t, "gitea@fake.local", response.Verification.Signer.Email)
}))
t.Run("CreateCRUDFile-ParentSigned-always", crudActionCreateFile(
t, testCtx, user, "parentsigned", "parentsigned-always", "signed-parent2.txt", func(t *testing.T, response api.FileResponse) {
assert.True(t, response.Verification.Verified)
assert.Equal(t, "gitea@fake.local", response.Verification.Signer.Email)
}))
})
}, false)
setting.Repository.Signing.CRUDActions = []string{"parentsigned"}
onGiteaRun(t, func(t *testing.T, u *url.URL) {
u.Path = baseAPITestContext.GitPath()
t.Run("Unsigned-Initial-CRUD-ParentSigned", func(t *testing.T) {
PrintCurrentTest(t)
testCtx := NewAPITestContext(t, username, "initial-unsigned")
t.Run("CreateCRUDFile-Always-ParentSigned", crudActionCreateFile(
t, testCtx, user, "always", "always-parentsigned", "signed-always-parentsigned.txt", func(t *testing.T, response api.FileResponse) {
assert.True(t, response.Verification.Verified)
assert.Equal(t, "gitea@fake.local", response.Verification.Signer.Email)
}))
})
}, false)
setting.Repository.Signing.InitialCommit = []string{"always"}
onGiteaRun(t, func(t *testing.T, u *url.URL) {
u.Path = baseAPITestContext.GitPath()
t.Run("AlwaysSign-Initial", func(t *testing.T) {
PrintCurrentTest(t)
testCtx := NewAPITestContext(t, username, "initial-always")
t.Run("CreateRepository", doAPICreateRepository(testCtx, false))
t.Run("CheckMasterBranchSigned", doAPIGetBranch(testCtx, "master", func(t *testing.T, branch api.Branch) {
assert.NotNil(t, branch.Commit)
assert.NotNil(t, branch.Commit.Verification)
assert.True(t, branch.Commit.Verification.Verified)
assert.Equal(t, "gitea@fake.local", branch.Commit.Verification.Signer.Email)
})) }))
setting.Repository.Signing.CRUDActions = []string{"parentsigned"} })
t.Run("CreateCRUDFile-ParentSigned", crudActionCreateFile( }, false)
t, testCtx, user, "master", "parentsigned", "signed-parent.txt", func(t *testing.T, response api.FileResponse) { setting.Repository.Signing.CRUDActions = []string{"never"}
assert.False(t, response.Verification.Verified) onGiteaRun(t, func(t *testing.T, u *url.URL) {
u.Path = baseAPITestContext.GitPath()
t.Run("AlwaysSign-Initial-CRUD-Never", func(t *testing.T) {
PrintCurrentTest(t)
testCtx := NewAPITestContext(t, username, "initial-always")
t.Run("CreateCRUDFile-Never", crudActionCreateFile(
t, testCtx, user, "master", "never", "unsigned-never.txt", func(t *testing.T, response api.FileResponse) {
assert.False(t, response.Verification.Verified)
}))
})
}, false)
setting.Repository.Signing.CRUDActions = []string{"parentsigned"}
onGiteaRun(t, func(t *testing.T, u *url.URL) {
u.Path = baseAPITestContext.GitPath()
t.Run("AlwaysSign-Initial-CRUD-ParentSigned-On-Always", func(t *testing.T) {
PrintCurrentTest(t)
testCtx := NewAPITestContext(t, username, "initial-always")
t.Run("CreateCRUDFile-ParentSigned", crudActionCreateFile(
t, testCtx, user, "master", "parentsigned", "signed-parent.txt", func(t *testing.T, response api.FileResponse) {
assert.True(t, response.Verification.Verified)
assert.Equal(t, "gitea@fake.local", response.Verification.Signer.Email)
}))
})
}, false)
setting.Repository.Signing.CRUDActions = []string{"always"}
onGiteaRun(t, func(t *testing.T, u *url.URL) {
u.Path = baseAPITestContext.GitPath()
t.Run("AlwaysSign-Initial-CRUD-Always", func(t *testing.T) {
PrintCurrentTest(t)
testCtx := NewAPITestContext(t, username, "initial-always")
t.Run("CreateCRUDFile-Always", crudActionCreateFile(
t, testCtx, user, "master", "always", "signed-always.txt", func(t *testing.T, response api.FileResponse) {
assert.True(t, response.Verification.Verified)
assert.Equal(t, "gitea@fake.local", response.Verification.Signer.Email)
}))
})
}, false)
var pr api.PullRequest
setting.Repository.Signing.Merges = []string{"commitssigned"}
onGiteaRun(t, func(t *testing.T, u *url.URL) {
u.Path = baseAPITestContext.GitPath()
t.Run("UnsignedMerging", func(t *testing.T) {
PrintCurrentTest(t)
testCtx := NewAPITestContext(t, username, "initial-unsigned")
var err error
t.Run("CreatePullRequest", func(t *testing.T) {
pr, err = doAPICreatePullRequest(testCtx, testCtx.Username, testCtx.Reponame, "master", "never2")(t)
assert.NoError(t, err)
})
t.Run("MergePR", doAPIMergePullRequest(testCtx, testCtx.Username, testCtx.Reponame, pr.Index))
t.Run("CheckMasterBranchUnsigned", doAPIGetBranch(testCtx, "master", func(t *testing.T, branch api.Branch) {
assert.NotNil(t, branch.Commit)
assert.NotNil(t, branch.Commit.Verification)
assert.False(t, branch.Commit.Verification.Verified)
assert.Empty(t, branch.Commit.Verification.Signature)
})) }))
t.Run("CreateCRUDFile-ParentSigned", crudActionCreateFile( })
t, testCtx, user, "parentsigned", "parentsigned2", "signed-parent2.txt", func(t *testing.T, response api.FileResponse) { }, false)
assert.False(t, response.Verification.Verified) setting.Repository.Signing.Merges = []string{"basesigned"}
onGiteaRun(t, func(t *testing.T, u *url.URL) {
u.Path = baseAPITestContext.GitPath()
t.Run("BaseSignedMerging", func(t *testing.T) {
PrintCurrentTest(t)
testCtx := NewAPITestContext(t, username, "initial-unsigned")
var err error
t.Run("CreatePullRequest", func(t *testing.T) {
pr, err = doAPICreatePullRequest(testCtx, testCtx.Username, testCtx.Reponame, "master", "parentsigned2")(t)
assert.NoError(t, err)
})
t.Run("MergePR", doAPIMergePullRequest(testCtx, testCtx.Username, testCtx.Reponame, pr.Index))
t.Run("CheckMasterBranchUnsigned", doAPIGetBranch(testCtx, "master", func(t *testing.T, branch api.Branch) {
assert.NotNil(t, branch.Commit)
assert.NotNil(t, branch.Commit.Verification)
assert.False(t, branch.Commit.Verification.Verified)
assert.Empty(t, branch.Commit.Verification.Signature)
})) }))
setting.Repository.Signing.CRUDActions = []string{"never"} })
t.Run("CreateCRUDFile-Never", crudActionCreateFile( }, false)
t, testCtx, user, "parentsigned", "parentsigned-never", "unsigned-never2.txt", func(t *testing.T, response api.FileResponse) { setting.Repository.Signing.Merges = []string{"commitssigned"}
assert.False(t, response.Verification.Verified) onGiteaRun(t, func(t *testing.T, u *url.URL) {
})) u.Path = baseAPITestContext.GitPath()
setting.Repository.Signing.CRUDActions = []string{"always"}
t.Run("CreateCRUDFile-Always", crudActionCreateFile( t.Run("CommitsSignedMerging", func(t *testing.T) {
t, testCtx, user, "master", "always", "signed-always.txt", func(t *testing.T, response api.FileResponse) { PrintCurrentTest(t)
assert.True(t, response.Verification.Verified) testCtx := NewAPITestContext(t, username, "initial-unsigned")
assert.Equal(t, "gitea@fake.local", response.Verification.Signer.Email) var err error
})) t.Run("CreatePullRequest", func(t *testing.T) {
t.Run("CreateCRUDFile-ParentSigned-always", crudActionCreateFile( pr, err = doAPICreatePullRequest(testCtx, testCtx.Username, testCtx.Reponame, "master", "always-parentsigned")(t)
t, testCtx, user, "parentsigned", "parentsigned-always", "signed-parent2.txt", func(t *testing.T, response api.FileResponse) { assert.NoError(t, err)
assert.True(t, response.Verification.Verified) })
assert.Equal(t, "gitea@fake.local", response.Verification.Signer.Email) t.Run("MergePR", doAPIMergePullRequest(testCtx, testCtx.Username, testCtx.Reponame, pr.Index))
})) t.Run("CheckMasterBranchUnsigned", doAPIGetBranch(testCtx, "master", func(t *testing.T, branch api.Branch) {
setting.Repository.Signing.CRUDActions = []string{"parentsigned"} assert.NotNil(t, branch.Commit)
t.Run("CreateCRUDFile-Always-ParentSigned", crudActionCreateFile( assert.NotNil(t, branch.Commit.Verification)
t, testCtx, user, "always", "always-parentsigned", "signed-always-parentsigned.txt", func(t *testing.T, response api.FileResponse) { assert.True(t, branch.Commit.Verification.Verified)
assert.True(t, response.Verification.Verified)
assert.Equal(t, "gitea@fake.local", response.Verification.Signer.Email)
}))
})
t.Run("AlwaysSign-Initial", func(t *testing.T) {
PrintCurrentTest(t)
setting.Repository.Signing.InitialCommit = []string{"always"}
testCtx := NewAPITestContext(t, username, "initial-always")
t.Run("CreateRepository", doAPICreateRepository(testCtx, false))
t.Run("CheckMasterBranchSigned", doAPIGetBranch(testCtx, "master", func(t *testing.T, branch api.Branch) {
assert.NotNil(t, branch.Commit)
assert.NotNil(t, branch.Commit.Verification)
assert.True(t, branch.Commit.Verification.Verified)
assert.Equal(t, "gitea@fake.local", branch.Commit.Verification.Signer.Email)
}))
setting.Repository.Signing.CRUDActions = []string{"never"}
t.Run("CreateCRUDFile-Never", crudActionCreateFile(
t, testCtx, user, "master", "never", "unsigned-never.txt", func(t *testing.T, response api.FileResponse) {
assert.False(t, response.Verification.Verified)
}))
setting.Repository.Signing.CRUDActions = []string{"parentsigned"}
t.Run("CreateCRUDFile-ParentSigned", crudActionCreateFile(
t, testCtx, user, "master", "parentsigned", "signed-parent.txt", func(t *testing.T, response api.FileResponse) {
assert.True(t, response.Verification.Verified)
assert.Equal(t, "gitea@fake.local", response.Verification.Signer.Email)
}))
setting.Repository.Signing.CRUDActions = []string{"always"}
t.Run("CreateCRUDFile-Always", crudActionCreateFile(
t, testCtx, user, "master", "always", "signed-always.txt", func(t *testing.T, response api.FileResponse) {
assert.True(t, response.Verification.Verified)
assert.Equal(t, "gitea@fake.local", response.Verification.Signer.Email)
})) }))
})
t.Run("UnsignedMerging", func(t *testing.T) {
PrintCurrentTest(t)
testCtx := NewAPITestContext(t, username, "initial-unsigned")
var pr api.PullRequest
var err error
t.Run("CreatePullRequest", func(t *testing.T) {
pr, err = doAPICreatePullRequest(testCtx, testCtx.Username, testCtx.Reponame, "master", "never2")(t)
assert.NoError(t, err)
}) })
setting.Repository.Signing.Merges = []string{"commitssigned"} }, false)
t.Run("MergePR", doAPIMergePullRequest(testCtx, testCtx.Username, testCtx.Reponame, pr.Index))
t.Run("CheckMasterBranchUnsigned", doAPIGetBranch(testCtx, "master", func(t *testing.T, branch api.Branch) {
assert.NotNil(t, branch.Commit)
assert.NotNil(t, branch.Commit.Verification)
assert.False(t, branch.Commit.Verification.Verified)
assert.Empty(t, branch.Commit.Verification.Signature)
}))
setting.Repository.Signing.Merges = []string{"basesigned"}
t.Run("CreatePullRequest", func(t *testing.T) {
pr, err = doAPICreatePullRequest(testCtx, testCtx.Username, testCtx.Reponame, "master", "parentsigned2")(t)
assert.NoError(t, err)
})
t.Run("MergePR", doAPIMergePullRequest(testCtx, testCtx.Username, testCtx.Reponame, pr.Index))
t.Run("CheckMasterBranchUnsigned", doAPIGetBranch(testCtx, "master", func(t *testing.T, branch api.Branch) {
assert.NotNil(t, branch.Commit)
assert.NotNil(t, branch.Commit.Verification)
assert.False(t, branch.Commit.Verification.Verified)
assert.Empty(t, branch.Commit.Verification.Signature)
}))
setting.Repository.Signing.Merges = []string{"commitssigned"}
t.Run("CreatePullRequest", func(t *testing.T) {
pr, err = doAPICreatePullRequest(testCtx, testCtx.Username, testCtx.Reponame, "master", "always-parentsigned")(t)
assert.NoError(t, err)
})
t.Run("MergePR", doAPIMergePullRequest(testCtx, testCtx.Username, testCtx.Reponame, pr.Index))
t.Run("CheckMasterBranchUnsigned", doAPIGetBranch(testCtx, "master", func(t *testing.T, branch api.Branch) {
assert.NotNil(t, branch.Commit)
assert.NotNil(t, branch.Commit.Verification)
assert.True(t, branch.Commit.Verification.Verified)
}))
})
} }
func crudActionCreateFile(t *testing.T, ctx APITestContext, user *models.User, from, to, path string, callback ...func(*testing.T, api.FileResponse)) func(*testing.T) { func crudActionCreateFile(t *testing.T, ctx APITestContext, user *models.User, from, to, path string, callback ...func(*testing.T, api.FileResponse)) func(*testing.T) {

View File

@ -30,26 +30,28 @@ type ActionType int
// Possible action types. // Possible action types.
const ( const (
ActionCreateRepo ActionType = iota + 1 // 1 ActionCreateRepo ActionType = iota + 1 // 1
ActionRenameRepo // 2 ActionRenameRepo // 2
ActionStarRepo // 3 ActionStarRepo // 3
ActionWatchRepo // 4 ActionWatchRepo // 4
ActionCommitRepo // 5 ActionCommitRepo // 5
ActionCreateIssue // 6 ActionCreateIssue // 6
ActionCreatePullRequest // 7 ActionCreatePullRequest // 7
ActionTransferRepo // 8 ActionTransferRepo // 8
ActionPushTag // 9 ActionPushTag // 9
ActionCommentIssue // 10 ActionCommentIssue // 10
ActionMergePullRequest // 11 ActionMergePullRequest // 11
ActionCloseIssue // 12 ActionCloseIssue // 12
ActionReopenIssue // 13 ActionReopenIssue // 13
ActionClosePullRequest // 14 ActionClosePullRequest // 14
ActionReopenPullRequest // 15 ActionReopenPullRequest // 15
ActionDeleteTag // 16 ActionDeleteTag // 16
ActionDeleteBranch // 17 ActionDeleteBranch // 17
ActionMirrorSyncPush // 18 ActionMirrorSyncPush // 18
ActionMirrorSyncCreate // 19 ActionMirrorSyncCreate // 19
ActionMirrorSyncDelete // 20 ActionMirrorSyncDelete // 20
ActionApprovePullRequest // 21
ActionRejectPullRequest // 22
) )
// Action represents user operation type and other information to // Action represents user operation type and other information to
@ -520,52 +522,6 @@ func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit, bra
return nil return nil
} }
func transferRepoAction(e Engine, doer, oldOwner *User, repo *Repository) (err error) {
if err = notifyWatchers(e, &Action{
ActUserID: doer.ID,
ActUser: doer,
OpType: ActionTransferRepo,
RepoID: repo.ID,
Repo: repo,
IsPrivate: repo.IsPrivate,
Content: path.Join(oldOwner.Name, repo.Name),
}); err != nil {
return fmt.Errorf("notifyWatchers: %v", err)
}
// Remove watch for organization.
if oldOwner.IsOrganization() {
if err = watchRepo(e, oldOwner.ID, repo.ID, false); err != nil {
return fmt.Errorf("watchRepo [false]: %v", err)
}
}
return nil
}
// TransferRepoAction adds new action for transferring repository,
// the Owner field of repository is assumed to be new owner.
func TransferRepoAction(doer, oldOwner *User, repo *Repository) error {
return transferRepoAction(x, doer, oldOwner, repo)
}
func mergePullRequestAction(e Engine, doer *User, repo *Repository, issue *Issue) error {
return notifyWatchers(e, &Action{
ActUserID: doer.ID,
ActUser: doer,
OpType: ActionMergePullRequest,
Content: fmt.Sprintf("%d|%s", issue.Index, issue.Title),
RepoID: repo.ID,
Repo: repo,
IsPrivate: repo.IsPrivate,
})
}
// MergePullRequestAction adds new action for merging pull request.
func MergePullRequestAction(actUser *User, repo *Repository, pull *Issue) error {
return mergePullRequestAction(x, actUser, repo, pull)
}
// GetFeedsOptions options for retrieving feeds // GetFeedsOptions options for retrieving feeds
type GetFeedsOptions struct { type GetFeedsOptions struct {
RequestedUser *User RequestedUser *User

View File

@ -332,54 +332,6 @@ func TestUpdateIssuesCommit_AnotherRepoNoPermission(t *testing.T) {
CheckConsistencyFor(t, &Action{}) CheckConsistencyFor(t, &Action{})
} }
func TestTransferRepoAction(t *testing.T) {
assert.NoError(t, PrepareTestDatabase())
user2 := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
user4 := AssertExistsAndLoadBean(t, &User{ID: 4}).(*User)
repo := AssertExistsAndLoadBean(t, &Repository{ID: 1, OwnerID: user2.ID}).(*Repository)
repo.OwnerID = user4.ID
repo.Owner = user4
actionBean := &Action{
OpType: ActionTransferRepo,
ActUserID: user2.ID,
ActUser: user2,
RepoID: repo.ID,
Repo: repo,
IsPrivate: repo.IsPrivate,
}
AssertNotExistsBean(t, actionBean)
assert.NoError(t, TransferRepoAction(user2, user2, repo))
AssertExistsAndLoadBean(t, actionBean)
_, err := x.ID(repo.ID).Cols("owner_id").Update(repo)
assert.NoError(t, err)
CheckConsistencyFor(t, &Action{})
}
func TestMergePullRequestAction(t *testing.T) {
assert.NoError(t, PrepareTestDatabase())
user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
repo := AssertExistsAndLoadBean(t, &Repository{ID: 1, OwnerID: user.ID}).(*Repository)
repo.Owner = user
issue := AssertExistsAndLoadBean(t, &Issue{ID: 3, RepoID: repo.ID}).(*Issue)
actionBean := &Action{
OpType: ActionMergePullRequest,
ActUserID: user.ID,
ActUser: user,
RepoID: repo.ID,
Repo: repo,
IsPrivate: repo.IsPrivate,
}
AssertNotExistsBean(t, actionBean)
assert.NoError(t, MergePullRequestAction(user, repo, issue))
AssertExistsAndLoadBean(t, actionBean)
CheckConsistencyFor(t, &Action{})
}
func TestGetFeeds(t *testing.T) { func TestGetFeeds(t *testing.T) {
// test with an individual user // test with an individual user
assert.NoError(t, PrepareTestDatabase()) assert.NoError(t, PrepareTestDatabase())

View File

@ -539,8 +539,10 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err
return nil, err return nil, err
} }
if err = sendCreateCommentAction(e, opts, comment); err != nil { if !opts.NoAction {
return nil, err if err = sendCreateCommentAction(e, opts, comment); err != nil {
return nil, err
}
} }
if err = comment.addCrossReferences(e, opts.Doer); err != nil { if err = comment.addCrossReferences(e, opts.Doer); err != nil {
@ -816,6 +818,7 @@ type CreateCommentOptions struct {
RefCommentID int64 RefCommentID int64
RefAction references.XRefAction RefAction references.XRefAction
RefIsPull bool RefIsPull bool
NoAction bool
} }
// CreateComment creates comment of issue or commit. // CreateComment creates comment of issue or commit.

View File

@ -1,4 +1,5 @@
// Copyright 2014 The Gogs Authors. All rights reserved. // Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2019 The Gitea Authors. All rights reserved.
// 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.
@ -403,6 +404,19 @@ func LoginViaLDAP(user *User, login, password string, source *LoginSource, autoR
var isAttributeSSHPublicKeySet = len(strings.TrimSpace(source.LDAP().AttributeSSHPublicKey)) > 0 var isAttributeSSHPublicKeySet = len(strings.TrimSpace(source.LDAP().AttributeSSHPublicKey)) > 0
// Update User admin flag if exist
if isExist, err := IsUserExist(0, sr.Username); err != nil {
return nil, err
} else if isExist &&
!user.ProhibitLogin && len(source.LDAP().AdminFilter) > 0 && user.IsAdmin != sr.IsAdmin {
// Change existing admin flag only if AdminFilter option is set
user.IsAdmin = sr.IsAdmin
err = UpdateUserCols(user, "is_admin")
if err != nil {
return nil, err
}
}
if !autoRegister { if !autoRegister {
if isAttributeSSHPublicKeySet && synchronizeLdapSSHPublicKeys(user, source, sr.SSHPublicKey) { if isAttributeSSHPublicKeySet && synchronizeLdapSSHPublicKeys(user, source, sr.SSHPublicKey) {
return user, RewriteAllPublicKeys() return user, RewriteAllPublicKeys()

View File

@ -1792,8 +1792,13 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error
if err = watchRepo(sess, doer.ID, repo.ID, true); err != nil { if err = watchRepo(sess, doer.ID, repo.ID, true); err != nil {
return fmt.Errorf("watchRepo: %v", err) return fmt.Errorf("watchRepo: %v", err)
} else if err = transferRepoAction(sess, doer, owner, repo); err != nil { }
return fmt.Errorf("transferRepoAction: %v", err)
// Remove watch for organization.
if owner.IsOrganization() {
if err = watchRepo(sess, owner.ID, repo.ID, false); err != nil {
return fmt.Errorf("watchRepo [false]: %v", err)
}
} }
// Rename remote repository to new path and delete local copy. // Rename remote repository to new path and delete local copy.
@ -1824,23 +1829,21 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error
} }
// ChangeRepositoryName changes all corresponding setting from old repository name to new one. // ChangeRepositoryName changes all corresponding setting from old repository name to new one.
func ChangeRepositoryName(u *User, oldRepoName, newRepoName string) (err error) { func ChangeRepositoryName(doer *User, repo *Repository, newRepoName string) (err error) {
oldRepoName = strings.ToLower(oldRepoName)
newRepoName = strings.ToLower(newRepoName) newRepoName = strings.ToLower(newRepoName)
if err = IsUsableRepoName(newRepoName); err != nil { if err = IsUsableRepoName(newRepoName); err != nil {
return err return err
} }
has, err := IsRepositoryExist(u, newRepoName) if err := repo.GetOwner(); err != nil {
return err
}
has, err := IsRepositoryExist(repo.Owner, newRepoName)
if err != nil { if err != nil {
return fmt.Errorf("IsRepositoryExist: %v", err) return fmt.Errorf("IsRepositoryExist: %v", err)
} else if has { } else if has {
return ErrRepoAlreadyExist{u.Name, newRepoName} return ErrRepoAlreadyExist{repo.Owner.Name, newRepoName}
}
repo, err := GetRepositoryByName(u.ID, oldRepoName)
if err != nil {
return fmt.Errorf("GetRepositoryByName: %v", err)
} }
// Change repository directory name. We must lock the local copy of the // Change repository directory name. We must lock the local copy of the
@ -1849,14 +1852,14 @@ func ChangeRepositoryName(u *User, oldRepoName, newRepoName string) (err error)
repoWorkingPool.CheckIn(com.ToStr(repo.ID)) repoWorkingPool.CheckIn(com.ToStr(repo.ID))
defer repoWorkingPool.CheckOut(com.ToStr(repo.ID)) defer repoWorkingPool.CheckOut(com.ToStr(repo.ID))
newRepoPath := RepoPath(u.Name, newRepoName) newRepoPath := RepoPath(repo.Owner.Name, newRepoName)
if err = os.Rename(repo.RepoPath(), newRepoPath); err != nil { if err = os.Rename(repo.RepoPath(), newRepoPath); err != nil {
return fmt.Errorf("rename repository directory: %v", err) return fmt.Errorf("rename repository directory: %v", err)
} }
wikiPath := repo.WikiPath() wikiPath := repo.WikiPath()
if com.IsExist(wikiPath) { if com.IsExist(wikiPath) {
if err = os.Rename(wikiPath, WikiPath(u.Name, newRepoName)); err != nil { if err = os.Rename(wikiPath, WikiPath(repo.Owner.Name, newRepoName)); err != nil {
return fmt.Errorf("rename repository wiki: %v", err) return fmt.Errorf("rename repository wiki: %v", err)
} }
} }
@ -1868,7 +1871,7 @@ func ChangeRepositoryName(u *User, oldRepoName, newRepoName string) (err error)
} }
// If there was previously a redirect at this location, remove it. // If there was previously a redirect at this location, remove it.
if err = deleteRepoRedirect(sess, u.ID, newRepoName); err != nil { if err = deleteRepoRedirect(sess, repo.OwnerID, newRepoName); err != nil {
return fmt.Errorf("delete repo redirect: %v", err) return fmt.Errorf("delete repo redirect: %v", err)
} }

View File

@ -15,7 +15,6 @@ import (
"code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/unknwon/com"
) )
func TestRepo(t *testing.T) { func TestRepo(t *testing.T) {
@ -142,29 +141,6 @@ func TestRepoAPIURL(t *testing.T) {
assert.Equal(t, "https://try.gitea.io/api/v1/repos/user12/repo10", repo.APIURL()) assert.Equal(t, "https://try.gitea.io/api/v1/repos/user12/repo10", repo.APIURL())
} }
func TestTransferOwnership(t *testing.T) {
assert.NoError(t, PrepareTestDatabase())
doer := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
repo := AssertExistsAndLoadBean(t, &Repository{ID: 3}).(*Repository)
repo.Owner = AssertExistsAndLoadBean(t, &User{ID: repo.OwnerID}).(*User)
assert.NoError(t, TransferOwnership(doer, "user2", repo))
transferredRepo := AssertExistsAndLoadBean(t, &Repository{ID: 3}).(*Repository)
assert.EqualValues(t, 2, transferredRepo.OwnerID)
assert.False(t, com.IsExist(RepoPath("user3", "repo3")))
assert.True(t, com.IsExist(RepoPath("user2", "repo3")))
AssertExistsAndLoadBean(t, &Action{
OpType: ActionTransferRepo,
ActUserID: 2,
RepoID: 3,
Content: "user3/repo3",
})
CheckConsistencyFor(t, &Repository{}, &User{}, &Team{})
}
func TestUploadAvatar(t *testing.T) { func TestUploadAvatar(t *testing.T) {
// Generate image // Generate image

View File

@ -216,6 +216,21 @@ func NotifyWatchers(act *Action) error {
return notifyWatchers(x, act) return notifyWatchers(x, act)
} }
// NotifyWatchersActions creates batch of actions for every watcher.
func NotifyWatchersActions(acts []*Action) error {
sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
return err
}
for _, act := range acts {
if err := notifyWatchers(sess, act); err != nil {
return err
}
}
return sess.Commit()
}
func watchIfAuto(e Engine, userID, repoID int64, isWrite bool) error { func watchIfAuto(e Engine, userID, repoID int64, isWrite bool) error {
if !isWrite || !setting.Service.AutoWatchOnChanges { if !isWrite || !setting.Service.AutoWatchOnChanges {
return nil return nil

View File

@ -5,14 +5,12 @@
package models package models
import ( import (
"fmt" "strings"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/timeutil"
"xorm.io/builder" "xorm.io/builder"
"xorm.io/core" "xorm.io/core"
"xorm.io/xorm"
) )
// ReviewType defines the sort of feedback a review gives // ReviewType defines the sort of feedback a review gives
@ -86,6 +84,11 @@ func (r *Review) loadReviewer(e Engine) (err error) {
return return
} }
// LoadReviewer loads reviewer
func (r *Review) LoadReviewer() error {
return r.loadReviewer(x)
}
func (r *Review) loadAttributes(e Engine) (err error) { func (r *Review) loadAttributes(e Engine) (err error) {
if err = r.loadReviewer(e); err != nil { if err = r.loadReviewer(e); err != nil {
return return
@ -101,54 +104,6 @@ func (r *Review) LoadAttributes() error {
return r.loadAttributes(x) return r.loadAttributes(x)
} }
// Publish will send notifications / actions to participants for all code comments; parts are concurrent
func (r *Review) Publish() error {
return r.publish(x)
}
func (r *Review) publish(e *xorm.Engine) error {
if r.Type == ReviewTypePending || r.Type == ReviewTypeUnknown {
return fmt.Errorf("review cannot be published if type is pending or unknown")
}
if r.Issue == nil {
if err := r.loadIssue(e); err != nil {
return err
}
}
if err := r.Issue.loadRepo(e); err != nil {
return err
}
if len(r.CodeComments) == 0 {
if err := r.loadCodeComments(e); err != nil {
return err
}
}
for _, lines := range r.CodeComments {
for _, comments := range lines {
for _, comment := range comments {
go func(en *xorm.Engine, review *Review, comm *Comment) {
sess := en.NewSession()
defer sess.Close()
opts := &CreateCommentOptions{
Doer: comm.Poster,
Issue: review.Issue,
Repo: review.Issue.Repo,
Type: comm.Type,
Content: comm.Content,
}
if err := updateCommentInfos(sess, opts, comm); err != nil {
log.Warn("updateCommentInfos: %v", err)
}
if err := sendCreateCommentAction(sess, opts, comm); err != nil {
log.Warn("sendCreateCommentAction: %v", err)
}
}(e, r, comment)
}
}
}
return nil
}
func getReviewByID(e Engine, id int64) (*Review, error) { func getReviewByID(e Engine, id int64) (*Review, error) {
review := new(Review) review := new(Review)
if has, err := e.ID(id).Get(review); err != nil { if has, err := e.ID(id).Get(review); err != nil {
@ -271,12 +226,79 @@ func GetCurrentReview(reviewer *User, issue *Issue) (*Review, error) {
return getCurrentReview(x, reviewer, issue) return getCurrentReview(x, reviewer, issue)
} }
// UpdateReview will update all cols of the given review in db // ContentEmptyErr represents an content empty error
func UpdateReview(r *Review) error { type ContentEmptyErr struct {
if _, err := x.ID(r.ID).AllCols().Update(r); err != nil { }
return err
func (ContentEmptyErr) Error() string {
return "Review content is empty"
}
// IsContentEmptyErr returns true if err is a ContentEmptyErr
func IsContentEmptyErr(err error) bool {
_, ok := err.(ContentEmptyErr)
return ok
}
// SubmitReview creates a review out of the existing pending review or creates a new one if no pending review exist
func SubmitReview(doer *User, issue *Issue, reviewType ReviewType, content string) (*Review, *Comment, error) {
sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
return nil, nil, err
} }
return nil
review, err := getCurrentReview(sess, doer, issue)
if err != nil {
if !IsErrReviewNotExist(err) {
return nil, nil, err
}
if reviewType != ReviewTypeApprove && len(strings.TrimSpace(content)) == 0 {
return nil, nil, ContentEmptyErr{}
}
// No current review. Create a new one!
review, err = createReview(sess, CreateReviewOptions{
Type: reviewType,
Issue: issue,
Reviewer: doer,
Content: content,
})
if err != nil {
return nil, nil, err
}
} else {
if err := review.loadCodeComments(sess); err != nil {
return nil, nil, err
}
if reviewType != ReviewTypeApprove && len(review.CodeComments) == 0 && len(strings.TrimSpace(content)) == 0 {
return nil, nil, ContentEmptyErr{}
}
review.Issue = issue
review.Content = content
review.Type = reviewType
if _, err := sess.ID(review.ID).Cols("content, type").Update(review); err != nil {
return nil, nil, err
}
}
comm, err := createComment(sess, &CreateCommentOptions{
Type: CommentTypeReview,
Doer: doer,
Content: review.Content,
Issue: issue,
Repo: issue.Repo,
ReviewID: review.ID,
NoAction: true,
})
if err != nil || comm == nil {
return nil, nil, err
}
comm.Review = review
return review, comm, sess.Commit()
} }
// PullReviewersWithType represents the type used to display a review overview // PullReviewersWithType represents the type used to display a review overview

View File

@ -98,14 +98,6 @@ func TestCreateReview(t *testing.T) {
AssertExistsAndLoadBean(t, &Review{Content: "New Review"}) AssertExistsAndLoadBean(t, &Review{Content: "New Review"})
} }
func TestUpdateReview(t *testing.T) {
assert.NoError(t, PrepareTestDatabase())
review := AssertExistsAndLoadBean(t, &Review{ID: 1}).(*Review)
review.Content = "Updated Review"
assert.NoError(t, UpdateReview(review))
AssertExistsAndLoadBean(t, &Review{ID: 1, Content: "Updated Review"})
}
func TestGetReviewersByPullID(t *testing.T) { func TestGetReviewersByPullID(t *testing.T) {
assert.NoError(t, PrepareTestDatabase()) assert.NoError(t, PrepareTestDatabase())

View File

@ -6,6 +6,7 @@
package git package git
import ( import (
"bytes"
"encoding/base64" "encoding/base64"
"io" "io"
"io/ioutil" "io/ioutil"
@ -50,6 +51,28 @@ func (b *Blob) GetBlobContent() (string, error) {
return string(buf), nil return string(buf), nil
} }
// GetBlobLineCount gets line count of lob as raw text
func (b *Blob) GetBlobLineCount() (int, error) {
reader, err := b.DataAsync()
if err != nil {
return 0, err
}
defer reader.Close()
buf := make([]byte, 32*1024)
count := 0
lineSep := []byte{'\n'}
for {
c, err := reader.Read(buf)
count += bytes.Count(buf[:c], lineSep)
switch {
case err == io.EOF:
return count, nil
case err != nil:
return count, err
}
}
}
// GetBlobContentBase64 Reads the content of the blob with a base64 encode and returns the encoded string // GetBlobContentBase64 Reads the content of the blob with a base64 encode and returns the encoded string
func (b *Blob) GetBlobContentBase64() (string, error) { func (b *Blob) GetBlobContentBase64() (string, error) {
dataRc, err := b.DataAsync() dataRc, err := b.DataAsync()

View File

@ -6,6 +6,8 @@ package action
import ( import (
"fmt" "fmt"
"path"
"strings"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
@ -76,7 +78,9 @@ func (a *actionNotifier) NotifyNewPullRequest(pull *models.PullRequest) {
} }
} }
func (a *actionNotifier) NotifyRenameRepository(doer *models.User, repo *models.Repository, oldName string) { func (a *actionNotifier) NotifyRenameRepository(doer *models.User, repo *models.Repository, oldRepoName string) {
log.Trace("action.ChangeRepositoryName: %s/%s", doer.Name, repo.Name)
if err := models.NotifyWatchers(&models.Action{ if err := models.NotifyWatchers(&models.Action{
ActUserID: doer.ID, ActUserID: doer.ID,
ActUser: doer, ActUser: doer,
@ -84,11 +88,23 @@ func (a *actionNotifier) NotifyRenameRepository(doer *models.User, repo *models.
RepoID: repo.ID, RepoID: repo.ID,
Repo: repo, Repo: repo,
IsPrivate: repo.IsPrivate, IsPrivate: repo.IsPrivate,
Content: oldName, Content: oldRepoName,
}); err != nil { }); err != nil {
log.Error("notify watchers: %v", err) log.Error("NotifyWatchers: %v", err)
} else { }
log.Trace("action.renameRepoAction: %s/%s", doer.Name, repo.Name) }
func (a *actionNotifier) NotifyTransferRepository(doer *models.User, repo *models.Repository, oldOwnerName string) {
if err := models.NotifyWatchers(&models.Action{
ActUserID: doer.ID,
ActUser: doer,
OpType: models.ActionTransferRepo,
RepoID: repo.ID,
Repo: repo,
IsPrivate: repo.IsPrivate,
Content: path.Join(oldOwnerName, repo.Name),
}); err != nil {
log.Error("NotifyWatchers: %v", err)
} }
} }
@ -117,3 +133,61 @@ func (a *actionNotifier) NotifyForkRepository(doer *models.User, oldRepo, repo *
log.Error("notify watchers '%d/%d': %v", doer.ID, repo.ID, err) log.Error("notify watchers '%d/%d': %v", doer.ID, repo.ID, err)
} }
} }
func (a *actionNotifier) NotifyPullRequestReview(pr *models.PullRequest, review *models.Review, comment *models.Comment) {
if err := review.LoadReviewer(); err != nil {
log.Error("LoadReviewer '%d/%d': %v", review.ID, review.ReviewerID, err)
return
}
if err := review.LoadCodeComments(); err != nil {
log.Error("LoadCodeComments '%d/%d': %v", review.Reviewer.ID, review.ID, err)
return
}
var actions = make([]*models.Action, 0, 10)
for _, lines := range review.CodeComments {
for _, comments := range lines {
for _, comm := range comments {
actions = append(actions, &models.Action{
ActUserID: review.Reviewer.ID,
ActUser: review.Reviewer,
Content: fmt.Sprintf("%d|%s", review.Issue.Index, strings.Split(comm.Content, "\n")[0]),
OpType: models.ActionCommentIssue,
RepoID: review.Issue.RepoID,
Repo: review.Issue.Repo,
IsPrivate: review.Issue.Repo.IsPrivate,
Comment: comm,
CommentID: comm.ID,
})
}
}
}
if review.Type != models.ReviewTypeComment || strings.TrimSpace(comment.Content) != "" {
action := &models.Action{
ActUserID: review.Reviewer.ID,
ActUser: review.Reviewer,
Content: fmt.Sprintf("%d|%s", review.Issue.Index, strings.Split(comment.Content, "\n")[0]),
RepoID: review.Issue.RepoID,
Repo: review.Issue.Repo,
IsPrivate: review.Issue.Repo.IsPrivate,
Comment: comment,
CommentID: comment.ID,
}
switch review.Type {
case models.ReviewTypeApprove:
action.OpType = models.ActionApprovePullRequest
case models.ReviewTypeReject:
action.OpType = models.ActionRejectPullRequest
default:
action.OpType = models.ActionCommentIssue
}
actions = append(actions, action)
}
if err := models.NotifyWatchersActions(actions); err != nil {
log.Error("notify watchers '%d/%d': %v", review.Reviewer.ID, review.Issue.RepoID, err)
}
}

View File

@ -17,7 +17,8 @@ type Notifier interface {
NotifyMigrateRepository(doer *models.User, u *models.User, repo *models.Repository) NotifyMigrateRepository(doer *models.User, u *models.User, repo *models.Repository)
NotifyDeleteRepository(doer *models.User, repo *models.Repository) NotifyDeleteRepository(doer *models.User, repo *models.Repository)
NotifyForkRepository(doer *models.User, oldRepo, repo *models.Repository) NotifyForkRepository(doer *models.User, oldRepo, repo *models.Repository)
NotifyRenameRepository(doer *models.User, repo *models.Repository, oldName string) NotifyRenameRepository(doer *models.User, repo *models.Repository, oldRepoName string)
NotifyTransferRepository(doer *models.User, repo *models.Repository, oldOwnerName string)
NotifyNewIssue(*models.Issue) NotifyNewIssue(*models.Issue)
NotifyIssueChangeStatus(*models.User, *models.Issue, bool) NotifyIssueChangeStatus(*models.User, *models.Issue, bool)

View File

@ -58,18 +58,6 @@ func (*NullNotifier) NotifyUpdateComment(doer *models.User, c *models.Comment, o
func (*NullNotifier) NotifyDeleteComment(doer *models.User, c *models.Comment) { func (*NullNotifier) NotifyDeleteComment(doer *models.User, c *models.Comment) {
} }
// NotifyDeleteRepository places a place holder function
func (*NullNotifier) NotifyDeleteRepository(doer *models.User, repo *models.Repository) {
}
// NotifyForkRepository places a place holder function
func (*NullNotifier) NotifyForkRepository(doer *models.User, oldRepo, repo *models.Repository) {
}
// NotifyRenameRepository places a place holder function
func (*NullNotifier) NotifyRenameRepository(doer *models.User, repo *models.Repository, oldName string) {
}
// NotifyNewRelease places a place holder function // NotifyNewRelease places a place holder function
func (*NullNotifier) NotifyNewRelease(rel *models.Release) { func (*NullNotifier) NotifyNewRelease(rel *models.Release) {
} }
@ -111,6 +99,14 @@ func (*NullNotifier) NotifyIssueChangeLabels(doer *models.User, issue *models.Is
func (*NullNotifier) NotifyCreateRepository(doer *models.User, u *models.User, repo *models.Repository) { func (*NullNotifier) NotifyCreateRepository(doer *models.User, u *models.User, repo *models.Repository) {
} }
// NotifyDeleteRepository places a place holder function
func (*NullNotifier) NotifyDeleteRepository(doer *models.User, repo *models.Repository) {
}
// NotifyForkRepository places a place holder function
func (*NullNotifier) NotifyForkRepository(doer *models.User, oldRepo, repo *models.Repository) {
}
// 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) {
} }
@ -126,3 +122,11 @@ func (*NullNotifier) NotifyCreateRef(doer *models.User, repo *models.Repository,
// NotifyDeleteRef notifies branch or tag deleteion to notifiers // NotifyDeleteRef notifies branch or tag deleteion to notifiers
func (*NullNotifier) NotifyDeleteRef(doer *models.User, repo *models.Repository, refType, refFullName string) { func (*NullNotifier) NotifyDeleteRef(doer *models.User, repo *models.Repository, refType, refFullName string) {
} }
// NotifyRenameRepository places a place holder function
func (*NullNotifier) NotifyRenameRepository(doer *models.User, repo *models.Repository, oldRepoName string) {
}
// NotifyTransferRepository places a place holder function
func (*NullNotifier) NotifyTransferRepository(doer *models.User, repo *models.Repository, oldOwnerName string) {
}

View File

@ -101,27 +101,6 @@ func NotifyDeleteComment(doer *models.User, c *models.Comment) {
} }
} }
// NotifyDeleteRepository notifies delete repository to notifiers
func NotifyDeleteRepository(doer *models.User, repo *models.Repository) {
for _, notifier := range notifiers {
notifier.NotifyDeleteRepository(doer, repo)
}
}
// NotifyForkRepository notifies fork repository to notifiers
func NotifyForkRepository(doer *models.User, oldRepo, repo *models.Repository) {
for _, notifier := range notifiers {
notifier.NotifyForkRepository(doer, oldRepo, repo)
}
}
// NotifyRenameRepository notifies repository renamed
func NotifyRenameRepository(doer *models.User, repo *models.Repository, oldName string) {
for _, notifier := range notifiers {
notifier.NotifyRenameRepository(doer, repo, oldName)
}
}
// NotifyNewRelease notifies new release to notifiers // NotifyNewRelease notifies new release to notifiers
func NotifyNewRelease(rel *models.Release) { func NotifyNewRelease(rel *models.Release) {
for _, notifier := range notifiers { for _, notifier := range notifiers {
@ -200,6 +179,34 @@ func NotifyMigrateRepository(doer *models.User, u *models.User, repo *models.Rep
} }
} }
// NotifyTransferRepository notifies create repository to notifiers
func NotifyTransferRepository(doer *models.User, repo *models.Repository, newOwnerName string) {
for _, notifier := range notifiers {
notifier.NotifyTransferRepository(doer, repo, newOwnerName)
}
}
// NotifyDeleteRepository notifies delete repository to notifiers
func NotifyDeleteRepository(doer *models.User, repo *models.Repository) {
for _, notifier := range notifiers {
notifier.NotifyDeleteRepository(doer, repo)
}
}
// NotifyForkRepository notifies fork repository to notifiers
func NotifyForkRepository(doer *models.User, oldRepo, repo *models.Repository) {
for _, notifier := range notifiers {
notifier.NotifyForkRepository(doer, oldRepo, repo)
}
}
// NotifyRenameRepository notifies repository renamed
func NotifyRenameRepository(doer *models.User, repo *models.Repository, oldName string) {
for _, notifier := range notifiers {
notifier.NotifyRenameRepository(doer, repo, oldName)
}
}
// NotifyPushCommits notifies commits pushed to notifiers // NotifyPushCommits notifies commits pushed to notifiers
func NotifyPushCommits(pusher *models.User, repo *models.Repository, refName, oldCommitID, newCommitID string, commits *models.PushCommits) { func NotifyPushCommits(pusher *models.User, repo *models.Repository, refName, oldCommitID, newCommitID string, commits *models.PushCommits) {
for _, notifier := range notifiers { for _, notifier := range notifiers {

View File

@ -55,6 +55,15 @@ func TestGetDiffPreview(t *testing.T) {
Type: 4, Type: 4,
Content: "@@ -1,3 +1,4 @@", Content: "@@ -1,3 +1,4 @@",
Comments: nil, Comments: nil,
SectionInfo: &gitdiff.DiffLineSectionInfo{
Path: "README.md",
LastLeftIdx: 0,
LastRightIdx: 0,
LeftIdx: 1,
RightIdx: 1,
LeftHunkSize: 3,
RightHunkSize: 4,
},
}, },
{ {
LeftIdx: 1, LeftIdx: 1,

View File

@ -140,18 +140,19 @@ var (
} }
// Security settings // Security settings
InstallLock bool InstallLock bool
SecretKey string SecretKey string
LogInRememberDays int LogInRememberDays int
CookieUserName string CookieUserName string
CookieRememberName string CookieRememberName string
ReverseProxyAuthUser string ReverseProxyAuthUser string
ReverseProxyAuthEmail string ReverseProxyAuthEmail string
MinPasswordLength int MinPasswordLength int
ImportLocalPaths bool ImportLocalPaths bool
DisableGitHooks bool DisableGitHooks bool
PasswordComplexity []string OnlyAllowPushIfGiteaEnvironmentSet bool
PasswordHashAlgo string PasswordComplexity []string
PasswordHashAlgo string
// UI settings // UI settings
UI = struct { UI = struct {
@ -778,6 +779,7 @@ func NewContext() {
MinPasswordLength = sec.Key("MIN_PASSWORD_LENGTH").MustInt(6) MinPasswordLength = sec.Key("MIN_PASSWORD_LENGTH").MustInt(6)
ImportLocalPaths = sec.Key("IMPORT_LOCAL_PATHS").MustBool(false) ImportLocalPaths = sec.Key("IMPORT_LOCAL_PATHS").MustBool(false)
DisableGitHooks = sec.Key("DISABLE_GIT_HOOKS").MustBool(false) DisableGitHooks = sec.Key("DISABLE_GIT_HOOKS").MustBool(false)
OnlyAllowPushIfGiteaEnvironmentSet = sec.Key("ONLY_ALLOW_PUSH_IF_GITEA_ENVIRONMENT_SET").MustBool(true)
PasswordHashAlgo = sec.Key("PASSWORD_HASH_ALGO").MustString("pbkdf2") PasswordHashAlgo = sec.Key("PASSWORD_HASH_ALGO").MustString("pbkdf2")
CSRFCookieHTTPOnly = sec.Key("CSRF_COOKIE_HTTP_ONLY").MustBool(true) CSRFCookieHTTPOnly = sec.Key("CSRF_COOKIE_HTTP_ONLY").MustBool(true)

View File

@ -555,6 +555,10 @@ func ActionIcon(opType models.ActionType) string {
return "issue-reopened" return "issue-reopened"
case models.ActionMirrorSyncPush, models.ActionMirrorSyncCreate, models.ActionMirrorSyncDelete: case models.ActionMirrorSyncPush, models.ActionMirrorSyncCreate, models.ActionMirrorSyncDelete:
return "repo-clone" return "repo-clone"
case models.ActionApprovePullRequest:
return "eye"
case models.ActionRejectPullRequest:
return "x"
default: default:
return "invalid type" return "invalid type"
} }

View File

@ -2000,6 +2000,8 @@ compare_commits_general = Compare commits
mirror_sync_push = synced commits to <a href="%[1]s/src/%[2]s">%[3]s</a> at <a href="%[1]s">%[4]s</a> from mirror mirror_sync_push = synced commits to <a href="%[1]s/src/%[2]s">%[3]s</a> at <a href="%[1]s">%[4]s</a> from mirror
mirror_sync_create = synced new reference <a href="%s/src/%s">%[2]s</a> to <a href="%[1]s">%[3]s</a> from mirror mirror_sync_create = synced new reference <a href="%s/src/%s">%[2]s</a> to <a href="%[1]s">%[3]s</a> from mirror
mirror_sync_delete = synced and deleted reference <code>%[2]s</code> at <a href="%[1]s">%[3]s</a> from mirror mirror_sync_delete = synced and deleted reference <code>%[2]s</code> at <a href="%[1]s">%[3]s</a> from mirror
approve_pull_request = `approved <a href="%s/pulls/%s">%s#%[2]s</a>`
reject_pull_request = `suggested changes for <a href="%s/pulls/%s">%s#%[2]s</a>`
[tool] [tool]
ago = %s ago ago = %s ago

View File

@ -581,6 +581,7 @@ email_notifications.submit=Atualizar preferências de e-mail
owner=Proprietário owner=Proprietário
repo_name=Nome do repositório repo_name=Nome do repositório
repo_name_helper=Um bom nome de repositório é composto por palavras curtas, memorizáveis e únicas. repo_name_helper=Um bom nome de repositório é composto por palavras curtas, memorizáveis e únicas.
repo_size=Tamanho do repositório
template=Modelo template=Modelo
template_select=Selecione um modelo. template_select=Selecione um modelo.
template_helper=Tornar repositório um modelo template_helper=Tornar repositório um modelo
@ -1711,6 +1712,7 @@ users.auth_login_name=Nome de acesso da autenticação
users.password_helper=Deixe a senha em branco para mantê-la inalterada. users.password_helper=Deixe a senha em branco para mantê-la inalterada.
users.update_profile_success=A conta de usuário foi atualizada. users.update_profile_success=A conta de usuário foi atualizada.
users.edit_account=Editar a conta de usuário users.edit_account=Editar a conta de usuário
users.max_repo_creation=Número máximo de repositórios
users.max_repo_creation_desc=(Use -1 para usar o limite padrão global.) users.max_repo_creation_desc=(Use -1 para usar o limite padrão global.)
users.is_activated=Conta de usuário está ativada users.is_activated=Conta de usuário está ativada
users.prohibit_login=Desabilitar acesso users.prohibit_login=Desabilitar acesso

View File

@ -68,6 +68,10 @@ pull_requests=合并请求
issues=工单管理 issues=工单管理
cancel=取消 cancel=取消
add=添加
add_all=添加所有
remove=移除
remove_all=移除所有
write=撰写 write=撰写
preview=预览 preview=预览
@ -577,6 +581,11 @@ email_notifications.submit=邮件通知设置
owner=拥有者 owner=拥有者
repo_name=仓库名称 repo_name=仓库名称
repo_name_helper=好的存储库名称使用简短、深刻和独特的关键字。 repo_name_helper=好的存储库名称使用简短、深刻和独特的关键字。
repo_size=仓库大小
template=模板
template_select=选择模板
template_helper=设置仓库为模板仓库
template_description=模板仓库让用户通过拷贝目录结构,文件和可选设置来生成仓库。
visibility=可见性 visibility=可见性
visibility_description=只有组织所有人或拥有权利的组织成员才能看到。 visibility_description=只有组织所有人或拥有权利的组织成员才能看到。
visibility_helper=将仓库设为私有 visibility_helper=将仓库设为私有
@ -586,6 +595,9 @@ clone_helper=不知道如何克隆?查看<a target="_blank" rel="noopener nore
fork_repo=派生仓库 fork_repo=派生仓库
fork_from=派生自 fork_from=派生自
fork_visibility_helper=无法更改派生仓库的可见性。 fork_visibility_helper=无法更改派生仓库的可见性。
use_template=使用此模板
generate_repo=生成仓库
generate_from=生成自
repo_desc=仓库描述 repo_desc=仓库描述
repo_lang=仓库语言 repo_lang=仓库语言
repo_gitignore_helper=选择 .gitignore 模板。 repo_gitignore_helper=选择 .gitignore 模板。
@ -613,6 +625,11 @@ forks=派生仓库
pick_reaction=选择你的表情 pick_reaction=选择你的表情
reactions_more=再加载 %d reactions_more=再加载 %d
template.items=模板选项
template.git_content=Git数据(默认分支)
template.topics=主题
template.one_item=必须至少选择一个模板项
template.invalid=必须选择一个模板仓库
archive.title=此仓库已存档。您可以查看文件和克隆,但不能推送或创建工单/合并请求。 archive.title=此仓库已存档。您可以查看文件和克隆,但不能推送或创建工单/合并请求。
archive.issue.nocomment=此仓库已存档,您不能在此工单添加评论。 archive.issue.nocomment=此仓库已存档,您不能在此工单添加评论。
@ -648,6 +665,7 @@ migrate.migrating_failed=从 <b>%s</b> 迁移失败。
mirror_from=镜像自地址 mirror_from=镜像自地址
forked_from=派生自 forked_from=派生自
generated_from=生成自
fork_from_self=无法派生已经拥有的仓库! fork_from_self=无法派生已经拥有的仓库!
fork_guest_user=登录并 派生 这个仓库。 fork_guest_user=登录并 派生 这个仓库。
copy_link=复制链接 copy_link=复制链接
@ -742,6 +760,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=文件%s被 %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'。
@ -1021,6 +1040,10 @@ pulls.rebase_merge_pull_request=变基并合并
pulls.rebase_merge_commit_pull_request=变基合并 (--no-ff) pulls.rebase_merge_commit_pull_request=变基合并 (--no-ff)
pulls.squash_merge_pull_request=压缩提交并合并 pulls.squash_merge_pull_request=压缩提交并合并
pulls.invalid_merge_option=你可以在此合并请求中使用合并选项。 pulls.invalid_merge_option=你可以在此合并请求中使用合并选项。
pulls.merge_conflict=合并失败:合并时发生冲突:%[1]s<br>[2]<br> 提示:尝试不同的合并策略
pulls.rebase_conflict=合并失败Rebase合并时发生冲突%[1]s<br>[2]<br> 提示:尝试不同的合并策略
pulls.unrelated_histories=合并失败:两个分支没有共同历史。提示:尝试不同的策略
pulls.merge_out_of_date=合并失败:在生成合并时,主分支已更新。提示:再试一次。
pulls.open_unmerged_pull_exists=`您不能执行重新打开操作, 因为已经存在相同的合并请求 (#%d)。` pulls.open_unmerged_pull_exists=`您不能执行重新打开操作, 因为已经存在相同的合并请求 (#%d)。`
pulls.status_checking=一些检测仍在等待运行 pulls.status_checking=一些检测仍在等待运行
pulls.status_checks_success=所有检测均成功 pulls.status_checks_success=所有检测均成功
@ -1089,6 +1112,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> 合并请求
@ -1511,6 +1537,7 @@ team_name=团队名称
team_desc=团队描述 team_desc=团队描述
team_name_helper=团队名字应该简单明了。 team_name_helper=团队名字应该简单明了。
team_desc_helper=描述团队的目的或作用。 team_desc_helper=描述团队的目的或作用。
team_access_desc=仓库权限
team_permission_desc=权限 team_permission_desc=权限
team_unit_desc=允许访问仓库单元 team_unit_desc=允许访问仓库单元
@ -1578,10 +1605,21 @@ teams.write_permission_desc=该团队拥有对所属仓库的 <strong>读取</st
teams.admin_permission_desc=该团队拥有一定的 <strong>管理</strong> 权限,团队成员可以读取、克隆、推送以及添加其它仓库协作者。 teams.admin_permission_desc=该团队拥有一定的 <strong>管理</strong> 权限,团队成员可以读取、克隆、推送以及添加其它仓库协作者。
teams.repositories=团队仓库 teams.repositories=团队仓库
teams.search_repo_placeholder=搜索仓库... teams.search_repo_placeholder=搜索仓库...
teams.remove_all_repos_title=移除所有团队仓库
teams.remove_all_repos_desc=这将从团队中移除所有仓库。
teams.add_all_repos_title=添加所有仓库
teams.add_all_repos_desc=这将把组织的所有仓库添加到团队。
teams.add_nonexistent_repo=您尝试添加到团队的仓库不存在,请先创建仓库! teams.add_nonexistent_repo=您尝试添加到团队的仓库不存在,请先创建仓库!
teams.add_duplicate_users=用户已经是团队成员。 teams.add_duplicate_users=用户已经是团队成员。
teams.repos.none=此团队无法访问任何仓库。 teams.repos.none=此团队无法访问任何仓库。
teams.members.none=团队中没有成员。 teams.members.none=团队中没有成员。
teams.specific_repositories=指定仓库
teams.specific_repositories_helper=团队成员将只能访问添加到团队的仓库。 选择此项 <strong>将不会</strong> 自动删除已经添加的仓库。
teams.all_repositories=所有仓库
teams.all_repositories_helper=团队可以访问所有仓库。选择此选项将 <strong>添加所有现有的</strong> 仓库到指定团队。
teams.all_repositories_read_permission_desc=此团队授予<strong>读取</strong><strong>所有仓库</strong>的访问权限: 成员可以查看和克隆仓库。
teams.all_repositories_write_permission_desc=此团队授予<strong>修改</strong><strong>所有仓库</strong>的访问权限: 成员可以查看和推送至仓库。
teams.all_repositories_admin_permission_desc=该团队拥有 <strong>管理</strong> <strong>所有仓库</strong>的权限:团队成员可以读取、克隆、推送以及添加其它仓库协作者。
[admin] [admin]
dashboard=管理面板 dashboard=管理面板
@ -1674,6 +1712,7 @@ users.auth_login_name=认证登录名称
users.password_helper=保持密码为空将不更改密码。 users.password_helper=保持密码为空将不更改密码。
users.update_profile_success=该帐户已被更新。 users.update_profile_success=该帐户已被更新。
users.edit_account=编辑帐号 users.edit_account=编辑帐号
users.max_repo_creation=最大仓库数
users.max_repo_creation_desc=(设置为 -1 表示使用全局默认值) users.max_repo_creation_desc=(设置为 -1 表示使用全局默认值)
users.is_activated=该用户已被激活 users.is_activated=该用户已被激活
users.prohibit_login=禁用登录 users.prohibit_login=禁用登录

3443
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -5,14 +5,23 @@
"node": ">=8" "node": ">=8"
}, },
"devDependencies": { "devDependencies": {
"autoprefixer": "9.6.1", "@babel/core": "7.7.2",
"eslint": "6.3.0", "@babel/preset-env": "7.7.1",
"autoprefixer": "9.7.1",
"babel-loader": "8.0.6",
"core-js": "3.4.1",
"eslint": "6.6.0",
"eslint-config-airbnb-base": "14.0.0",
"eslint-plugin-import": "2.18.2",
"less": "3.10.3", "less": "3.10.3",
"less-plugin-clean-css": "1.5.1", "less-plugin-clean-css": "1.5.1",
"postcss-cli": "6.1.3", "postcss-cli": "6.1.3",
"stylelint": "10.1.0", "stylelint": "11.1.1",
"stylelint-config-standard": "18.3.0", "stylelint-config-standard": "19.0.0",
"updates": "8.5.3" "terser-webpack-plugin": "2.2.1",
"updates": "9.0.1",
"webpack": "4.41.2",
"webpack-cli": "3.3.10"
}, },
"browserslist": [ "browserslist": [
"> 1%", "> 1%",

View File

@ -73,7 +73,7 @@ a{cursor:pointer}
.right.stackable.menu{margin-left:auto;display:flex;align-items:inherit;flex-direction:inherit} .right.stackable.menu{margin-left:auto;display:flex;align-items:inherit;flex-direction:inherit}
.ui.left{float:left} .ui.left{float:left}
.ui.right{float:right} .ui.right{float:right}
.ui.button,.ui.menu .item{-webkit-user-select:auto;-moz-user-select:auto;-ms-user-select:auto;user-select:auto} .ui.button,.ui.menu .item{-webkit-user-select:auto;-ms-user-select:auto;user-select:auto}
.ui.container.fluid.padded{padding:0 10px 0 10px} .ui.container.fluid.padded{padding:0 10px 0 10px}
.ui.form .ui.button{font-weight:400} .ui.form .ui.button{font-weight:400}
.ui.floating.label{z-index:10} .ui.floating.label{z-index:10}
@ -233,14 +233,14 @@ i.icons .icon:first-child{margin-right:0}
i.icon.centerlock{top:1.5em} i.icon.centerlock{top:1.5em}
.ui.label>.detail .icons{margin-right:.25em} .ui.label>.detail .icons{margin-right:.25em}
.ui.label>.detail .icons .icon{margin-right:0} .ui.label>.detail .icons .icon{margin-right:0}
.lines-num{vertical-align:top;text-align:right!important;color:#999;background:#f5f5f5;width:1%;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none} .lines-num{vertical-align:top;text-align:right!important;color:#999;background:#f5f5f5;width:1%;-webkit-user-select:none;-ms-user-select:none;user-select:none}
.lines-num span:before{content:attr(data-line-number);line-height:20px!important;padding:0 10px;cursor:pointer;display:block} .lines-num span:before{content:attr(data-line-number);line-height:20px!important;padding:0 10px;cursor:pointer;display:block}
.lines-code,.lines-num{padding:0!important} .lines-code,.lines-num{padding:0!important}
.lines-code .hljs,.lines-code ol,.lines-code pre,.lines-num .hljs,.lines-num ol,.lines-num pre{background-color:#fff;margin:0;padding:0!important} .lines-code .hljs,.lines-code ol,.lines-code pre,.lines-num .hljs,.lines-num ol,.lines-num pre{background-color:#fff;margin:0;padding:0!important}
.lines-code .hljs li,.lines-code ol li,.lines-code pre li,.lines-num .hljs li,.lines-num ol li,.lines-num pre li{display:block;width:100%} .lines-code .hljs li,.lines-code ol li,.lines-code pre li,.lines-num .hljs li,.lines-num ol li,.lines-num pre li{display:block;width:100%}
.lines-code .hljs li:before,.lines-code ol li:before,.lines-code pre li:before,.lines-num .hljs li:before,.lines-num ol li:before,.lines-num pre li:before{content:' '} .lines-code .hljs li:before,.lines-code ol li:before,.lines-code pre li:before,.lines-num .hljs li:before,.lines-num ol li:before,.lines-num pre li:before{content:' '}
.lines-commit{vertical-align:top;color:#999;padding:0!important;background:#f5f5f5;width:1%;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none} .lines-commit{vertical-align:top;color:#999;padding:0!important;background:#f5f5f5;width:1%;-ms-user-select:none;-webkit-user-select:none;user-select:none}
.lines-commit .blame-info{width:350px;max-width:350px;display:block;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;padding:0 0 0 10px} .lines-commit .blame-info{width:350px;max-width:350px;display:block;-webkit-user-select:none;-ms-user-select:none;user-select:none;padding:0 0 0 10px}
.lines-commit .blame-info .blame-data{display:flex;font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial} .lines-commit .blame-info .blame-data{display:flex;font-family:-apple-system,BlinkMacSystemFont,system-ui,'Segoe UI',Roboto,Helvetica,Arial}
.lines-commit .blame-info .blame-data .blame-message{flex-grow:2;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;line-height:20px} .lines-commit .blame-info .blame-data .blame-message{flex-grow:2;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;line-height:20px}
.lines-commit .blame-info .blame-data .blame-avatar,.lines-commit .blame-info .blame-data .blame-time{flex-shrink:0} .lines-commit .blame-info .blame-data .blame-avatar,.lines-commit .blame-info .blame-data .blame-time{flex-shrink:0}
@ -333,7 +333,7 @@ i.icon.centerlock{top:1.5em}
.repository.wiki.revisions .ui.container>.ui.stackable.grid>.header{margin-top:0} .repository.wiki.revisions .ui.container>.ui.stackable.grid>.header{margin-top:0}
.repository.wiki.revisions .ui.container>.ui.stackable.grid>.header .sub.header{padding-left:52px;word-break:break-word} .repository.wiki.revisions .ui.container>.ui.stackable.grid>.header .sub.header{padding-left:52px;word-break:break-word}
.file-revisions-btn{display:block;float:left;margin-bottom:2px!important;padding:11px!important;margin-right:10px!important} .file-revisions-btn{display:block;float:left;margin-bottom:2px!important;padding:11px!important;margin-right:10px!important}
.file-revisions-btn i{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none} .file-revisions-btn i{-webkit-touch-callout:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}
.home .logo{max-width:220px} .home .logo{max-width:220px}
@media only screen and (max-width:767px){.home .hero h1{font-size:3.5em} @media only screen and (max-width:767px){.home .hero h1{font-size:3.5em}
.home .hero h2{font-size:2em} .home .hero h2{font-size:2em}
@ -687,7 +687,7 @@ i.icon.centerlock{top:1.5em}
.repository .diff-box .header .file{flex:1;color:#888;word-break:break-all} .repository .diff-box .header .file{flex:1;color:#888;word-break:break-all}
.repository .diff-box .header .button{margin:-5px 0 -5px 12px;padding:8px 10px;flex:0 0 auto} .repository .diff-box .header .button{margin:-5px 0 -5px 12px;padding:8px 10px;flex:0 0 auto}
.repository .diff-file-box .header{background-color:#f7f7f7} .repository .diff-file-box .header{background-color:#f7f7f7}
.repository .diff-file-box .file-body.file-code .lines-num{text-align:right;color:#a6a6a6;background:#fafafa;width:1%;min-width:50px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;vertical-align:top} .repository .diff-file-box .file-body.file-code .lines-num{text-align:right;color:#a6a6a6;background:#fafafa;width:1%;min-width:50px;-webkit-user-select:none;-ms-user-select:none;user-select:none;vertical-align:top}
.repository .diff-file-box .file-body.file-code .lines-num span.fold{display:block;text-align:center} .repository .diff-file-box .file-body.file-code .lines-num span.fold{display:block;text-align:center}
.repository .diff-file-box .file-body.file-code .lines-num-old{border-right:1px solid #ddd} .repository .diff-file-box .file-body.file-code .lines-num-old{border-right:1px solid #ddd}
.repository .diff-file-box .code-diff{font-size:12px} .repository .diff-file-box .code-diff{font-size:12px}
@ -698,7 +698,7 @@ i.icon.centerlock{top:1.5em}
.repository .diff-file-box .code-diff tbody tr .removed-code{background-color:#f99} .repository .diff-file-box .code-diff tbody tr .removed-code{background-color:#f99}
.repository .diff-file-box .code-diff tbody tr .added-code{background-color:#9f9} .repository .diff-file-box .code-diff tbody tr .added-code{background-color:#9f9}
.repository .diff-file-box .code-diff tbody tr [data-line-num]::before{content:attr(data-line-num);text-align:right} .repository .diff-file-box .code-diff tbody tr [data-line-num]::before{content:attr(data-line-num);text-align:right}
.repository .diff-file-box .code-diff tbody tr .lines-type-marker{width:10px;min-width:10px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none} .repository .diff-file-box .code-diff tbody tr .lines-type-marker{width:10px;min-width:10px;-webkit-user-select:none;-ms-user-select:none;user-select:none}
.repository .diff-file-box .code-diff tbody tr [data-type-marker]::before{content:attr(data-type-marker);text-align:right;display:inline-block} .repository .diff-file-box .code-diff tbody tr [data-type-marker]::before{content:attr(data-type-marker);text-align:right;display:inline-block}
.repository .diff-file-box .code-diff-unified tbody tr.del-code td{background-color:#ffe0e0!important;border-color:#f1c0c0!important} .repository .diff-file-box .code-diff-unified tbody tr.del-code td{background-color:#ffe0e0!important;border-color:#f1c0c0!important}
.repository .diff-file-box .code-diff-unified tbody tr.add-code td{background-color:#d6fcd6!important;border-color:#c1e9c1!important} .repository .diff-file-box .code-diff-unified tbody tr.add-code td{background-color:#d6fcd6!important;border-color:#c1e9c1!important}
@ -898,6 +898,7 @@ tbody.commit-list{vertical-align:baseline}
.repo-buttons .disabled-repo-button a.button:hover{background:0 0!important;color:rgba(0,0,0,.6)!important;box-shadow:0 0 0 1px rgba(34,36,38,.15) inset!important} .repo-buttons .disabled-repo-button a.button:hover{background:0 0!important;color:rgba(0,0,0,.6)!important;box-shadow:0 0 0 1px rgba(34,36,38,.15) inset!important}
.repo-buttons .ui.labeled.button>.label{border-left:0!important;margin:0!important} .repo-buttons .ui.labeled.button>.label{border-left:0!important;margin:0!important}
.tag-code,.tag-code td{background-color:#f0f0f0!important;border-color:#d3cfcf!important;padding-top:8px;padding-bottom:8px} .tag-code,.tag-code td{background-color:#f0f0f0!important;border-color:#d3cfcf!important;padding-top:8px;padding-bottom:8px}
td.blob-excerpt{background-color:#fafafa}
.issue-keyword{border-bottom:1px dotted #959da5;display:inline-block} .issue-keyword{border-bottom:1px dotted #959da5;display:inline-block}
.file-header{display:flex;justify-content:space-between;align-items:center;padding:8px 12px!important} .file-header{display:flex;justify-content:space-between;align-items:center;padding:8px 12px!important}
.file-info{display:flex;align-items:center} .file-info{display:flex;align-items:center}
@ -1069,3 +1070,7 @@ tbody.commit-list{vertical-align:baseline}
.comment-code-cloud button.comment-form-reply{margin:.5em .5em .5em 4.5em} .comment-code-cloud button.comment-form-reply{margin:.5em .5em .5em 4.5em}
.comment-code-cloud form.comment-form-reply{margin:0 0 0 4em} .comment-code-cloud form.comment-form-reply{margin:0 0 0 4em}
.file-comment{font:12px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;color:rgba(0,0,0,.87)} .file-comment{font:12px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;color:rgba(0,0,0,.87)}
.ui.fold-code{margin-right:1em;padding-left:5px;cursor:pointer;width:22px;font-size:12px}
.ui.fold-code:hover{color:#428bca}
.ui.blob-excerpt{display:block;line-height:20px;font-size:16px;cursor:pointer}
.ui.blob-excerpt:hover{color:#428bca}

View File

@ -14,7 +14,7 @@ body{background:#383c4a;color:#9e9e9e}
*{scrollbar-width:thin;scrollbar-color:#87ab63 rgba(255,255,255,.1)} *{scrollbar-width:thin;scrollbar-color:#87ab63 rgba(255,255,255,.1)}
::-webkit-scrollbar{-webkit-appearance:none!important;width:10px!important;height:10px!important} ::-webkit-scrollbar{-webkit-appearance:none!important;width:10px!important;height:10px!important}
::-webkit-scrollbar-track{border-radius:0!important;background:rgba(255,255,255,.1)!important} ::-webkit-scrollbar-track{border-radius:0!important;background:rgba(255,255,255,.1)!important}
::-webkit-scrollbar-thumb{cursor:pointer!important;border-radius:5px!important;transition:color .2s ease!important;background:#87ab63!important} ::-webkit-scrollbar-thumb{cursor:pointer!important;border-radius:5px!important;-webkit-transition:color .2s ease!important;transition:color .2s ease!important;background:#87ab63!important}
::-webkit-scrollbar-thumb:window-inactive{background:#87ab63!important} ::-webkit-scrollbar-thumb:window-inactive{background:#87ab63!important}
::-webkit-scrollbar-thumb:hover{background:#87ab63!important} ::-webkit-scrollbar-thumb:hover{background:#87ab63!important}
a{color:#87ab63} a{color:#87ab63}

View File

@ -1,15 +0,0 @@
/* globals gitGraph */
$(document).ready(function () {
const graphList = [];
if (!document.getElementById('graph-canvas')) {
return;
}
$("#graph-raw-list li span.node-relation").each(function () {
graphList.push($(this).text());
})
gitGraph(document.getElementById('graph-canvas'), graphList);
})

File diff suppressed because one or more lines are too long

1
public/js/index.js.map Normal file

File diff suppressed because one or more lines are too long

View File

@ -23,7 +23,7 @@ Version: 745f604212e2abfe2f0a59169ea530857b46625c
File(s): /vendor/plugins/vue/vue.min.js File(s): /vendor/plugins/vue/vue.min.js
Version: 2.1.10 Version: 2.1.10
File(s): /vendor/plugins/emojify/emojify.min.js File(s): /vendor/plugins/emojify/emojify.custom.js
Version: 1.1.0 Version: 1.1.0
File(s): /vendor/plugins/cssrelpreload/ File(s): /vendor/plugins/cssrelpreload/

View File

@ -38,12 +38,7 @@
<tr> <tr>
<td><a href="../js/index.js">index.js</a></td> <td><a href="../js/index.js">index.js</a></td>
<td><a href="https://github.com/go-gitea/gitea/blob/master/LICENSE">Expat</a></td> <td><a href="https://github.com/go-gitea/gitea/blob/master/LICENSE">Expat</a></td>
<td><a href="https://github.com/go-gitea/gitea/tree/master/public/js">index.js</a></td> <td><a href="https://github.com/go-gitea/gitea/tree/master/web_src/js">*.js</a></td>
</tr>
<tr>
<td><a href="../js/draw.js">draw.js</a></td>
<td><a href="https://github.com/go-gitea/gitea/blob/master/LICENSE">Expat</a></td>
<td><a href="https://github.com/go-gitea/gitea/tree/master/public/js">draw.js</a></td>
</tr> </tr>
<tr> <tr>
<td><a href="./plugins/clipboard/clipboard.min.js">clipboard.min.js</a></td> <td><a href="./plugins/clipboard/clipboard.min.js">clipboard.min.js</a></td>
@ -61,7 +56,7 @@
<td><a href="https://github.com/vuejs/vue/archive/v2.6.6.tar.gz">vue.js-v2.6.6.tar.gz</a></td> <td><a href="https://github.com/vuejs/vue/archive/v2.6.6.tar.gz">vue.js-v2.6.6.tar.gz</a></td>
</tr> </tr>
<tr> <tr>
<td><a href="./plugins/emojify/emojify.min.js">emojify.min.js</a></td> <td><a href="./plugins/emojify/emojify.custom.js">emojify.custom.js</a></td>
<td><a href="http://www.freebsd.org/copyright/freebsd-license.html">Expat</a></td> <td><a href="http://www.freebsd.org/copyright/freebsd-license.html">Expat</a></td>
<td><a href="https://github.com/Ranks/emojify.js/archive/1.1.0.tar.gz">emojify-1.1.0.tar.gz</a></td> <td><a href="https://github.com/Ranks/emojify.js/archive/1.1.0.tar.gz">emojify-1.1.0.tar.gz</a></td>
</tr> </tr>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

@ -6,6 +6,7 @@
package admin package admin
import ( import (
"encoding/json"
"fmt" "fmt"
"net/url" "net/url"
"os" "os"
@ -25,6 +26,7 @@ import (
"code.gitea.io/gitea/services/mailer" "code.gitea.io/gitea/services/mailer"
"gitea.com/macaron/macaron" "gitea.com/macaron/macaron"
"gitea.com/macaron/session"
"github.com/unknwon/com" "github.com/unknwon/com"
) )
@ -207,7 +209,7 @@ func SendTestMail(ctx *context.Context) {
ctx.Redirect(setting.AppSubURL + "/admin/config") ctx.Redirect(setting.AppSubURL + "/admin/config")
} }
func shadownPasswordKV(cfgItem, splitter string) string { func shadowPasswordKV(cfgItem, splitter string) string {
fields := strings.Split(cfgItem, splitter) fields := strings.Split(cfgItem, splitter)
for i := 0; i < len(fields); i++ { for i := 0; i < len(fields); i++ {
if strings.HasPrefix(fields[i], "password=") { if strings.HasPrefix(fields[i], "password=") {
@ -218,10 +220,10 @@ func shadownPasswordKV(cfgItem, splitter string) string {
return strings.Join(fields, splitter) return strings.Join(fields, splitter)
} }
func shadownURL(provider, cfgItem string) string { func shadowURL(provider, cfgItem string) string {
u, err := url.Parse(cfgItem) u, err := url.Parse(cfgItem)
if err != nil { if err != nil {
log.Error("shodowPassword %v failed: %v", provider, err) log.Error("Shadowing Password for %v failed: %v", provider, err)
return cfgItem return cfgItem
} }
if u.User != nil { if u.User != nil {
@ -239,7 +241,7 @@ func shadownURL(provider, cfgItem string) string {
func shadowPassword(provider, cfgItem string) string { func shadowPassword(provider, cfgItem string) string {
switch provider { switch provider {
case "redis": case "redis":
return shadownPasswordKV(cfgItem, ",") return shadowPasswordKV(cfgItem, ",")
case "mysql": case "mysql":
//root:@tcp(localhost:3306)/macaron?charset=utf8 //root:@tcp(localhost:3306)/macaron?charset=utf8
atIdx := strings.Index(cfgItem, "@") atIdx := strings.Index(cfgItem, "@")
@ -253,15 +255,21 @@ func shadowPassword(provider, cfgItem string) string {
case "postgres": case "postgres":
// user=jiahuachen dbname=macaron port=5432 sslmode=disable // user=jiahuachen dbname=macaron port=5432 sslmode=disable
if !strings.HasPrefix(cfgItem, "postgres://") { if !strings.HasPrefix(cfgItem, "postgres://") {
return shadownPasswordKV(cfgItem, " ") return shadowPasswordKV(cfgItem, " ")
} }
fallthrough
case "couchbase":
return shadowURL(provider, cfgItem)
// postgres://pqgotest:password@localhost/pqgotest?sslmode=verify-full // postgres://pqgotest:password@localhost/pqgotest?sslmode=verify-full
// Notice: use shadwonURL // Notice: use shadowURL
case "VirtualSession":
var realSession session.Options
if err := json.Unmarshal([]byte(cfgItem), &realSession); err == nil {
return shadowPassword(realSession.Provider, realSession.ProviderConfig)
}
} }
// "couchbase" return cfgItem
return shadownURL(provider, cfgItem)
} }
// Config show admin config page // Config show admin config page

View File

@ -631,15 +631,13 @@ func Edit(ctx *context.APIContext, opts api.EditRepoOption) {
func updateBasicProperties(ctx *context.APIContext, opts api.EditRepoOption) error { func updateBasicProperties(ctx *context.APIContext, opts api.EditRepoOption) error {
owner := ctx.Repo.Owner owner := ctx.Repo.Owner
repo := ctx.Repo.Repository repo := ctx.Repo.Repository
oldRepoName := repo.Name
newRepoName := repo.Name newRepoName := repo.Name
if opts.Name != nil { if opts.Name != nil {
newRepoName = *opts.Name newRepoName = *opts.Name
} }
// Check if repository name has been changed and not just a case change // Check if repository name has been changed and not just a case change
if repo.LowerName != strings.ToLower(newRepoName) { if repo.LowerName != strings.ToLower(newRepoName) {
if err := models.ChangeRepositoryName(ctx.Repo.Owner, repo.Name, newRepoName); err != nil { if err := repo_service.ChangeRepositoryName(ctx.User, repo, newRepoName); err != nil {
switch { switch {
case models.IsErrRepoAlreadyExist(err): case models.IsErrRepoAlreadyExist(err):
ctx.Error(http.StatusUnprocessableEntity, fmt.Sprintf("repo name is already taken [name: %s]", newRepoName), err) ctx.Error(http.StatusUnprocessableEntity, fmt.Sprintf("repo name is already taken [name: %s]", newRepoName), err)
@ -653,14 +651,6 @@ func updateBasicProperties(ctx *context.APIContext, opts api.EditRepoOption) err
return err return err
} }
err := models.NewRepoRedirect(ctx.Repo.Owner.ID, repo.ID, repo.Name, newRepoName)
if err != nil {
ctx.Error(http.StatusUnprocessableEntity, "NewRepoRedirect", err)
return err
}
notification.NotifyRenameRepository(ctx.User, repo, oldRepoName)
log.Trace("Repository name changed: %s/%s -> %s", ctx.Repo.Owner.Name, repo.Name, newRepoName) log.Trace("Repository name changed: %s/%s -> %s", ctx.Repo.Owner.Name, repo.Name, newRepoName)
} }
// Update the name in the repo object for the response // Update the name in the repo object for the response

View File

@ -245,6 +245,7 @@ func Diff(ctx *context.Context) {
} }
ctx.Data["CommitID"] = commitID ctx.Data["CommitID"] = commitID
ctx.Data["AfterCommitID"] = commitID
ctx.Data["Username"] = userName ctx.Data["Username"] = userName
ctx.Data["Reponame"] = repoName ctx.Data["Reponame"] = repoName

View File

@ -5,21 +5,26 @@
package repo package repo
import ( import (
"bufio"
"fmt" "fmt"
"html"
"path" "path"
"path/filepath"
"strings" "strings"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/highlight"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/services/gitdiff" "code.gitea.io/gitea/services/gitdiff"
) )
const ( const (
tplCompare base.TplName = "repo/diff/compare" tplCompare base.TplName = "repo/diff/compare"
tplBlobExcerpt base.TplName = "repo/diff/blob_excerpt"
) )
// setPathsCompareContext sets context data for source and raw paths // setPathsCompareContext sets context data for source and raw paths
@ -434,3 +439,109 @@ func CompareDiff(ctx *context.Context) {
ctx.HTML(200, tplCompare) ctx.HTML(200, tplCompare)
} }
// ExcerptBlob render blob excerpt contents
func ExcerptBlob(ctx *context.Context) {
commitID := ctx.Params("sha")
lastLeft := ctx.QueryInt("last_left")
lastRight := ctx.QueryInt("last_right")
idxLeft := ctx.QueryInt("left")
idxRight := ctx.QueryInt("right")
leftHunkSize := ctx.QueryInt("left_hunk_size")
rightHunkSize := ctx.QueryInt("right_hunk_size")
anchor := ctx.Query("anchor")
direction := ctx.Query("direction")
filePath := ctx.Query("path")
gitRepo := ctx.Repo.GitRepo
chunkSize := gitdiff.BlobExceprtChunkSize
commit, err := gitRepo.GetCommit(commitID)
if err != nil {
ctx.Error(500, "GetCommit")
return
}
section := &gitdiff.DiffSection{
Name: filePath,
}
if direction == "up" && (idxLeft-lastLeft) > chunkSize {
idxLeft -= chunkSize
idxRight -= chunkSize
leftHunkSize += chunkSize
rightHunkSize += chunkSize
section.Lines, err = getExcerptLines(commit, filePath, idxLeft-1, idxRight-1, chunkSize)
} else if direction == "down" && (idxLeft-lastLeft) > chunkSize {
section.Lines, err = getExcerptLines(commit, filePath, lastLeft, lastRight, chunkSize)
lastLeft += chunkSize
lastRight += chunkSize
} else {
section.Lines, err = getExcerptLines(commit, filePath, lastLeft, lastRight, idxRight-lastRight-1)
leftHunkSize = 0
rightHunkSize = 0
idxLeft = lastLeft
idxRight = lastRight
}
if err != nil {
ctx.Error(500, "getExcerptLines")
return
}
if idxRight > lastRight {
lineText := " "
if rightHunkSize > 0 || leftHunkSize > 0 {
lineText = fmt.Sprintf("@@ -%d,%d +%d,%d @@\n", idxLeft, leftHunkSize, idxRight, rightHunkSize)
}
lineText = html.EscapeString(lineText)
lineSection := &gitdiff.DiffLine{
Type: gitdiff.DiffLineSection,
Content: lineText,
SectionInfo: &gitdiff.DiffLineSectionInfo{
Path: filePath,
LastLeftIdx: lastLeft,
LastRightIdx: lastRight,
LeftIdx: idxLeft,
RightIdx: idxRight,
LeftHunkSize: leftHunkSize,
RightHunkSize: rightHunkSize,
}}
if direction == "up" {
section.Lines = append([]*gitdiff.DiffLine{lineSection}, section.Lines...)
} else if direction == "down" {
section.Lines = append(section.Lines, lineSection)
}
}
ctx.Data["section"] = section
ctx.Data["fileName"] = filePath
ctx.Data["highlightClass"] = highlight.FileNameToHighlightClass(filepath.Base(filePath))
ctx.Data["AfterCommitID"] = commitID
ctx.Data["Anchor"] = anchor
ctx.HTML(200, tplBlobExcerpt)
}
func getExcerptLines(commit *git.Commit, filePath string, idxLeft int, idxRight int, chunkSize int) ([]*gitdiff.DiffLine, error) {
blob, err := commit.Tree.GetBlobByPath(filePath)
if err != nil {
return nil, err
}
reader, err := blob.DataAsync()
if err != nil {
return nil, err
}
defer reader.Close()
scanner := bufio.NewScanner(reader)
var diffLines []*gitdiff.DiffLine
for line := 0; line < idxRight+chunkSize; line++ {
if ok := scanner.Scan(); !ok {
break
}
if line < idxRight {
continue
}
lineText := scanner.Text()
diffLine := &gitdiff.DiffLine{
LeftIdx: idxLeft + (line - idxRight) + 1,
RightIdx: line + 1,
Type: gitdiff.DiffLinePlain,
Content: " " + lineText,
}
diffLines = append(diffLines, diffLine)
}
return diffLines, nil
}

View File

@ -552,6 +552,7 @@ func ViewPullFiles(ctx *context.Context) {
ctx.Data["Username"] = pull.MustHeadUserName() ctx.Data["Username"] = pull.MustHeadUserName()
ctx.Data["Reponame"] = pull.HeadRepo.Name ctx.Data["Reponame"] = pull.HeadRepo.Name
} }
ctx.Data["AfterCommitID"] = endCommitID
diff, err := gitdiff.GetDiffRangeWithWhitespaceBehavior(diffRepoPath, diff, err := gitdiff.GetDiffRangeWithWhitespaceBehavior(diffRepoPath,
startCommitID, endCommitID, setting.Git.MaxGitDiffLines, startCommitID, endCommitID, setting.Git.MaxGitDiffLines,

View File

@ -11,8 +11,6 @@ import (
"code.gitea.io/gitea/modules/auth" "code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/notification"
comment_service "code.gitea.io/gitea/services/comments"
pull_service "code.gitea.io/gitea/services/pull" pull_service "code.gitea.io/gitea/services/pull"
) )
@ -31,64 +29,33 @@ func CreateCodeComment(ctx *context.Context, form auth.CodeCommentForm) {
ctx.Redirect(fmt.Sprintf("%s/pulls/%d/files", ctx.Repo.RepoLink, issue.Index)) ctx.Redirect(fmt.Sprintf("%s/pulls/%d/files", ctx.Repo.RepoLink, issue.Index))
return return
} }
var comment *models.Comment
defer func() {
if comment != nil {
ctx.Redirect(comment.HTMLURL())
} else {
ctx.Redirect(fmt.Sprintf("%s/pulls/%d/files", ctx.Repo.RepoLink, issue.Index))
}
}()
signedLine := form.Line signedLine := form.Line
if form.Side == "previous" { if form.Side == "previous" {
signedLine *= -1 signedLine *= -1
} }
review := new(models.Review) comment, err := pull_service.CreateCodeComment(
if form.IsReview {
var err error
// Check if the user has already a pending review for this issue
if review, err = models.GetCurrentReview(ctx.User, issue); err != nil {
if !models.IsErrReviewNotExist(err) {
ctx.ServerError("CreateCodeComment", err)
return
}
// No pending review exists
// Create a new pending review for this issue & user
if review, err = pull_service.CreateReview(models.CreateReviewOptions{
Type: models.ReviewTypePending,
Reviewer: ctx.User,
Issue: issue,
}); err != nil {
ctx.ServerError("CreateCodeComment", err)
return
}
}
}
if review.ID == 0 {
review.ID = form.Reply
}
//FIXME check if line, commit and treepath exist
comment, err := comment_service.CreateCodeComment(
ctx.User, ctx.User,
issue.Repo,
issue, issue,
signedLine,
form.Content, form.Content,
form.TreePath, form.TreePath,
signedLine, form.IsReview,
review.ID, form.Reply,
) )
if err != nil { if err != nil {
ctx.ServerError("CreateCodeComment", err) ctx.ServerError("CreateCodeComment", err)
return return
} }
// Send no notification if comment is pending
if !form.IsReview || form.Reply != 0 {
notification.NotifyCreateIssueComment(ctx.User, issue.Repo, issue, comment)
}
log.Trace("Comment created: %d/%d/%d", ctx.Repo.Repository.ID, issue.ID, comment.ID) log.Trace("Comment created: %d/%d/%d", ctx.Repo.Repository.ID, issue.ID, comment.ID)
if comment != nil {
ctx.Redirect(comment.HTMLURL())
} else {
ctx.Redirect(fmt.Sprintf("%s/pulls/%d/files", ctx.Repo.RepoLink, issue.Index))
}
} }
// SubmitReview creates a review out of the existing pending review or creates a new one if no pending review exist // SubmitReview creates a review out of the existing pending review or creates a new one if no pending review exist
@ -105,23 +72,17 @@ func SubmitReview(ctx *context.Context, form auth.SubmitReviewForm) {
ctx.Redirect(fmt.Sprintf("%s/pulls/%d/files", ctx.Repo.RepoLink, issue.Index)) ctx.Redirect(fmt.Sprintf("%s/pulls/%d/files", ctx.Repo.RepoLink, issue.Index))
return return
} }
var review *models.Review
var err error
reviewType := form.ReviewType() reviewType := form.ReviewType()
switch reviewType { switch reviewType {
case models.ReviewTypeUnknown: case models.ReviewTypeUnknown:
ctx.ServerError("GetCurrentReview", fmt.Errorf("unknown ReviewType: %s", form.Type)) ctx.ServerError("ReviewType", fmt.Errorf("unknown ReviewType: %s", form.Type))
return return
// can not approve/reject your own PR // can not approve/reject your own PR
case models.ReviewTypeApprove, models.ReviewTypeReject: case models.ReviewTypeApprove, models.ReviewTypeReject:
if issue.Poster.ID == ctx.User.ID { if issue.Poster.ID == ctx.User.ID {
var translated string var translated string
if reviewType == models.ReviewTypeApprove { if reviewType == models.ReviewTypeApprove {
translated = ctx.Tr("repo.issues.review.self.approval") translated = ctx.Tr("repo.issues.review.self.approval")
} else { } else {
@ -134,69 +95,16 @@ func SubmitReview(ctx *context.Context, form auth.SubmitReviewForm) {
} }
} }
review, err = models.GetCurrentReview(ctx.User, issue) _, comm, err := pull_service.SubmitReview(ctx.User, issue, reviewType, form.Content)
if err == nil {
review.Issue = issue
if errl := review.LoadCodeComments(); errl != nil {
ctx.ServerError("LoadCodeComments", err)
return
}
}
if ((err == nil && len(review.CodeComments) == 0) ||
(err != nil && models.IsErrReviewNotExist(err))) &&
form.HasEmptyContent() {
ctx.Flash.Error(ctx.Tr("repo.issues.review.content.empty"))
ctx.Redirect(fmt.Sprintf("%s/pulls/%d/files", ctx.Repo.RepoLink, issue.Index))
return
}
if err != nil { if err != nil {
if !models.IsErrReviewNotExist(err) { if models.IsContentEmptyErr(err) {
ctx.ServerError("GetCurrentReview", err) ctx.Flash.Error(ctx.Tr("repo.issues.review.content.empty"))
return ctx.Redirect(fmt.Sprintf("%s/pulls/%d/files", ctx.Repo.RepoLink, issue.Index))
} else {
ctx.ServerError("SubmitReview", err)
} }
// No current review. Create a new one!
if review, err = pull_service.CreateReview(models.CreateReviewOptions{
Type: reviewType,
Issue: issue,
Reviewer: ctx.User,
Content: form.Content,
}); err != nil {
ctx.ServerError("CreateReview", err)
return
}
} else {
review.Content = form.Content
review.Type = reviewType
if err = pull_service.UpdateReview(review); err != nil {
ctx.ServerError("UpdateReview", err)
return
}
}
comm, err := models.CreateComment(&models.CreateCommentOptions{
Type: models.CommentTypeReview,
Doer: ctx.User,
Content: review.Content,
Issue: issue,
Repo: issue.Repo,
ReviewID: review.ID,
})
if err != nil || comm == nil {
ctx.ServerError("CreateComment", err)
return return
} }
if err = review.Publish(); err != nil {
ctx.ServerError("Publish", err)
return
}
pr, err := issue.GetPullRequest()
if err != nil {
ctx.ServerError("GetPullRequest", err)
return
}
notification.NotifyPullRequestReview(pr, review, comm)
ctx.Redirect(fmt.Sprintf("%s/pulls/%d#%s", ctx.Repo.RepoLink, issue.Index, comm.HashTag())) ctx.Redirect(fmt.Sprintf("%s/pulls/%d#%s", ctx.Repo.RepoLink, issue.Index, comm.HashTag()))
} }

View File

@ -20,7 +20,6 @@ import (
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"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"
"code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/validation" "code.gitea.io/gitea/modules/validation"
@ -67,18 +66,15 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
return return
} }
isNameChanged := false
oldRepoName := repo.Name
newRepoName := form.RepoName newRepoName := form.RepoName
// Check if repository name has been changed. // Check if repository name has been changed.
if repo.LowerName != strings.ToLower(newRepoName) { if repo.LowerName != strings.ToLower(newRepoName) {
isNameChanged = true
// Close the GitRepo if open // Close the GitRepo if open
if ctx.Repo.GitRepo != nil { if ctx.Repo.GitRepo != nil {
ctx.Repo.GitRepo.Close() ctx.Repo.GitRepo.Close()
ctx.Repo.GitRepo = nil ctx.Repo.GitRepo = nil
} }
if err := models.ChangeRepositoryName(ctx.Repo.Owner, repo.Name, newRepoName); err != nil { if err := repo_service.ChangeRepositoryName(ctx.Repo.Owner, repo, newRepoName); err != nil {
ctx.Data["Err_RepoName"] = true ctx.Data["Err_RepoName"] = true
switch { switch {
case models.IsErrRepoAlreadyExist(err): case models.IsErrRepoAlreadyExist(err):
@ -93,12 +89,6 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
return return
} }
err := models.NewRepoRedirect(ctx.Repo.Owner.ID, repo.ID, repo.Name, newRepoName)
if err != nil {
ctx.ServerError("NewRepoRedirect", err)
return
}
log.Trace("Repository name changed: %s/%s -> %s", ctx.Repo.Owner.Name, repo.Name, newRepoName) log.Trace("Repository name changed: %s/%s -> %s", ctx.Repo.Owner.Name, repo.Name, newRepoName)
} }
// In case it's just a case change. // In case it's just a case change.
@ -127,10 +117,6 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
} }
log.Trace("Repository basic settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name) log.Trace("Repository basic settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
if isNameChanged {
notification.NotifyRenameRepository(ctx.User, repo, oldRepoName)
}
ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success")) ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
ctx.Redirect(repo.Link() + "/settings") ctx.Redirect(repo.Link() + "/settings")
@ -383,13 +369,12 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
return return
} }
oldOwnerID := ctx.Repo.Owner.ID
// Close the GitRepo if open // Close the GitRepo if open
if ctx.Repo.GitRepo != nil { if ctx.Repo.GitRepo != nil {
ctx.Repo.GitRepo.Close() ctx.Repo.GitRepo.Close()
ctx.Repo.GitRepo = nil ctx.Repo.GitRepo = nil
} }
if err = models.TransferOwnership(ctx.User, newOwner, repo); err != nil { if err = repo_service.TransferOwnership(ctx.User, newOwner, repo); err != nil {
if models.IsErrRepoAlreadyExist(err) { if models.IsErrRepoAlreadyExist(err) {
ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplSettingsOptions, nil) ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplSettingsOptions, nil)
} else { } else {
@ -398,12 +383,6 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
return return
} }
err = models.NewRepoRedirect(oldOwnerID, repo.ID, repo.Name, repo.Name)
if err != nil {
ctx.ServerError("NewRepoRedirect", err)
return
}
log.Trace("Repository transferred: %s/%s -> %s", ctx.Repo.Owner.Name, repo.Name, newOwner) log.Trace("Repository transferred: %s/%s -> %s", ctx.Repo.Owner.Name, repo.Name, newOwner)
ctx.Flash.Success(ctx.Tr("repo.settings.transfer_succeed")) ctx.Flash.Success(ctx.Tr("repo.settings.transfer_succeed"))
ctx.Redirect(setting.AppSubURL + "/" + newOwner + "/" + repo.Name) ctx.Redirect(setting.AppSubURL + "/" + newOwner + "/" + repo.Name)
@ -707,6 +686,7 @@ func GitHooks(ctx *context.Context) {
func GitHooksEdit(ctx *context.Context) { func GitHooksEdit(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.settings.githooks") ctx.Data["Title"] = ctx.Tr("repo.settings.githooks")
ctx.Data["PageIsSettingsGitHooks"] = true ctx.Data["PageIsSettingsGitHooks"] = true
ctx.Data["RequireSimpleMDE"] = true
name := ctx.Params(":name") name := ctx.Params(":name")
hook, err := ctx.Repo.GitRepo.GetHook(name) hook, err := ctx.Repo.GitRepo.GetHook(name)

View File

@ -864,6 +864,10 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("", repo.Branches) m.Get("", repo.Branches)
}, repo.MustBeNotEmpty, context.RepoRef(), reqRepoCodeReader) }, repo.MustBeNotEmpty, context.RepoRef(), reqRepoCodeReader)
m.Group("/blob_excerpt", func() {
m.Get("/:sha", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.ExcerptBlob)
}, repo.MustBeNotEmpty, context.RepoRef(), reqRepoCodeReader)
m.Group("/pulls/:index", func() { m.Group("/pulls/:index", func() {
m.Get(".diff", repo.DownloadPullDiff) m.Get(".diff", repo.DownloadPullDiff)
m.Get(".patch", repo.DownloadPullPatch) m.Get(".patch", repo.DownloadPullPatch)

View File

@ -5,15 +5,8 @@
package comments package comments
import ( import (
"bytes"
"fmt"
"strings"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/notification" "code.gitea.io/gitea/modules/notification"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/services/gitdiff"
) )
// CreateIssueComment creates a plain issue comment. // CreateIssueComment creates a plain issue comment.
@ -35,60 +28,6 @@ func CreateIssueComment(doer *models.User, repo *models.Repository, issue *model
return comment, nil return comment, nil
} }
// CreateCodeComment creates a plain code comment at the specified line / path
func CreateCodeComment(doer *models.User, repo *models.Repository, issue *models.Issue, content, treePath string, line, reviewID int64) (*models.Comment, error) {
var commitID, patch string
pr, err := models.GetPullRequestByIssueID(issue.ID)
if err != nil {
return nil, fmt.Errorf("GetPullRequestByIssueID: %v", err)
}
if err := pr.GetBaseRepo(); err != nil {
return nil, fmt.Errorf("GetHeadRepo: %v", err)
}
gitRepo, err := git.OpenRepository(pr.BaseRepo.RepoPath())
if err != nil {
return nil, fmt.Errorf("OpenRepository: %v", err)
}
defer gitRepo.Close()
// FIXME validate treePath
// Get latest commit referencing the commented line
// No need for get commit for base branch changes
if line > 0 {
commit, err := gitRepo.LineBlame(pr.GetGitRefName(), gitRepo.Path, treePath, uint(line))
if err == nil {
commitID = commit.ID.String()
} else if !strings.Contains(err.Error(), "exit status 128 - fatal: no such path") {
return nil, fmt.Errorf("LineBlame[%s, %s, %s, %d]: %v", pr.GetGitRefName(), gitRepo.Path, treePath, line, err)
}
}
// Only fetch diff if comment is review comment
if reviewID != 0 {
headCommitID, err := gitRepo.GetRefCommitID(pr.GetGitRefName())
if err != nil {
return nil, fmt.Errorf("GetRefCommitID[%s]: %v", pr.GetGitRefName(), err)
}
patchBuf := new(bytes.Buffer)
if err := gitdiff.GetRawDiffForFile(gitRepo.Path, pr.MergeBase, headCommitID, gitdiff.RawDiffNormal, treePath, patchBuf); err != nil {
return nil, fmt.Errorf("GetRawDiffForLine[%s, %s, %s, %s]: %v", err, gitRepo.Path, pr.MergeBase, headCommitID, treePath)
}
patch = gitdiff.CutDiffAroundLine(patchBuf, int64((&models.Comment{Line: line}).UnsignedLine()), line < 0, setting.UI.CodeCommentLines)
}
return models.CreateComment(&models.CreateCommentOptions{
Type: models.CommentTypeCode,
Doer: doer,
Repo: repo,
Issue: issue,
Content: content,
LineNum: line,
TreePath: treePath,
CommitSHA: commitID,
ReviewID: reviewID,
Patch: patch,
})
}
// UpdateComment updates information of comment. // UpdateComment updates information of comment.
func UpdateComment(c *models.Comment, doer *models.User, oldContent string) error { func UpdateComment(c *models.Comment, doer *models.User, oldContent string) error {
if err := models.UpdateComment(c, doer); err != nil { if err := models.UpdateComment(c, doer); err != nil {

View File

@ -13,6 +13,7 @@ import (
"html/template" "html/template"
"io" "io"
"io/ioutil" "io/ioutil"
"net/url"
"os" "os"
"os/exec" "os/exec"
"regexp" "regexp"
@ -56,15 +57,42 @@ const (
DiffFileRename DiffFileRename
) )
// DiffLineExpandDirection represents the DiffLineSection expand direction
type DiffLineExpandDirection uint8
// DiffLineExpandDirection possible values.
const (
DiffLineExpandNone DiffLineExpandDirection = iota + 1
DiffLineExpandSingle
DiffLineExpandUpDown
DiffLineExpandUp
DiffLineExpandDown
)
// DiffLine represents a line difference in a DiffSection. // DiffLine represents a line difference in a DiffSection.
type DiffLine struct { type DiffLine struct {
LeftIdx int LeftIdx int
RightIdx int RightIdx int
Type DiffLineType Type DiffLineType
Content string Content string
Comments []*models.Comment Comments []*models.Comment
SectionInfo *DiffLineSectionInfo
} }
// DiffLineSectionInfo represents diff line section meta data
type DiffLineSectionInfo struct {
Path string
LastLeftIdx int
LastRightIdx int
LeftIdx int
RightIdx int
LeftHunkSize int
RightHunkSize int
}
// BlobExceprtChunkSize represent max lines of excerpt
const BlobExceprtChunkSize = 20
// GetType returns the type of a DiffLine. // GetType returns the type of a DiffLine.
func (d *DiffLine) GetType() int { func (d *DiffLine) GetType() int {
return int(d.Type) return int(d.Type)
@ -91,6 +119,71 @@ func (d *DiffLine) GetLineTypeMarker() string {
return "" return ""
} }
// GetBlobExcerptQuery builds query string to get blob excerpt
func (d *DiffLine) GetBlobExcerptQuery() string {
query := fmt.Sprintf(
"last_left=%d&last_right=%d&"+
"left=%d&right=%d&"+
"left_hunk_size=%d&right_hunk_size=%d&"+
"path=%s",
d.SectionInfo.LastLeftIdx, d.SectionInfo.LastRightIdx,
d.SectionInfo.LeftIdx, d.SectionInfo.RightIdx,
d.SectionInfo.LeftHunkSize, d.SectionInfo.RightHunkSize,
url.QueryEscape(d.SectionInfo.Path))
return query
}
// GetExpandDirection gets DiffLineExpandDirection
func (d *DiffLine) GetExpandDirection() DiffLineExpandDirection {
if d.Type != DiffLineSection || d.SectionInfo == nil || d.SectionInfo.RightIdx-d.SectionInfo.LastRightIdx <= 1 {
return DiffLineExpandNone
}
if d.SectionInfo.LastLeftIdx <= 0 && d.SectionInfo.LastRightIdx <= 0 {
return DiffLineExpandUp
} else if d.SectionInfo.RightIdx-d.SectionInfo.LastRightIdx > BlobExceprtChunkSize && d.SectionInfo.RightHunkSize > 0 {
return DiffLineExpandUpDown
} else if d.SectionInfo.LeftHunkSize <= 0 && d.SectionInfo.RightHunkSize <= 0 {
return DiffLineExpandDown
}
return DiffLineExpandSingle
}
func getDiffLineSectionInfo(curFile *DiffFile, line string, lastLeftIdx, lastRightIdx int) *DiffLineSectionInfo {
var (
leftLine int
leftHunk int
rightLine int
righHunk int
)
ss := strings.Split(line, "@@")
ranges := strings.Split(ss[1][1:], " ")
leftRange := strings.Split(ranges[0], ",")
leftLine, _ = com.StrTo(leftRange[0][1:]).Int()
if len(leftRange) > 1 {
leftHunk, _ = com.StrTo(leftRange[1]).Int()
}
if len(ranges) > 1 {
rightRange := strings.Split(ranges[1], ",")
rightLine, _ = com.StrTo(rightRange[0]).Int()
if len(rightRange) > 1 {
righHunk, _ = com.StrTo(rightRange[1]).Int()
}
} else {
log.Warn("Parse line number failed: %v", line)
rightLine = leftLine
righHunk = leftHunk
}
return &DiffLineSectionInfo{
Path: curFile.Name,
LastLeftIdx: lastLeftIdx,
LastRightIdx: lastRightIdx,
LeftIdx: leftLine,
RightIdx: rightLine,
LeftHunkSize: leftHunk,
RightHunkSize: righHunk,
}
}
// escape a line's content or return <br> needed for copy/paste purposes // escape a line's content or return <br> needed for copy/paste purposes
func getLineContent(content string) string { func getLineContent(content string) string {
if len(content) > 0 { if len(content) > 0 {
@ -248,6 +341,53 @@ func (diffFile *DiffFile) GetHighlightClass() string {
return highlight.FileNameToHighlightClass(diffFile.Name) return highlight.FileNameToHighlightClass(diffFile.Name)
} }
// GetTailSection creates a fake DiffLineSection if the last section is not the end of the file
func (diffFile *DiffFile) GetTailSection(gitRepo *git.Repository, leftCommitID, rightCommitID string) *DiffSection {
if diffFile.Type != DiffFileChange || diffFile.IsBin || diffFile.IsLFSFile {
return nil
}
leftCommit, err := gitRepo.GetCommit(leftCommitID)
if err != nil {
return nil
}
rightCommit, err := gitRepo.GetCommit(rightCommitID)
if err != nil {
return nil
}
lastSection := diffFile.Sections[len(diffFile.Sections)-1]
lastLine := lastSection.Lines[len(lastSection.Lines)-1]
leftLineCount := getCommitFileLineCount(leftCommit, diffFile.Name)
rightLineCount := getCommitFileLineCount(rightCommit, diffFile.Name)
if leftLineCount <= lastLine.LeftIdx || rightLineCount <= lastLine.RightIdx {
return nil
}
tailDiffLine := &DiffLine{
Type: DiffLineSection,
Content: " ",
SectionInfo: &DiffLineSectionInfo{
Path: diffFile.Name,
LastLeftIdx: lastLine.LeftIdx,
LastRightIdx: lastLine.RightIdx,
LeftIdx: leftLineCount,
RightIdx: rightLineCount,
}}
tailSection := &DiffSection{Lines: []*DiffLine{tailDiffLine}}
return tailSection
}
func getCommitFileLineCount(commit *git.Commit, filePath string) int {
blob, err := commit.GetBlobByPath(filePath)
if err != nil {
return 0
}
lineCount, err := blob.GetBlobLineCount()
if err != nil {
return 0
}
return lineCount
}
// Diff represents a difference between two git trees. // Diff represents a difference between two git trees.
type Diff struct { type Diff struct {
TotalAddition, TotalDeletion int TotalAddition, TotalDeletion int
@ -510,19 +650,16 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D
case line[0] == '@': case line[0] == '@':
curSection = &DiffSection{} curSection = &DiffSection{}
curFile.Sections = append(curFile.Sections, curSection) curFile.Sections = append(curFile.Sections, curSection)
ss := strings.Split(line, "@@") lineSectionInfo := getDiffLineSectionInfo(curFile, line, leftLine-1, rightLine-1)
diffLine := &DiffLine{Type: DiffLineSection, Content: line} diffLine := &DiffLine{
curSection.Lines = append(curSection.Lines, diffLine) Type: DiffLineSection,
Content: line,
// Parse line number. SectionInfo: lineSectionInfo,
ranges := strings.Split(ss[1][1:], " ")
leftLine, _ = com.StrTo(strings.Split(ranges[0], ",")[0][1:]).Int()
if len(ranges) > 1 {
rightLine, _ = com.StrTo(strings.Split(ranges[1], ",")[0]).Int()
} else {
log.Warn("Parse line number failed: %v", line)
rightLine = leftLine
} }
curSection.Lines = append(curSection.Lines, diffLine)
// update line number.
leftLine = lineSectionInfo.LeftIdx
rightLine = lineSectionInfo.RightIdx
continue continue
case line[0] == '+': case line[0] == '+':
curFile.Addition++ curFile.Addition++
@ -599,6 +736,8 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D
break break
} }
curFileLinesCount = 0 curFileLinesCount = 0
leftLine = 1
rightLine = 1
curFileLFSPrefix = false curFileLFSPrefix = false
// Check file diff type and is submodule. // Check file diff type and is submodule.
@ -701,6 +840,7 @@ func GetDiffRangeWithWhitespaceBehavior(repoPath, beforeCommitID, afterCommitID
diffArgs = append(diffArgs, actualBeforeCommitID) diffArgs = append(diffArgs, actualBeforeCommitID)
diffArgs = append(diffArgs, afterCommitID) diffArgs = append(diffArgs, afterCommitID)
cmd = exec.Command(git.GitExecutable, diffArgs...) cmd = exec.Command(git.GitExecutable, diffArgs...)
beforeCommitID = actualBeforeCommitID
} }
cmd.Dir = repoPath cmd.Dir = repoPath
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
@ -721,6 +861,12 @@ func GetDiffRangeWithWhitespaceBehavior(repoPath, beforeCommitID, afterCommitID
if err != nil { if err != nil {
return nil, fmt.Errorf("ParsePatch: %v", err) return nil, fmt.Errorf("ParsePatch: %v", err)
} }
for _, diffFile := range diff.Files {
tailSection := diffFile.GetTailSection(gitRepo, beforeCommitID, afterCommitID)
if tailSection != nil {
diffFile.Sections = append(diffFile.Sections, tailSection)
}
}
if err = cmd.Wait(); err != nil { if err = cmd.Wait(); err != nil {
return nil, fmt.Errorf("Wait: %v", err) return nil, fmt.Errorf("Wait: %v", err)

View File

@ -76,6 +76,7 @@ func TestRelease_MirrorDelete(t *testing.T) {
assert.True(t, ok) assert.True(t, ok)
count, err := models.GetReleaseCountByRepoID(mirror.ID, findOptions) count, err := models.GetReleaseCountByRepoID(mirror.ID, findOptions)
assert.NoError(t, err)
assert.EqualValues(t, initCount+1, count) assert.EqualValues(t, initCount+1, count)
release, err := models.GetRelease(repo.ID, "v0.2") release, err := models.GetRelease(repo.ID, "v0.2")
@ -86,5 +87,6 @@ func TestRelease_MirrorDelete(t *testing.T) {
assert.True(t, ok) assert.True(t, ok)
count, err = models.GetReleaseCountByRepoID(mirror.ID, findOptions) count, err = models.GetReleaseCountByRepoID(mirror.ID, findOptions)
assert.NoError(t, err)
assert.EqualValues(t, initCount, count) assert.EqualValues(t, initCount, count)
} }

View File

@ -424,8 +424,16 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
log.Error("setMerged [%d]: %v", pr.ID, err) log.Error("setMerged [%d]: %v", pr.ID, err)
} }
if err = models.MergePullRequestAction(doer, pr.Issue.Repo, pr.Issue); err != nil { if err := models.NotifyWatchers(&models.Action{
log.Error("MergePullRequestAction [%d]: %v", pr.ID, err) ActUserID: doer.ID,
ActUser: doer,
OpType: models.ActionMergePullRequest,
Content: fmt.Sprintf("%d|%s", pr.Issue.Index, pr.Issue.Title),
RepoID: pr.Issue.Repo.ID,
Repo: pr.Issue.Repo,
IsPrivate: pr.Issue.Repo.IsPrivate,
}); err != nil {
log.Error("NotifyWatchers [%d]: %v", pr.ID, err)
} }
// Reset cached commit count // Reset cached commit count

View File

@ -6,30 +6,144 @@
package pull package pull
import ( import (
"bytes"
"fmt"
"strings"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/notification" "code.gitea.io/gitea/modules/notification"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/services/gitdiff"
) )
// CreateReview creates a new review based on opts // CreateCodeComment creates a comment on the code line
func CreateReview(opts models.CreateReviewOptions) (*models.Review, error) { func CreateCodeComment(doer *models.User, issue *models.Issue, line int64, content string, treePath string, isReview bool, replyReviewID int64) (*models.Comment, error) {
review, err := models.CreateReview(opts) // It's not a review, maybe a reply to a review comment or a single comment.
if !isReview {
if err := issue.LoadRepo(); err != nil {
return nil, err
}
comment, err := createCodeComment(
doer,
issue.Repo,
issue,
content,
treePath,
line,
replyReviewID,
)
if err != nil {
return nil, err
}
notification.NotifyCreateIssueComment(doer, issue.Repo, issue, comment)
return comment, nil
}
review, err := models.GetCurrentReview(doer, issue)
if err != nil {
if !models.IsErrReviewNotExist(err) {
return nil, err
}
review, err = models.CreateReview(models.CreateReviewOptions{
Type: models.ReviewTypePending,
Reviewer: doer,
Issue: issue,
})
if err != nil {
return nil, err
}
}
comment, err := createCodeComment(
doer,
issue.Repo,
issue,
content,
treePath,
line,
review.ID,
)
if err != nil { if err != nil {
return nil, err return nil, err
} }
notification.NotifyPullRequestReview(review.Issue.PullRequest, review, nil) // NOTICE: it's a pending review, so the notifications will not be fired until user submit review.
return review, nil return comment, nil
} }
// UpdateReview updates a review // createCodeComment creates a plain code comment at the specified line / path
func UpdateReview(review *models.Review) error { func createCodeComment(doer *models.User, repo *models.Repository, issue *models.Issue, content, treePath string, line, reviewID int64) (*models.Comment, error) {
err := models.UpdateReview(review) var commitID, patch string
if err := issue.LoadPullRequest(); err != nil {
return nil, fmt.Errorf("GetPullRequestByIssueID: %v", err)
}
pr := issue.PullRequest
if err := pr.GetBaseRepo(); err != nil {
return nil, fmt.Errorf("GetHeadRepo: %v", err)
}
gitRepo, err := git.OpenRepository(pr.BaseRepo.RepoPath())
if err != nil { if err != nil {
return err return nil, fmt.Errorf("OpenRepository: %v", err)
}
defer gitRepo.Close()
// FIXME validate treePath
// Get latest commit referencing the commented line
// No need for get commit for base branch changes
if line > 0 {
commit, err := gitRepo.LineBlame(pr.GetGitRefName(), gitRepo.Path, treePath, uint(line))
if err == nil {
commitID = commit.ID.String()
} else if !strings.Contains(err.Error(), "exit status 128 - fatal: no such path") {
return nil, fmt.Errorf("LineBlame[%s, %s, %s, %d]: %v", pr.GetGitRefName(), gitRepo.Path, treePath, line, err)
}
} }
notification.NotifyPullRequestReview(review.Issue.PullRequest, review, nil) // Only fetch diff if comment is review comment
if reviewID != 0 {
return nil headCommitID, err := gitRepo.GetRefCommitID(pr.GetGitRefName())
if err != nil {
return nil, fmt.Errorf("GetRefCommitID[%s]: %v", pr.GetGitRefName(), err)
}
patchBuf := new(bytes.Buffer)
if err := gitdiff.GetRawDiffForFile(gitRepo.Path, pr.MergeBase, headCommitID, gitdiff.RawDiffNormal, treePath, patchBuf); err != nil {
return nil, fmt.Errorf("GetRawDiffForLine[%s, %s, %s, %s]: %v", err, gitRepo.Path, pr.MergeBase, headCommitID, treePath)
}
patch = gitdiff.CutDiffAroundLine(patchBuf, int64((&models.Comment{Line: line}).UnsignedLine()), line < 0, setting.UI.CodeCommentLines)
}
return models.CreateComment(&models.CreateCommentOptions{
Type: models.CommentTypeCode,
Doer: doer,
Repo: repo,
Issue: issue,
Content: content,
LineNum: line,
TreePath: treePath,
CommitSHA: commitID,
ReviewID: reviewID,
Patch: patch,
NoAction: true,
})
}
// SubmitReview creates a review out of the existing pending review or creates a new one if no pending review exist
func SubmitReview(doer *models.User, issue *models.Issue, reviewType models.ReviewType, content string) (*models.Review, *models.Comment, error) {
review, comm, err := models.SubmitReview(doer, issue, reviewType, content)
if err != nil {
return nil, nil, err
}
pr, err := issue.GetPullRequest()
if err != nil {
return nil, nil, err
}
notification.NotifyPullRequestReview(pr, review, comm)
return review, comm, nil
} }

View File

@ -0,0 +1,16 @@
// 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 repository
import (
"path/filepath"
"testing"
"code.gitea.io/gitea/models"
)
func TestMain(m *testing.M) {
models.MainTest(m, filepath.Join("..", ".."))
}

View File

@ -0,0 +1,54 @@
// 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 repository
import (
"fmt"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/notification"
)
// TransferOwnership transfers all corresponding setting from old user to new one.
func TransferOwnership(doer *models.User, newOwnerName string, repo *models.Repository) error {
if err := repo.GetOwner(); err != nil {
return err
}
oldOwner := repo.Owner
if err := models.TransferOwnership(doer, newOwnerName, repo); err != nil {
return err
}
if err := models.NewRepoRedirect(oldOwner.ID, repo.ID, repo.Name, repo.Name); err != nil {
return fmt.Errorf("NewRepoRedirect: %v", err)
}
notification.NotifyTransferRepository(doer, repo, oldOwner.Name)
return nil
}
// ChangeRepositoryName changes all corresponding setting from old repository name to new one.
func ChangeRepositoryName(doer *models.User, repo *models.Repository, newRepoName string) error {
oldRepoName := repo.Name
if err := models.ChangeRepositoryName(doer, repo, newRepoName); err != nil {
return err
}
if err := repo.GetOwner(); err != nil {
return err
}
if err := models.NewRepoRedirect(repo.Owner.ID, repo.ID, oldRepoName, newRepoName); err != nil {
return err
}
notification.NotifyRenameRepository(doer, repo, oldRepoName)
return nil
}

View File

@ -0,0 +1,50 @@
// 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 repository
import (
"sync"
"testing"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/notification"
"code.gitea.io/gitea/modules/notification/action"
"github.com/stretchr/testify/assert"
"github.com/unknwon/com"
)
var notifySync sync.Once
func registerNotifier() {
notifySync.Do(func() {
notification.RegisterNotifier(action.NewNotifier())
})
}
func TestTransferOwnership(t *testing.T) {
registerNotifier()
assert.NoError(t, models.PrepareTestDatabase())
doer := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)
repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 3}).(*models.Repository)
repo.Owner = models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
assert.NoError(t, TransferOwnership(doer, "user2", repo))
transferredRepo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 3}).(*models.Repository)
assert.EqualValues(t, 2, transferredRepo.OwnerID)
assert.False(t, com.IsExist(models.RepoPath("user3", "repo3")))
assert.True(t, com.IsExist(models.RepoPath("user2", "repo3")))
models.AssertExistsAndLoadBean(t, &models.Action{
OpType: models.ActionTransferRepo,
ActUserID: 2,
RepoID: 3,
Content: "user3/repo3",
})
models.CheckConsistencyFor(t, &models.Repository{}, &models.User{}, &models.Team{})
}

View File

@ -26,7 +26,6 @@
{{if .RequireGitGraph}} {{if .RequireGitGraph}}
<!-- graph --> <!-- graph -->
<script src="{{StaticUrlPrefix}}/vendor/plugins/gitgraph/gitgraph.js"></script> <script src="{{StaticUrlPrefix}}/vendor/plugins/gitgraph/gitgraph.js"></script>
<script src="{{StaticUrlPrefix}}/js/draw.js"></script>
{{end}} {{end}}
<!-- Third-party libraries --> <!-- Third-party libraries -->
@ -117,7 +116,7 @@
} }
</script> </script>
{{end}} {{end}}
<script src="{{StaticUrlPrefix}}/vendor/plugins/emojify/emojify.min.js"></script> <script src="{{StaticUrlPrefix}}/vendor/plugins/emojify/emojify.custom.js"></script>
<script src="{{StaticUrlPrefix}}/vendor/plugins/clipboard/clipboard.min.js"></script> <script src="{{StaticUrlPrefix}}/vendor/plugins/clipboard/clipboard.min.js"></script>
<script src="{{StaticUrlPrefix}}/vendor/plugins/vue/vue.min.js"></script> <script src="{{StaticUrlPrefix}}/vendor/plugins/vue/vue.min.js"></script>
@ -129,7 +128,7 @@
<script src="{{StaticUrlPrefix}}/vendor/plugins/moment/moment.min.js" charset="utf-8"></script> <script src="{{StaticUrlPrefix}}/vendor/plugins/moment/moment.min.js" charset="utf-8"></script>
<script src="{{StaticUrlPrefix}}/vendor/plugins/vue-calendar-heatmap/vue-calendar-heatmap.browser.js" charset="utf-8"></script> <script src="{{StaticUrlPrefix}}/vendor/plugins/vue-calendar-heatmap/vue-calendar-heatmap.browser.js" charset="utf-8"></script>
<script type="text/javascript"> <script type="text/javascript">
initHeatmap('user-heatmap', '{{.HeatmapUser}}'); window.initHeatmap('user-heatmap', '{{.HeatmapUser}}');
</script> </script>
{{end}} {{end}}
{{template "custom/footer" .}} {{template "custom/footer" .}}

View File

@ -7,11 +7,10 @@ var urlsToCache = [
'{{StaticUrlPrefix}}/vendor/plugins/semantic/semantic.min.js', '{{StaticUrlPrefix}}/vendor/plugins/semantic/semantic.min.js',
'{{StaticUrlPrefix}}/js/index.js?v={{MD5 AppVer}}', '{{StaticUrlPrefix}}/js/index.js?v={{MD5 AppVer}}',
'{{StaticUrlPrefix}}/js/semantic.dropdown.custom.js?v={{MD5 AppVer}}', '{{StaticUrlPrefix}}/js/semantic.dropdown.custom.js?v={{MD5 AppVer}}',
'{{StaticUrlPrefix}}/js/draw.js',
'{{StaticUrlPrefix}}/vendor/plugins/clipboard/clipboard.min.js', '{{StaticUrlPrefix}}/vendor/plugins/clipboard/clipboard.min.js',
'{{StaticUrlPrefix}}/vendor/plugins/gitgraph/gitgraph.js', '{{StaticUrlPrefix}}/vendor/plugins/gitgraph/gitgraph.js',
'{{StaticUrlPrefix}}/vendor/plugins/vue/vue.min.js', '{{StaticUrlPrefix}}/vendor/plugins/vue/vue.min.js',
'{{StaticUrlPrefix}}/vendor/plugins/emojify/emojify.min.js', '{{StaticUrlPrefix}}/vendor/plugins/emojify/emojify.custom.js',
'{{StaticUrlPrefix}}/vendor/plugins/cssrelpreload/loadCSS.min.js', '{{StaticUrlPrefix}}/vendor/plugins/cssrelpreload/loadCSS.min.js',
'{{StaticUrlPrefix}}/vendor/plugins/cssrelpreload/cssrelpreload.min.js', '{{StaticUrlPrefix}}/vendor/plugins/cssrelpreload/cssrelpreload.min.js',
'{{StaticUrlPrefix}}/vendor/plugins/dropzone/dropzone.js', '{{StaticUrlPrefix}}/vendor/plugins/dropzone/dropzone.js',

View File

@ -0,0 +1,50 @@
{{if $.IsSplitStyle}}
{{range $k, $line := $.section.Lines}}
<tr class="{{DiffLineTypeToStr .GetType}}-code nl-{{$k}} ol-{{$k}}">
{{if eq .GetType 4}}
<td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}">
{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5) }}
<i class="ui blob-excerpt fa fa-caret-down" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=down" data-anchor="{{$.Anchor}}"></i>
{{end}}
{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4) }}
<i class="ui blob-excerpt fa fa-caret-up" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=up" data-anchor="{{$.Anchor}}"></i>
{{end}}
{{if or (eq $line.GetExpandDirection 2)}}
<i class="ui blob-excerpt octicon octicon-fold" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=" data-anchor="{{$.Anchor}}"></i>
{{end}}
</td>
<td colspan="5" class="lines-code lines-code-old "><span class="mono wrap{{if $.highlightClass}} language-{{$.highlightClass}}{{else}} nohighlight{{end}}">{{$.section.GetComputedInlineDiffFor $line}}</span></td>
{{else}}
<td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{Sha1 $.fileName}}L{{$line.LeftIdx}}{{end}}"></span></td>
<td class="blob-excerpt lines-type-marker lines-type-marker-old">{{if $line.LeftIdx}}<span class="mono" data-type-marker=""></span>{{end}}</td>
<td class="blob-excerpt lines-code lines-code-old halfwidth"><span class="mono wrap{{if $.highlightClass}} language-{{$.highlightClass}}{{else}} nohighlight{{end}}">{{if $line.LeftIdx}}{{$.section.GetComputedInlineDiffFor $line}}{{end}}</span></td>
<td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{Sha1 $.fileName}}R{{$line.RightIdx}}{{end}}"></span></td>
<td class="blob-excerpt lines-type-marker lines-type-marker-new">{{if $line.RightIdx}}<span class="mono" data-type-marker=""></span>{{end}}</td>
<td class="blob-excerpt lines-code lines-code-new halfwidth"><span class="mono wrap{{if $.highlightClass}} language-{{$.highlightClass}}{{else}} nohighlight{{end}}">{{if $line.RightIdx}}{{$.section.GetComputedInlineDiffFor $line}}{{end}}</span></td>
{{end}}
</tr>
{{end}}
{{else}}
{{range $k, $line := $.section.Lines}}
<tr class="{{DiffLineTypeToStr .GetType}}-code nl-{{$k}} ol-{{$k}}">
{{if eq .GetType 4}}
<td colspan="2" class="lines-num">
{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4) }}
<i class="ui blob-excerpt fa fa-caret-up" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=up" data-anchor="{{$.Anchor}}"></i>
{{end}}
{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5) }}
<i class="ui blob-excerpt fa fa-caret-down" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=down" data-anchor="{{$.Anchor}}"></i>
{{end}}
{{if or (eq $line.GetExpandDirection 2)}}
<i class="ui blob-excerpt octicon octicon-fold" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=" data-anchor="{{$.Anchor}}"></i>
{{end}}
</td>
{{else}}
<td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{Sha1 $.fileName}}L{{$line.LeftIdx}}{{end}}"></span></td>
<td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{Sha1 $.fileName}}R{{$line.RightIdx}}{{end}}"></span></td>
{{end}}
<td class="blob-excerpt lines-type-marker"><span class="mono" data-type-marker="{{$line.GetLineTypeMarker}}"></span></td>
<td class="blob-excerpt lines-code{{if (not $line.RightIdx)}} lines-code-old{{end}}"><span class="mono wrap{{if $.highlightClass}} language-{{$.highlightClass}}{{else}} nohighlight{{end}}">{{$.section.GetComputedInlineDiffFor $line}}</span></td>
</tr>
{{end}}
{{end}}

View File

@ -81,6 +81,15 @@
{{else}} {{else}}
<div class="diff-file-box diff-box file-content {{TabSizeClass $.Editorconfig $file.Name}}" id="diff-{{.Index}}"> <div class="diff-file-box diff-box file-content {{TabSizeClass $.Editorconfig $file.Name}}" id="diff-{{.Index}}">
<h4 class="ui top attached normal header"> <h4 class="ui top attached normal header">
{{$isImage := false}}
{{if $file.IsDeleted}}
{{$isImage = (call $.IsImageFileInBase $file.Name)}}
{{else}}
{{$isImage = (call $.IsImageFileInHead $file.Name)}}
{{end}}
{{if or (not $file.IsBin) $isImage}}
<i class="ui fold-code grey fa fa-chevron-down"></i>
{{end}}
<div class="diff-counter count"> <div class="diff-counter count">
{{if $file.IsBin}} {{if $file.IsBin}}
{{$.i18n.Tr "repo.diff.bin"}} {{$.i18n.Tr "repo.diff.bin"}}
@ -104,12 +113,6 @@
</h4> </h4>
<div class="ui attached unstackable table segment"> <div class="ui attached unstackable table segment">
{{if ne $file.Type 4}} {{if ne $file.Type 4}}
{{$isImage := false}}
{{if $file.IsDeleted}}
{{$isImage = (call $.IsImageFileInBase $file.Name)}}
{{else}}
{{$isImage = (call $.IsImageFileInHead $file.Name)}}
{{end}}
<div class="file-body file-code code-view code-diff {{if $.IsSplitStyle}}code-diff-split{{else}}code-diff-unified{{end}}"> <div class="file-body file-code code-view code-diff {{if $.IsSplitStyle}}code-diff-split{{else}}code-diff-unified{{end}}">
<table> <table>
<tbody> <tbody>
@ -121,12 +124,27 @@
{{range $j, $section := $file.Sections}} {{range $j, $section := $file.Sections}}
{{range $k, $line := $section.Lines}} {{range $k, $line := $section.Lines}}
<tr class="{{DiffLineTypeToStr .GetType}}-code nl-{{$k}} ol-{{$k}}"> <tr class="{{DiffLineTypeToStr .GetType}}-code nl-{{$k}} ol-{{$k}}">
<td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{Sha1 $file.Name}}L{{$line.LeftIdx}}{{end}}"></span></td> {{if eq .GetType 4}}
<td class="lines-type-marker lines-type-marker-old">{{if $line.LeftIdx}}<span class="mono" data-type-marker="{{$line.GetLineTypeMarker}}"></span>{{end}}</td> <td class="lines-num lines-num-old">
<td class="lines-code lines-code-old halfwidth">{{if and $.SignedUserID $line.CanComment $.PageIsPullFiles (not (eq .GetType 2))}}<a class="ui green button add-code-comment add-code-comment-left" data-path="{{$file.Name}}" data-side="left" data-idx="{{$line.LeftIdx}}">+</a>{{end}}<span class="mono wrap{{if $highlightClass}} language-{{$highlightClass}}{{else}} nohighlight{{end}}">{{if $line.LeftIdx}}{{$section.GetComputedInlineDiffFor $line}}{{end}}</span></td> {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5) }}
<td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{Sha1 $file.Name}}R{{$line.RightIdx}}{{end}}"></span></td> <i class="ui blob-excerpt fa fa-caret-down" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=down" data-anchor="diff-{{Sha1 $file.Name}}K{{$line.SectionInfo.RightIdx}}"></i>
<td class="lines-type-marker lines-type-marker-new">{{if $line.RightIdx}}<span class="mono" data-type-marker="{{$line.GetLineTypeMarker}}"></span>{{end}}</td> {{end}}
<td class="lines-code lines-code-new halfwidth">{{if and $.SignedUserID $line.CanComment $.PageIsPullFiles (not (eq .GetType 3))}}<a class="ui green button add-code-comment add-code-comment-right" data-path="{{$file.Name}}" data-side="right" data-idx="{{$line.RightIdx}}">+</a>{{end}}<span class="mono wrap{{if $highlightClass}} language-{{$highlightClass}}{{else}} nohighlight{{end}}">{{if $line.RightIdx}}{{$section.GetComputedInlineDiffFor $line}}{{end}}</span></td> {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4) }}
<i class="ui blob-excerpt fa fa-caret-up" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=up" data-anchor="diff-{{Sha1 $file.Name}}K{{$line.SectionInfo.RightIdx}}"></i>
{{end}}
{{if or (eq $line.GetExpandDirection 2)}}
<i class="ui blob-excerpt octicon octicon-fold" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=" data-anchor="diff-{{Sha1 $file.Name}}K{{$line.SectionInfo.RightIdx}}"></i>
{{end}}
</td>
<td colspan="5" class="lines-code lines-code-old "><span class="mono wrap{{if $highlightClass}} language-{{$highlightClass}}{{else}} nohighlight{{end}}">{{$section.GetComputedInlineDiffFor $line}}</span></td>
{{else}}
<td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{Sha1 $file.Name}}L{{$line.LeftIdx}}{{end}}"></span></td>
<td class="lines-type-marker lines-type-marker-old">{{if $line.LeftIdx}}<span class="mono" data-type-marker="{{$line.GetLineTypeMarker}}"></span>{{end}}</td>
<td class="lines-code lines-code-old halfwidth">{{if and $.SignedUserID $line.CanComment $.PageIsPullFiles (not (eq .GetType 2))}}<a class="ui green button add-code-comment add-code-comment-left" data-path="{{$file.Name}}" data-side="left" data-idx="{{$line.LeftIdx}}">+</a>{{end}}<span class="mono wrap{{if $highlightClass}} language-{{$highlightClass}}{{else}} nohighlight{{end}}">{{if $line.LeftIdx}}{{$section.GetComputedInlineDiffFor $line}}{{end}}</span></td>
<td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{Sha1 $file.Name}}R{{$line.RightIdx}}{{end}}"></span></td>
<td class="lines-type-marker lines-type-marker-new">{{if $line.RightIdx}}<span class="mono" data-type-marker="{{$line.GetLineTypeMarker}}"></span>{{end}}</td>
<td class="lines-code lines-code-new halfwidth">{{if and $.SignedUserID $line.CanComment $.PageIsPullFiles (not (eq .GetType 3))}}<a class="ui green button add-code-comment add-code-comment-right" data-path="{{$file.Name}}" data-side="right" data-idx="{{$line.RightIdx}}">+</a>{{end}}<span class="mono wrap{{if $highlightClass}} language-{{$highlightClass}}{{else}} nohighlight{{end}}">{{if $line.RightIdx}}{{$section.GetComputedInlineDiffFor $line}}{{end}}</span></td>
{{end}}
</tr> </tr>
{{if gt (len $line.Comments) 0}} {{if gt (len $line.Comments) 0}}
<tr class="add-code-comment"> <tr class="add-code-comment">

View File

@ -39,7 +39,7 @@
{{end}} {{end}}
{{end}} {{end}}
{{if or (not $.HasComments) $.hidden}} {{if or (not $.HasComments) $.hidden}}
<button type="button" class="ui submit tiny basic button btn-cancel" onclick="cancelCodeComment(this);">{{$.root.i18n.Tr "cancel"}}</button> <button type="button" class="ui submit tiny basic button btn-cancel" onclick="window.cancelCodeComment(this);">{{$.root.i18n.Tr "cancel"}}</button>
{{end}} {{end}}
</div> </div>
</div> </div>

View File

@ -4,9 +4,17 @@
{{range $k, $line := $section.Lines}} {{range $k, $line := $section.Lines}}
<tr class="{{DiffLineTypeToStr .GetType}}-code nl-{{$k}} ol-{{$k}}"> <tr class="{{DiffLineTypeToStr .GetType}}-code nl-{{$k}} ol-{{$k}}">
{{if eq .GetType 4}} {{if eq .GetType 4}}
<td colspan="2" class="lines-num"> <td colspan="2" class="lines-num">
{{/* {{if gt $j 0}}<span class="fold octicon octicon-fold"></span>{{end}} */}} {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5) }}
</td> <i class="ui blob-excerpt fa fa-caret-down" data-url="{{$.root.RepoLink}}/blob_excerpt/{{$.root.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=down" data-anchor="diff-{{Sha1 $file.Name}}K{{$line.SectionInfo.RightIdx}}"></i>
{{end}}
{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4) }}
<i class="ui blob-excerpt fa fa-caret-up" data-url="{{$.root.RepoLink}}/blob_excerpt/{{$.root.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=up" data-anchor="diff-{{Sha1 $file.Name}}K{{$line.SectionInfo.RightIdx}}"></i>
{{end}}
{{if or (eq $line.GetExpandDirection 2)}}
<i class="ui blob-excerpt octicon octicon-fold" data-url="{{$.root.RepoLink}}/blob_excerpt/{{$.root.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=" data-anchor="diff-{{Sha1 $file.Name}}K{{$line.SectionInfo.RightIdx}}"></i>
{{end}}
</td>
{{else}} {{else}}
<td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{Sha1 $file.Name}}L{{$line.LeftIdx}}{{end}}"></span></td> <td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{Sha1 $file.Name}}L{{$line.LeftIdx}}{{end}}"></span></td>
<td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{Sha1 $file.Name}}R{{$line.RightIdx}}{{end}}"></span></td> <td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{Sha1 $file.Name}}R{{$line.RightIdx}}{{end}}"></span></td>

View File

@ -155,8 +155,8 @@
</form> </form>
{{if $.IsStopwatchRunning}} {{if $.IsStopwatchRunning}}
<div class="ui buttons fluid stop-cancel"> <div class="ui buttons fluid stop-cancel">
<button onclick="this.disabled=true;toggleStopwatch()" class="ui button stop">{{.i18n.Tr "repo.issues.stop_tracking"}}</button> <button onclick="this.disabled=true;window.toggleStopwatch()" class="ui button stop">{{.i18n.Tr "repo.issues.stop_tracking"}}</button>
<button onclick="this.disabled=true;cancelStopwatch()" class="ui negative button cancel">{{.i18n.Tr "repo.issues.cancel_tracking"}}</button> <button onclick="this.disabled=true;window.cancelStopwatch()" class="ui negative button cancel">{{.i18n.Tr "repo.issues.cancel_tracking"}}</button>
</div> </div>
{{else}} {{else}}
{{if .HasUserStopwatch}} {{if .HasUserStopwatch}}
@ -165,8 +165,8 @@
</div> </div>
{{end}} {{end}}
<div class="ui buttons two fluid start-add"> <div class="ui buttons two fluid start-add">
<button onclick="this.disabled=true;toggleStopwatch()" class="ui button poping up start" data-content='{{.i18n.Tr "repo.issues.start_tracking"}}' data-position="top center" data-variation="small inverted">{{.i18n.Tr "repo.issues.start_tracking_short"}}</button> <button onclick="this.disabled=true;window.toggleStopwatch()" class="ui button poping up start" data-content='{{.i18n.Tr "repo.issues.start_tracking"}}' data-position="top center" data-variation="small inverted">{{.i18n.Tr "repo.issues.start_tracking_short"}}</button>
<button onclick="timeAddManual()" class="ui button green poping up add-time" data-content='{{.i18n.Tr "repo.issues.add_time"}}' data-position="top center" data-variation="small inverted">{{.i18n.Tr "repo.issues.add_time_short"}}</button> <button onclick="window.timeAddManual()" class="ui button green poping up add-time" data-content='{{.i18n.Tr "repo.issues.add_time"}}' data-position="top center" data-variation="small inverted">{{.i18n.Tr "repo.issues.add_time_short"}}</button>
<div class="ui mini modal"> <div class="ui mini modal">
<div class="header">{{.i18n.Tr "repo.issues.add_time"}}</div> <div class="header">{{.i18n.Tr "repo.issues.add_time"}}</div>
<div class="content"> <div class="content">
@ -225,8 +225,8 @@
{{end}} {{end}}
{{if and .IsIssueWriter (not .Repository.IsArchived)}} {{if and .IsIssueWriter (not .Repository.IsArchived)}}
<br/> <br/>
<a style="cursor:pointer;" onclick="toggleDeadlineForm();"><i class="edit icon"></i>{{$.i18n.Tr "repo.issues.due_date_form_edit"}}</a> - <a style="cursor:pointer;" onclick="window.toggleDeadlineForm();"><i class="edit icon"></i>{{$.i18n.Tr "repo.issues.due_date_form_edit"}}</a> -
<a style="cursor:pointer;" onclick="updateDeadline('');"><i class="remove icon"></i>{{$.i18n.Tr "repo.issues.due_date_form_remove"}}</a> <a style="cursor:pointer;" onclick="window.updateDeadline('');"><i class="remove icon"></i>{{$.i18n.Tr "repo.issues.due_date_form_remove"}}</a>
{{end}} {{end}}
</p> </p>
{{else}} {{else}}
@ -235,7 +235,7 @@
{{if and .IsIssueWriter (not .Repository.IsArchived)}} {{if and .IsIssueWriter (not .Repository.IsArchived)}}
<div {{if ne .Issue.DeadlineUnix 0}} style="display: none;"{{end}} id="deadlineForm"> <div {{if ne .Issue.DeadlineUnix 0}} style="display: none;"{{end}} id="deadlineForm">
<form class="ui fluid action input" action="{{AppSubUrl}}/api/v1/repos/{{.Repository.Owner.Name}}/{{.Repository.Name}}/issues/{{.Issue.Index}}" method="post" id="update-issue-deadline-form" onsubmit="setDeadline();return false;"> <form class="ui fluid action input" action="{{AppSubUrl}}/api/v1/repos/{{.Repository.Owner.Name}}/{{.Repository.Name}}/issues/{{.Issue.Index}}" method="post" id="update-issue-deadline-form" onsubmit="window.setDeadline();return false;">
{{$.CsrfTokenHtml}} {{$.CsrfTokenHtml}}
<input required placeholder="{{.i18n.Tr "repo.issues.due_date_form"}}" {{if gt .Issue.DeadlineUnix 0}}value="{{.Issue.DeadlineUnix.Format "2006-01-02"}}"{{end}} type="date" name="deadlineDate" id="deadlineDate"> <input required placeholder="{{.i18n.Tr "repo.issues.due_date_form"}}" {{if gt .Issue.DeadlineUnix 0}}value="{{.Issue.DeadlineUnix.Format "2006-01-02"}}"{{end}} type="date" name="deadlineDate" id="deadlineDate">
<button class="ui green icon button"> <button class="ui green icon button">
@ -280,7 +280,7 @@
<div class="text small">{{.Repository.OwnerName}}/{{.Repository.Name}}</div> <div class="text small">{{.Repository.OwnerName}}/{{.Repository.Name}}</div>
<div class="ui transparent label right floated nopadding"> <div class="ui transparent label right floated nopadding">
{{if and $.CanCreateIssueDependencies (not $.Repository.IsArchived)}} {{if and $.CanCreateIssueDependencies (not $.Repository.IsArchived)}}
<a class="delete-dependency-button" onclick="deleteDependencyModal({{.Issue.ID}}, 'blocking');" <a class="delete-dependency-button" onclick="window.deleteDependencyModal({{.Issue.ID}}, 'blocking');"
data-tooltip="{{$.i18n.Tr "repo.issues.dependency.remove_info"}}" data-inverted=""> data-tooltip="{{$.i18n.Tr "repo.issues.dependency.remove_info"}}" data-inverted="">
<i class="delete icon text red nopadding nomargin"></i> <i class="delete icon text red nopadding nomargin"></i>
</a> </a>
@ -307,7 +307,7 @@
<div class="text small">{{.Repository.OwnerName}}/{{.Repository.Name}}</div> <div class="text small">{{.Repository.OwnerName}}/{{.Repository.Name}}</div>
<div class="ui transparent label right floated nopadding"> <div class="ui transparent label right floated nopadding">
{{if and $.CanCreateIssueDependencies (not $.Repository.IsArchived)}} {{if and $.CanCreateIssueDependencies (not $.Repository.IsArchived)}}
<a class="delete-dependency-button" onclick="deleteDependencyModal({{.Issue.ID}}, 'blockedBy');" <a class="delete-dependency-button" onclick="window.deleteDependencyModal({{.Issue.ID}}, 'blockedBy');"
data-tooltip="{{$.i18n.Tr "repo.issues.dependency.remove_info"}}" data-inverted=""> data-tooltip="{{$.i18n.Tr "repo.issues.dependency.remove_info"}}" data-inverted="">
<i class="delete icon text red nopadding nomargin"></i> <i class="delete icon text red nopadding nomargin"></i>
</a> </a>

View File

@ -65,7 +65,7 @@
title="{{$provider.DisplayName}}{{if eq $provider.Name "openidConnect"}} ({{$key}}){{end}}" title="{{$provider.DisplayName}}{{if eq $provider.Name "openidConnect"}} ({{$key}}){{end}}"
class="{{$provider.Name}}" class="{{$provider.Name}}"
src="{{AppSubUrl}}{{$provider.Image}}" src="{{AppSubUrl}}{{$provider.Image}}"
onclick="onOAuthLoginClick()" onclick="window.onOAuthLoginClick()"
></a> ></a>
{{end}} {{end}}
</div> </div>

View File

@ -61,6 +61,12 @@
{{$.i18n.Tr "action.mirror_sync_create" .GetRepoLink .GetBranch .ShortRepoPath | Str2html}} {{$.i18n.Tr "action.mirror_sync_create" .GetRepoLink .GetBranch .ShortRepoPath | Str2html}}
{{else if eq .GetOpType 20}} {{else if eq .GetOpType 20}}
{{$.i18n.Tr "action.mirror_sync_delete" .GetRepoLink .GetBranch .ShortRepoPath | Str2html}} {{$.i18n.Tr "action.mirror_sync_delete" .GetRepoLink .GetBranch .ShortRepoPath | Str2html}}
{{else if eq .GetOpType 21}}
{{ $index := index .GetIssueInfos 0}}
{{$.i18n.Tr "action.approve_pull_request" .GetRepoLink $index .ShortRepoPath | Str2html}}
{{else if eq .GetOpType 22}}
{{ $index := index .GetIssueInfos 0}}
{{$.i18n.Tr "action.reject_pull_request" .GetRepoLink $index .ShortRepoPath | Str2html}}
{{end}} {{end}}
</p> </p>
{{if or (eq .GetOpType 5) (eq .GetOpType 18)}} {{if or (eq .GetOpType 5) (eq .GetOpType 18)}}
@ -80,7 +86,7 @@
<span class="text truncate issue title has-emoji">{{index .GetIssueInfos 1}}</span> <span class="text truncate issue title has-emoji">{{index .GetIssueInfos 1}}</span>
{{else if eq .GetOpType 7}} {{else if eq .GetOpType 7}}
<span class="text truncate issue title has-emoji">{{index .GetIssueInfos 1}}</span> <span class="text truncate issue title has-emoji">{{index .GetIssueInfos 1}}</span>
{{else if eq .GetOpType 10}} {{else if or (eq .GetOpType 10) (eq .GetOpType 21) (eq .GetOpType 22)}}
<a href="{{.GetCommentLink}}" class="text truncate issue title has-emoji">{{.GetIssueTitle}}</a> <a href="{{.GetCommentLink}}" class="text truncate issue title has-emoji">{{.GetIssueTitle}}</a>
<p class="text light grey has-emoji">{{index .GetIssueInfos 1}}</p> <p class="text light grey has-emoji">{{index .GetIssueInfos 1}}</p>
{{else if eq .GetOpType 11}} {{else if eq .GetOpType 11}}

15
web_src/js/draw.js Normal file
View File

@ -0,0 +1,15 @@
/* globals gitGraph */
$(() => {
const graphList = [];
if (!document.getElementById('graph-canvas')) {
return;
}
$('#graph-raw-list li span.node-relation').each(function () {
graphList.push($(this).text());
});
gitGraph(document.getElementById('graph-canvas'), graphList);
});

3309
web_src/js/index.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -2438,6 +2438,10 @@ tbody.commit-list {
padding-bottom: 8px; padding-bottom: 8px;
} }
td.blob-excerpt {
background-color: #fafafa;
}
.issue-keyword { .issue-keyword {
border-bottom: 1px dotted #959da5; border-bottom: 1px dotted #959da5;
display: inline-block; display: inline-block;

View File

@ -108,3 +108,26 @@
font: 12px @monospaced-fonts, monospace; font: 12px @monospaced-fonts, monospace;
color: rgba(0, 0, 0, 0.87); color: rgba(0, 0, 0, 0.87);
} }
.ui.fold-code {
margin-right: 1em;
padding-left: 5px;
cursor: pointer;
width: 22px;
font-size: 12px;
}
.ui.fold-code:hover {
color: #428bca;
}
.ui.blob-excerpt {
display: block;
line-height: 20px;
font-size: 16px;
cursor: pointer;
}
.ui.blob-excerpt:hover {
color: #428bca;
}

42
webpack.config.js Normal file
View File

@ -0,0 +1,42 @@
const path = require('path');
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
mode: 'production',
entry: {
index: ['./web_src/js/index', './web_src/js/draw']
},
devtool: 'source-map',
output: {
path: path.resolve(__dirname, 'public/js'),
filename: 'index.js'
},
optimization: {
minimize: true,
minimizer: [new TerserPlugin({
sourceMap: true,
})],
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'entry',
corejs: 3,
}
]
]
}
}
}
]
}
};