mirror of
https://github.com/go-gitea/gitea
synced 2024-12-22 12:17:53 +01:00
Merge branch 'master' into refactor_issues-subscription
This commit is contained in:
commit
cd6f2bef54
@ -24,7 +24,7 @@ indent_size = 2
|
||||
|
||||
[*.js]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
indent_size = 2
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
|
40
.eslintrc
40
.eslintrc
@ -1,27 +1,51 @@
|
||||
root: true
|
||||
|
||||
extends:
|
||||
- eslint-config-airbnb-base
|
||||
- eslint:recommended
|
||||
|
||||
parserOptions:
|
||||
ecmaVersion: 2015
|
||||
ecmaVersion: 2020
|
||||
|
||||
env:
|
||||
browser: true
|
||||
jquery: true
|
||||
es6: true
|
||||
jquery: true
|
||||
node: true
|
||||
|
||||
globals:
|
||||
Clipboard: false
|
||||
CodeMirror: false
|
||||
emojify: false
|
||||
SimpleMDE: false
|
||||
Vue: false
|
||||
Dropzone: false
|
||||
u2fApi: false
|
||||
emojify: false
|
||||
hljs: false
|
||||
SimpleMDE: false
|
||||
u2fApi: false
|
||||
Vue: false
|
||||
|
||||
rules:
|
||||
no-unused-vars: [error, {args: all, argsIgnorePattern: ^_, varsIgnorePattern: ^_, ignoreRestSiblings: true}]
|
||||
prefer-const: [2, {destructuring: all}]
|
||||
camelcase: [0]
|
||||
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]
|
||||
one-var-declaration-per-line: [0]
|
||||
one-var: [0]
|
||||
prefer-const: [2, {destructuring: all}]
|
||||
prefer-destructuring: [0]
|
||||
radix: [2, as-needed]
|
||||
|
64
CHANGELOG.md
64
CHANGELOG.md
@ -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
|
||||
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
|
||||
* 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)
|
||||
* 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
|
||||
* 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)
|
||||
* Fix milestone close timestamp (#8728) (#8730)
|
||||
* 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)
|
||||
* Prevent .code-view from overriding font on icon fonts (#8614) (#8627)
|
||||
* 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 bug on FindExternalUsersByProvider (#8504)
|
||||
* 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)
|
||||
* Move migrating repository from frontend to backend (#6200)
|
||||
* 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
|
||||
* Latvian translation for home page (#8468)
|
||||
* 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)
|
||||
* Tweak label border CSS (#7739)
|
||||
* 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 Table Header (#7622)
|
||||
* [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)
|
||||
* 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
|
||||
* BREAKING
|
||||
* Hide some user information via API if user doesn't have enough permission (#8655) (#8658)
|
||||
|
3
Makefile
3
Makefile
@ -434,7 +434,8 @@ npm-update: npm-check
|
||||
|
||||
.PHONY: js
|
||||
js: npm
|
||||
npx eslint public/js
|
||||
npx eslint web_src/js webpack.config.js
|
||||
npx webpack
|
||||
|
||||
.PHONY: css
|
||||
css: npm
|
||||
|
25
cmd/hook.go
25
cmd/hook.go
@ -16,6 +16,7 @@ import (
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/private"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
@ -55,7 +56,13 @@ var (
|
||||
|
||||
func runHookPreReceive(c *cli.Context) error {
|
||||
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")
|
||||
@ -115,7 +122,13 @@ func runHookPreReceive(c *cli.Context) error {
|
||||
|
||||
func runHookUpdate(c *cli.Context) error {
|
||||
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")
|
||||
@ -125,7 +138,13 @@ func runHookUpdate(c *cli.Context) error {
|
||||
|
||||
func runHookPostReceive(c *cli.Context) error {
|
||||
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")
|
||||
|
@ -190,7 +190,7 @@ PROTOCOL = http
|
||||
DOMAIN = localhost
|
||||
ROOT_URL = %(PROTOCOL)s://%(DOMAIN)s:%(HTTP_PORT)s/
|
||||
; when STATIC_URL_PREFIX is empty it will follow APP_URL
|
||||
STATIC_URL_PREFIX =
|
||||
STATIC_URL_PREFIX =
|
||||
; The address to listen on. Either a IPv4/IPv6 address or the path to a unix socket.
|
||||
HTTP_ADDR = 0.0.0.0
|
||||
HTTP_PORT = 3000
|
||||
@ -383,6 +383,8 @@ MIN_PASSWORD_LENGTH = 6
|
||||
IMPORT_LOCAL_PATHS = false
|
||||
; Set to true to prevent all users (including admin) from creating custom git hooks
|
||||
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.
|
||||
;If left empty or no valid values are specified, the default values ("lower,upper,digit,spec") will be used.
|
||||
;Use "off" to disable checking.
|
||||
@ -515,9 +517,9 @@ SKIP_TLS_VERIFY = false
|
||||
; Number of history information in each page
|
||||
PAGING_NUM = 10
|
||||
; Proxy server URL, support http://, https//, socks://, blank will follow environment http_proxy/https_proxy
|
||||
PROXY_URL =
|
||||
PROXY_URL =
|
||||
; Comma separated list of host names requiring proxy. Glob patterns (*) are accepted; use ** to match all hosts.
|
||||
PROXY_HOSTS =
|
||||
PROXY_HOSTS =
|
||||
|
||||
[mailer]
|
||||
ENABLED = false
|
||||
|
1
docs/.gitignore
vendored
1
docs/.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
public/
|
||||
templates/swagger/v1_json.tmpl
|
||||
themes/
|
||||
resources/
|
||||
|
176
docs/assets/js/search.js
Normal file
176
docs/assets/js/search.js
Normal 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;
|
||||
}
|
@ -18,7 +18,13 @@ params:
|
||||
description: Git with a cup of tea
|
||||
author: The Gitea Authors
|
||||
website: https://docs.gitea.io
|
||||
version: 1.9.5
|
||||
version: 1.10.0
|
||||
|
||||
outputs:
|
||||
home:
|
||||
- HTML
|
||||
- RSS
|
||||
- JSON
|
||||
|
||||
menu:
|
||||
page:
|
||||
|
@ -244,6 +244,7 @@ relation to port exhaustion.
|
||||
authentication provided email.
|
||||
- `DISABLE_GIT_HOOKS`: **false**: Set to `true` to prevent all users (including admin) from creating custom
|
||||
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.
|
||||
- `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`)
|
||||
@ -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
|
||||
- `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.
|
||||
- `ALLOW_ONLY_EXTERNAL_REGISTRATION`: **false** Set to true to force registration only using third-party services.
|
||||
|
||||
## Webhook (`webhook`)
|
||||
|
||||
|
@ -2,12 +2,12 @@
|
||||
date: "2017-01-20T15:00:00+08:00"
|
||||
title: "Help"
|
||||
slug: "help"
|
||||
weight: 50
|
||||
weight: 5
|
||||
toc: false
|
||||
draft: false
|
||||
menu:
|
||||
sidebar:
|
||||
name: "Help"
|
||||
weight: 50
|
||||
weight: 5
|
||||
identifier: "help"
|
||||
---
|
||||
|
13
docs/content/doc/help.fr-fr.md
Normal file
13
docs/content/doc/help.fr-fr.md
Normal 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"
|
||||
---
|
@ -2,12 +2,12 @@
|
||||
date: "2017-01-20T15:00:00+08:00"
|
||||
title: "帮助"
|
||||
slug: "help"
|
||||
weight: 50
|
||||
weight: 5
|
||||
toc: false
|
||||
draft: false
|
||||
menu:
|
||||
sidebar:
|
||||
name: "帮助"
|
||||
weight: 50
|
||||
weight: 5
|
||||
identifier: "help"
|
||||
---
|
||||
|
13
docs/content/doc/help.zh-tw.md
Normal file
13
docs/content/doc/help.zh-tw.md
Normal 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"
|
||||
---
|
25
docs/content/doc/help/search.en-us.md
Normal file
25
docs/content/doc/help/search.en-us.md
Normal 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.
|
||||
|
25
docs/content/doc/help/search.fr-fr.md
Normal file
25
docs/content/doc/help/search.fr-fr.md
Normal 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.
|
||||
|
25
docs/content/doc/help/search.zh-cn.md
Normal file
25
docs/content/doc/help/search.zh-cn.md
Normal 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.
|
||||
|
25
docs/content/doc/help/search.zh-tw.md
Normal file
25
docs/content/doc/help/search.zh-tw.md
Normal 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.
|
||||
|
@ -40,7 +40,7 @@ To register Gitea as a Windows service, open a command prompt (cmd) as an Admini
|
||||
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.
|
||||
|
@ -18,7 +18,7 @@ menu:
|
||||
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.
|
||||
|
@ -18,7 +18,7 @@ menu:
|
||||
要注册为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 安装目录。
|
||||
|
@ -18,7 +18,7 @@ menu:
|
||||
要註冊為 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 安裝路徑。
|
||||
|
@ -51,6 +51,8 @@ services:
|
||||
- gitea
|
||||
volumes:
|
||||
- ./gitea:/data
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
ports:
|
||||
- "3000:3000"
|
||||
- "222:22"
|
||||
@ -80,6 +82,8 @@ services:
|
||||
- gitea
|
||||
volumes:
|
||||
- ./gitea:/data
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
ports:
|
||||
- - "3000:3000"
|
||||
- - "222:22"
|
||||
@ -115,6 +119,8 @@ services:
|
||||
- gitea
|
||||
volumes:
|
||||
- ./gitea:/data
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
ports:
|
||||
- "3000:3000"
|
||||
- "222:22"
|
||||
@ -163,6 +169,8 @@ services:
|
||||
- gitea
|
||||
volumes:
|
||||
- ./gitea:/data
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
ports:
|
||||
- "3000:3000"
|
||||
- "222:22"
|
||||
@ -209,6 +217,8 @@ services:
|
||||
volumes:
|
||||
- - ./gitea:/data
|
||||
+ - gitea:/data
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
ports:
|
||||
- "3000:3000"
|
||||
- "222:22"
|
||||
@ -306,6 +316,8 @@ UID/GID as the container values `USER_UID`/`USER_GID`. You should also create th
|
||||
- gitea
|
||||
volumes:
|
||||
- /var/lib/gitea:/data
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
ports:
|
||||
- "3000:3000"
|
||||
- "127.0.0.1:2222:22"
|
||||
|
5
docs/layouts/_default/index.json
Normal file
5
docs/layouts/_default/index.json
Normal 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 -}}
|
44
docs/layouts/doc/search.html
Normal file
44
docs/layouts/doc/search.html
Normal 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" . }}
|
2
docs/static/_headers
vendored
2
docs/static/_headers
vendored
@ -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-Xss-Protection: 1; mode=block
|
||||
X-Content-Type-Options: nosniff
|
||||
|
1
go.mod
1
go.mod
@ -80,7 +80,6 @@ require (
|
||||
github.com/prometheus/client_golang v1.1.0
|
||||
github.com/prometheus/procfs v0.0.4 // 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/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca // indirect
|
||||
github.com/satori/go.uuid v1.2.0
|
||||
|
45
go.sum
45
go.sum
@ -1,12 +1,10 @@
|
||||
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.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.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.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.45.0 h1:bALuGBSgE+BD4rxsopAYlqjcwqcQtye6pWG4bC3N/k0=
|
||||
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/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
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.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
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.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.4 h1:1TjOzrWkj+9BrjnM1yPAICbaoC0FyfD49oVkTBrSSa0=
|
||||
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/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/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.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.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
|
||||
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.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.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o=
|
||||
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.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.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.3 h1:jwIoahqCmaA5OBoc/B+1+Mu2L0Gr8xYQnbeyQEo/7b0=
|
||||
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.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.5 h1:h4Zk7oTfB3ZYM2oMNliQvL+3BrDstTIX8lqP7yaYCuI=
|
||||
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.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.3 h1:0XRyw8kguri6Yw4SxhsQA/atC88yqrk0+G4YhI2wabc=
|
||||
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.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.2 h1:clPGfBnJohokno0e+d7hs6Yocrzjlgz6EsQSDncCRnE=
|
||||
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/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/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.19.2 h1:ky5l57HjyVRrsJfd2+Ro5Z9PjGuKbsmftwyMtk8H7js=
|
||||
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/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.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.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||
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/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.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||
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 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.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.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
||||
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.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-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-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4=
|
||||
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/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/sessions v1.1.1 h1:YMDmfaK68mUixINzY/XjscuJ47uXFWSSHzFbBQM0PrE=
|
||||
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/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-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-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
|
||||
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/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/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/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/go.mod h1:AsLD6X7djzRIz4/RFZu8vwRL0VGjUvGZCCH1Nz0VdrU=
|
||||
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/go.mod h1:4BenG2/4GuRBDbVm/OPahDVqbrOemzpPiG5mi1iryBU=
|
||||
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.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w=
|
||||
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.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo=
|
||||
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_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-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-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
|
||||
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 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/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/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
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/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/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/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
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.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-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY=
|
||||
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/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.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
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.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
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 v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
||||
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/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
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.1 h1:Sq1fR+0c58RME5EoqKdjkiQAmPjmfHlZOoRI6fTUOcs=
|
||||
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-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-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
|
||||
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/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-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-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-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-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/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-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-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
||||
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-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-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-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
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.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.6.0 h1:Tfd7cKwKbFRsI8RMAD3oqqw7JPFRrvFlOsfbgVkjOOw=
|
||||
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.4 h1:WiKh4+/eMB2HaY7QhCfW/R7MuRAoA8QMCSJA6jP5/fo=
|
||||
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/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
|
||||
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-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
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.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
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.48.0 h1:URjZc+8ugRY5mL5uUeQH/a63JcHwdX9xZaWvmNWD7z8=
|
||||
gopkg.in/ini.v1 v1.48.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
|
@ -79,8 +79,10 @@ func allowLFSFilters() []string {
|
||||
return globalArgs
|
||||
}
|
||||
|
||||
func onGiteaRun(t *testing.T, callback func(*testing.T, *url.URL)) {
|
||||
prepareTestEnv(t, 1)
|
||||
func onGiteaRun(t *testing.T, callback func(*testing.T, *url.URL), prepare ...bool) {
|
||||
if len(prepare) == 0 || prepare[0] {
|
||||
prepareTestEnv(t, 1)
|
||||
}
|
||||
s := http.Server{
|
||||
Handler: mac,
|
||||
}
|
||||
|
@ -23,14 +23,7 @@ import (
|
||||
)
|
||||
|
||||
func TestGPGGit(t *testing.T) {
|
||||
onGiteaRun(t, testGPGGit)
|
||||
}
|
||||
|
||||
func testGPGGit(t *testing.T, u *url.URL) {
|
||||
username := "user2"
|
||||
baseAPITestContext := NewAPITestContext(t, username, "repo1")
|
||||
|
||||
u.Path = baseAPITestContext.GitPath()
|
||||
|
||||
// OK Set a new GPG home
|
||||
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"
|
||||
user := models.AssertExistsAndLoadBean(t, &models.User{Name: username}).(*models.User)
|
||||
|
||||
t.Run("Unsigned-Initial", func(t *testing.T) {
|
||||
PrintCurrentTest(t)
|
||||
setting.Repository.Signing.InitialCommit = []string{"never"}
|
||||
testCtx := NewAPITestContext(t, username, "initial-unsigned")
|
||||
t.Run("CreateRepository", doAPICreateRepository(testCtx, false))
|
||||
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(
|
||||
t, testCtx, user, "master", "never", "unsigned-never.txt", func(t *testing.T, response api.FileResponse) {
|
||||
assert.False(t, response.Verification.Verified)
|
||||
setting.Repository.Signing.InitialCommit = []string{"never"}
|
||||
setting.Repository.Signing.CRUDActions = []string{"never"}
|
||||
|
||||
baseAPITestContext := NewAPITestContext(t, username, "repo1")
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
u.Path = baseAPITestContext.GitPath()
|
||||
|
||||
t.Run("Unsigned-Initial", func(t *testing.T) {
|
||||
PrintCurrentTest(t)
|
||||
testCtx := NewAPITestContext(t, username, "initial-unsigned")
|
||||
t.Run("CreateRepository", doAPICreateRepository(testCtx, false))
|
||||
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-Never", crudActionCreateFile(
|
||||
t, testCtx, user, "never", "never2", "unsigned-never2.txt", func(t *testing.T, response api.FileResponse) {
|
||||
assert.False(t, response.Verification.Verified)
|
||||
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)
|
||||
}))
|
||||
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(
|
||||
t, testCtx, user, "master", "parentsigned", "signed-parent.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("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) {
|
||||
assert.False(t, response.Verification.Verified)
|
||||
})
|
||||
}, false)
|
||||
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(
|
||||
t, testCtx, user, "parentsigned", "parentsigned-never", "unsigned-never2.txt", func(t *testing.T, response api.FileResponse) {
|
||||
assert.False(t, response.Verification.Verified)
|
||||
}))
|
||||
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("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)
|
||||
}))
|
||||
setting.Repository.Signing.CRUDActions = []string{"parentsigned"}
|
||||
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)
|
||||
}))
|
||||
})
|
||||
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)
|
||||
})
|
||||
}, false)
|
||||
setting.Repository.Signing.Merges = []string{"commitssigned"}
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
u.Path = baseAPITestContext.GitPath()
|
||||
|
||||
t.Run("CommitsSignedMerging", 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", "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)
|
||||
}))
|
||||
|
||||
})
|
||||
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"}
|
||||
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)
|
||||
}))
|
||||
|
||||
})
|
||||
}, false)
|
||||
}
|
||||
|
||||
func crudActionCreateFile(t *testing.T, ctx APITestContext, user *models.User, from, to, path string, callback ...func(*testing.T, api.FileResponse)) func(*testing.T) {
|
||||
|
@ -30,26 +30,28 @@ type ActionType int
|
||||
|
||||
// Possible action types.
|
||||
const (
|
||||
ActionCreateRepo ActionType = iota + 1 // 1
|
||||
ActionRenameRepo // 2
|
||||
ActionStarRepo // 3
|
||||
ActionWatchRepo // 4
|
||||
ActionCommitRepo // 5
|
||||
ActionCreateIssue // 6
|
||||
ActionCreatePullRequest // 7
|
||||
ActionTransferRepo // 8
|
||||
ActionPushTag // 9
|
||||
ActionCommentIssue // 10
|
||||
ActionMergePullRequest // 11
|
||||
ActionCloseIssue // 12
|
||||
ActionReopenIssue // 13
|
||||
ActionClosePullRequest // 14
|
||||
ActionReopenPullRequest // 15
|
||||
ActionDeleteTag // 16
|
||||
ActionDeleteBranch // 17
|
||||
ActionMirrorSyncPush // 18
|
||||
ActionMirrorSyncCreate // 19
|
||||
ActionMirrorSyncDelete // 20
|
||||
ActionCreateRepo ActionType = iota + 1 // 1
|
||||
ActionRenameRepo // 2
|
||||
ActionStarRepo // 3
|
||||
ActionWatchRepo // 4
|
||||
ActionCommitRepo // 5
|
||||
ActionCreateIssue // 6
|
||||
ActionCreatePullRequest // 7
|
||||
ActionTransferRepo // 8
|
||||
ActionPushTag // 9
|
||||
ActionCommentIssue // 10
|
||||
ActionMergePullRequest // 11
|
||||
ActionCloseIssue // 12
|
||||
ActionReopenIssue // 13
|
||||
ActionClosePullRequest // 14
|
||||
ActionReopenPullRequest // 15
|
||||
ActionDeleteTag // 16
|
||||
ActionDeleteBranch // 17
|
||||
ActionMirrorSyncPush // 18
|
||||
ActionMirrorSyncCreate // 19
|
||||
ActionMirrorSyncDelete // 20
|
||||
ActionApprovePullRequest // 21
|
||||
ActionRejectPullRequest // 22
|
||||
)
|
||||
|
||||
// Action represents user operation type and other information to
|
||||
@ -520,52 +522,6 @@ func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit, bra
|
||||
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
|
||||
type GetFeedsOptions struct {
|
||||
RequestedUser *User
|
||||
|
@ -332,54 +332,6 @@ func TestUpdateIssuesCommit_AnotherRepoNoPermission(t *testing.T) {
|
||||
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) {
|
||||
// test with an individual user
|
||||
assert.NoError(t, PrepareTestDatabase())
|
||||
|
@ -539,8 +539,10 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = sendCreateCommentAction(e, opts, comment); err != nil {
|
||||
return nil, err
|
||||
if !opts.NoAction {
|
||||
if err = sendCreateCommentAction(e, opts, comment); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if err = comment.addCrossReferences(e, opts.Doer); err != nil {
|
||||
@ -816,6 +818,7 @@ type CreateCommentOptions struct {
|
||||
RefCommentID int64
|
||||
RefAction references.XRefAction
|
||||
RefIsPull bool
|
||||
NoAction bool
|
||||
}
|
||||
|
||||
// CreateComment creates comment of issue or commit.
|
||||
|
@ -1,4 +1,5 @@
|
||||
// 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
|
||||
// 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
|
||||
|
||||
// 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 isAttributeSSHPublicKeySet && synchronizeLdapSSHPublicKeys(user, source, sr.SSHPublicKey) {
|
||||
return user, RewriteAllPublicKeys()
|
||||
|
@ -1792,8 +1792,13 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error
|
||||
|
||||
if err = watchRepo(sess, doer.ID, repo.ID, true); err != nil {
|
||||
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.
|
||||
@ -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.
|
||||
func ChangeRepositoryName(u *User, oldRepoName, newRepoName string) (err error) {
|
||||
oldRepoName = strings.ToLower(oldRepoName)
|
||||
func ChangeRepositoryName(doer *User, repo *Repository, newRepoName string) (err error) {
|
||||
newRepoName = strings.ToLower(newRepoName)
|
||||
if err = IsUsableRepoName(newRepoName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
has, err := IsRepositoryExist(u, newRepoName)
|
||||
if err := repo.GetOwner(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
has, err := IsRepositoryExist(repo.Owner, newRepoName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("IsRepositoryExist: %v", err)
|
||||
} else if has {
|
||||
return ErrRepoAlreadyExist{u.Name, newRepoName}
|
||||
}
|
||||
|
||||
repo, err := GetRepositoryByName(u.ID, oldRepoName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetRepositoryByName: %v", err)
|
||||
return ErrRepoAlreadyExist{repo.Owner.Name, newRepoName}
|
||||
}
|
||||
|
||||
// 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))
|
||||
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 {
|
||||
return fmt.Errorf("rename repository directory: %v", err)
|
||||
}
|
||||
|
||||
wikiPath := repo.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)
|
||||
}
|
||||
}
|
||||
@ -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 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)
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,6 @@ import (
|
||||
"code.gitea.io/gitea/modules/markup"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/unknwon/com"
|
||||
)
|
||||
|
||||
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())
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
// Generate image
|
||||
|
@ -216,6 +216,21 @@ func NotifyWatchers(act *Action) error {
|
||||
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 {
|
||||
if !isWrite || !setting.Service.AutoWatchOnChanges {
|
||||
return nil
|
||||
|
134
models/review.go
134
models/review.go
@ -5,14 +5,12 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
|
||||
"xorm.io/builder"
|
||||
"xorm.io/core"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
// ReviewType defines the sort of feedback a review gives
|
||||
@ -86,6 +84,11 @@ func (r *Review) loadReviewer(e Engine) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// LoadReviewer loads reviewer
|
||||
func (r *Review) LoadReviewer() error {
|
||||
return r.loadReviewer(x)
|
||||
}
|
||||
|
||||
func (r *Review) loadAttributes(e Engine) (err error) {
|
||||
if err = r.loadReviewer(e); err != nil {
|
||||
return
|
||||
@ -101,54 +104,6 @@ func (r *Review) LoadAttributes() error {
|
||||
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) {
|
||||
review := new(Review)
|
||||
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)
|
||||
}
|
||||
|
||||
// UpdateReview will update all cols of the given review in db
|
||||
func UpdateReview(r *Review) error {
|
||||
if _, err := x.ID(r.ID).AllCols().Update(r); err != nil {
|
||||
return err
|
||||
// ContentEmptyErr represents an content empty error
|
||||
type ContentEmptyErr struct {
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -98,14 +98,6 @@ func TestCreateReview(t *testing.T) {
|
||||
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) {
|
||||
assert.NoError(t, PrepareTestDatabase())
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
@ -50,6 +51,28 @@ func (b *Blob) GetBlobContent() (string, error) {
|
||||
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
|
||||
func (b *Blob) GetBlobContentBase64() (string, error) {
|
||||
dataRc, err := b.DataAsync()
|
||||
|
@ -6,6 +6,8 @@ package action
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"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{
|
||||
ActUserID: doer.ID,
|
||||
ActUser: doer,
|
||||
@ -84,11 +88,23 @@ func (a *actionNotifier) NotifyRenameRepository(doer *models.User, repo *models.
|
||||
RepoID: repo.ID,
|
||||
Repo: repo,
|
||||
IsPrivate: repo.IsPrivate,
|
||||
Content: oldName,
|
||||
Content: oldRepoName,
|
||||
}); err != nil {
|
||||
log.Error("notify watchers: %v", err)
|
||||
} else {
|
||||
log.Trace("action.renameRepoAction: %s/%s", doer.Name, repo.Name)
|
||||
log.Error("NotifyWatchers: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,8 @@ type Notifier interface {
|
||||
NotifyMigrateRepository(doer *models.User, u *models.User, repo *models.Repository)
|
||||
NotifyDeleteRepository(doer *models.User, 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)
|
||||
NotifyIssueChangeStatus(*models.User, *models.Issue, bool)
|
||||
|
@ -58,18 +58,6 @@ func (*NullNotifier) NotifyUpdateComment(doer *models.User, c *models.Comment, o
|
||||
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
|
||||
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) {
|
||||
}
|
||||
|
||||
// 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
|
||||
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
|
||||
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) {
|
||||
}
|
||||
|
@ -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
|
||||
func NotifyNewRelease(rel *models.Release) {
|
||||
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
|
||||
func NotifyPushCommits(pusher *models.User, repo *models.Repository, refName, oldCommitID, newCommitID string, commits *models.PushCommits) {
|
||||
for _, notifier := range notifiers {
|
||||
|
@ -55,6 +55,15 @@ func TestGetDiffPreview(t *testing.T) {
|
||||
Type: 4,
|
||||
Content: "@@ -1,3 +1,4 @@",
|
||||
Comments: nil,
|
||||
SectionInfo: &gitdiff.DiffLineSectionInfo{
|
||||
Path: "README.md",
|
||||
LastLeftIdx: 0,
|
||||
LastRightIdx: 0,
|
||||
LeftIdx: 1,
|
||||
RightIdx: 1,
|
||||
LeftHunkSize: 3,
|
||||
RightHunkSize: 4,
|
||||
},
|
||||
},
|
||||
{
|
||||
LeftIdx: 1,
|
||||
|
@ -140,18 +140,19 @@ var (
|
||||
}
|
||||
|
||||
// Security settings
|
||||
InstallLock bool
|
||||
SecretKey string
|
||||
LogInRememberDays int
|
||||
CookieUserName string
|
||||
CookieRememberName string
|
||||
ReverseProxyAuthUser string
|
||||
ReverseProxyAuthEmail string
|
||||
MinPasswordLength int
|
||||
ImportLocalPaths bool
|
||||
DisableGitHooks bool
|
||||
PasswordComplexity []string
|
||||
PasswordHashAlgo string
|
||||
InstallLock bool
|
||||
SecretKey string
|
||||
LogInRememberDays int
|
||||
CookieUserName string
|
||||
CookieRememberName string
|
||||
ReverseProxyAuthUser string
|
||||
ReverseProxyAuthEmail string
|
||||
MinPasswordLength int
|
||||
ImportLocalPaths bool
|
||||
DisableGitHooks bool
|
||||
OnlyAllowPushIfGiteaEnvironmentSet bool
|
||||
PasswordComplexity []string
|
||||
PasswordHashAlgo string
|
||||
|
||||
// UI settings
|
||||
UI = struct {
|
||||
@ -778,6 +779,7 @@ func NewContext() {
|
||||
MinPasswordLength = sec.Key("MIN_PASSWORD_LENGTH").MustInt(6)
|
||||
ImportLocalPaths = sec.Key("IMPORT_LOCAL_PATHS").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")
|
||||
CSRFCookieHTTPOnly = sec.Key("CSRF_COOKIE_HTTP_ONLY").MustBool(true)
|
||||
|
||||
|
@ -555,6 +555,10 @@ func ActionIcon(opType models.ActionType) string {
|
||||
return "issue-reopened"
|
||||
case models.ActionMirrorSyncPush, models.ActionMirrorSyncCreate, models.ActionMirrorSyncDelete:
|
||||
return "repo-clone"
|
||||
case models.ActionApprovePullRequest:
|
||||
return "eye"
|
||||
case models.ActionRejectPullRequest:
|
||||
return "x"
|
||||
default:
|
||||
return "invalid type"
|
||||
}
|
||||
|
@ -582,7 +582,7 @@ email_notifications.submit = Set Email Preference
|
||||
owner = Owner
|
||||
repo_name = Repository Name
|
||||
repo_name_helper = Good repository names use short, memorable and unique keywords.
|
||||
repo_size = Repository Size
|
||||
repo_size = Repository Size
|
||||
template = Template
|
||||
template_select = Select a template.
|
||||
template_helper = Make repository a template
|
||||
@ -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_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
|
||||
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]
|
||||
ago = %s ago
|
||||
|
@ -581,6 +581,7 @@ email_notifications.submit=Atualizar preferências de e-mail
|
||||
owner=Proprietá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_size=Tamanho do repositório
|
||||
template=Modelo
|
||||
template_select=Selecione 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.update_profile_success=A conta de usuário foi atualizada.
|
||||
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.is_activated=Conta de usuário está ativada
|
||||
users.prohibit_login=Desabilitar acesso
|
||||
|
@ -68,6 +68,10 @@ pull_requests=合并请求
|
||||
issues=工单管理
|
||||
|
||||
cancel=取消
|
||||
add=添加
|
||||
add_all=添加所有
|
||||
remove=移除
|
||||
remove_all=移除所有
|
||||
|
||||
write=撰写
|
||||
preview=预览
|
||||
@ -577,6 +581,11 @@ email_notifications.submit=邮件通知设置
|
||||
owner=拥有者
|
||||
repo_name=仓库名称
|
||||
repo_name_helper=好的存储库名称使用简短、深刻和独特的关键字。
|
||||
repo_size=仓库大小
|
||||
template=模板
|
||||
template_select=选择模板
|
||||
template_helper=设置仓库为模板仓库
|
||||
template_description=模板仓库让用户通过拷贝目录结构,文件和可选设置来生成仓库。
|
||||
visibility=可见性
|
||||
visibility_description=只有组织所有人或拥有权利的组织成员才能看到。
|
||||
visibility_helper=将仓库设为私有
|
||||
@ -586,6 +595,9 @@ clone_helper=不知道如何克隆?查看<a target="_blank" rel="noopener nore
|
||||
fork_repo=派生仓库
|
||||
fork_from=派生自
|
||||
fork_visibility_helper=无法更改派生仓库的可见性。
|
||||
use_template=使用此模板
|
||||
generate_repo=生成仓库
|
||||
generate_from=生成自
|
||||
repo_desc=仓库描述
|
||||
repo_lang=仓库语言
|
||||
repo_gitignore_helper=选择 .gitignore 模板。
|
||||
@ -613,6 +625,11 @@ forks=派生仓库
|
||||
pick_reaction=选择你的表情
|
||||
reactions_more=再加载 %d
|
||||
|
||||
template.items=模板选项
|
||||
template.git_content=Git数据(默认分支)
|
||||
template.topics=主题
|
||||
template.one_item=必须至少选择一个模板项
|
||||
template.invalid=必须选择一个模板仓库
|
||||
|
||||
archive.title=此仓库已存档。您可以查看文件和克隆,但不能推送或创建工单/合并请求。
|
||||
archive.issue.nocomment=此仓库已存档,您不能在此工单添加评论。
|
||||
@ -648,6 +665,7 @@ migrate.migrating_failed=从 <b>%s</b> 迁移失败。
|
||||
|
||||
mirror_from=镜像自地址
|
||||
forked_from=派生自
|
||||
generated_from=生成自
|
||||
fork_from_self=无法派生已经拥有的仓库!
|
||||
fork_guest_user=登录并 派生 这个仓库。
|
||||
copy_link=复制链接
|
||||
@ -742,6 +760,7 @@ editor.no_changes_to_show=没有可以显示的变更。
|
||||
editor.fail_to_update_file=更新/创建文件 '%s' 时发生错误:%v
|
||||
editor.add_subdir=添加目录
|
||||
editor.unable_to_upload_files=上传文件至 '%s' 时发生错误:%v
|
||||
editor.upload_file_is_locked=文件%s被 %s 锁定。
|
||||
editor.upload_files_to_dir=上传文件至 '%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.squash_merge_pull_request=压缩提交并合并
|
||||
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.status_checking=一些检测仍在等待运行
|
||||
pulls.status_checks_success=所有检测均成功
|
||||
@ -1089,6 +1112,9 @@ activity.period.daily=1 天
|
||||
activity.period.halfweekly=3 天
|
||||
activity.period.weekly=1周
|
||||
activity.period.monthly=1 个月
|
||||
activity.period.quarterly=3个月
|
||||
activity.period.semiyearly=6 个月
|
||||
activity.period.yearly=1年
|
||||
activity.overview=概览
|
||||
activity.active_prs_count_1=<strong>%d</strong> 合并请求
|
||||
activity.active_prs_count_n=<strong>%d</strong> 合并请求
|
||||
@ -1511,6 +1537,7 @@ team_name=团队名称
|
||||
team_desc=团队描述
|
||||
team_name_helper=团队名字应该简单明了。
|
||||
team_desc_helper=描述团队的目的或作用。
|
||||
team_access_desc=仓库权限
|
||||
team_permission_desc=权限
|
||||
team_unit_desc=允许访问仓库单元
|
||||
|
||||
@ -1578,10 +1605,21 @@ teams.write_permission_desc=该团队拥有对所属仓库的 <strong>读取</st
|
||||
teams.admin_permission_desc=该团队拥有一定的 <strong>管理</strong> 权限,团队成员可以读取、克隆、推送以及添加其它仓库协作者。
|
||||
teams.repositories=团队仓库
|
||||
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_duplicate_users=用户已经是团队成员。
|
||||
teams.repos.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]
|
||||
dashboard=管理面板
|
||||
@ -1674,6 +1712,7 @@ users.auth_login_name=认证登录名称
|
||||
users.password_helper=保持密码为空将不更改密码。
|
||||
users.update_profile_success=该帐户已被更新。
|
||||
users.edit_account=编辑帐号
|
||||
users.max_repo_creation=最大仓库数
|
||||
users.max_repo_creation_desc=(设置为 -1 表示使用全局默认值)
|
||||
users.is_activated=该用户已被激活
|
||||
users.prohibit_login=禁用登录
|
||||
|
3443
package-lock.json
generated
3443
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
19
package.json
19
package.json
@ -5,14 +5,23 @@
|
||||
"node": ">=8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "9.6.1",
|
||||
"eslint": "6.3.0",
|
||||
"@babel/core": "7.7.2",
|
||||
"@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-plugin-clean-css": "1.5.1",
|
||||
"postcss-cli": "6.1.3",
|
||||
"stylelint": "10.1.0",
|
||||
"stylelint-config-standard": "18.3.0",
|
||||
"updates": "8.5.3"
|
||||
"stylelint": "11.1.1",
|
||||
"stylelint-config-standard": "19.0.0",
|
||||
"terser-webpack-plugin": "2.2.1",
|
||||
"updates": "9.0.1",
|
||||
"webpack": "4.41.2",
|
||||
"webpack-cli": "3.3.10"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
|
@ -73,7 +73,7 @@ a{cursor:pointer}
|
||||
.right.stackable.menu{margin-left:auto;display:flex;align-items:inherit;flex-direction:inherit}
|
||||
.ui.left{float:left}
|
||||
.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.form .ui.button{font-weight:400}
|
||||
.ui.floating.label{z-index:10}
|
||||
@ -233,14 +233,14 @@ i.icons .icon:first-child{margin-right:0}
|
||||
i.icon.centerlock{top:1.5em}
|
||||
.ui.label>.detail .icons{margin-right:.25em}
|
||||
.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-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 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-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 .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{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;-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 .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}
|
||||
@ -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 .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 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}
|
||||
@media only screen and (max-width:767px){.home .hero h1{font-size:3.5em}
|
||||
.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 .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 .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-old{border-right:1px solid #ddd}
|
||||
.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 .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 .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-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}
|
||||
@ -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 .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}
|
||||
td.blob-excerpt{background-color:#fafafa}
|
||||
.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-info{display:flex;align-items:center}
|
||||
@ -1068,4 +1069,8 @@ tbody.commit-list{vertical-align:baseline}
|
||||
.comment-code-cloud .footer:after{clear:both;content:"";display:block}
|
||||
.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}
|
||||
.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}
|
@ -14,7 +14,7 @@ body{background:#383c4a;color:#9e9e9e}
|
||||
*{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-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:hover{background:#87ab63!important}
|
||||
a{color:#87ab63}
|
||||
|
@ -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);
|
||||
})
|
3426
public/js/index.js
3426
public/js/index.js
File diff suppressed because one or more lines are too long
1
public/js/index.js.map
Normal file
1
public/js/index.js.map
Normal file
File diff suppressed because one or more lines are too long
2
public/vendor/VERSIONS
vendored
2
public/vendor/VERSIONS
vendored
@ -23,7 +23,7 @@ Version: 745f604212e2abfe2f0a59169ea530857b46625c
|
||||
File(s): /vendor/plugins/vue/vue.min.js
|
||||
Version: 2.1.10
|
||||
|
||||
File(s): /vendor/plugins/emojify/emojify.min.js
|
||||
File(s): /vendor/plugins/emojify/emojify.custom.js
|
||||
Version: 1.1.0
|
||||
|
||||
File(s): /vendor/plugins/cssrelpreload/
|
||||
|
9
public/vendor/librejs.html
vendored
9
public/vendor/librejs.html
vendored
@ -38,12 +38,7 @@
|
||||
<tr>
|
||||
<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/tree/master/public/js">index.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>
|
||||
<td><a href="https://github.com/go-gitea/gitea/tree/master/web_src/js">*.js</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<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>
|
||||
</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="https://github.com/Ranks/emojify.js/archive/1.1.0.tar.gz">emojify-1.1.0.tar.gz</a></td>
|
||||
</tr>
|
||||
|
1
public/vendor/plugins/emojify/emojify.custom.js
vendored
Normal file
1
public/vendor/plugins/emojify/emojify.custom.js
vendored
Normal file
File diff suppressed because one or more lines are too long
4
public/vendor/plugins/emojify/emojify.min.js
vendored
4
public/vendor/plugins/emojify/emojify.min.js
vendored
File diff suppressed because one or more lines are too long
BIN
public/vendor/plugins/emojify/images/gitea.png
vendored
Normal file
BIN
public/vendor/plugins/emojify/images/gitea.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.2 KiB |
@ -6,6 +6,7 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
@ -25,6 +26,7 @@ import (
|
||||
"code.gitea.io/gitea/services/mailer"
|
||||
|
||||
"gitea.com/macaron/macaron"
|
||||
"gitea.com/macaron/session"
|
||||
"github.com/unknwon/com"
|
||||
)
|
||||
|
||||
@ -207,7 +209,7 @@ func SendTestMail(ctx *context.Context) {
|
||||
ctx.Redirect(setting.AppSubURL + "/admin/config")
|
||||
}
|
||||
|
||||
func shadownPasswordKV(cfgItem, splitter string) string {
|
||||
func shadowPasswordKV(cfgItem, splitter string) string {
|
||||
fields := strings.Split(cfgItem, splitter)
|
||||
for i := 0; i < len(fields); i++ {
|
||||
if strings.HasPrefix(fields[i], "password=") {
|
||||
@ -218,10 +220,10 @@ func shadownPasswordKV(cfgItem, splitter string) string {
|
||||
return strings.Join(fields, splitter)
|
||||
}
|
||||
|
||||
func shadownURL(provider, cfgItem string) string {
|
||||
func shadowURL(provider, cfgItem string) string {
|
||||
u, err := url.Parse(cfgItem)
|
||||
if err != nil {
|
||||
log.Error("shodowPassword %v failed: %v", provider, err)
|
||||
log.Error("Shadowing Password for %v failed: %v", provider, err)
|
||||
return cfgItem
|
||||
}
|
||||
if u.User != nil {
|
||||
@ -239,7 +241,7 @@ func shadownURL(provider, cfgItem string) string {
|
||||
func shadowPassword(provider, cfgItem string) string {
|
||||
switch provider {
|
||||
case "redis":
|
||||
return shadownPasswordKV(cfgItem, ",")
|
||||
return shadowPasswordKV(cfgItem, ",")
|
||||
case "mysql":
|
||||
//root:@tcp(localhost:3306)/macaron?charset=utf8
|
||||
atIdx := strings.Index(cfgItem, "@")
|
||||
@ -253,15 +255,21 @@ func shadowPassword(provider, cfgItem string) string {
|
||||
case "postgres":
|
||||
// user=jiahuachen dbname=macaron port=5432 sslmode=disable
|
||||
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
|
||||
// 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 shadownURL(provider, cfgItem)
|
||||
return cfgItem
|
||||
}
|
||||
|
||||
// Config show admin config page
|
||||
|
@ -631,15 +631,13 @@ func Edit(ctx *context.APIContext, opts api.EditRepoOption) {
|
||||
func updateBasicProperties(ctx *context.APIContext, opts api.EditRepoOption) error {
|
||||
owner := ctx.Repo.Owner
|
||||
repo := ctx.Repo.Repository
|
||||
|
||||
oldRepoName := repo.Name
|
||||
newRepoName := repo.Name
|
||||
if opts.Name != nil {
|
||||
newRepoName = *opts.Name
|
||||
}
|
||||
// Check if repository name has been changed and not just a case change
|
||||
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 {
|
||||
case models.IsErrRepoAlreadyExist(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
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
// Update the name in the repo object for the response
|
||||
|
@ -245,6 +245,7 @@ func Diff(ctx *context.Context) {
|
||||
}
|
||||
|
||||
ctx.Data["CommitID"] = commitID
|
||||
ctx.Data["AfterCommitID"] = commitID
|
||||
ctx.Data["Username"] = userName
|
||||
ctx.Data["Reponame"] = repoName
|
||||
|
||||
|
@ -5,21 +5,26 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"html"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/highlight"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/services/gitdiff"
|
||||
)
|
||||
|
||||
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
|
||||
@ -434,3 +439,109 @@ func CompareDiff(ctx *context.Context) {
|
||||
|
||||
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
|
||||
}
|
||||
|
@ -552,6 +552,7 @@ func ViewPullFiles(ctx *context.Context) {
|
||||
ctx.Data["Username"] = pull.MustHeadUserName()
|
||||
ctx.Data["Reponame"] = pull.HeadRepo.Name
|
||||
}
|
||||
ctx.Data["AfterCommitID"] = endCommitID
|
||||
|
||||
diff, err := gitdiff.GetDiffRangeWithWhitespaceBehavior(diffRepoPath,
|
||||
startCommitID, endCommitID, setting.Git.MaxGitDiffLines,
|
||||
|
@ -11,8 +11,6 @@ import (
|
||||
"code.gitea.io/gitea/modules/auth"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"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"
|
||||
)
|
||||
|
||||
@ -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))
|
||||
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
|
||||
if form.Side == "previous" {
|
||||
signedLine *= -1
|
||||
}
|
||||
|
||||
review := new(models.Review)
|
||||
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(
|
||||
comment, err := pull_service.CreateCodeComment(
|
||||
ctx.User,
|
||||
issue.Repo,
|
||||
issue,
|
||||
signedLine,
|
||||
form.Content,
|
||||
form.TreePath,
|
||||
signedLine,
|
||||
review.ID,
|
||||
form.IsReview,
|
||||
form.Reply,
|
||||
)
|
||||
if err != nil {
|
||||
ctx.ServerError("CreateCodeComment", err)
|
||||
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)
|
||||
|
||||
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
|
||||
@ -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))
|
||||
return
|
||||
}
|
||||
var review *models.Review
|
||||
var err error
|
||||
|
||||
reviewType := form.ReviewType()
|
||||
|
||||
switch reviewType {
|
||||
case models.ReviewTypeUnknown:
|
||||
ctx.ServerError("GetCurrentReview", fmt.Errorf("unknown ReviewType: %s", form.Type))
|
||||
ctx.ServerError("ReviewType", fmt.Errorf("unknown ReviewType: %s", form.Type))
|
||||
return
|
||||
|
||||
// can not approve/reject your own PR
|
||||
case models.ReviewTypeApprove, models.ReviewTypeReject:
|
||||
|
||||
if issue.Poster.ID == ctx.User.ID {
|
||||
|
||||
var translated string
|
||||
|
||||
if reviewType == models.ReviewTypeApprove {
|
||||
translated = ctx.Tr("repo.issues.review.self.approval")
|
||||
} else {
|
||||
@ -134,69 +95,16 @@ func SubmitReview(ctx *context.Context, form auth.SubmitReviewForm) {
|
||||
}
|
||||
}
|
||||
|
||||
review, err = models.GetCurrentReview(ctx.User, issue)
|
||||
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
|
||||
}
|
||||
|
||||
_, comm, err := pull_service.SubmitReview(ctx.User, issue, reviewType, form.Content)
|
||||
if err != nil {
|
||||
if !models.IsErrReviewNotExist(err) {
|
||||
ctx.ServerError("GetCurrentReview", err)
|
||||
return
|
||||
if models.IsContentEmptyErr(err) {
|
||||
ctx.Flash.Error(ctx.Tr("repo.issues.review.content.empty"))
|
||||
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
|
||||
}
|
||||
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()))
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ import (
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/notification"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/validation"
|
||||
@ -67,18 +66,15 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
|
||||
return
|
||||
}
|
||||
|
||||
isNameChanged := false
|
||||
oldRepoName := repo.Name
|
||||
newRepoName := form.RepoName
|
||||
// Check if repository name has been changed.
|
||||
if repo.LowerName != strings.ToLower(newRepoName) {
|
||||
isNameChanged = true
|
||||
// Close the GitRepo if open
|
||||
if ctx.Repo.GitRepo != nil {
|
||||
ctx.Repo.GitRepo.Close()
|
||||
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
|
||||
switch {
|
||||
case models.IsErrRepoAlreadyExist(err):
|
||||
@ -93,12 +89,6 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
|
||||
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)
|
||||
}
|
||||
// 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)
|
||||
|
||||
if isNameChanged {
|
||||
notification.NotifyRenameRepository(ctx.User, repo, oldRepoName)
|
||||
}
|
||||
|
||||
ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
|
||||
ctx.Redirect(repo.Link() + "/settings")
|
||||
|
||||
@ -383,13 +369,12 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
|
||||
return
|
||||
}
|
||||
|
||||
oldOwnerID := ctx.Repo.Owner.ID
|
||||
// Close the GitRepo if open
|
||||
if ctx.Repo.GitRepo != nil {
|
||||
ctx.Repo.GitRepo.Close()
|
||||
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) {
|
||||
ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplSettingsOptions, nil)
|
||||
} else {
|
||||
@ -398,12 +383,6 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
|
||||
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)
|
||||
ctx.Flash.Success(ctx.Tr("repo.settings.transfer_succeed"))
|
||||
ctx.Redirect(setting.AppSubURL + "/" + newOwner + "/" + repo.Name)
|
||||
@ -707,6 +686,7 @@ func GitHooks(ctx *context.Context) {
|
||||
func GitHooksEdit(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("repo.settings.githooks")
|
||||
ctx.Data["PageIsSettingsGitHooks"] = true
|
||||
ctx.Data["RequireSimpleMDE"] = true
|
||||
|
||||
name := ctx.Params(":name")
|
||||
hook, err := ctx.Repo.GitRepo.GetHook(name)
|
||||
|
@ -864,6 +864,10 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||
m.Get("", repo.Branches)
|
||||
}, 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.Get(".diff", repo.DownloadPullDiff)
|
||||
m.Get(".patch", repo.DownloadPullPatch)
|
||||
|
@ -5,15 +5,8 @@
|
||||
package comments
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/notification"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/services/gitdiff"
|
||||
)
|
||||
|
||||
// CreateIssueComment creates a plain issue comment.
|
||||
@ -35,60 +28,6 @@ func CreateIssueComment(doer *models.User, repo *models.Repository, issue *model
|
||||
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.
|
||||
func UpdateComment(c *models.Comment, doer *models.User, oldContent string) error {
|
||||
if err := models.UpdateComment(c, doer); err != nil {
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"html/template"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
@ -56,15 +57,42 @@ const (
|
||||
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.
|
||||
type DiffLine struct {
|
||||
LeftIdx int
|
||||
RightIdx int
|
||||
Type DiffLineType
|
||||
Content string
|
||||
Comments []*models.Comment
|
||||
LeftIdx int
|
||||
RightIdx int
|
||||
Type DiffLineType
|
||||
Content string
|
||||
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.
|
||||
func (d *DiffLine) GetType() int {
|
||||
return int(d.Type)
|
||||
@ -91,6 +119,71 @@ func (d *DiffLine) GetLineTypeMarker() string {
|
||||
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
|
||||
func getLineContent(content string) string {
|
||||
if len(content) > 0 {
|
||||
@ -248,6 +341,53 @@ func (diffFile *DiffFile) GetHighlightClass() string {
|
||||
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.
|
||||
type Diff struct {
|
||||
TotalAddition, TotalDeletion int
|
||||
@ -510,19 +650,16 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D
|
||||
case line[0] == '@':
|
||||
curSection = &DiffSection{}
|
||||
curFile.Sections = append(curFile.Sections, curSection)
|
||||
ss := strings.Split(line, "@@")
|
||||
diffLine := &DiffLine{Type: DiffLineSection, Content: line}
|
||||
curSection.Lines = append(curSection.Lines, diffLine)
|
||||
|
||||
// Parse line number.
|
||||
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
|
||||
lineSectionInfo := getDiffLineSectionInfo(curFile, line, leftLine-1, rightLine-1)
|
||||
diffLine := &DiffLine{
|
||||
Type: DiffLineSection,
|
||||
Content: line,
|
||||
SectionInfo: lineSectionInfo,
|
||||
}
|
||||
curSection.Lines = append(curSection.Lines, diffLine)
|
||||
// update line number.
|
||||
leftLine = lineSectionInfo.LeftIdx
|
||||
rightLine = lineSectionInfo.RightIdx
|
||||
continue
|
||||
case line[0] == '+':
|
||||
curFile.Addition++
|
||||
@ -599,6 +736,8 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D
|
||||
break
|
||||
}
|
||||
curFileLinesCount = 0
|
||||
leftLine = 1
|
||||
rightLine = 1
|
||||
curFileLFSPrefix = false
|
||||
|
||||
// Check file diff type and is submodule.
|
||||
@ -701,6 +840,7 @@ func GetDiffRangeWithWhitespaceBehavior(repoPath, beforeCommitID, afterCommitID
|
||||
diffArgs = append(diffArgs, actualBeforeCommitID)
|
||||
diffArgs = append(diffArgs, afterCommitID)
|
||||
cmd = exec.Command(git.GitExecutable, diffArgs...)
|
||||
beforeCommitID = actualBeforeCommitID
|
||||
}
|
||||
cmd.Dir = repoPath
|
||||
cmd.Stderr = os.Stderr
|
||||
@ -721,6 +861,12 @@ func GetDiffRangeWithWhitespaceBehavior(repoPath, beforeCommitID, afterCommitID
|
||||
if err != nil {
|
||||
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 {
|
||||
return nil, fmt.Errorf("Wait: %v", err)
|
||||
|
@ -76,6 +76,7 @@ func TestRelease_MirrorDelete(t *testing.T) {
|
||||
assert.True(t, ok)
|
||||
|
||||
count, err := models.GetReleaseCountByRepoID(mirror.ID, findOptions)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, initCount+1, count)
|
||||
|
||||
release, err := models.GetRelease(repo.ID, "v0.2")
|
||||
@ -86,5 +87,6 @@ func TestRelease_MirrorDelete(t *testing.T) {
|
||||
assert.True(t, ok)
|
||||
|
||||
count, err = models.GetReleaseCountByRepoID(mirror.ID, findOptions)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, initCount, count)
|
||||
}
|
||||
|
@ -424,8 +424,16 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
|
||||
log.Error("setMerged [%d]: %v", pr.ID, err)
|
||||
}
|
||||
|
||||
if err = models.MergePullRequestAction(doer, pr.Issue.Repo, pr.Issue); err != nil {
|
||||
log.Error("MergePullRequestAction [%d]: %v", pr.ID, err)
|
||||
if err := models.NotifyWatchers(&models.Action{
|
||||
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
|
||||
|
@ -6,30 +6,144 @@
|
||||
package pull
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"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
|
||||
func CreateReview(opts models.CreateReviewOptions) (*models.Review, error) {
|
||||
review, err := models.CreateReview(opts)
|
||||
// CreateCodeComment creates a comment on the code line
|
||||
func CreateCodeComment(doer *models.User, issue *models.Issue, line int64, content string, treePath string, isReview bool, replyReviewID int64) (*models.Comment, error) {
|
||||
// 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 {
|
||||
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
|
||||
func UpdateReview(review *models.Review) error {
|
||||
err := models.UpdateReview(review)
|
||||
// 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
|
||||
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 {
|
||||
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)
|
||||
|
||||
return nil
|
||||
// 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,
|
||||
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
|
||||
}
|
||||
|
16
services/repository/main_test.go
Normal file
16
services/repository/main_test.go
Normal 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("..", ".."))
|
||||
}
|
54
services/repository/transfer.go
Normal file
54
services/repository/transfer.go
Normal 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
|
||||
}
|
50
services/repository/transfer_test.go
Normal file
50
services/repository/transfer_test.go
Normal 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{})
|
||||
}
|
@ -26,7 +26,6 @@
|
||||
{{if .RequireGitGraph}}
|
||||
<!-- graph -->
|
||||
<script src="{{StaticUrlPrefix}}/vendor/plugins/gitgraph/gitgraph.js"></script>
|
||||
<script src="{{StaticUrlPrefix}}/js/draw.js"></script>
|
||||
{{end}}
|
||||
|
||||
<!-- Third-party libraries -->
|
||||
@ -117,7 +116,7 @@
|
||||
}
|
||||
</script>
|
||||
{{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/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/vue-calendar-heatmap/vue-calendar-heatmap.browser.js" charset="utf-8"></script>
|
||||
<script type="text/javascript">
|
||||
initHeatmap('user-heatmap', '{{.HeatmapUser}}');
|
||||
window.initHeatmap('user-heatmap', '{{.HeatmapUser}}');
|
||||
</script>
|
||||
{{end}}
|
||||
{{template "custom/footer" .}}
|
||||
|
@ -7,11 +7,10 @@ var urlsToCache = [
|
||||
'{{StaticUrlPrefix}}/vendor/plugins/semantic/semantic.min.js',
|
||||
'{{StaticUrlPrefix}}/js/index.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/gitgraph/gitgraph.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/cssrelpreload.min.js',
|
||||
'{{StaticUrlPrefix}}/vendor/plugins/dropzone/dropzone.js',
|
||||
|
50
templates/repo/diff/blob_excerpt.tmpl
Normal file
50
templates/repo/diff/blob_excerpt.tmpl
Normal 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}}
|
@ -81,6 +81,15 @@
|
||||
{{else}}
|
||||
<div class="diff-file-box diff-box file-content {{TabSizeClass $.Editorconfig $file.Name}}" id="diff-{{.Index}}">
|
||||
<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">
|
||||
{{if $file.IsBin}}
|
||||
{{$.i18n.Tr "repo.diff.bin"}}
|
||||
@ -104,12 +113,6 @@
|
||||
</h4>
|
||||
<div class="ui attached unstackable table segment">
|
||||
{{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}}">
|
||||
<table>
|
||||
<tbody>
|
||||
@ -121,12 +124,27 @@
|
||||
{{range $j, $section := $file.Sections}}
|
||||
{{range $k, $line := $section.Lines}}
|
||||
<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>
|
||||
<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>
|
||||
{{if eq .GetType 4}}
|
||||
<td class="lines-num lines-num-old">
|
||||
{{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="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="{{$.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>
|
||||
{{if gt (len $line.Comments) 0}}
|
||||
<tr class="add-code-comment">
|
||||
|
@ -39,7 +39,7 @@
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{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}}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -4,9 +4,17 @@
|
||||
{{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 gt $j 0}}<span class="fold octicon octicon-fold"></span>{{end}} */}}
|
||||
</td>
|
||||
<td colspan="2" class="lines-num">
|
||||
{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5) }}
|
||||
<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}}
|
||||
<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>
|
||||
|
@ -155,8 +155,8 @@
|
||||
</form>
|
||||
{{if $.IsStopwatchRunning}}
|
||||
<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;cancelStopwatch()" class="ui negative button cancel">{{.i18n.Tr "repo.issues.cancel_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;window.cancelStopwatch()" class="ui negative button cancel">{{.i18n.Tr "repo.issues.cancel_tracking"}}</button>
|
||||
</div>
|
||||
{{else}}
|
||||
{{if .HasUserStopwatch}}
|
||||
@ -165,8 +165,8 @@
|
||||
</div>
|
||||
{{end}}
|
||||
<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="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="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="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="header">{{.i18n.Tr "repo.issues.add_time"}}</div>
|
||||
<div class="content">
|
||||
@ -225,8 +225,8 @@
|
||||
{{end}}
|
||||
{{if and .IsIssueWriter (not .Repository.IsArchived)}}
|
||||
<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="updateDeadline('');"><i class="remove icon"></i>{{$.i18n.Tr "repo.issues.due_date_form_remove"}}</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="window.updateDeadline('');"><i class="remove icon"></i>{{$.i18n.Tr "repo.issues.due_date_form_remove"}}</a>
|
||||
{{end}}
|
||||
</p>
|
||||
{{else}}
|
||||
@ -235,7 +235,7 @@
|
||||
|
||||
{{if and .IsIssueWriter (not .Repository.IsArchived)}}
|
||||
<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}}
|
||||
<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">
|
||||
@ -280,7 +280,7 @@
|
||||
<div class="text small">{{.Repository.OwnerName}}/{{.Repository.Name}}</div>
|
||||
<div class="ui transparent label right floated nopadding">
|
||||
{{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="">
|
||||
<i class="delete icon text red nopadding nomargin"></i>
|
||||
</a>
|
||||
@ -307,7 +307,7 @@
|
||||
<div class="text small">{{.Repository.OwnerName}}/{{.Repository.Name}}</div>
|
||||
<div class="ui transparent label right floated nopadding">
|
||||
{{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="">
|
||||
<i class="delete icon text red nopadding nomargin"></i>
|
||||
</a>
|
||||
|
@ -65,7 +65,7 @@
|
||||
title="{{$provider.DisplayName}}{{if eq $provider.Name "openidConnect"}} ({{$key}}){{end}}"
|
||||
class="{{$provider.Name}}"
|
||||
src="{{AppSubUrl}}{{$provider.Image}}"
|
||||
onclick="onOAuthLoginClick()"
|
||||
onclick="window.onOAuthLoginClick()"
|
||||
></a>
|
||||
{{end}}
|
||||
</div>
|
||||
|
@ -61,6 +61,12 @@
|
||||
{{$.i18n.Tr "action.mirror_sync_create" .GetRepoLink .GetBranch .ShortRepoPath | Str2html}}
|
||||
{{else if eq .GetOpType 20}}
|
||||
{{$.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}}
|
||||
</p>
|
||||
{{if or (eq .GetOpType 5) (eq .GetOpType 18)}}
|
||||
@ -80,7 +86,7 @@
|
||||
<span class="text truncate issue title has-emoji">{{index .GetIssueInfos 1}}</span>
|
||||
{{else if eq .GetOpType 7}}
|
||||
<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>
|
||||
<p class="text light grey has-emoji">{{index .GetIssueInfos 1}}</p>
|
||||
{{else if eq .GetOpType 11}}
|
||||
|
15
web_src/js/draw.js
Normal file
15
web_src/js/draw.js
Normal 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
3309
web_src/js/index.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -2438,6 +2438,10 @@ tbody.commit-list {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
td.blob-excerpt {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
.issue-keyword {
|
||||
border-bottom: 1px dotted #959da5;
|
||||
display: inline-block;
|
||||
|
@ -108,3 +108,26 @@
|
||||
font: 12px @monospaced-fonts, monospace;
|
||||
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
42
webpack.config.js
Normal 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,
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue
Block a user