You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

pull.go 32 kB

Move macaron to chi (#14293) Use [chi](https://github.com/go-chi/chi) instead of the forked [macaron](https://gitea.com/macaron/macaron). Since macaron and chi have conflicts with session share, this big PR becomes a have-to thing. According my previous idea, we can replace macaron step by step but I'm wrong. :( Below is a list of big changes on this PR. - [x] Define `context.ResponseWriter` interface with an implementation `context.Response`. - [x] Use chi instead of macaron, and also a customize `Route` to wrap chi so that the router usage is similar as before. - [x] Create different routers for `web`, `api`, `internal` and `install` so that the codes will be more clear and no magic . - [x] Use https://github.com/unrolled/render instead of macaron's internal render - [x] Use https://github.com/NYTimes/gziphandler instead of https://gitea.com/macaron/gzip - [x] Use https://gitea.com/go-chi/session which is a modified version of https://gitea.com/macaron/session and removed `nodb` support since it will not be maintained. **BREAK** - [x] Use https://gitea.com/go-chi/captcha which is a modified version of https://gitea.com/macaron/captcha - [x] Use https://gitea.com/go-chi/cache which is a modified version of https://gitea.com/macaron/cache - [x] Use https://gitea.com/go-chi/binding which is a modified version of https://gitea.com/macaron/binding - [x] Use https://github.com/go-chi/cors instead of https://gitea.com/macaron/cors - [x] Dropped https://gitea.com/macaron/i18n and make a new one in `code.gitea.io/gitea/modules/translation` - [x] Move validation form structs from `code.gitea.io/gitea/modules/auth` to `code.gitea.io/gitea/modules/forms` to avoid dependency cycle. - [x] Removed macaron log service because it's not need any more. **BREAK** - [x] All form structs have to be get by `web.GetForm(ctx)` in the route function but not as a function parameter on routes definition. - [x] Move Git HTTP protocol implementation to use routers directly. - [x] Fix the problem that chi routes don't support trailing slash but macaron did. - [x] `/api/v1/swagger` now will be redirect to `/api/swagger` but not render directly so that `APIContext` will not create a html render. Notices: - Chi router don't support request with trailing slash - Integration test `TestUserHeatmap` maybe mysql version related. It's failed on my macOS(mysql 5.7.29 installed via brew) but succeed on CI. Co-authored-by: 6543 <6543@obermui.de>
4 years ago
Move macaron to chi (#14293) Use [chi](https://github.com/go-chi/chi) instead of the forked [macaron](https://gitea.com/macaron/macaron). Since macaron and chi have conflicts with session share, this big PR becomes a have-to thing. According my previous idea, we can replace macaron step by step but I'm wrong. :( Below is a list of big changes on this PR. - [x] Define `context.ResponseWriter` interface with an implementation `context.Response`. - [x] Use chi instead of macaron, and also a customize `Route` to wrap chi so that the router usage is similar as before. - [x] Create different routers for `web`, `api`, `internal` and `install` so that the codes will be more clear and no magic . - [x] Use https://github.com/unrolled/render instead of macaron's internal render - [x] Use https://github.com/NYTimes/gziphandler instead of https://gitea.com/macaron/gzip - [x] Use https://gitea.com/go-chi/session which is a modified version of https://gitea.com/macaron/session and removed `nodb` support since it will not be maintained. **BREAK** - [x] Use https://gitea.com/go-chi/captcha which is a modified version of https://gitea.com/macaron/captcha - [x] Use https://gitea.com/go-chi/cache which is a modified version of https://gitea.com/macaron/cache - [x] Use https://gitea.com/go-chi/binding which is a modified version of https://gitea.com/macaron/binding - [x] Use https://github.com/go-chi/cors instead of https://gitea.com/macaron/cors - [x] Dropped https://gitea.com/macaron/i18n and make a new one in `code.gitea.io/gitea/modules/translation` - [x] Move validation form structs from `code.gitea.io/gitea/modules/auth` to `code.gitea.io/gitea/modules/forms` to avoid dependency cycle. - [x] Removed macaron log service because it's not need any more. **BREAK** - [x] All form structs have to be get by `web.GetForm(ctx)` in the route function but not as a function parameter on routes definition. - [x] Move Git HTTP protocol implementation to use routers directly. - [x] Fix the problem that chi routes don't support trailing slash but macaron did. - [x] `/api/v1/swagger` now will be redirect to `/api/swagger` but not render directly so that `APIContext` will not create a html render. Notices: - Chi router don't support request with trailing slash - Integration test `TestUserHeatmap` maybe mysql version related. It's failed on my macOS(mysql 5.7.29 installed via brew) but succeed on CI. Co-authored-by: 6543 <6543@obermui.de>
4 years ago
API add/generalize pagination (#9452) * paginate results * fixed deadlock * prevented breaking change * updated swagger * go fmt * fixed find topic * go mod tidy * go mod vendor with go1.13.5 * fixed repo find topics * fixed unit test * added Limit method to Engine struct; use engine variable when provided; fixed gitignore * use ItemsPerPage for default pagesize; fix GetWatchers, getOrgUsersByOrgID and GetStargazers; fix GetAllCommits headers; reverted some changed behaviors * set Page value on Home route * improved memory allocations * fixed response headers * removed logfiles * fixed import order * import order * improved swagger * added function to get models.ListOptions from context * removed pagesize diff on unit test * fixed imports * removed unnecessary struct field * fixed go fmt * scoped PR * code improvements * code improvements * go mod tidy * fixed import order * fixed commit statuses session * fixed files headers * fixed headers; added pagination for notifications * go mod tidy * go fmt * removed Private from user search options; added setting.UI.IssuePagingNum as default valeu on repo's issues list * Apply suggestions from code review Co-Authored-By: 6543 <6543@obermui.de> Co-Authored-By: zeripath <art27@cantab.net> * fixed build error * CI.restart() * fixed merge conflicts resolve * fixed conflicts resolve * improved FindTrackedTimesOptions.ToOptions() method * added backwards compatibility on ListReleases request; fixed issue tracked time ToSession * fixed build error; fixed swagger template * fixed swagger template * fixed ListReleases backwards compatibility * added page to user search route Co-authored-by: techknowlogick <matti@mdranta.net> Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: zeripath <art27@cantab.net>
5 years ago
Move macaron to chi (#14293) Use [chi](https://github.com/go-chi/chi) instead of the forked [macaron](https://gitea.com/macaron/macaron). Since macaron and chi have conflicts with session share, this big PR becomes a have-to thing. According my previous idea, we can replace macaron step by step but I'm wrong. :( Below is a list of big changes on this PR. - [x] Define `context.ResponseWriter` interface with an implementation `context.Response`. - [x] Use chi instead of macaron, and also a customize `Route` to wrap chi so that the router usage is similar as before. - [x] Create different routers for `web`, `api`, `internal` and `install` so that the codes will be more clear and no magic . - [x] Use https://github.com/unrolled/render instead of macaron's internal render - [x] Use https://github.com/NYTimes/gziphandler instead of https://gitea.com/macaron/gzip - [x] Use https://gitea.com/go-chi/session which is a modified version of https://gitea.com/macaron/session and removed `nodb` support since it will not be maintained. **BREAK** - [x] Use https://gitea.com/go-chi/captcha which is a modified version of https://gitea.com/macaron/captcha - [x] Use https://gitea.com/go-chi/cache which is a modified version of https://gitea.com/macaron/cache - [x] Use https://gitea.com/go-chi/binding which is a modified version of https://gitea.com/macaron/binding - [x] Use https://github.com/go-chi/cors instead of https://gitea.com/macaron/cors - [x] Dropped https://gitea.com/macaron/i18n and make a new one in `code.gitea.io/gitea/modules/translation` - [x] Move validation form structs from `code.gitea.io/gitea/modules/auth` to `code.gitea.io/gitea/modules/forms` to avoid dependency cycle. - [x] Removed macaron log service because it's not need any more. **BREAK** - [x] All form structs have to be get by `web.GetForm(ctx)` in the route function but not as a function parameter on routes definition. - [x] Move Git HTTP protocol implementation to use routers directly. - [x] Fix the problem that chi routes don't support trailing slash but macaron did. - [x] `/api/v1/swagger` now will be redirect to `/api/swagger` but not render directly so that `APIContext` will not create a html render. Notices: - Chi router don't support request with trailing slash - Integration test `TestUserHeatmap` maybe mysql version related. It's failed on my macOS(mysql 5.7.29 installed via brew) but succeed on CI. Co-authored-by: 6543 <6543@obermui.de>
4 years ago
API add/generalize pagination (#9452) * paginate results * fixed deadlock * prevented breaking change * updated swagger * go fmt * fixed find topic * go mod tidy * go mod vendor with go1.13.5 * fixed repo find topics * fixed unit test * added Limit method to Engine struct; use engine variable when provided; fixed gitignore * use ItemsPerPage for default pagesize; fix GetWatchers, getOrgUsersByOrgID and GetStargazers; fix GetAllCommits headers; reverted some changed behaviors * set Page value on Home route * improved memory allocations * fixed response headers * removed logfiles * fixed import order * import order * improved swagger * added function to get models.ListOptions from context * removed pagesize diff on unit test * fixed imports * removed unnecessary struct field * fixed go fmt * scoped PR * code improvements * code improvements * go mod tidy * fixed import order * fixed commit statuses session * fixed files headers * fixed headers; added pagination for notifications * go mod tidy * go fmt * removed Private from user search options; added setting.UI.IssuePagingNum as default valeu on repo's issues list * Apply suggestions from code review Co-Authored-By: 6543 <6543@obermui.de> Co-Authored-By: zeripath <art27@cantab.net> * fixed build error * CI.restart() * fixed merge conflicts resolve * fixed conflicts resolve * improved FindTrackedTimesOptions.ToOptions() method * added backwards compatibility on ListReleases request; fixed issue tracked time ToSession * fixed build error; fixed swagger template * fixed swagger template * fixed ListReleases backwards compatibility * added page to user search route Co-authored-by: techknowlogick <matti@mdranta.net> Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: zeripath <art27@cantab.net>
5 years ago
API add/generalize pagination (#9452) * paginate results * fixed deadlock * prevented breaking change * updated swagger * go fmt * fixed find topic * go mod tidy * go mod vendor with go1.13.5 * fixed repo find topics * fixed unit test * added Limit method to Engine struct; use engine variable when provided; fixed gitignore * use ItemsPerPage for default pagesize; fix GetWatchers, getOrgUsersByOrgID and GetStargazers; fix GetAllCommits headers; reverted some changed behaviors * set Page value on Home route * improved memory allocations * fixed response headers * removed logfiles * fixed import order * import order * improved swagger * added function to get models.ListOptions from context * removed pagesize diff on unit test * fixed imports * removed unnecessary struct field * fixed go fmt * scoped PR * code improvements * code improvements * go mod tidy * fixed import order * fixed commit statuses session * fixed files headers * fixed headers; added pagination for notifications * go mod tidy * go fmt * removed Private from user search options; added setting.UI.IssuePagingNum as default valeu on repo's issues list * Apply suggestions from code review Co-Authored-By: 6543 <6543@obermui.de> Co-Authored-By: zeripath <art27@cantab.net> * fixed build error * CI.restart() * fixed merge conflicts resolve * fixed conflicts resolve * improved FindTrackedTimesOptions.ToOptions() method * added backwards compatibility on ListReleases request; fixed issue tracked time ToSession * fixed build error; fixed swagger template * fixed swagger template * fixed ListReleases backwards compatibility * added page to user search route Co-authored-by: techknowlogick <matti@mdranta.net> Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: zeripath <art27@cantab.net>
5 years ago
API add/generalize pagination (#9452) * paginate results * fixed deadlock * prevented breaking change * updated swagger * go fmt * fixed find topic * go mod tidy * go mod vendor with go1.13.5 * fixed repo find topics * fixed unit test * added Limit method to Engine struct; use engine variable when provided; fixed gitignore * use ItemsPerPage for default pagesize; fix GetWatchers, getOrgUsersByOrgID and GetStargazers; fix GetAllCommits headers; reverted some changed behaviors * set Page value on Home route * improved memory allocations * fixed response headers * removed logfiles * fixed import order * import order * improved swagger * added function to get models.ListOptions from context * removed pagesize diff on unit test * fixed imports * removed unnecessary struct field * fixed go fmt * scoped PR * code improvements * code improvements * go mod tidy * fixed import order * fixed commit statuses session * fixed files headers * fixed headers; added pagination for notifications * go mod tidy * go fmt * removed Private from user search options; added setting.UI.IssuePagingNum as default valeu on repo's issues list * Apply suggestions from code review Co-Authored-By: 6543 <6543@obermui.de> Co-Authored-By: zeripath <art27@cantab.net> * fixed build error * CI.restart() * fixed merge conflicts resolve * fixed conflicts resolve * improved FindTrackedTimesOptions.ToOptions() method * added backwards compatibility on ListReleases request; fixed issue tracked time ToSession * fixed build error; fixed swagger template * fixed swagger template * fixed ListReleases backwards compatibility * added page to user search route Co-authored-by: techknowlogick <matti@mdranta.net> Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: zeripath <art27@cantab.net>
5 years ago
API add/generalize pagination (#9452) * paginate results * fixed deadlock * prevented breaking change * updated swagger * go fmt * fixed find topic * go mod tidy * go mod vendor with go1.13.5 * fixed repo find topics * fixed unit test * added Limit method to Engine struct; use engine variable when provided; fixed gitignore * use ItemsPerPage for default pagesize; fix GetWatchers, getOrgUsersByOrgID and GetStargazers; fix GetAllCommits headers; reverted some changed behaviors * set Page value on Home route * improved memory allocations * fixed response headers * removed logfiles * fixed import order * import order * improved swagger * added function to get models.ListOptions from context * removed pagesize diff on unit test * fixed imports * removed unnecessary struct field * fixed go fmt * scoped PR * code improvements * code improvements * go mod tidy * fixed import order * fixed commit statuses session * fixed files headers * fixed headers; added pagination for notifications * go mod tidy * go fmt * removed Private from user search options; added setting.UI.IssuePagingNum as default valeu on repo's issues list * Apply suggestions from code review Co-Authored-By: 6543 <6543@obermui.de> Co-Authored-By: zeripath <art27@cantab.net> * fixed build error * CI.restart() * fixed merge conflicts resolve * fixed conflicts resolve * improved FindTrackedTimesOptions.ToOptions() method * added backwards compatibility on ListReleases request; fixed issue tracked time ToSession * fixed build error; fixed swagger template * fixed swagger template * fixed ListReleases backwards compatibility * added page to user search route Co-authored-by: techknowlogick <matti@mdranta.net> Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: zeripath <art27@cantab.net>
5 years ago
API add/generalize pagination (#9452) * paginate results * fixed deadlock * prevented breaking change * updated swagger * go fmt * fixed find topic * go mod tidy * go mod vendor with go1.13.5 * fixed repo find topics * fixed unit test * added Limit method to Engine struct; use engine variable when provided; fixed gitignore * use ItemsPerPage for default pagesize; fix GetWatchers, getOrgUsersByOrgID and GetStargazers; fix GetAllCommits headers; reverted some changed behaviors * set Page value on Home route * improved memory allocations * fixed response headers * removed logfiles * fixed import order * import order * improved swagger * added function to get models.ListOptions from context * removed pagesize diff on unit test * fixed imports * removed unnecessary struct field * fixed go fmt * scoped PR * code improvements * code improvements * go mod tidy * fixed import order * fixed commit statuses session * fixed files headers * fixed headers; added pagination for notifications * go mod tidy * go fmt * removed Private from user search options; added setting.UI.IssuePagingNum as default valeu on repo's issues list * Apply suggestions from code review Co-Authored-By: 6543 <6543@obermui.de> Co-Authored-By: zeripath <art27@cantab.net> * fixed build error * CI.restart() * fixed merge conflicts resolve * fixed conflicts resolve * improved FindTrackedTimesOptions.ToOptions() method * added backwards compatibility on ListReleases request; fixed issue tracked time ToSession * fixed build error; fixed swagger template * fixed swagger template * fixed ListReleases backwards compatibility * added page to user search route Co-authored-by: techknowlogick <matti@mdranta.net> Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: zeripath <art27@cantab.net>
5 years ago
Move macaron to chi (#14293) Use [chi](https://github.com/go-chi/chi) instead of the forked [macaron](https://gitea.com/macaron/macaron). Since macaron and chi have conflicts with session share, this big PR becomes a have-to thing. According my previous idea, we can replace macaron step by step but I'm wrong. :( Below is a list of big changes on this PR. - [x] Define `context.ResponseWriter` interface with an implementation `context.Response`. - [x] Use chi instead of macaron, and also a customize `Route` to wrap chi so that the router usage is similar as before. - [x] Create different routers for `web`, `api`, `internal` and `install` so that the codes will be more clear and no magic . - [x] Use https://github.com/unrolled/render instead of macaron's internal render - [x] Use https://github.com/NYTimes/gziphandler instead of https://gitea.com/macaron/gzip - [x] Use https://gitea.com/go-chi/session which is a modified version of https://gitea.com/macaron/session and removed `nodb` support since it will not be maintained. **BREAK** - [x] Use https://gitea.com/go-chi/captcha which is a modified version of https://gitea.com/macaron/captcha - [x] Use https://gitea.com/go-chi/cache which is a modified version of https://gitea.com/macaron/cache - [x] Use https://gitea.com/go-chi/binding which is a modified version of https://gitea.com/macaron/binding - [x] Use https://github.com/go-chi/cors instead of https://gitea.com/macaron/cors - [x] Dropped https://gitea.com/macaron/i18n and make a new one in `code.gitea.io/gitea/modules/translation` - [x] Move validation form structs from `code.gitea.io/gitea/modules/auth` to `code.gitea.io/gitea/modules/forms` to avoid dependency cycle. - [x] Removed macaron log service because it's not need any more. **BREAK** - [x] All form structs have to be get by `web.GetForm(ctx)` in the route function but not as a function parameter on routes definition. - [x] Move Git HTTP protocol implementation to use routers directly. - [x] Fix the problem that chi routes don't support trailing slash but macaron did. - [x] `/api/v1/swagger` now will be redirect to `/api/swagger` but not render directly so that `APIContext` will not create a html render. Notices: - Chi router don't support request with trailing slash - Integration test `TestUserHeatmap` maybe mysql version related. It's failed on my macOS(mysql 5.7.29 installed via brew) but succeed on CI. Co-authored-by: 6543 <6543@obermui.de>
4 years ago
Move macaron to chi (#14293) Use [chi](https://github.com/go-chi/chi) instead of the forked [macaron](https://gitea.com/macaron/macaron). Since macaron and chi have conflicts with session share, this big PR becomes a have-to thing. According my previous idea, we can replace macaron step by step but I'm wrong. :( Below is a list of big changes on this PR. - [x] Define `context.ResponseWriter` interface with an implementation `context.Response`. - [x] Use chi instead of macaron, and also a customize `Route` to wrap chi so that the router usage is similar as before. - [x] Create different routers for `web`, `api`, `internal` and `install` so that the codes will be more clear and no magic . - [x] Use https://github.com/unrolled/render instead of macaron's internal render - [x] Use https://github.com/NYTimes/gziphandler instead of https://gitea.com/macaron/gzip - [x] Use https://gitea.com/go-chi/session which is a modified version of https://gitea.com/macaron/session and removed `nodb` support since it will not be maintained. **BREAK** - [x] Use https://gitea.com/go-chi/captcha which is a modified version of https://gitea.com/macaron/captcha - [x] Use https://gitea.com/go-chi/cache which is a modified version of https://gitea.com/macaron/cache - [x] Use https://gitea.com/go-chi/binding which is a modified version of https://gitea.com/macaron/binding - [x] Use https://github.com/go-chi/cors instead of https://gitea.com/macaron/cors - [x] Dropped https://gitea.com/macaron/i18n and make a new one in `code.gitea.io/gitea/modules/translation` - [x] Move validation form structs from `code.gitea.io/gitea/modules/auth` to `code.gitea.io/gitea/modules/forms` to avoid dependency cycle. - [x] Removed macaron log service because it's not need any more. **BREAK** - [x] All form structs have to be get by `web.GetForm(ctx)` in the route function but not as a function parameter on routes definition. - [x] Move Git HTTP protocol implementation to use routers directly. - [x] Fix the problem that chi routes don't support trailing slash but macaron did. - [x] `/api/v1/swagger` now will be redirect to `/api/swagger` but not render directly so that `APIContext` will not create a html render. Notices: - Chi router don't support request with trailing slash - Integration test `TestUserHeatmap` maybe mysql version related. It's failed on my macOS(mysql 5.7.29 installed via brew) but succeed on CI. Co-authored-by: 6543 <6543@obermui.de>
4 years ago
Issue due date (#3794) * Started adding deadline to ui * Implemented basic issue due date managing * Improved UI for due date managing * Added at least write access to the repo in order to modify issue due dates * Ui improvements * Added issue comments creation when adding/modifying/removing a due date * Show due date in issue list * Added api support for issue due dates * Fixed lint suggestions * Added deadline to sdk * Updated css * Added support for adding/modifiying deadlines for pull requests via api * Fixed comments not created when updating or removing a deadline * update sdk (will do properly once go-gitea/go-sdk#103 is merged) * enhanced updateIssueDeadline * Removed unnessecary Issue.DeadlineString * UI improvements * Small improvments to comment creation + ui & validation improvements * Check if an issue is overdue is now a seperate function * Updated go-sdk with govendor as it was merged * Simplified isOverdue method * removed unessecary deadline to 0 set * Update swagger definitions * Added missing return * Added an explanary comment * Improved updateIssueDeadline method so it'll only update `deadline_unix` * Small changes and improvements * no need to explicitly load the issue when updating a deadline, just use whats already there * small optimisations * Added check if a deadline was modified before updating it * Moved comment creating logic into its own function * Code cleanup for creating deadline comment * locale improvement * When modifying a deadline, the old deadline is saved with the comment * small improvments to xorm session handling when updating an issue deadline + style nitpicks * style nitpicks * Moved checking for if the user has write acces to middleware
7 years ago
Issue due date (#3794) * Started adding deadline to ui * Implemented basic issue due date managing * Improved UI for due date managing * Added at least write access to the repo in order to modify issue due dates * Ui improvements * Added issue comments creation when adding/modifying/removing a due date * Show due date in issue list * Added api support for issue due dates * Fixed lint suggestions * Added deadline to sdk * Updated css * Added support for adding/modifiying deadlines for pull requests via api * Fixed comments not created when updating or removing a deadline * update sdk (will do properly once go-gitea/go-sdk#103 is merged) * enhanced updateIssueDeadline * Removed unnessecary Issue.DeadlineString * UI improvements * Small improvments to comment creation + ui & validation improvements * Check if an issue is overdue is now a seperate function * Updated go-sdk with govendor as it was merged * Simplified isOverdue method * removed unessecary deadline to 0 set * Update swagger definitions * Added missing return * Added an explanary comment * Improved updateIssueDeadline method so it'll only update `deadline_unix` * Small changes and improvements * no need to explicitly load the issue when updating a deadline, just use whats already there * small optimisations * Added check if a deadline was modified before updating it * Moved comment creating logic into its own function * Code cleanup for creating deadline comment * locale improvement * When modifying a deadline, the old deadline is saved with the comment * small improvments to xorm session handling when updating an issue deadline + style nitpicks * style nitpicks * Moved checking for if the user has write acces to middleware
7 years ago
Issue due date (#3794) * Started adding deadline to ui * Implemented basic issue due date managing * Improved UI for due date managing * Added at least write access to the repo in order to modify issue due dates * Ui improvements * Added issue comments creation when adding/modifying/removing a due date * Show due date in issue list * Added api support for issue due dates * Fixed lint suggestions * Added deadline to sdk * Updated css * Added support for adding/modifiying deadlines for pull requests via api * Fixed comments not created when updating or removing a deadline * update sdk (will do properly once go-gitea/go-sdk#103 is merged) * enhanced updateIssueDeadline * Removed unnessecary Issue.DeadlineString * UI improvements * Small improvments to comment creation + ui & validation improvements * Check if an issue is overdue is now a seperate function * Updated go-sdk with govendor as it was merged * Simplified isOverdue method * removed unessecary deadline to 0 set * Update swagger definitions * Added missing return * Added an explanary comment * Improved updateIssueDeadline method so it'll only update `deadline_unix` * Small changes and improvements * no need to explicitly load the issue when updating a deadline, just use whats already there * small optimisations * Added check if a deadline was modified before updating it * Moved comment creating logic into its own function * Code cleanup for creating deadline comment * locale improvement * When modifying a deadline, the old deadline is saved with the comment * small improvments to xorm session handling when updating an issue deadline + style nitpicks * style nitpicks * Moved checking for if the user has write acces to middleware
7 years ago
Move macaron to chi (#14293) Use [chi](https://github.com/go-chi/chi) instead of the forked [macaron](https://gitea.com/macaron/macaron). Since macaron and chi have conflicts with session share, this big PR becomes a have-to thing. According my previous idea, we can replace macaron step by step but I'm wrong. :( Below is a list of big changes on this PR. - [x] Define `context.ResponseWriter` interface with an implementation `context.Response`. - [x] Use chi instead of macaron, and also a customize `Route` to wrap chi so that the router usage is similar as before. - [x] Create different routers for `web`, `api`, `internal` and `install` so that the codes will be more clear and no magic . - [x] Use https://github.com/unrolled/render instead of macaron's internal render - [x] Use https://github.com/NYTimes/gziphandler instead of https://gitea.com/macaron/gzip - [x] Use https://gitea.com/go-chi/session which is a modified version of https://gitea.com/macaron/session and removed `nodb` support since it will not be maintained. **BREAK** - [x] Use https://gitea.com/go-chi/captcha which is a modified version of https://gitea.com/macaron/captcha - [x] Use https://gitea.com/go-chi/cache which is a modified version of https://gitea.com/macaron/cache - [x] Use https://gitea.com/go-chi/binding which is a modified version of https://gitea.com/macaron/binding - [x] Use https://github.com/go-chi/cors instead of https://gitea.com/macaron/cors - [x] Dropped https://gitea.com/macaron/i18n and make a new one in `code.gitea.io/gitea/modules/translation` - [x] Move validation form structs from `code.gitea.io/gitea/modules/auth` to `code.gitea.io/gitea/modules/forms` to avoid dependency cycle. - [x] Removed macaron log service because it's not need any more. **BREAK** - [x] All form structs have to be get by `web.GetForm(ctx)` in the route function but not as a function parameter on routes definition. - [x] Move Git HTTP protocol implementation to use routers directly. - [x] Fix the problem that chi routes don't support trailing slash but macaron did. - [x] `/api/v1/swagger` now will be redirect to `/api/swagger` but not render directly so that `APIContext` will not create a html render. Notices: - Chi router don't support request with trailing slash - Integration test `TestUserHeatmap` maybe mysql version related. It's failed on my macOS(mysql 5.7.29 installed via brew) but succeed on CI. Co-authored-by: 6543 <6543@obermui.de>
4 years ago
Move macaron to chi (#14293) Use [chi](https://github.com/go-chi/chi) instead of the forked [macaron](https://gitea.com/macaron/macaron). Since macaron and chi have conflicts with session share, this big PR becomes a have-to thing. According my previous idea, we can replace macaron step by step but I'm wrong. :( Below is a list of big changes on this PR. - [x] Define `context.ResponseWriter` interface with an implementation `context.Response`. - [x] Use chi instead of macaron, and also a customize `Route` to wrap chi so that the router usage is similar as before. - [x] Create different routers for `web`, `api`, `internal` and `install` so that the codes will be more clear and no magic . - [x] Use https://github.com/unrolled/render instead of macaron's internal render - [x] Use https://github.com/NYTimes/gziphandler instead of https://gitea.com/macaron/gzip - [x] Use https://gitea.com/go-chi/session which is a modified version of https://gitea.com/macaron/session and removed `nodb` support since it will not be maintained. **BREAK** - [x] Use https://gitea.com/go-chi/captcha which is a modified version of https://gitea.com/macaron/captcha - [x] Use https://gitea.com/go-chi/cache which is a modified version of https://gitea.com/macaron/cache - [x] Use https://gitea.com/go-chi/binding which is a modified version of https://gitea.com/macaron/binding - [x] Use https://github.com/go-chi/cors instead of https://gitea.com/macaron/cors - [x] Dropped https://gitea.com/macaron/i18n and make a new one in `code.gitea.io/gitea/modules/translation` - [x] Move validation form structs from `code.gitea.io/gitea/modules/auth` to `code.gitea.io/gitea/modules/forms` to avoid dependency cycle. - [x] Removed macaron log service because it's not need any more. **BREAK** - [x] All form structs have to be get by `web.GetForm(ctx)` in the route function but not as a function parameter on routes definition. - [x] Move Git HTTP protocol implementation to use routers directly. - [x] Fix the problem that chi routes don't support trailing slash but macaron did. - [x] `/api/v1/swagger` now will be redirect to `/api/swagger` but not render directly so that `APIContext` will not create a html render. Notices: - Chi router don't support request with trailing slash - Integration test `TestUserHeatmap` maybe mysql version related. It's failed on my macOS(mysql 5.7.29 installed via brew) but succeed on CI. Co-authored-by: 6543 <6543@obermui.de>
4 years ago
Issue due date (#3794) * Started adding deadline to ui * Implemented basic issue due date managing * Improved UI for due date managing * Added at least write access to the repo in order to modify issue due dates * Ui improvements * Added issue comments creation when adding/modifying/removing a due date * Show due date in issue list * Added api support for issue due dates * Fixed lint suggestions * Added deadline to sdk * Updated css * Added support for adding/modifiying deadlines for pull requests via api * Fixed comments not created when updating or removing a deadline * update sdk (will do properly once go-gitea/go-sdk#103 is merged) * enhanced updateIssueDeadline * Removed unnessecary Issue.DeadlineString * UI improvements * Small improvments to comment creation + ui & validation improvements * Check if an issue is overdue is now a seperate function * Updated go-sdk with govendor as it was merged * Simplified isOverdue method * removed unessecary deadline to 0 set * Update swagger definitions * Added missing return * Added an explanary comment * Improved updateIssueDeadline method so it'll only update `deadline_unix` * Small changes and improvements * no need to explicitly load the issue when updating a deadline, just use whats already there * small optimisations * Added check if a deadline was modified before updating it * Moved comment creating logic into its own function * Code cleanup for creating deadline comment * locale improvement * When modifying a deadline, the old deadline is saved with the comment * small improvments to xorm session handling when updating an issue deadline + style nitpicks * style nitpicks * Moved checking for if the user has write acces to middleware
7 years ago
Move macaron to chi (#14293) Use [chi](https://github.com/go-chi/chi) instead of the forked [macaron](https://gitea.com/macaron/macaron). Since macaron and chi have conflicts with session share, this big PR becomes a have-to thing. According my previous idea, we can replace macaron step by step but I'm wrong. :( Below is a list of big changes on this PR. - [x] Define `context.ResponseWriter` interface with an implementation `context.Response`. - [x] Use chi instead of macaron, and also a customize `Route` to wrap chi so that the router usage is similar as before. - [x] Create different routers for `web`, `api`, `internal` and `install` so that the codes will be more clear and no magic . - [x] Use https://github.com/unrolled/render instead of macaron's internal render - [x] Use https://github.com/NYTimes/gziphandler instead of https://gitea.com/macaron/gzip - [x] Use https://gitea.com/go-chi/session which is a modified version of https://gitea.com/macaron/session and removed `nodb` support since it will not be maintained. **BREAK** - [x] Use https://gitea.com/go-chi/captcha which is a modified version of https://gitea.com/macaron/captcha - [x] Use https://gitea.com/go-chi/cache which is a modified version of https://gitea.com/macaron/cache - [x] Use https://gitea.com/go-chi/binding which is a modified version of https://gitea.com/macaron/binding - [x] Use https://github.com/go-chi/cors instead of https://gitea.com/macaron/cors - [x] Dropped https://gitea.com/macaron/i18n and make a new one in `code.gitea.io/gitea/modules/translation` - [x] Move validation form structs from `code.gitea.io/gitea/modules/auth` to `code.gitea.io/gitea/modules/forms` to avoid dependency cycle. - [x] Removed macaron log service because it's not need any more. **BREAK** - [x] All form structs have to be get by `web.GetForm(ctx)` in the route function but not as a function parameter on routes definition. - [x] Move Git HTTP protocol implementation to use routers directly. - [x] Fix the problem that chi routes don't support trailing slash but macaron did. - [x] `/api/v1/swagger` now will be redirect to `/api/swagger` but not render directly so that `APIContext` will not create a html render. Notices: - Chi router don't support request with trailing slash - Integration test `TestUserHeatmap` maybe mysql version related. It's failed on my macOS(mysql 5.7.29 installed via brew) but succeed on CI. Co-authored-by: 6543 <6543@obermui.de>
4 years ago
Move macaron to chi (#14293) Use [chi](https://github.com/go-chi/chi) instead of the forked [macaron](https://gitea.com/macaron/macaron). Since macaron and chi have conflicts with session share, this big PR becomes a have-to thing. According my previous idea, we can replace macaron step by step but I'm wrong. :( Below is a list of big changes on this PR. - [x] Define `context.ResponseWriter` interface with an implementation `context.Response`. - [x] Use chi instead of macaron, and also a customize `Route` to wrap chi so that the router usage is similar as before. - [x] Create different routers for `web`, `api`, `internal` and `install` so that the codes will be more clear and no magic . - [x] Use https://github.com/unrolled/render instead of macaron's internal render - [x] Use https://github.com/NYTimes/gziphandler instead of https://gitea.com/macaron/gzip - [x] Use https://gitea.com/go-chi/session which is a modified version of https://gitea.com/macaron/session and removed `nodb` support since it will not be maintained. **BREAK** - [x] Use https://gitea.com/go-chi/captcha which is a modified version of https://gitea.com/macaron/captcha - [x] Use https://gitea.com/go-chi/cache which is a modified version of https://gitea.com/macaron/cache - [x] Use https://gitea.com/go-chi/binding which is a modified version of https://gitea.com/macaron/binding - [x] Use https://github.com/go-chi/cors instead of https://gitea.com/macaron/cors - [x] Dropped https://gitea.com/macaron/i18n and make a new one in `code.gitea.io/gitea/modules/translation` - [x] Move validation form structs from `code.gitea.io/gitea/modules/auth` to `code.gitea.io/gitea/modules/forms` to avoid dependency cycle. - [x] Removed macaron log service because it's not need any more. **BREAK** - [x] All form structs have to be get by `web.GetForm(ctx)` in the route function but not as a function parameter on routes definition. - [x] Move Git HTTP protocol implementation to use routers directly. - [x] Fix the problem that chi routes don't support trailing slash but macaron did. - [x] `/api/v1/swagger` now will be redirect to `/api/swagger` but not render directly so that `APIContext` will not create a html render. Notices: - Chi router don't support request with trailing slash - Integration test `TestUserHeatmap` maybe mysql version related. It's failed on my macOS(mysql 5.7.29 installed via brew) but succeed on CI. Co-authored-by: 6543 <6543@obermui.de>
4 years ago
[Enhancement] Allow admin to merge pr with protected file changes (#12078) * [Enhancement] Allow admin to merge pr with protected file changes As tilte, show protected message in diff page and merge box. Signed-off-by: a1012112796 <1012112796@qq.com> * remove unused ver * Update options/locale/locale_en-US.ini Co-authored-by: Cirno the Strongest <1447794+CirnoT@users.noreply.github.com> * Add TrN * Apply suggestions from code review * fix lint * Update options/locale/locale_en-US.ini Co-authored-by: zeripath <art27@cantab.net> * Apply suggestions from code review * move pr proteced files check to TestPatch * Call TestPatch when protected branches settings changed * Apply review suggestion @CirnoT * move to service @lunny * slightly restructure routers/private/hook.go Adds a lot of comments and simplifies the logic Signed-off-by: Andrew Thornton <art27@cantab.net> * placate lint Signed-off-by: Andrew Thornton <art27@cantab.net> * skip duplicate protected files check * fix check logic * slight refactor of TestPatch Signed-off-by: Andrew Thornton <art27@cantab.net> * When checking for protected files changes in TestPatch use the temporary repository Signed-off-by: Andrew Thornton <art27@cantab.net> * fix introduced issue with hook Signed-off-by: Andrew Thornton <art27@cantab.net> * Remove the check on PR index being greater than 0 as it unnecessary Signed-off-by: Andrew Thornton <art27@cantab.net> Co-authored-by: techknowlogick <matti@mdranta.net> Co-authored-by: Cirno the Strongest <1447794+CirnoT@users.noreply.github.com> Co-authored-by: zeripath <art27@cantab.net> Co-authored-by: techknowlogick <techknowlogick@gitea.io>
4 years ago
Compare branches, commits and tags with each other (#6991) * Supports tags when comparing commits or branches Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Hide headline when only comparing and don't load unused data Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Merges compare logics to allow comparing branches, commits and tags with eachother Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Display branch or tag instead of commit when used for comparing Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Show pull request form after click on button Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Transfers relevant pull.go changes from master to compare.go Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Fixes error when comparing forks against a commit or tag Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Removes console.log from JavaScript file Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Show icon next to commit reference when comparing branch or tag Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Updates css file Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Fixes import order * Renames template variable * Update routers/repo/compare.go Co-Authored-By: zeripath <art27@cantab.net> * Update from master Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Allow short-shas in compare * Renames prInfo to compareInfo Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Check PR permissions only if compare is pull request Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Adjusts comment Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Use compareInfo instead of prInfo
6 years ago
Compare branches, commits and tags with each other (#6991) * Supports tags when comparing commits or branches Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Hide headline when only comparing and don't load unused data Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Merges compare logics to allow comparing branches, commits and tags with eachother Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Display branch or tag instead of commit when used for comparing Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Show pull request form after click on button Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Transfers relevant pull.go changes from master to compare.go Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Fixes error when comparing forks against a commit or tag Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Removes console.log from JavaScript file Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Show icon next to commit reference when comparing branch or tag Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Updates css file Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Fixes import order * Renames template variable * Update routers/repo/compare.go Co-Authored-By: zeripath <art27@cantab.net> * Update from master Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Allow short-shas in compare * Renames prInfo to compareInfo Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Check PR permissions only if compare is pull request Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Adjusts comment Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Use compareInfo instead of prInfo
6 years ago
Compare branches, commits and tags with each other (#6991) * Supports tags when comparing commits or branches Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Hide headline when only comparing and don't load unused data Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Merges compare logics to allow comparing branches, commits and tags with eachother Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Display branch or tag instead of commit when used for comparing Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Show pull request form after click on button Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Transfers relevant pull.go changes from master to compare.go Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Fixes error when comparing forks against a commit or tag Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Removes console.log from JavaScript file Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Show icon next to commit reference when comparing branch or tag Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Updates css file Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Fixes import order * Renames template variable * Update routers/repo/compare.go Co-Authored-By: zeripath <art27@cantab.net> * Update from master Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Allow short-shas in compare * Renames prInfo to compareInfo Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Check PR permissions only if compare is pull request Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Adjusts comment Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com> * Use compareInfo instead of prInfo
6 years ago
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105
  1. // Copyright 2016 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package repo
  5. import (
  6. "fmt"
  7. "net/http"
  8. "strings"
  9. "time"
  10. "code.gitea.io/gitea/models"
  11. "code.gitea.io/gitea/modules/context"
  12. "code.gitea.io/gitea/modules/convert"
  13. auth "code.gitea.io/gitea/modules/forms"
  14. "code.gitea.io/gitea/modules/git"
  15. "code.gitea.io/gitea/modules/log"
  16. "code.gitea.io/gitea/modules/notification"
  17. api "code.gitea.io/gitea/modules/structs"
  18. "code.gitea.io/gitea/modules/timeutil"
  19. "code.gitea.io/gitea/modules/web"
  20. "code.gitea.io/gitea/routers/api/v1/utils"
  21. issue_service "code.gitea.io/gitea/services/issue"
  22. pull_service "code.gitea.io/gitea/services/pull"
  23. )
  24. // ListPullRequests returns a list of all PRs
  25. func ListPullRequests(ctx *context.APIContext) {
  26. // swagger:operation GET /repos/{owner}/{repo}/pulls repository repoListPullRequests
  27. // ---
  28. // summary: List a repo's pull requests
  29. // produces:
  30. // - application/json
  31. // parameters:
  32. // - name: owner
  33. // in: path
  34. // description: owner of the repo
  35. // type: string
  36. // required: true
  37. // - name: repo
  38. // in: path
  39. // description: name of the repo
  40. // type: string
  41. // required: true
  42. // - name: state
  43. // in: query
  44. // description: "State of pull request: open or closed (optional)"
  45. // type: string
  46. // enum: [closed, open, all]
  47. // - name: sort
  48. // in: query
  49. // description: "Type of sort"
  50. // type: string
  51. // enum: [oldest, recentupdate, leastupdate, mostcomment, leastcomment, priority]
  52. // - name: milestone
  53. // in: query
  54. // description: "ID of the milestone"
  55. // type: integer
  56. // format: int64
  57. // - name: labels
  58. // in: query
  59. // description: "Label IDs"
  60. // type: array
  61. // collectionFormat: multi
  62. // items:
  63. // type: integer
  64. // format: int64
  65. // - name: page
  66. // in: query
  67. // description: page number of results to return (1-based)
  68. // type: integer
  69. // - name: limit
  70. // in: query
  71. // description: page size of results
  72. // type: integer
  73. // responses:
  74. // "200":
  75. // "$ref": "#/responses/PullRequestList"
  76. listOptions := utils.GetListOptions(ctx)
  77. prs, maxResults, err := models.PullRequests(ctx.Repo.Repository.ID, &models.PullRequestsOptions{
  78. ListOptions: listOptions,
  79. State: ctx.QueryTrim("state"),
  80. SortType: ctx.QueryTrim("sort"),
  81. Labels: ctx.QueryStrings("labels"),
  82. MilestoneID: ctx.QueryInt64("milestone"),
  83. })
  84. if err != nil {
  85. ctx.Error(http.StatusInternalServerError, "PullRequests", err)
  86. return
  87. }
  88. apiPrs := make([]*api.PullRequest, len(prs))
  89. for i := range prs {
  90. if err = prs[i].LoadIssue(); err != nil {
  91. ctx.Error(http.StatusInternalServerError, "LoadIssue", err)
  92. return
  93. }
  94. if err = prs[i].LoadAttributes(); err != nil {
  95. ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
  96. return
  97. }
  98. if err = prs[i].LoadBaseRepo(); err != nil {
  99. ctx.Error(http.StatusInternalServerError, "LoadBaseRepo", err)
  100. return
  101. }
  102. if err = prs[i].LoadHeadRepo(); err != nil {
  103. ctx.Error(http.StatusInternalServerError, "LoadHeadRepo", err)
  104. return
  105. }
  106. apiPrs[i] = convert.ToAPIPullRequest(prs[i])
  107. }
  108. ctx.SetLinkHeader(int(maxResults), listOptions.PageSize)
  109. ctx.Header().Set("X-Total-Count", fmt.Sprintf("%d", maxResults))
  110. ctx.Header().Set("Access-Control-Expose-Headers", "X-Total-Count, Link")
  111. ctx.JSON(http.StatusOK, &apiPrs)
  112. }
  113. // GetPullRequest returns a single PR based on index
  114. func GetPullRequest(ctx *context.APIContext) {
  115. // swagger:operation GET /repos/{owner}/{repo}/pulls/{index} repository repoGetPullRequest
  116. // ---
  117. // summary: Get a pull request
  118. // produces:
  119. // - application/json
  120. // parameters:
  121. // - name: owner
  122. // in: path
  123. // description: owner of the repo
  124. // type: string
  125. // required: true
  126. // - name: repo
  127. // in: path
  128. // description: name of the repo
  129. // type: string
  130. // required: true
  131. // - name: index
  132. // in: path
  133. // description: index of the pull request to get
  134. // type: integer
  135. // format: int64
  136. // required: true
  137. // responses:
  138. // "200":
  139. // "$ref": "#/responses/PullRequest"
  140. // "404":
  141. // "$ref": "#/responses/notFound"
  142. pr, err := models.GetPullRequestByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
  143. if err != nil {
  144. if models.IsErrPullRequestNotExist(err) {
  145. ctx.NotFound()
  146. } else {
  147. ctx.Error(http.StatusInternalServerError, "GetPullRequestByIndex", err)
  148. }
  149. return
  150. }
  151. if err = pr.LoadBaseRepo(); err != nil {
  152. ctx.Error(http.StatusInternalServerError, "LoadBaseRepo", err)
  153. return
  154. }
  155. if err = pr.LoadHeadRepo(); err != nil {
  156. ctx.Error(http.StatusInternalServerError, "LoadHeadRepo", err)
  157. return
  158. }
  159. ctx.JSON(http.StatusOK, convert.ToAPIPullRequest(pr))
  160. }
  161. // DownloadPullDiff render a pull's raw diff
  162. func DownloadPullDiff(ctx *context.APIContext) {
  163. // swagger:operation GET /repos/{owner}/{repo}/pulls/{index}.diff repository repoDownloadPullDiff
  164. // ---
  165. // summary: Get a pull request diff
  166. // produces:
  167. // - text/plain
  168. // parameters:
  169. // - name: owner
  170. // in: path
  171. // description: owner of the repo
  172. // type: string
  173. // required: true
  174. // - name: repo
  175. // in: path
  176. // description: name of the repo
  177. // type: string
  178. // required: true
  179. // - name: index
  180. // in: path
  181. // description: index of the pull request to get
  182. // type: integer
  183. // format: int64
  184. // required: true
  185. // responses:
  186. // "200":
  187. // "$ref": "#/responses/string"
  188. // "404":
  189. // "$ref": "#/responses/notFound"
  190. DownloadPullDiffOrPatch(ctx, false)
  191. }
  192. // DownloadPullPatch render a pull's raw patch
  193. func DownloadPullPatch(ctx *context.APIContext) {
  194. // swagger:operation GET /repos/{owner}/{repo}/pulls/{index}.patch repository repoDownloadPullPatch
  195. // ---
  196. // summary: Get a pull request patch file
  197. // produces:
  198. // - text/plain
  199. // parameters:
  200. // - name: owner
  201. // in: path
  202. // description: owner of the repo
  203. // type: string
  204. // required: true
  205. // - name: repo
  206. // in: path
  207. // description: name of the repo
  208. // type: string
  209. // required: true
  210. // - name: index
  211. // in: path
  212. // description: index of the pull request to get
  213. // type: integer
  214. // format: int64
  215. // required: true
  216. // responses:
  217. // "200":
  218. // "$ref": "#/responses/string"
  219. // "404":
  220. // "$ref": "#/responses/notFound"
  221. DownloadPullDiffOrPatch(ctx, true)
  222. }
  223. // DownloadPullDiffOrPatch render a pull's raw diff or patch
  224. func DownloadPullDiffOrPatch(ctx *context.APIContext, patch bool) {
  225. pr, err := models.GetPullRequestByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
  226. if err != nil {
  227. if models.IsErrPullRequestNotExist(err) {
  228. ctx.NotFound()
  229. } else {
  230. ctx.InternalServerError(err)
  231. }
  232. return
  233. }
  234. if err := pull_service.DownloadDiffOrPatch(pr, ctx, patch); err != nil {
  235. ctx.InternalServerError(err)
  236. return
  237. }
  238. }
  239. // CreatePullRequest does what it says
  240. func CreatePullRequest(ctx *context.APIContext) {
  241. // swagger:operation POST /repos/{owner}/{repo}/pulls repository repoCreatePullRequest
  242. // ---
  243. // summary: Create a pull request
  244. // consumes:
  245. // - application/json
  246. // produces:
  247. // - application/json
  248. // parameters:
  249. // - name: owner
  250. // in: path
  251. // description: owner of the repo
  252. // type: string
  253. // required: true
  254. // - name: repo
  255. // in: path
  256. // description: name of the repo
  257. // type: string
  258. // required: true
  259. // - name: body
  260. // in: body
  261. // schema:
  262. // "$ref": "#/definitions/CreatePullRequestOption"
  263. // responses:
  264. // "201":
  265. // "$ref": "#/responses/PullRequest"
  266. // "409":
  267. // "$ref": "#/responses/error"
  268. // "422":
  269. // "$ref": "#/responses/validationError"
  270. form := *web.GetForm(ctx).(*api.CreatePullRequestOption)
  271. if form.Head == form.Base {
  272. ctx.Error(http.StatusUnprocessableEntity, "BaseHeadSame",
  273. "Invalid PullRequest: There are no changes between the head and the base")
  274. return
  275. }
  276. var (
  277. repo = ctx.Repo.Repository
  278. labelIDs []int64
  279. assigneeID int64
  280. milestoneID int64
  281. )
  282. // Get repo/branch information
  283. _, headRepo, headGitRepo, compareInfo, baseBranch, headBranch := parseCompareInfo(ctx, form)
  284. if ctx.Written() {
  285. return
  286. }
  287. defer headGitRepo.Close()
  288. // Check if another PR exists with the same targets
  289. existingPr, err := models.GetUnmergedPullRequest(headRepo.ID, ctx.Repo.Repository.ID, headBranch, baseBranch)
  290. if err != nil {
  291. if !models.IsErrPullRequestNotExist(err) {
  292. ctx.Error(http.StatusInternalServerError, "GetUnmergedPullRequest", err)
  293. return
  294. }
  295. } else {
  296. err = models.ErrPullRequestAlreadyExists{
  297. ID: existingPr.ID,
  298. IssueID: existingPr.Index,
  299. HeadRepoID: existingPr.HeadRepoID,
  300. BaseRepoID: existingPr.BaseRepoID,
  301. HeadBranch: existingPr.HeadBranch,
  302. BaseBranch: existingPr.BaseBranch,
  303. }
  304. ctx.Error(http.StatusConflict, "GetUnmergedPullRequest", err)
  305. return
  306. }
  307. if len(form.Labels) > 0 {
  308. labels, err := models.GetLabelsInRepoByIDs(ctx.Repo.Repository.ID, form.Labels)
  309. if err != nil {
  310. ctx.Error(http.StatusInternalServerError, "GetLabelsInRepoByIDs", err)
  311. return
  312. }
  313. labelIDs = make([]int64, len(form.Labels))
  314. orgLabelIDs := make([]int64, len(form.Labels))
  315. for i := range labels {
  316. labelIDs[i] = labels[i].ID
  317. }
  318. if ctx.Repo.Owner.IsOrganization() {
  319. orgLabels, err := models.GetLabelsInOrgByIDs(ctx.Repo.Owner.ID, form.Labels)
  320. if err != nil {
  321. ctx.Error(http.StatusInternalServerError, "GetLabelsInOrgByIDs", err)
  322. return
  323. }
  324. for i := range orgLabels {
  325. orgLabelIDs[i] = orgLabels[i].ID
  326. }
  327. }
  328. labelIDs = append(labelIDs, orgLabelIDs...)
  329. }
  330. if form.Milestone > 0 {
  331. milestone, err := models.GetMilestoneByRepoID(ctx.Repo.Repository.ID, milestoneID)
  332. if err != nil {
  333. if models.IsErrMilestoneNotExist(err) {
  334. ctx.NotFound()
  335. } else {
  336. ctx.Error(http.StatusInternalServerError, "GetMilestoneByRepoID", err)
  337. }
  338. return
  339. }
  340. milestoneID = milestone.ID
  341. }
  342. var deadlineUnix timeutil.TimeStamp
  343. if form.Deadline != nil {
  344. deadlineUnix = timeutil.TimeStamp(form.Deadline.Unix())
  345. }
  346. prIssue := &models.Issue{
  347. RepoID: repo.ID,
  348. Title: form.Title,
  349. PosterID: ctx.User.ID,
  350. Poster: ctx.User,
  351. MilestoneID: milestoneID,
  352. AssigneeID: assigneeID,
  353. IsPull: true,
  354. Content: form.Body,
  355. DeadlineUnix: deadlineUnix,
  356. }
  357. pr := &models.PullRequest{
  358. HeadRepoID: headRepo.ID,
  359. BaseRepoID: repo.ID,
  360. HeadBranch: headBranch,
  361. BaseBranch: baseBranch,
  362. HeadRepo: headRepo,
  363. BaseRepo: repo,
  364. MergeBase: compareInfo.MergeBase,
  365. Type: models.PullRequestGitea,
  366. }
  367. // Get all assignee IDs
  368. assigneeIDs, err := models.MakeIDsFromAPIAssigneesToAdd(form.Assignee, form.Assignees)
  369. if err != nil {
  370. if models.IsErrUserNotExist(err) {
  371. ctx.Error(http.StatusUnprocessableEntity, "", fmt.Sprintf("Assignee does not exist: [name: %s]", err))
  372. } else {
  373. ctx.Error(http.StatusInternalServerError, "AddAssigneeByName", err)
  374. }
  375. return
  376. }
  377. // Check if the passed assignees is assignable
  378. for _, aID := range assigneeIDs {
  379. assignee, err := models.GetUserByID(aID)
  380. if err != nil {
  381. ctx.Error(http.StatusInternalServerError, "GetUserByID", err)
  382. return
  383. }
  384. valid, err := models.CanBeAssigned(assignee, repo, true)
  385. if err != nil {
  386. ctx.Error(http.StatusInternalServerError, "canBeAssigned", err)
  387. return
  388. }
  389. if !valid {
  390. ctx.Error(http.StatusUnprocessableEntity, "canBeAssigned", models.ErrUserDoesNotHaveAccessToRepo{UserID: aID, RepoName: repo.Name})
  391. return
  392. }
  393. }
  394. if err := pull_service.NewPullRequest(repo, prIssue, labelIDs, []string{}, pr, assigneeIDs); err != nil {
  395. if models.IsErrUserDoesNotHaveAccessToRepo(err) {
  396. ctx.Error(http.StatusBadRequest, "UserDoesNotHaveAccessToRepo", err)
  397. return
  398. }
  399. ctx.Error(http.StatusInternalServerError, "NewPullRequest", err)
  400. return
  401. }
  402. log.Trace("Pull request created: %d/%d", repo.ID, prIssue.ID)
  403. ctx.JSON(http.StatusCreated, convert.ToAPIPullRequest(pr))
  404. }
  405. // EditPullRequest does what it says
  406. func EditPullRequest(ctx *context.APIContext) {
  407. // swagger:operation PATCH /repos/{owner}/{repo}/pulls/{index} repository repoEditPullRequest
  408. // ---
  409. // summary: Update a pull request. If using deadline only the date will be taken into account, and time of day ignored.
  410. // consumes:
  411. // - application/json
  412. // produces:
  413. // - application/json
  414. // parameters:
  415. // - name: owner
  416. // in: path
  417. // description: owner of the repo
  418. // type: string
  419. // required: true
  420. // - name: repo
  421. // in: path
  422. // description: name of the repo
  423. // type: string
  424. // required: true
  425. // - name: index
  426. // in: path
  427. // description: index of the pull request to edit
  428. // type: integer
  429. // format: int64
  430. // required: true
  431. // - name: body
  432. // in: body
  433. // schema:
  434. // "$ref": "#/definitions/EditPullRequestOption"
  435. // responses:
  436. // "201":
  437. // "$ref": "#/responses/PullRequest"
  438. // "403":
  439. // "$ref": "#/responses/forbidden"
  440. // "409":
  441. // "$ref": "#/responses/error"
  442. // "412":
  443. // "$ref": "#/responses/error"
  444. // "422":
  445. // "$ref": "#/responses/validationError"
  446. form := web.GetForm(ctx).(*api.EditPullRequestOption)
  447. pr, err := models.GetPullRequestByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
  448. if err != nil {
  449. if models.IsErrPullRequestNotExist(err) {
  450. ctx.NotFound()
  451. } else {
  452. ctx.Error(http.StatusInternalServerError, "GetPullRequestByIndex", err)
  453. }
  454. return
  455. }
  456. err = pr.LoadIssue()
  457. if err != nil {
  458. ctx.Error(http.StatusInternalServerError, "LoadIssue", err)
  459. return
  460. }
  461. issue := pr.Issue
  462. issue.Repo = ctx.Repo.Repository
  463. if !issue.IsPoster(ctx.User.ID) && !ctx.Repo.CanWrite(models.UnitTypePullRequests) {
  464. ctx.Status(http.StatusForbidden)
  465. return
  466. }
  467. oldTitle := issue.Title
  468. if len(form.Title) > 0 {
  469. issue.Title = form.Title
  470. }
  471. if len(form.Body) > 0 {
  472. issue.Content = form.Body
  473. }
  474. // Update or remove deadline if set
  475. if form.Deadline != nil || form.RemoveDeadline != nil {
  476. var deadlineUnix timeutil.TimeStamp
  477. if (form.RemoveDeadline == nil || !*form.RemoveDeadline) && !form.Deadline.IsZero() {
  478. deadline := time.Date(form.Deadline.Year(), form.Deadline.Month(), form.Deadline.Day(),
  479. 23, 59, 59, 0, form.Deadline.Location())
  480. deadlineUnix = timeutil.TimeStamp(deadline.Unix())
  481. }
  482. if err := models.UpdateIssueDeadline(issue, deadlineUnix, ctx.User); err != nil {
  483. ctx.Error(http.StatusInternalServerError, "UpdateIssueDeadline", err)
  484. return
  485. }
  486. issue.DeadlineUnix = deadlineUnix
  487. }
  488. // Add/delete assignees
  489. // Deleting is done the GitHub way (quote from their api documentation):
  490. // https://developer.github.com/v3/issues/#edit-an-issue
  491. // "assignees" (array): Logins for Users to assign to this issue.
  492. // Pass one or more user logins to replace the set of assignees on this Issue.
  493. // Send an empty array ([]) to clear all assignees from the Issue.
  494. if ctx.Repo.CanWrite(models.UnitTypePullRequests) && (form.Assignees != nil || len(form.Assignee) > 0) {
  495. err = issue_service.UpdateAssignees(issue, form.Assignee, form.Assignees, ctx.User)
  496. if err != nil {
  497. if models.IsErrUserNotExist(err) {
  498. ctx.Error(http.StatusUnprocessableEntity, "", fmt.Sprintf("Assignee does not exist: [name: %s]", err))
  499. } else {
  500. ctx.Error(http.StatusInternalServerError, "UpdateAssignees", err)
  501. }
  502. return
  503. }
  504. }
  505. if ctx.Repo.CanWrite(models.UnitTypePullRequests) && form.Milestone != 0 &&
  506. issue.MilestoneID != form.Milestone {
  507. oldMilestoneID := issue.MilestoneID
  508. issue.MilestoneID = form.Milestone
  509. if err = issue_service.ChangeMilestoneAssign(issue, ctx.User, oldMilestoneID); err != nil {
  510. ctx.Error(http.StatusInternalServerError, "ChangeMilestoneAssign", err)
  511. return
  512. }
  513. }
  514. if ctx.Repo.CanWrite(models.UnitTypePullRequests) && form.Labels != nil {
  515. labels, err := models.GetLabelsInRepoByIDs(ctx.Repo.Repository.ID, form.Labels)
  516. if err != nil {
  517. ctx.Error(http.StatusInternalServerError, "GetLabelsInRepoByIDsError", err)
  518. return
  519. }
  520. if ctx.Repo.Owner.IsOrganization() {
  521. orgLabels, err := models.GetLabelsInOrgByIDs(ctx.Repo.Owner.ID, form.Labels)
  522. if err != nil {
  523. ctx.Error(http.StatusInternalServerError, "GetLabelsInOrgByIDs", err)
  524. return
  525. }
  526. labels = append(labels, orgLabels...)
  527. }
  528. if err = issue.ReplaceLabels(labels, ctx.User); err != nil {
  529. ctx.Error(http.StatusInternalServerError, "ReplaceLabelsError", err)
  530. return
  531. }
  532. }
  533. if form.State != nil {
  534. issue.IsClosed = (api.StateClosed == api.StateType(*form.State))
  535. }
  536. statusChangeComment, titleChanged, err := models.UpdateIssueByAPI(issue, ctx.User)
  537. if err != nil {
  538. if models.IsErrDependenciesLeft(err) {
  539. ctx.Error(http.StatusPreconditionFailed, "DependenciesLeft", "cannot close this pull request because it still has open dependencies")
  540. return
  541. }
  542. ctx.Error(http.StatusInternalServerError, "UpdateIssueByAPI", err)
  543. return
  544. }
  545. if titleChanged {
  546. notification.NotifyIssueChangeTitle(ctx.User, issue, oldTitle)
  547. }
  548. if statusChangeComment != nil {
  549. notification.NotifyIssueChangeStatus(ctx.User, issue, statusChangeComment, issue.IsClosed)
  550. }
  551. // change pull target branch
  552. if len(form.Base) != 0 && form.Base != pr.BaseBranch {
  553. if !ctx.Repo.GitRepo.IsBranchExist(form.Base) {
  554. ctx.Error(http.StatusNotFound, "NewBaseBranchNotExist", fmt.Errorf("new base '%s' not exist", form.Base))
  555. return
  556. }
  557. if err := pull_service.ChangeTargetBranch(pr, ctx.User, form.Base); err != nil {
  558. if models.IsErrPullRequestAlreadyExists(err) {
  559. ctx.Error(http.StatusConflict, "IsErrPullRequestAlreadyExists", err)
  560. return
  561. } else if models.IsErrIssueIsClosed(err) {
  562. ctx.Error(http.StatusUnprocessableEntity, "IsErrIssueIsClosed", err)
  563. return
  564. } else if models.IsErrPullRequestHasMerged(err) {
  565. ctx.Error(http.StatusConflict, "IsErrPullRequestHasMerged", err)
  566. return
  567. } else {
  568. ctx.InternalServerError(err)
  569. }
  570. return
  571. }
  572. notification.NotifyPullRequestChangeTargetBranch(ctx.User, pr, form.Base)
  573. }
  574. // Refetch from database
  575. pr, err = models.GetPullRequestByIndex(ctx.Repo.Repository.ID, pr.Index)
  576. if err != nil {
  577. if models.IsErrPullRequestNotExist(err) {
  578. ctx.NotFound()
  579. } else {
  580. ctx.Error(http.StatusInternalServerError, "GetPullRequestByIndex", err)
  581. }
  582. return
  583. }
  584. // TODO this should be 200, not 201
  585. ctx.JSON(http.StatusCreated, convert.ToAPIPullRequest(pr))
  586. }
  587. // IsPullRequestMerged checks if a PR exists given an index
  588. func IsPullRequestMerged(ctx *context.APIContext) {
  589. // swagger:operation GET /repos/{owner}/{repo}/pulls/{index}/merge repository repoPullRequestIsMerged
  590. // ---
  591. // summary: Check if a pull request has been merged
  592. // produces:
  593. // - application/json
  594. // parameters:
  595. // - name: owner
  596. // in: path
  597. // description: owner of the repo
  598. // type: string
  599. // required: true
  600. // - name: repo
  601. // in: path
  602. // description: name of the repo
  603. // type: string
  604. // required: true
  605. // - name: index
  606. // in: path
  607. // description: index of the pull request
  608. // type: integer
  609. // format: int64
  610. // required: true
  611. // responses:
  612. // "204":
  613. // description: pull request has been merged
  614. // "404":
  615. // description: pull request has not been merged
  616. pr, err := models.GetPullRequestByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
  617. if err != nil {
  618. if models.IsErrPullRequestNotExist(err) {
  619. ctx.NotFound()
  620. } else {
  621. ctx.Error(http.StatusInternalServerError, "GetPullRequestByIndex", err)
  622. }
  623. return
  624. }
  625. if pr.HasMerged {
  626. ctx.Status(http.StatusNoContent)
  627. }
  628. ctx.NotFound()
  629. }
  630. // MergePullRequest merges a PR given an index
  631. func MergePullRequest(ctx *context.APIContext) {
  632. // swagger:operation POST /repos/{owner}/{repo}/pulls/{index}/merge repository repoMergePullRequest
  633. // ---
  634. // summary: Merge a pull request
  635. // produces:
  636. // - application/json
  637. // parameters:
  638. // - name: owner
  639. // in: path
  640. // description: owner of the repo
  641. // type: string
  642. // required: true
  643. // - name: repo
  644. // in: path
  645. // description: name of the repo
  646. // type: string
  647. // required: true
  648. // - name: index
  649. // in: path
  650. // description: index of the pull request to merge
  651. // type: integer
  652. // format: int64
  653. // required: true
  654. // - name: body
  655. // in: body
  656. // schema:
  657. // $ref: "#/definitions/MergePullRequestOption"
  658. // responses:
  659. // "200":
  660. // "$ref": "#/responses/empty"
  661. // "405":
  662. // "$ref": "#/responses/empty"
  663. // "409":
  664. // "$ref": "#/responses/error"
  665. form := web.GetForm(ctx).(*auth.MergePullRequestForm)
  666. pr, err := models.GetPullRequestByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
  667. if err != nil {
  668. if models.IsErrPullRequestNotExist(err) {
  669. ctx.NotFound("GetPullRequestByIndex", err)
  670. } else {
  671. ctx.Error(http.StatusInternalServerError, "GetPullRequestByIndex", err)
  672. }
  673. return
  674. }
  675. if err = pr.LoadHeadRepo(); err != nil {
  676. ctx.Error(http.StatusInternalServerError, "LoadHeadRepo", err)
  677. return
  678. }
  679. err = pr.LoadIssue()
  680. if err != nil {
  681. ctx.Error(http.StatusInternalServerError, "LoadIssue", err)
  682. return
  683. }
  684. pr.Issue.Repo = ctx.Repo.Repository
  685. if ctx.IsSigned {
  686. // Update issue-user.
  687. if err = pr.Issue.ReadBy(ctx.User.ID); err != nil {
  688. ctx.Error(http.StatusInternalServerError, "ReadBy", err)
  689. return
  690. }
  691. }
  692. if pr.Issue.IsClosed {
  693. ctx.NotFound()
  694. return
  695. }
  696. allowedMerge, err := pull_service.IsUserAllowedToMerge(pr, ctx.Repo.Permission, ctx.User)
  697. if err != nil {
  698. ctx.Error(http.StatusInternalServerError, "IsUSerAllowedToMerge", err)
  699. return
  700. }
  701. if !allowedMerge {
  702. ctx.Error(http.StatusMethodNotAllowed, "Merge", "User not allowed to merge PR")
  703. return
  704. }
  705. if pr.HasMerged {
  706. ctx.Error(http.StatusMethodNotAllowed, "PR already merged", "")
  707. return
  708. }
  709. // handle manually-merged mark
  710. if models.MergeStyle(form.Do) == models.MergeStyleManuallyMerged {
  711. if err = pull_service.MergedManually(pr, ctx.User, ctx.Repo.GitRepo, form.MergeCommitID); err != nil {
  712. if models.IsErrInvalidMergeStyle(err) {
  713. ctx.Error(http.StatusMethodNotAllowed, "Invalid merge style", fmt.Errorf("%s is not allowed an allowed merge style for this repository", models.MergeStyle(form.Do)))
  714. return
  715. }
  716. if strings.Contains(err.Error(), "Wrong commit ID") {
  717. ctx.JSON(http.StatusConflict, err)
  718. return
  719. }
  720. ctx.Error(http.StatusInternalServerError, "Manually-Merged", err)
  721. return
  722. }
  723. ctx.Status(http.StatusOK)
  724. return
  725. }
  726. if !pr.CanAutoMerge() {
  727. ctx.Error(http.StatusMethodNotAllowed, "PR not in mergeable state", "Please try again later")
  728. return
  729. }
  730. if pr.IsWorkInProgress() {
  731. ctx.Error(http.StatusMethodNotAllowed, "PR is a work in progress", "Work in progress PRs cannot be merged")
  732. return
  733. }
  734. if err := pull_service.CheckPRReadyToMerge(pr, false); err != nil {
  735. if !models.IsErrNotAllowedToMerge(err) {
  736. ctx.Error(http.StatusInternalServerError, "CheckPRReadyToMerge", err)
  737. return
  738. }
  739. if form.ForceMerge != nil && *form.ForceMerge {
  740. if isRepoAdmin, err := models.IsUserRepoAdmin(pr.BaseRepo, ctx.User); err != nil {
  741. ctx.Error(http.StatusInternalServerError, "IsUserRepoAdmin", err)
  742. return
  743. } else if !isRepoAdmin {
  744. ctx.Error(http.StatusMethodNotAllowed, "Merge", "Only repository admin can merge if not all checks are ok (force merge)")
  745. }
  746. } else {
  747. ctx.Error(http.StatusMethodNotAllowed, "PR is not ready to be merged", err)
  748. return
  749. }
  750. }
  751. if _, err := pull_service.IsSignedIfRequired(pr, ctx.User); err != nil {
  752. if !models.IsErrWontSign(err) {
  753. ctx.Error(http.StatusInternalServerError, "IsSignedIfRequired", err)
  754. return
  755. }
  756. ctx.Error(http.StatusMethodNotAllowed, fmt.Sprintf("Protected branch %s requires signed commits but this merge would not be signed", pr.BaseBranch), err)
  757. return
  758. }
  759. if len(form.Do) == 0 {
  760. form.Do = string(models.MergeStyleMerge)
  761. }
  762. message := strings.TrimSpace(form.MergeTitleField)
  763. if len(message) == 0 {
  764. if models.MergeStyle(form.Do) == models.MergeStyleMerge {
  765. message = pr.GetDefaultMergeMessage()
  766. }
  767. if models.MergeStyle(form.Do) == models.MergeStyleSquash {
  768. message = pr.GetDefaultSquashMessage()
  769. }
  770. }
  771. form.MergeMessageField = strings.TrimSpace(form.MergeMessageField)
  772. if len(form.MergeMessageField) > 0 {
  773. message += "\n\n" + form.MergeMessageField
  774. }
  775. if err := pull_service.Merge(pr, ctx.User, ctx.Repo.GitRepo, models.MergeStyle(form.Do), message); err != nil {
  776. if models.IsErrInvalidMergeStyle(err) {
  777. ctx.Error(http.StatusMethodNotAllowed, "Invalid merge style", fmt.Errorf("%s is not allowed an allowed merge style for this repository", models.MergeStyle(form.Do)))
  778. return
  779. } else if models.IsErrMergeConflicts(err) {
  780. conflictError := err.(models.ErrMergeConflicts)
  781. ctx.JSON(http.StatusConflict, conflictError)
  782. } else if models.IsErrRebaseConflicts(err) {
  783. conflictError := err.(models.ErrRebaseConflicts)
  784. ctx.JSON(http.StatusConflict, conflictError)
  785. } else if models.IsErrMergeUnrelatedHistories(err) {
  786. conflictError := err.(models.ErrMergeUnrelatedHistories)
  787. ctx.JSON(http.StatusConflict, conflictError)
  788. } else if git.IsErrPushOutOfDate(err) {
  789. ctx.Error(http.StatusConflict, "Merge", "merge push out of date")
  790. return
  791. } else if git.IsErrPushRejected(err) {
  792. errPushRej := err.(*git.ErrPushRejected)
  793. if len(errPushRej.Message) == 0 {
  794. ctx.Error(http.StatusConflict, "Merge", "PushRejected without remote error message")
  795. return
  796. }
  797. ctx.Error(http.StatusConflict, "Merge", "PushRejected with remote message: "+errPushRej.Message)
  798. return
  799. }
  800. ctx.Error(http.StatusInternalServerError, "Merge", err)
  801. return
  802. }
  803. log.Trace("Pull request merged: %d", pr.ID)
  804. ctx.Status(http.StatusOK)
  805. }
  806. func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption) (*models.User, *models.Repository, *git.Repository, *git.CompareInfo, string, string) {
  807. baseRepo := ctx.Repo.Repository
  808. // Get compared branches information
  809. // format: <base branch>...[<head repo>:]<head branch>
  810. // base<-head: master...head:feature
  811. // same repo: master...feature
  812. // TODO: Validate form first?
  813. baseBranch := form.Base
  814. var (
  815. headUser *models.User
  816. headBranch string
  817. isSameRepo bool
  818. err error
  819. )
  820. // If there is no head repository, it means pull request between same repository.
  821. headInfos := strings.Split(form.Head, ":")
  822. if len(headInfos) == 1 {
  823. isSameRepo = true
  824. headUser = ctx.Repo.Owner
  825. headBranch = headInfos[0]
  826. } else if len(headInfos) == 2 {
  827. headUser, err = models.GetUserByName(headInfos[0])
  828. if err != nil {
  829. if models.IsErrUserNotExist(err) {
  830. ctx.NotFound("GetUserByName")
  831. } else {
  832. ctx.Error(http.StatusInternalServerError, "GetUserByName", err)
  833. }
  834. return nil, nil, nil, nil, "", ""
  835. }
  836. headBranch = headInfos[1]
  837. } else {
  838. ctx.NotFound()
  839. return nil, nil, nil, nil, "", ""
  840. }
  841. ctx.Repo.PullRequest.SameRepo = isSameRepo
  842. log.Info("Base branch: %s", baseBranch)
  843. log.Info("Repo path: %s", ctx.Repo.GitRepo.Path)
  844. // Check if base branch is valid.
  845. if !ctx.Repo.GitRepo.IsBranchExist(baseBranch) {
  846. ctx.NotFound("IsBranchExist")
  847. return nil, nil, nil, nil, "", ""
  848. }
  849. // Check if current user has fork of repository or in the same repository.
  850. headRepo, has := models.HasForkedRepo(headUser.ID, baseRepo.ID)
  851. if !has && !isSameRepo {
  852. log.Trace("parseCompareInfo[%d]: does not have fork or in same repository", baseRepo.ID)
  853. ctx.NotFound("HasForkedRepo")
  854. return nil, nil, nil, nil, "", ""
  855. }
  856. var headGitRepo *git.Repository
  857. if isSameRepo {
  858. headRepo = ctx.Repo.Repository
  859. headGitRepo = ctx.Repo.GitRepo
  860. } else {
  861. headGitRepo, err = git.OpenRepository(models.RepoPath(headUser.Name, headRepo.Name))
  862. if err != nil {
  863. ctx.Error(http.StatusInternalServerError, "OpenRepository", err)
  864. return nil, nil, nil, nil, "", ""
  865. }
  866. }
  867. // user should have permission to read baseRepo's codes and pulls, NOT headRepo's
  868. permBase, err := models.GetUserRepoPermission(baseRepo, ctx.User)
  869. if err != nil {
  870. headGitRepo.Close()
  871. ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
  872. return nil, nil, nil, nil, "", ""
  873. }
  874. if !permBase.CanReadIssuesOrPulls(true) || !permBase.CanRead(models.UnitTypeCode) {
  875. if log.IsTrace() {
  876. log.Trace("Permission Denied: User %-v cannot create/read pull requests or cannot read code in Repo %-v\nUser in baseRepo has Permissions: %-+v",
  877. ctx.User,
  878. baseRepo,
  879. permBase)
  880. }
  881. headGitRepo.Close()
  882. ctx.NotFound("Can't read pulls or can't read UnitTypeCode")
  883. return nil, nil, nil, nil, "", ""
  884. }
  885. // user should have permission to read headrepo's codes
  886. permHead, err := models.GetUserRepoPermission(headRepo, ctx.User)
  887. if err != nil {
  888. headGitRepo.Close()
  889. ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
  890. return nil, nil, nil, nil, "", ""
  891. }
  892. if !permHead.CanRead(models.UnitTypeCode) {
  893. if log.IsTrace() {
  894. log.Trace("Permission Denied: User: %-v cannot read code in Repo: %-v\nUser in headRepo has Permissions: %-+v",
  895. ctx.User,
  896. headRepo,
  897. permHead)
  898. }
  899. headGitRepo.Close()
  900. ctx.NotFound("Can't read headRepo UnitTypeCode")
  901. return nil, nil, nil, nil, "", ""
  902. }
  903. // Check if head branch is valid.
  904. if !headGitRepo.IsBranchExist(headBranch) {
  905. headGitRepo.Close()
  906. ctx.NotFound()
  907. return nil, nil, nil, nil, "", ""
  908. }
  909. compareInfo, err := headGitRepo.GetCompareInfo(models.RepoPath(baseRepo.Owner.Name, baseRepo.Name), baseBranch, headBranch)
  910. if err != nil {
  911. headGitRepo.Close()
  912. ctx.Error(http.StatusInternalServerError, "GetCompareInfo", err)
  913. return nil, nil, nil, nil, "", ""
  914. }
  915. return headUser, headRepo, headGitRepo, compareInfo, baseBranch, headBranch
  916. }
  917. // UpdatePullRequest merge PR's baseBranch into headBranch
  918. func UpdatePullRequest(ctx *context.APIContext) {
  919. // swagger:operation POST /repos/{owner}/{repo}/pulls/{index}/update repository repoUpdatePullRequest
  920. // ---
  921. // summary: Merge PR's baseBranch into headBranch
  922. // produces:
  923. // - application/json
  924. // parameters:
  925. // - name: owner
  926. // in: path
  927. // description: owner of the repo
  928. // type: string
  929. // required: true
  930. // - name: repo
  931. // in: path
  932. // description: name of the repo
  933. // type: string
  934. // required: true
  935. // - name: index
  936. // in: path
  937. // description: index of the pull request to get
  938. // type: integer
  939. // format: int64
  940. // required: true
  941. // responses:
  942. // "200":
  943. // "$ref": "#/responses/empty"
  944. // "403":
  945. // "$ref": "#/responses/forbidden"
  946. // "404":
  947. // "$ref": "#/responses/notFound"
  948. // "409":
  949. // "$ref": "#/responses/error"
  950. // "422":
  951. // "$ref": "#/responses/validationError"
  952. pr, err := models.GetPullRequestByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
  953. if err != nil {
  954. if models.IsErrPullRequestNotExist(err) {
  955. ctx.NotFound()
  956. } else {
  957. ctx.Error(http.StatusInternalServerError, "GetPullRequestByIndex", err)
  958. }
  959. return
  960. }
  961. if pr.HasMerged {
  962. ctx.Error(http.StatusUnprocessableEntity, "UpdatePullRequest", err)
  963. return
  964. }
  965. if err = pr.LoadIssue(); err != nil {
  966. ctx.Error(http.StatusInternalServerError, "LoadIssue", err)
  967. return
  968. }
  969. if pr.Issue.IsClosed {
  970. ctx.Error(http.StatusUnprocessableEntity, "UpdatePullRequest", err)
  971. return
  972. }
  973. if err = pr.LoadBaseRepo(); err != nil {
  974. ctx.Error(http.StatusInternalServerError, "LoadBaseRepo", err)
  975. return
  976. }
  977. if err = pr.LoadHeadRepo(); err != nil {
  978. ctx.Error(http.StatusInternalServerError, "LoadHeadRepo", err)
  979. return
  980. }
  981. allowedUpdate, err := pull_service.IsUserAllowedToUpdate(pr, ctx.User)
  982. if err != nil {
  983. ctx.Error(http.StatusInternalServerError, "IsUserAllowedToMerge", err)
  984. return
  985. }
  986. if !allowedUpdate {
  987. ctx.Status(http.StatusForbidden)
  988. return
  989. }
  990. // default merge commit message
  991. message := fmt.Sprintf("Merge branch '%s' into %s", pr.BaseBranch, pr.HeadBranch)
  992. if err = pull_service.Update(pr, ctx.User, message); err != nil {
  993. if models.IsErrMergeConflicts(err) {
  994. ctx.Error(http.StatusConflict, "Update", "merge failed because of conflict")
  995. return
  996. }
  997. ctx.Error(http.StatusInternalServerError, "pull_service.Update", err)
  998. return
  999. }
  1000. ctx.Status(http.StatusOK)
  1001. }