mirror of
https://github.com/go-gitea/gitea.git
synced 2025-07-17 00:01:00 -04:00
Compare commits
6 Commits
aab7cb6750
...
7735da1c66
Author | SHA1 | Date | |
---|---|---|---|
|
7735da1c66 | ||
|
5b79eeabd1 | ||
|
807c9712ef | ||
|
640a88fa09 | ||
|
36f1fa7792 | ||
|
eab011db58 |
@ -130,3 +130,20 @@ func FindBranchNames(ctx context.Context, opts FindBranchOptions) ([]string, err
|
|||||||
}
|
}
|
||||||
return branches, nil
|
return branches, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func FindBranchesByRepoAndBranchName(ctx context.Context, repoBranches map[int64]string) (map[int64]string, error) {
|
||||||
|
cond := builder.NewCond()
|
||||||
|
for repoID, branchName := range repoBranches {
|
||||||
|
cond = cond.Or(builder.And(builder.Eq{"repo_id": repoID}, builder.Eq{"name": branchName}))
|
||||||
|
}
|
||||||
|
var branches []*Branch
|
||||||
|
if err := db.GetEngine(ctx).
|
||||||
|
Where(cond).Find(&branches); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
branchMap := make(map[int64]string, len(branches))
|
||||||
|
for _, branch := range branches {
|
||||||
|
branchMap[branch.RepoID] = branch.CommitID
|
||||||
|
}
|
||||||
|
return branchMap, nil
|
||||||
|
}
|
||||||
|
@ -346,6 +346,53 @@ func GetLatestCommitStatusForPairs(ctx context.Context, repoIDsToLatestCommitSHA
|
|||||||
return repoStatuses, nil
|
return repoStatuses, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetLatestCommitStatusForRepoCommitIDs returns all statuses with a unique context for a given list of repo-sha pairs
|
||||||
|
func GetLatestCommitStatusForRepoCommitIDs(ctx context.Context, repoID int64, commitIDs []string) (map[string][]*CommitStatus, error) {
|
||||||
|
type result struct {
|
||||||
|
ID int64
|
||||||
|
Sha string
|
||||||
|
}
|
||||||
|
|
||||||
|
results := make([]result, 0, len(commitIDs))
|
||||||
|
|
||||||
|
sess := db.GetEngine(ctx).Table(&CommitStatus{})
|
||||||
|
|
||||||
|
// Create a disjunction of conditions for each repoID and SHA pair
|
||||||
|
conds := make([]builder.Cond, 0, len(commitIDs))
|
||||||
|
for _, sha := range commitIDs {
|
||||||
|
conds = append(conds, builder.Eq{"sha": sha})
|
||||||
|
}
|
||||||
|
sess = sess.Where(builder.Eq{"repo_id": repoID}.And(builder.Or(conds...))).
|
||||||
|
Select("max( id ) as id, sha").
|
||||||
|
GroupBy("context_hash, sha").OrderBy("max( id ) desc")
|
||||||
|
|
||||||
|
err := sess.Find(&results)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ids := make([]int64, 0, len(results))
|
||||||
|
repoStatuses := make(map[string][]*CommitStatus)
|
||||||
|
for _, result := range results {
|
||||||
|
ids = append(ids, result.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
statuses := make([]*CommitStatus, 0, len(ids))
|
||||||
|
if len(ids) > 0 {
|
||||||
|
err = db.GetEngine(ctx).In("id", ids).Find(&statuses)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Group the statuses by repo ID
|
||||||
|
for _, status := range statuses {
|
||||||
|
repoStatuses[status.SHA] = append(repoStatuses[status.SHA], status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return repoStatuses, nil
|
||||||
|
}
|
||||||
|
|
||||||
// FindRepoRecentCommitStatusContexts returns repository's recent commit status contexts
|
// FindRepoRecentCommitStatusContexts returns repository's recent commit status contexts
|
||||||
func FindRepoRecentCommitStatusContexts(ctx context.Context, repoID int64, before time.Duration) ([]string, error) {
|
func FindRepoRecentCommitStatusContexts(ctx context.Context, repoID int64, before time.Duration) ([]string, error) {
|
||||||
start := timeutil.TimeStampNow().AddDuration(-before)
|
start := timeutil.TimeStampNow().AddDuration(-before)
|
||||||
|
5
options/license/Asterisk-exception
Normal file
5
options/license/Asterisk-exception
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
In addition, when this program is distributed with Asterisk in any
|
||||||
|
form that would qualify as a 'combined work' or as a 'derivative work'
|
||||||
|
(but not mere aggregation), you can redistribute and/or modify the
|
||||||
|
combination under the terms of the license provided with that copy
|
||||||
|
of Asterisk, instead of the license terms granted here.
|
12
options/license/Boehm-GC
Normal file
12
options/license/Boehm-GC
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
Copyright (c) ...
|
||||||
|
|
||||||
|
THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||||
|
OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||||
|
|
||||||
|
Permission is hereby granted to use or copy this program
|
||||||
|
for any purpose, provided the above notices are retained on all copies.
|
||||||
|
Permission to modify the code and to distribute modified code is granted,
|
||||||
|
provided the above notices are retained, and a notice that the code was
|
||||||
|
modified is included with the above copyright notice.
|
||||||
|
|
||||||
|
A few files have other copyright holders.
|
34
options/license/Inner-Net-2.0
Normal file
34
options/license/Inner-Net-2.0
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
The Inner Net License, Version 2.00
|
||||||
|
|
||||||
|
The author(s) grant permission for redistribution and use in source and
|
||||||
|
binary forms, with or without modification, of the software and documentation
|
||||||
|
provided that the following conditions are met:
|
||||||
|
|
||||||
|
0. If you receive a version of the software that is specifically labelled
|
||||||
|
as not being for redistribution (check the version message and/or README),
|
||||||
|
you are not permitted to redistribute that version of the software in any
|
||||||
|
way or form.
|
||||||
|
1. All terms of the all other applicable copyrights and licenses must be
|
||||||
|
followed.
|
||||||
|
2. Redistributions of source code must retain the authors' copyright
|
||||||
|
notice(s), this list of conditions, and the following disclaimer.
|
||||||
|
3. Redistributions in binary form must reproduce the authors' copyright
|
||||||
|
notice(s), this list of conditions, and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
4. [The copyright holder has authorized the removal of this clause.]
|
||||||
|
5. Neither the name(s) of the author(s) nor the names of its contributors
|
||||||
|
may be used to endorse or promote products derived from this software
|
||||||
|
without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||||
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
If these license terms cause you a real problem, contact the author.
|
56
options/license/LLGPL
Normal file
56
options/license/LLGPL
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
Preamble to the Gnu Lesser General Public License
|
||||||
|
|
||||||
|
Copyright (c) 2016 Franz Inc., Berkeley, CA 94704
|
||||||
|
|
||||||
|
The concept of the GNU Lesser General Public License version 2.1 ("LGPL")
|
||||||
|
has been adopted to govern the use and distribution of above-mentioned
|
||||||
|
application. However, the LGPL uses terminology that is more appropriate
|
||||||
|
for a program written in C than one written in Lisp. Nevertheless, the
|
||||||
|
LGPL can still be applied to a Lisp program if certain clarifications
|
||||||
|
are made. This document details those clarifications. Accordingly, the
|
||||||
|
license for the open-source Lisp applications consists of this document
|
||||||
|
plus the LGPL. Wherever there is a conflict between this document and
|
||||||
|
the LGPL, this document takes precedence over the LGPL.
|
||||||
|
|
||||||
|
A "Library" in Lisp is a collection of Lisp functions, data and foreign
|
||||||
|
modules. The form of the Library can be Lisp source code (for processing
|
||||||
|
by an interpreter) or object code (usually the result of compilation of
|
||||||
|
source code or built with some other mechanisms). Foreign modules are
|
||||||
|
object code in a form that can be linked into a Lisp executable. When
|
||||||
|
we speak of functions we do so in the most general way to include, in
|
||||||
|
addition, methods and unnamed functions. Lisp "data" is also a general
|
||||||
|
term that includes the data structures resulting from defining Lisp
|
||||||
|
classes. A Lisp application may include the same set of Lisp objects
|
||||||
|
as does a Library, but this does not mean that the application is
|
||||||
|
necessarily a "work based on the Library" it contains.
|
||||||
|
|
||||||
|
The Library consists of everything in the distribution file set before
|
||||||
|
any modifications are made to the files. If any of the functions or
|
||||||
|
classes in the Library are redefined in other files, then those
|
||||||
|
redefinitions ARE considered a work based on the Library. If additional
|
||||||
|
methods are added to generic functions in the Library, those additional
|
||||||
|
methods are NOT considered a work based on the Library. If Library classes
|
||||||
|
are subclassed, these subclasses are NOT considered a work based on the Library.
|
||||||
|
If the Library is modified to explicitly call other functions that are neither
|
||||||
|
part of Lisp itself nor an available add-on module to Lisp, then the functions
|
||||||
|
called by the modified Library ARE considered a work based on the Library.
|
||||||
|
The goal is to ensure that the Library will compile and run without getting
|
||||||
|
undefined function errors.
|
||||||
|
|
||||||
|
It is permitted to add proprietary source code to the Library, but it must
|
||||||
|
be done in a way such that the Library will still run without that proprietary
|
||||||
|
code present. Section 5 of the LGPL distinguishes between the case of a
|
||||||
|
library being dynamically linked at runtime and one being statically linked
|
||||||
|
at build time. Section 5 of the LGPL states that the former results in an
|
||||||
|
executable that is a "work that uses the Library." Section 5 of the LGPL
|
||||||
|
states that the latter results in one that is a "derivative of the Library",
|
||||||
|
which is therefore covered by the LGPL. Since Lisp only offers one choice,
|
||||||
|
which is to link the Library into an executable at build time, we declare that,
|
||||||
|
for the purpose applying the LGPL to the Library, an executable that results
|
||||||
|
from linking a "work that uses the Library" with the Library is considered a
|
||||||
|
"work that uses the Library" and is therefore NOT covered by the LGPL.
|
||||||
|
|
||||||
|
Because of this declaration, section 6 of LGPL is not applicable to the Library.
|
||||||
|
However, in connection with each distribution of this executable, you must also
|
||||||
|
deliver, in accordance with the terms and conditions of the LGPL, the source code
|
||||||
|
of Library (or your derivative thereof) that is incorporated into this executable.
|
8
options/license/Linux-man-pages-copyleft-2-para
Normal file
8
options/license/Linux-man-pages-copyleft-2-para
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
Permission is granted to make and distribute verbatim copies of this
|
||||||
|
manual provided the copyright notice and this permission notice are
|
||||||
|
preserved on all copies.
|
||||||
|
|
||||||
|
Permission is granted to copy and distribute modified versions of this
|
||||||
|
manual under the conditions for verbatim copying, provided that the
|
||||||
|
entire resulting derived work is distributed under the terms of a
|
||||||
|
permission notice identical to this one.
|
16
options/license/Linux-man-pages-copyleft-var
Normal file
16
options/license/Linux-man-pages-copyleft-var
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
Permission is granted to make and distribute verbatim copies of
|
||||||
|
this manual provided the copyright notice and this permission
|
||||||
|
notice are preserved on all copies.
|
||||||
|
|
||||||
|
Permission is granted to copy and distribute modified versions of
|
||||||
|
this manual under the conditions for verbatim copying, provided
|
||||||
|
that the entire resulting derived work is distributed under the
|
||||||
|
terms of a permission notice identical to this one.
|
||||||
|
|
||||||
|
Since the Linux kernel and libraries are constantly changing, this
|
||||||
|
manual page may be incorrect or out-of-date. The author(s) assume
|
||||||
|
no responsibility for errors or omissions, or for damages resulting
|
||||||
|
from the use of the information contained herein.
|
||||||
|
|
||||||
|
Formatted or processed versions of this manual, if unaccompanied by
|
||||||
|
the source, must acknowledge the copyright and authors of this work.
|
114
options/license/OPL-UK-3.0
Normal file
114
options/license/OPL-UK-3.0
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
United Kingdom Open Parliament Licence v3.0
|
||||||
|
|
||||||
|
Open Parliament Licence
|
||||||
|
|
||||||
|
You are encouraged to use and re-use the information that
|
||||||
|
is available under this licence freely and flexibly, with
|
||||||
|
only a few conditions. Using information under this licence
|
||||||
|
|
||||||
|
Use of copyright and database right material made
|
||||||
|
available under this licence (the ‘information’) indicates
|
||||||
|
your acceptance of the terms and conditions below.
|
||||||
|
|
||||||
|
The Licensor grants you a worldwide, royalty-free,
|
||||||
|
perpetual, non-exclusive licence to use the
|
||||||
|
information subject to the conditions below.
|
||||||
|
|
||||||
|
This licence does not affect your freedom under
|
||||||
|
fair dealing or fair use or any other copyright
|
||||||
|
or database right exceptions and limitations.
|
||||||
|
|
||||||
|
You are free to:
|
||||||
|
* copy, publish, distribute and transmit the information
|
||||||
|
* adapt the information
|
||||||
|
* exploit the information commercially and non-commercially,
|
||||||
|
for example, by combining it with other information,
|
||||||
|
or by including it in your own product or application
|
||||||
|
|
||||||
|
You must (where you do any of the above):
|
||||||
|
* acknowledge the source of the information in your
|
||||||
|
product or application by including the following
|
||||||
|
attribution statement and, where possible, provide a
|
||||||
|
link to this licence: Contains Parliamentary information
|
||||||
|
licensed under the Open Parliament Licence v3.0.
|
||||||
|
|
||||||
|
These are important conditions of this licence and
|
||||||
|
if you fail to comply with them the rights granted to
|
||||||
|
you under this licence, or any similar licence granted
|
||||||
|
by the Licensor, will end automatically.
|
||||||
|
|
||||||
|
Exemptions
|
||||||
|
|
||||||
|
This licence does not cover the use of:
|
||||||
|
* personal data in the information;
|
||||||
|
* information that has neither been published nor disclosed
|
||||||
|
under information access legislation (including the
|
||||||
|
Freedom of Information Acts for the UK and Scotland) by or
|
||||||
|
with the consent of the Licensor;
|
||||||
|
* the Royal Arms and the Crowned Portcullis;
|
||||||
|
* third party rights the Licensor is not authorised to license;
|
||||||
|
* information subject to other intellectual property rights,
|
||||||
|
including patents, trademarks, and design rights
|
||||||
|
|
||||||
|
Non-endorsment
|
||||||
|
|
||||||
|
This licence does not grant you any right to use the
|
||||||
|
information in a way that suggests any official status or
|
||||||
|
that the Licensor endorses you or your use of the Information.
|
||||||
|
|
||||||
|
No warranty
|
||||||
|
|
||||||
|
The information is licensed ‘as is’ and the
|
||||||
|
Licensor excludes all representations, warranties,
|
||||||
|
obligations and liabilities in relation to the
|
||||||
|
information to the maximum extent permitted by law.
|
||||||
|
The Licensor is not liable for any errors or omissions in
|
||||||
|
the information and shall not be liable for any loss, injury
|
||||||
|
or damage of any kind caused by its use. The Licensor does
|
||||||
|
not guarantee the continued supply of the information.
|
||||||
|
|
||||||
|
Governing law
|
||||||
|
|
||||||
|
This licence is governed by the laws of England and Wales.
|
||||||
|
|
||||||
|
Definitions
|
||||||
|
|
||||||
|
In this licence, the terms below have the following meanings:
|
||||||
|
|
||||||
|
‘Information’ means information protected by copyright
|
||||||
|
or by database right (for example, literary and
|
||||||
|
artistic works, content, data and source code)
|
||||||
|
offered for use under the terms of this licence.
|
||||||
|
|
||||||
|
‘Information Provider’ means either House of Parliament.
|
||||||
|
|
||||||
|
‘Licensor’ means—
|
||||||
|
(a) in relation to copyright, the Speaker of the House of
|
||||||
|
Commons and the Clerk of the Parliaments representing
|
||||||
|
the House of Commons and House of Lords respectively, and
|
||||||
|
(b) in relation to database right, the Corporate
|
||||||
|
Officer of the House of Commons and the Corporate
|
||||||
|
Officer of the House of Lords respectively.
|
||||||
|
|
||||||
|
‘Use’ means doing any act which is restricted by copyright
|
||||||
|
or database right, whether in the original medium or in any
|
||||||
|
other medium, and includes without limitation distributing,
|
||||||
|
copying, adapting and modifying as may be technically
|
||||||
|
necessary to use it in a different mode or format.
|
||||||
|
|
||||||
|
‘You’ means the natural or legal person, or body of persons
|
||||||
|
corporate or incorporate, acquiring rights under this licence.
|
||||||
|
|
||||||
|
About the Open Parliament Licence
|
||||||
|
|
||||||
|
This is version 3.0 of the Open Parliament Licence. The
|
||||||
|
Licensor may, from time to time, issue new versions of the
|
||||||
|
Open Parliament Licence. However, you may continue to use
|
||||||
|
information licensed under this version should you wish to do so.
|
||||||
|
|
||||||
|
The information licensed under the Open Parliament
|
||||||
|
Licence includes Parliamentary information in which
|
||||||
|
Crown copyright subsists. Further context, best practice
|
||||||
|
and guidance relating to the re-use of public sector
|
||||||
|
information can be found in the UK Government Licensing
|
||||||
|
Framework section on The National Archives website.
|
14
options/license/dtoa
Normal file
14
options/license/dtoa
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
The author of this software is David M. Gay.
|
||||||
|
|
||||||
|
Copyright (c) 1991, 2000, 2001 by Lucent Technologies.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and distribute this software for any
|
||||||
|
purpose without fee is hereby granted, provided that this entire notice
|
||||||
|
is included in all copies of any software which is or includes a copy
|
||||||
|
or modification of this software and in all copies of the supporting
|
||||||
|
documentation for such software.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
||||||
|
WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
|
||||||
|
REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
||||||
|
OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
@ -57,7 +57,25 @@ func Branches(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
commitIDs := []string{defaultBranch.DBBranch.CommitID}
|
||||||
|
for _, branch := range branches {
|
||||||
|
commitIDs = append(commitIDs, branch.DBBranch.CommitID)
|
||||||
|
}
|
||||||
|
|
||||||
|
commitStatuses, err := git_model.GetLatestCommitStatusForRepoCommitIDs(ctx, ctx.Repo.Repository.ID, commitIDs)
|
||||||
|
if err != nil {
|
||||||
|
ctx.ServerError("LoadBranches", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
commitStatus := make(map[string]*git_model.CommitStatus)
|
||||||
|
for commitID, cs := range commitStatuses {
|
||||||
|
commitStatus[commitID] = git_model.CalcCommitStatus(cs)
|
||||||
|
}
|
||||||
|
|
||||||
ctx.Data["Branches"] = branches
|
ctx.Data["Branches"] = branches
|
||||||
|
ctx.Data["CommitStatus"] = commitStatus
|
||||||
|
ctx.Data["CommitStatuses"] = commitStatuses
|
||||||
ctx.Data["DefaultBranchBranch"] = defaultBranch
|
ctx.Data["DefaultBranchBranch"] = defaultBranch
|
||||||
pager := context.NewPagination(int(branchesCount), pageSize, page, 5)
|
pager := context.NewPagination(int(branchesCount), pageSize, page, 5)
|
||||||
pager.SetDefaultParams(ctx)
|
pager.SetDefaultParams(ctx)
|
||||||
|
@ -356,12 +356,46 @@ func setMergeTarget(ctx *context.Context, pull *issues_model.PullRequest) {
|
|||||||
ctx.Data["BaseBranchLink"] = pull.GetBaseBranchLink()
|
ctx.Data["BaseBranchLink"] = pull.GetBaseBranchLink()
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrepareMergedViewPullInfo show meta information for a merged pull request view page
|
// GetPullDiffStats get Pull Requests diff stats
|
||||||
func PrepareMergedViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.CompareInfo {
|
func GetPullDiffStats(ctx *context.Context) {
|
||||||
|
issue := checkPullInfo(ctx)
|
||||||
pull := issue.PullRequest
|
pull := issue.PullRequest
|
||||||
|
|
||||||
setMergeTarget(ctx, pull)
|
mergeBaseCommitID := GetMergedBaseCommitID(ctx, issue)
|
||||||
ctx.Data["HasMerged"] = true
|
|
||||||
|
if ctx.Written() {
|
||||||
|
return
|
||||||
|
} else if mergeBaseCommitID == "" {
|
||||||
|
ctx.NotFound("PullFiles", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
headCommitID, err := ctx.Repo.GitRepo.GetRefCommitID(pull.GetGitRefName())
|
||||||
|
if err != nil {
|
||||||
|
ctx.ServerError("GetRefCommitID", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
diffOptions := &gitdiff.DiffOptions{
|
||||||
|
BeforeCommitID: mergeBaseCommitID,
|
||||||
|
AfterCommitID: headCommitID,
|
||||||
|
MaxLines: setting.Git.MaxGitDiffLines,
|
||||||
|
MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
|
||||||
|
MaxFiles: setting.Git.MaxGitDiffFiles,
|
||||||
|
WhitespaceBehavior: gitdiff.GetWhitespaceFlag(ctx.Data["WhitespaceBehavior"].(string)),
|
||||||
|
}
|
||||||
|
|
||||||
|
diff, err := gitdiff.GetPullDiffStats(ctx.Repo.GitRepo, diffOptions)
|
||||||
|
if err != nil {
|
||||||
|
ctx.ServerError("GetPullDiffStats", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Data["Diff"] = diff
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMergedBaseCommitID(ctx *context.Context, issue *issues_model.Issue) string {
|
||||||
|
pull := issue.PullRequest
|
||||||
|
|
||||||
var baseCommit string
|
var baseCommit string
|
||||||
// Some migrated PR won't have any Base SHA and lose history, try to get one
|
// Some migrated PR won't have any Base SHA and lose history, try to get one
|
||||||
@ -401,6 +435,18 @@ func PrepareMergedViewPullInfo(ctx *context.Context, issue *issues_model.Issue)
|
|||||||
baseCommit = pull.MergeBase
|
baseCommit = pull.MergeBase
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return baseCommit
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrepareMergedViewPullInfo show meta information for a merged pull request view page
|
||||||
|
func PrepareMergedViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.CompareInfo {
|
||||||
|
pull := issue.PullRequest
|
||||||
|
|
||||||
|
setMergeTarget(ctx, pull)
|
||||||
|
ctx.Data["HasMerged"] = true
|
||||||
|
|
||||||
|
baseCommit := GetMergedBaseCommitID(ctx, issue)
|
||||||
|
|
||||||
compareInfo, err := ctx.Repo.GitRepo.GetCompareInfo(ctx.Repo.Repository.RepoPath(),
|
compareInfo, err := ctx.Repo.GitRepo.GetCompareInfo(ctx.Repo.Repository.RepoPath(),
|
||||||
baseCommit, pull.GetGitRefName(), false, false)
|
baseCommit, pull.GetGitRefName(), false, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -579,13 +579,15 @@ func SearchRepo(ctx *context.Context) {
|
|||||||
|
|
||||||
// collect the latest commit of each repo
|
// collect the latest commit of each repo
|
||||||
// at most there are dozens of repos (limited by MaxResponseItems), so it's not a big problem at the moment
|
// at most there are dozens of repos (limited by MaxResponseItems), so it's not a big problem at the moment
|
||||||
repoIDsToLatestCommitSHAs := make(map[int64]string, len(repos))
|
repoBranchNames := make(map[int64]string, len(repos))
|
||||||
for _, repo := range repos {
|
for _, repo := range repos {
|
||||||
commitID, err := repo_service.GetBranchCommitID(ctx, repo, repo.DefaultBranch)
|
repoBranchNames[repo.ID] = repo.DefaultBranch
|
||||||
if err != nil {
|
}
|
||||||
continue
|
|
||||||
}
|
repoIDsToLatestCommitSHAs, err := git_model.FindBranchesByRepoAndBranchName(ctx, repoBranchNames)
|
||||||
repoIDsToLatestCommitSHAs[repo.ID] = commitID
|
if err != nil {
|
||||||
|
log.Error("FindBranchesByRepoAndBranchName: %v", err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// call the database O(1) times to get the commit statuses for all repos
|
// call the database O(1) times to get the commit statuses for all repos
|
||||||
|
@ -1277,9 +1277,10 @@ func registerRoutes(m *web.Route) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
m.Group("/pulls/{index}", func() {
|
m.Group("/pulls/{index}", func() {
|
||||||
|
m.Get("", repo.SetWhitespaceBehavior, repo.GetPullDiffStats, repo.ViewIssue)
|
||||||
m.Get(".diff", repo.DownloadPullDiff)
|
m.Get(".diff", repo.DownloadPullDiff)
|
||||||
m.Get(".patch", repo.DownloadPullPatch)
|
m.Get(".patch", repo.DownloadPullPatch)
|
||||||
m.Get("/commits", context.RepoRef(), repo.ViewPullCommits)
|
m.Get("/commits", context.RepoRef(), repo.SetWhitespaceBehavior, repo.GetPullDiffStats, repo.ViewPullCommits)
|
||||||
m.Post("/merge", context.RepoMustNotBeArchived(), web.Bind(forms.MergePullRequestForm{}), repo.MergePullRequest)
|
m.Post("/merge", context.RepoMustNotBeArchived(), web.Bind(forms.MergePullRequestForm{}), repo.MergePullRequest)
|
||||||
m.Post("/cancel_auto_merge", context.RepoMustNotBeArchived(), repo.CancelAutoMergePullRequest)
|
m.Post("/cancel_auto_merge", context.RepoMustNotBeArchived(), repo.CancelAutoMergePullRequest)
|
||||||
m.Post("/update", repo.UpdatePullRequest)
|
m.Post("/update", repo.UpdatePullRequest)
|
||||||
|
@ -1229,6 +1229,42 @@ func GetDiff(gitRepo *git.Repository, opts *DiffOptions, files ...string) (*Diff
|
|||||||
return diff, nil
|
return diff, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PullDiffStats struct {
|
||||||
|
TotalAddition, TotalDeletion int
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPullDiffStats
|
||||||
|
func GetPullDiffStats(gitRepo *git.Repository, opts *DiffOptions) (*PullDiffStats, error) {
|
||||||
|
repoPath := gitRepo.Path
|
||||||
|
|
||||||
|
diff := &PullDiffStats{}
|
||||||
|
|
||||||
|
separator := "..."
|
||||||
|
if opts.DirectComparison {
|
||||||
|
separator = ".."
|
||||||
|
}
|
||||||
|
|
||||||
|
diffPaths := []string{opts.BeforeCommitID + separator + opts.AfterCommitID}
|
||||||
|
if len(opts.BeforeCommitID) == 0 || opts.BeforeCommitID == git.EmptySHA {
|
||||||
|
diffPaths = []string{git.EmptyTreeSHA, opts.AfterCommitID}
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
_, diff.TotalAddition, diff.TotalDeletion, err = git.GetDiffShortStat(gitRepo.Ctx, repoPath, nil, diffPaths...)
|
||||||
|
if err != nil && strings.Contains(err.Error(), "no merge base") {
|
||||||
|
// git >= 2.28 now returns an error if base and head have become unrelated.
|
||||||
|
// previously it would return the results of git diff --shortstat base head so let's try that...
|
||||||
|
diffPaths = []string{opts.BeforeCommitID, opts.AfterCommitID}
|
||||||
|
_, diff.TotalAddition, diff.TotalDeletion, err = git.GetDiffShortStat(gitRepo.Ctx, repoPath, nil, diffPaths...)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return diff, nil
|
||||||
|
}
|
||||||
|
|
||||||
// SyncAndGetUserSpecificDiff is like GetDiff, except that user specific data such as which files the given user has already viewed on the given PR will also be set
|
// SyncAndGetUserSpecificDiff is like GetDiff, except that user specific data such as which files the given user has already viewed on the given PR will also be set
|
||||||
// Additionally, the database asynchronously is updated if files have changed since the last review
|
// Additionally, the database asynchronously is updated if files have changed since the last review
|
||||||
func SyncAndGetUserSpecificDiff(ctx context.Context, userID int64, pull *issues_model.PullRequest, gitRepo *git.Repository, opts *DiffOptions, files ...string) (*Diff, error) {
|
func SyncAndGetUserSpecificDiff(ctx context.Context, userID int64, pull *issues_model.PullRequest, gitRepo *git.Repository, opts *DiffOptions, files ...string) (*Diff, error) {
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
<div class="gt-df gt-ac">
|
<div class="gt-df gt-ac">
|
||||||
<a class="gt-ellipsis" href="{{.RepoLink}}/src/branch/{{PathEscapeSegments .DefaultBranchBranch.DBBranch.Name}}">{{.DefaultBranchBranch.DBBranch.Name}}</a>
|
<a class="gt-ellipsis" href="{{.RepoLink}}/src/branch/{{PathEscapeSegments .DefaultBranchBranch.DBBranch.Name}}">{{.DefaultBranchBranch.DBBranch.Name}}</a>
|
||||||
<button class="btn interact-fg gt-p-3" data-clipboard-text="{{.DefaultBranchBranch.DBBranch.Name}}">{{svg "octicon-copy" 14}}</button>
|
<button class="btn interact-fg gt-p-3" data-clipboard-text="{{.DefaultBranchBranch.DBBranch.Name}}">{{svg "octicon-copy" 14}}</button>
|
||||||
|
{{template "repo/commit_statuses" dict "Status" (index $.CommitStatus .DefaultBranchBranch.DBBranch.CommitID) "Statuses" (index $.CommitStatuses .DefaultBranchBranch.DBBranch.CommitID)}}
|
||||||
</div>
|
</div>
|
||||||
<p class="info gt-df gt-ac gt-my-2">{{svg "octicon-git-commit" 16 "gt-mr-2"}}<a href="{{.RepoLink}}/commit/{{PathEscape .DefaultBranchBranch.DBBranch.CommitID}}">{{ShortSha .DefaultBranchBranch.DBBranch.CommitID}}</a> · <span class="commit-message">{{RenderCommitMessage $.Context .DefaultBranchBranch.DBBranch.CommitMessage .RepoLink .Repository.ComposeMetas}}</span> · {{.locale.Tr "org.repo_updated"}} {{TimeSince .DefaultBranchBranch.DBBranch.CommitTime.AsTime .locale}}{{if .DefaultBranchBranch.DBBranch.Pusher}} {{template "shared/user/avatarlink" dict "Context" $.Context "user" .DefaultBranchBranch.DBBranch.Pusher}}{{template "shared/user/namelink" .DefaultBranchBranch.DBBranch.Pusher}}{{end}}</p>
|
<p class="info gt-df gt-ac gt-my-2">{{svg "octicon-git-commit" 16 "gt-mr-2"}}<a href="{{.RepoLink}}/commit/{{PathEscape .DefaultBranchBranch.DBBranch.CommitID}}">{{ShortSha .DefaultBranchBranch.DBBranch.CommitID}}</a> · <span class="commit-message">{{RenderCommitMessage $.Context .DefaultBranchBranch.DBBranch.CommitMessage .RepoLink .Repository.ComposeMetas}}</span> · {{.locale.Tr "org.repo_updated"}} {{TimeSince .DefaultBranchBranch.DBBranch.CommitTime.AsTime .locale}}{{if .DefaultBranchBranch.DBBranch.Pusher}} {{template "shared/user/avatarlink" dict "Context" $.Context "user" .DefaultBranchBranch.DBBranch.Pusher}}{{template "shared/user/namelink" .DefaultBranchBranch.DBBranch.Pusher}}{{end}}</p>
|
||||||
</td>
|
</td>
|
||||||
@ -91,6 +92,7 @@
|
|||||||
<div class="gt-df gt-ac">
|
<div class="gt-df gt-ac">
|
||||||
<a class="gt-ellipsis" href="{{$.RepoLink}}/src/branch/{{PathEscapeSegments .DBBranch.Name}}">{{.DBBranch.Name}}</a>
|
<a class="gt-ellipsis" href="{{$.RepoLink}}/src/branch/{{PathEscapeSegments .DBBranch.Name}}">{{.DBBranch.Name}}</a>
|
||||||
<button class="btn interact-fg gt-p-3" data-clipboard-text="{{.DBBranch.Name}}">{{svg "octicon-copy" 14}}</button>
|
<button class="btn interact-fg gt-p-3" data-clipboard-text="{{.DBBranch.Name}}">{{svg "octicon-copy" 14}}</button>
|
||||||
|
{{template "repo/commit_statuses" dict "Status" (index $.CommitStatus .DBBranch.CommitID) "Statuses" (index $.CommitStatuses .DBBranch.CommitID)}}
|
||||||
</div>
|
</div>
|
||||||
<p class="info gt-df gt-ac gt-my-2">{{svg "octicon-git-commit" 16 "gt-mr-2"}}<a href="{{$.RepoLink}}/commit/{{PathEscape .DBBranch.CommitID}}">{{ShortSha .DBBranch.CommitID}}</a> · <span class="commit-message">{{RenderCommitMessage $.Context .DBBranch.CommitMessage $.RepoLink $.Repository.ComposeMetas}}</span> · {{$.locale.Tr "org.repo_updated"}} {{TimeSince .DBBranch.CommitTime.AsTime $.locale}}{{if .DBBranch.Pusher}} {{template "shared/user/avatarlink" dict "Context" $.Context "user" .DBBranch.Pusher}} {{template "shared/user/namelink" .DBBranch.Pusher}}{{end}}</p>
|
<p class="info gt-df gt-ac gt-my-2">{{svg "octicon-git-commit" 16 "gt-mr-2"}}<a href="{{$.RepoLink}}/commit/{{PathEscape .DBBranch.CommitID}}">{{ShortSha .DBBranch.CommitID}}</a> · <span class="commit-message">{{RenderCommitMessage $.Context .DBBranch.CommitMessage $.RepoLink $.Repository.ComposeMetas}}</span> · {{$.locale.Tr "org.repo_updated"}} {{TimeSince .DBBranch.CommitTime.AsTime $.locale}}{{if .DBBranch.Pusher}} {{template "shared/user/avatarlink" dict "Context" $.Context "user" .DBBranch.Pusher}} {{template "shared/user/namelink" .DBBranch.Pusher}}{{end}}</p>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -14,4 +14,10 @@
|
|||||||
{{$.locale.Tr "repo.pulls.tab_files"}}
|
{{$.locale.Tr "repo.pulls.tab_files"}}
|
||||||
<span class="ui small label">{{if .NumFiles}}{{.NumFiles}}{{else}}-{{end}}</span>
|
<span class="ui small label">{{if .NumFiles}}{{.NumFiles}}{{else}}-{{end}}</span>
|
||||||
</a>
|
</a>
|
||||||
|
<span class="item gt-ml-auto gt-pr-0 gt-font-bold gt-df gt-ac gt-gap-3">
|
||||||
|
<span><span class="text green">{{if .Diff.TotalAddition}}+{{.Diff.TotalAddition}}{{end}}</span> <span class="text red">{{if .Diff.TotalDeletion}}-{{.Diff.TotalDeletion}}{{end}}</span></span>
|
||||||
|
<span class="diff-stats-bar">
|
||||||
|
<div class="diff-stats-add-bar" style="width: {{Eval 100 "*" .Diff.TotalAddition "/" "(" .Diff.TotalAddition "+" .Diff.TotalDeletion "+" 0.0 ")"}}%"></div>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
<label>{{.locale.Tr "actions.runners.labels"}}</label>
|
<label>{{.locale.Tr "actions.runners.labels"}}</label>
|
||||||
<span>
|
<span>
|
||||||
{{range .Runner.AgentLabels}}
|
{{range .Runner.AgentLabels}}
|
||||||
<span>{{.}}</span>
|
<span class="ui label">{{.}}</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -204,15 +204,19 @@ const sfc = {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
async mounted() {
|
||||||
// load job data and then auto-reload periodically
|
// load job data and then auto-reload periodically
|
||||||
this.loadJob();
|
// need to await first loadJob so this.currentJobStepsStates is initialized and can be used in hashChangeListener
|
||||||
|
await this.loadJob();
|
||||||
this.intervalID = setInterval(this.loadJob, 1000);
|
this.intervalID = setInterval(this.loadJob, 1000);
|
||||||
document.body.addEventListener('click', this.closeDropdown);
|
document.body.addEventListener('click', this.closeDropdown);
|
||||||
|
this.hashChangeListener();
|
||||||
|
window.addEventListener('hashchange', this.hashChangeListener);
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeUnmount() {
|
beforeUnmount() {
|
||||||
document.body.removeEventListener('click', this.closeDropdown);
|
document.body.removeEventListener('click', this.closeDropdown);
|
||||||
|
window.removeEventListener('hashchange', this.hashChangeListener);
|
||||||
},
|
},
|
||||||
|
|
||||||
unmounted() {
|
unmounted() {
|
||||||
@ -280,14 +284,16 @@ const sfc = {
|
|||||||
this.fetchPost(`${this.run.link}/approve`);
|
this.fetchPost(`${this.run.link}/approve`);
|
||||||
},
|
},
|
||||||
|
|
||||||
createLogLine(line, startTime) {
|
createLogLine(line, startTime, stepIndex) {
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
div.classList.add('job-log-line');
|
div.classList.add('job-log-line');
|
||||||
|
div.setAttribute('id', `jobstep-${stepIndex}-${line.index}`);
|
||||||
div._jobLogTime = line.timestamp;
|
div._jobLogTime = line.timestamp;
|
||||||
|
|
||||||
const lineNumber = document.createElement('div');
|
const lineNumber = document.createElement('a');
|
||||||
lineNumber.className = 'line-num';
|
lineNumber.classList.add('line-num', 'muted');
|
||||||
lineNumber.textContent = line.index;
|
lineNumber.textContent = line.index;
|
||||||
|
lineNumber.setAttribute('href', `#jobstep-${stepIndex}-${line.index}`);
|
||||||
div.append(lineNumber);
|
div.append(lineNumber);
|
||||||
|
|
||||||
// for "Show timestamps"
|
// for "Show timestamps"
|
||||||
@ -318,7 +324,7 @@ const sfc = {
|
|||||||
for (const line of logLines) {
|
for (const line of logLines) {
|
||||||
// TODO: group support: ##[group]GroupTitle , ##[endgroup]
|
// TODO: group support: ##[group]GroupTitle , ##[endgroup]
|
||||||
const el = this.getLogsContainer(stepIndex);
|
const el = this.getLogsContainer(stepIndex);
|
||||||
el.append(this.createLogLine(line, startTime));
|
el.append(this.createLogLine(line, startTime, stepIndex));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -429,6 +435,21 @@ const sfc = {
|
|||||||
} else {
|
} else {
|
||||||
actionBodyEl.append(fullScreenEl);
|
actionBodyEl.append(fullScreenEl);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
async hashChangeListener() {
|
||||||
|
const selectedLogStep = window.location.hash;
|
||||||
|
if (!selectedLogStep) return;
|
||||||
|
const [_, step, _line] = selectedLogStep.split('-');
|
||||||
|
if (!this.currentJobStepsStates[step]) return;
|
||||||
|
if (!this.currentJobStepsStates[step].expanded && this.currentJobStepsStates[step].cursor === null) {
|
||||||
|
this.currentJobStepsStates[step].expanded = true;
|
||||||
|
// need to await for load job if the step log is loaded for the first time
|
||||||
|
// so logline can be selected by querySelector
|
||||||
|
await this.loadJob();
|
||||||
|
}
|
||||||
|
const logLine = this.$refs.steps.querySelector(selectedLogStep);
|
||||||
|
if (!logLine) return;
|
||||||
|
logLine.querySelector('.line-num').click();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -802,10 +823,15 @@ export function initRepositoryActionView() {
|
|||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.job-step-section .job-step-logs .job-log-line:hover {
|
.job-log-line:hover,
|
||||||
|
.job-log-line:target {
|
||||||
background-color: var(--color-console-hover-bg);
|
background-color: var(--color-console-hover-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.job-log-line:target {
|
||||||
|
scroll-margin-top: 95px;
|
||||||
|
}
|
||||||
|
|
||||||
/* class names 'log-time-seconds' and 'log-time-stamp' are used in the method toggleTimeDisplay */
|
/* class names 'log-time-seconds' and 'log-time-stamp' are used in the method toggleTimeDisplay */
|
||||||
.job-log-line .line-num, .log-time-seconds {
|
.job-log-line .line-num, .log-time-seconds {
|
||||||
width: 48px;
|
width: 48px;
|
||||||
@ -814,6 +840,11 @@ export function initRepositoryActionView() {
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.job-log-line:target > .line-num {
|
||||||
|
color: var(--color-primary);
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
.log-time-seconds {
|
.log-time-seconds {
|
||||||
padding-right: 2px;
|
padding-right: 2px;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user