Compare commits

..

No commits in common. "93e907de4173a64263b024293ac867f8111d4c40" and "426c0ad14c5edc6b7afdf7386d71889732ca11ac" have entirely different histories.

16 changed files with 102 additions and 122 deletions

View File

@ -1087,9 +1087,6 @@ func (ctx *Context) IssueTemplatesErrorsFromDefaultBranch() ([]*api.IssueTemplat
if it, err := template.UnmarshalFromEntry(entry, dirName); err != nil { if it, err := template.UnmarshalFromEntry(entry, dirName); err != nil {
invalidFiles[fullName] = err invalidFiles[fullName] = err
} else { } else {
if !strings.HasPrefix(it.Ref, "refs/") { // Assume that the ref intended is always a branch - for tags users should use refs/tags/<ref>
it.Ref = git.BranchPrefix + it.Ref
}
issueTemplates = append(issueTemplates, it) issueTemplates = append(issueTemplates, it)
} }
} }

View File

@ -100,9 +100,6 @@ func RefURL(repoURL, ref string) string {
return repoURL + "/src/branch/" + refName return repoURL + "/src/branch/" + refName
case strings.HasPrefix(ref, TagPrefix): case strings.HasPrefix(ref, TagPrefix):
return repoURL + "/src/tag/" + refName return repoURL + "/src/tag/" + refName
case !IsValidSHAPattern(ref):
// assume they mean a branch
return repoURL + "/src/branch/" + refName
default: default:
return repoURL + "/src/commit/" + refName return repoURL + "/src/commit/" + refName
} }

View File

@ -110,6 +110,32 @@ func (q *ChannelQueue) Flush(timeout time.Duration) error {
return q.FlushWithContext(ctx) return q.FlushWithContext(ctx)
} }
// FlushWithContext is very similar to CleanUp but it will return as soon as the dataChan is empty
func (q *ChannelQueue) FlushWithContext(ctx context.Context) error {
log.Trace("ChannelQueue: %d Flush", q.qid)
paused, _ := q.IsPausedIsResumed()
for {
select {
case <-paused:
return nil
case data, ok := <-q.dataChan:
if !ok {
return nil
}
if unhandled := q.handle(data); unhandled != nil {
log.Error("Unhandled Data whilst flushing queue %d", q.qid)
}
atomic.AddInt64(&q.numInQueue, -1)
case <-q.baseCtx.Done():
return q.baseCtx.Err()
case <-ctx.Done():
return ctx.Err()
default:
return nil
}
}
}
// Shutdown processing from this queue // Shutdown processing from this queue
func (q *ChannelQueue) Shutdown() { func (q *ChannelQueue) Shutdown() {
q.lock.Lock() q.lock.Lock()

View File

@ -9,6 +9,7 @@ import (
"fmt" "fmt"
"runtime/pprof" "runtime/pprof"
"sync" "sync"
"sync/atomic"
"time" "time"
"code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/container"
@ -167,6 +168,35 @@ func (q *ChannelUniqueQueue) Flush(timeout time.Duration) error {
return q.FlushWithContext(ctx) return q.FlushWithContext(ctx)
} }
// FlushWithContext is very similar to CleanUp but it will return as soon as the dataChan is empty
func (q *ChannelUniqueQueue) FlushWithContext(ctx context.Context) error {
log.Trace("ChannelUniqueQueue: %d Flush", q.qid)
paused, _ := q.IsPausedIsResumed()
for {
select {
case <-paused:
return nil
default:
}
select {
case data, ok := <-q.dataChan:
if !ok {
return nil
}
if unhandled := q.handle(data); unhandled != nil {
log.Error("Unhandled Data whilst flushing queue %d", q.qid)
}
atomic.AddInt64(&q.numInQueue, -1)
case <-q.baseCtx.Done():
return q.baseCtx.Err()
case <-ctx.Done():
return ctx.Err()
default:
return nil
}
}
}
// Shutdown processing from this queue // Shutdown processing from this queue
func (q *ChannelUniqueQueue) Shutdown() { func (q *ChannelUniqueQueue) Shutdown() {
log.Trace("ChannelUniqueQueue: %s Shutting down", q.name) log.Trace("ChannelUniqueQueue: %s Shutting down", q.name)

View File

@ -464,43 +464,13 @@ func (p *WorkerPool) IsEmpty() bool {
return atomic.LoadInt64(&p.numInQueue) == 0 return atomic.LoadInt64(&p.numInQueue) == 0
} }
// contextError returns either ctx.Done(), the base context's error or nil
func (p *WorkerPool) contextError(ctx context.Context) error {
select {
case <-p.baseCtx.Done():
return p.baseCtx.Err()
case <-ctx.Done():
return ctx.Err()
default:
return nil
}
}
// FlushWithContext is very similar to CleanUp but it will return as soon as the dataChan is empty // FlushWithContext is very similar to CleanUp but it will return as soon as the dataChan is empty
// NB: The worker will not be registered with the manager. // NB: The worker will not be registered with the manager.
func (p *WorkerPool) FlushWithContext(ctx context.Context) error { func (p *WorkerPool) FlushWithContext(ctx context.Context) error {
log.Trace("WorkerPool: %d Flush", p.qid) log.Trace("WorkerPool: %d Flush", p.qid)
paused, _ := p.IsPausedIsResumed()
for { for {
// Because select will return any case that is satisified at random we precheck here before looking at dataChan.
select { select {
case <-paused: case data := <-p.dataChan:
// Ensure that even if paused that the cancelled error is still sent
return p.contextError(ctx)
case <-p.baseCtx.Done():
return p.baseCtx.Err()
case <-ctx.Done():
return ctx.Err()
default:
}
select {
case <-paused:
return p.contextError(ctx)
case data, ok := <-p.dataChan:
if !ok {
return nil
}
if unhandled := p.handle(data); unhandled != nil { if unhandled := p.handle(data); unhandled != nil {
log.Error("Unhandled Data whilst flushing queue %d", p.qid) log.Error("Unhandled Data whilst flushing queue %d", p.qid)
} }
@ -526,7 +496,6 @@ func (p *WorkerPool) doWork(ctx context.Context) {
paused, _ := p.IsPausedIsResumed() paused, _ := p.IsPausedIsResumed()
data := make([]Data, 0, p.batchLength) data := make([]Data, 0, p.batchLength)
for { for {
// Because select will return any case that is satisified at random we precheck here before looking at dataChan.
select { select {
case <-paused: case <-paused:
log.Trace("Worker for Queue %d Pausing", p.qid) log.Trace("Worker for Queue %d Pausing", p.qid)
@ -547,19 +516,8 @@ func (p *WorkerPool) doWork(ctx context.Context) {
log.Trace("Worker shutting down") log.Trace("Worker shutting down")
return return
} }
case <-ctx.Done():
if len(data) > 0 {
log.Trace("Handling: %d data, %v", len(data), data)
if unhandled := p.handle(data...); unhandled != nil {
log.Error("Unhandled Data in queue %d", p.qid)
}
atomic.AddInt64(&p.numInQueue, -1*int64(len(data)))
}
log.Trace("Worker shutting down")
return
default: default:
} }
select { select {
case <-paused: case <-paused:
// go back around // go back around

View File

@ -784,10 +784,6 @@ func setTemplateIfExists(ctx *context.Context, ctxDataKey string, possibleFiles
} }
} }
} }
}
if !strings.HasPrefix(template.Ref, "refs/") { // Assume that the ref intended is always a branch - for tags users should use refs/tags/<ref>
template.Ref = git.BranchPrefix + template.Ref
} }
ctx.Data["HasSelectedLabel"] = len(labelIDs) > 0 ctx.Data["HasSelectedLabel"] = len(labelIDs) > 0
ctx.Data["label_ids"] = strings.Join(labelIDs, ",") ctx.Data["label_ids"] = strings.Join(labelIDs, ",")

View File

@ -18,6 +18,7 @@ import (
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/notification" "code.gitea.io/gitea/modules/notification"
"code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/modules/util"
) )
// NewIssue creates new issue with labels for repository. // NewIssue creates new issue with labels for repository.
@ -200,7 +201,7 @@ func GetRefEndNamesAndURLs(issues []*issues_model.Issue, repoLink string) (map[i
for _, issue := range issues { for _, issue := range issues {
if issue.Ref != "" { if issue.Ref != "" {
issueRefEndNames[issue.ID] = git.RefEndName(issue.Ref) issueRefEndNames[issue.ID] = git.RefEndName(issue.Ref)
issueRefURLs[issue.ID] = git.RefURL(repoLink, issue.Ref) issueRefURLs[issue.ID] = git.RefURL(repoLink, util.PathEscapeSegments(issue.Ref))
} }
} }
return issueRefEndNames, issueRefURLs return issueRefEndNames, issueRefURLs

View File

@ -73,8 +73,32 @@ func GitGcRepos(ctx context.Context, timeout time.Duration, args ...git.CmdArg)
return db.ErrCancelledf("before GC of %s", repo.FullName()) return db.ErrCancelledf("before GC of %s", repo.FullName())
default: default:
} }
// we can ignore the error here because it will be logged in GitGCRepo log.Trace("Running git gc on %v", repo)
_ = GitGcRepo(ctx, repo, timeout, args) command := git.NewCommand(ctx, args...).
SetDescription(fmt.Sprintf("Repository Garbage Collection: %s", repo.FullName()))
var stdout string
var err error
stdout, _, err = command.RunStdString(&git.RunOpts{Timeout: timeout, Dir: repo.RepoPath()})
if err != nil {
log.Error("Repository garbage collection failed for %v. Stdout: %s\nError: %v", repo, stdout, err)
desc := fmt.Sprintf("Repository garbage collection failed for %s. Stdout: %s\nError: %v", repo.RepoPath(), stdout, err)
if err = system_model.CreateRepositoryNotice(desc); err != nil {
log.Error("CreateRepositoryNotice: %v", err)
}
return fmt.Errorf("Repository garbage collection failed in repo: %s: Error: %w", repo.FullName(), err)
}
// Now update the size of the repository
if err := repo_module.UpdateRepoSize(ctx, repo); err != nil {
log.Error("Updating size as part of garbage collection failed for %v. Stdout: %s\nError: %v", repo, stdout, err)
desc := fmt.Sprintf("Updating size as part of garbage collection failed for %s. Stdout: %s\nError: %v", repo.RepoPath(), stdout, err)
if err = system_model.CreateRepositoryNotice(desc); err != nil {
log.Error("CreateRepositoryNotice: %v", err)
}
return fmt.Errorf("Updating size as part of garbage collection failed in repo: %s: Error: %w", repo.FullName(), err)
}
return nil return nil
}, },
); err != nil { ); err != nil {
@ -85,37 +109,6 @@ func GitGcRepos(ctx context.Context, timeout time.Duration, args ...git.CmdArg)
return nil return nil
} }
// GitGcRepo calls 'git gc' to remove unnecessary files and optimize the local repository
func GitGcRepo(ctx context.Context, repo *repo_model.Repository, timeout time.Duration, args []git.CmdArg) error {
log.Trace("Running git gc on %-v", repo)
command := git.NewCommand(ctx, args...).
SetDescription(fmt.Sprintf("Repository Garbage Collection: %s", repo.FullName()))
var stdout string
var err error
stdout, _, err = command.RunStdString(&git.RunOpts{Timeout: timeout, Dir: repo.RepoPath()})
if err != nil {
log.Error("Repository garbage collection failed for %-v. Stdout: %s\nError: %v", repo, stdout, err)
desc := fmt.Sprintf("Repository garbage collection failed for %s. Stdout: %s\nError: %v", repo.RepoPath(), stdout, err)
if err := system_model.CreateRepositoryNotice(desc); err != nil {
log.Error("CreateRepositoryNotice: %v", err)
}
return fmt.Errorf("Repository garbage collection failed in repo: %s: Error: %w", repo.FullName(), err)
}
// Now update the size of the repository
if err := repo_module.UpdateRepoSize(ctx, repo); err != nil {
log.Error("Updating size as part of garbage collection failed for %-v. Stdout: %s\nError: %v", repo, stdout, err)
desc := fmt.Sprintf("Updating size as part of garbage collection failed for %s. Stdout: %s\nError: %v", repo.RepoPath(), stdout, err)
if err := system_model.CreateRepositoryNotice(desc); err != nil {
log.Error("CreateRepositoryNotice: %v", err)
}
return fmt.Errorf("Updating size as part of garbage collection failed in repo: %s: Error: %w", repo.FullName(), err)
}
return nil
}
func gatherMissingRepoRecords(ctx context.Context) ([]*repo_model.Repository, error) { func gatherMissingRepoRecords(ctx context.Context) ([]*repo_model.Repository, error) {
repos := make([]*repo_model.Repository, 0, 10) repos := make([]*repo_model.Repository, 0, 10)
if err := db.Iterate( if err := db.Iterate(
@ -169,7 +162,7 @@ func DeleteMissingRepositories(ctx context.Context, doer *user_model.User) error
} }
log.Trace("Deleting %d/%d...", repo.OwnerID, repo.ID) log.Trace("Deleting %d/%d...", repo.OwnerID, repo.ID)
if err := models.DeleteRepository(doer, repo.OwnerID, repo.ID); err != nil { if err := models.DeleteRepository(doer, repo.OwnerID, repo.ID); err != nil {
log.Error("Failed to DeleteRepository %-v: Error: %v", repo, err) log.Error("Failed to DeleteRepository %s [%d]: Error: %v", repo.FullName(), repo.ID, err)
if err2 := system_model.CreateRepositoryNotice("Failed to DeleteRepository %s [%d]: Error: %v", repo.FullName(), repo.ID, err); err2 != nil { if err2 := system_model.CreateRepositoryNotice("Failed to DeleteRepository %s [%d]: Error: %v", repo.FullName(), repo.ID, err); err2 != nil {
log.Error("CreateRepositoryNotice: %v", err) log.Error("CreateRepositoryNotice: %v", err)
} }

View File

@ -139,7 +139,7 @@ func (f *WechatworkPayload) PullRequest(p *api.PullRequestPayload) (api.Payloade
func (f *WechatworkPayload) Review(p *api.PullRequestPayload, event webhook_model.HookEventType) (api.Payloader, error) { func (f *WechatworkPayload) Review(p *api.PullRequestPayload, event webhook_model.HookEventType) (api.Payloader, error) {
var text, title string var text, title string
switch p.Action { switch p.Action {
case api.HookIssueReviewed: case api.HookIssueSynchronized:
action, err := parseHookPullRequestEventType(event) action, err := parseHookPullRequestEventType(event)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -27,7 +27,7 @@
</a> </a>
{{if and ($.Permission.CanWrite $.UnitTypeCode) (not $.Repository.IsArchived) (not .IsDeleted)}}{{- /* */ -}} {{if and ($.Permission.CanWrite $.UnitTypeCode) (not $.Repository.IsArchived) (not .IsDeleted)}}{{- /* */ -}}
<div class="ui primary tiny floating dropdown icon button">{{.locale.Tr "repo.commit.actions"}} <div class="ui primary tiny floating dropdown icon button">{{.locale.Tr "repo.commit.actions"}}
{{svg "octicon-triangle-down" 14 "dropdown icon"}} {{svg "octicon-triangle-down" 14 "dropdown icon"}}<span class="sr-mobile-only">{{.locale.Tr "repo.commit.actions"}}</span>
<div class="menu"> <div class="menu">
<div class="ui header">{{.locale.Tr "repo.commit.actions"}}</div> <div class="ui header">{{.locale.Tr "repo.commit.actions"}}</div>
<div class="divider"></div> <div class="divider"></div>

View File

@ -143,7 +143,7 @@
{{$.locale.Tr "repo.diff.file_suppressed_line_too_long"}} {{$.locale.Tr "repo.diff.file_suppressed_line_too_long"}}
{{else}} {{else}}
{{$.locale.Tr "repo.diff.file_suppressed"}} {{$.locale.Tr "repo.diff.file_suppressed"}}
<a class="ui basic tiny button diff-load-button" data-href="{{$.Link}}?file-only=true&files={{$file.Name}}&files={{$file.OldName}}">{{$.locale.Tr "repo.diff.load"}}</a> <a class="ui basic tiny button diff-show-more-button" data-href="{{$.Link}}?file-only=true&files={{$file.Name}}&files={{$file.OldName}}">{{$.locale.Tr "repo.diff.load"}}</a>
{{end}} {{end}}
{{else}} {{else}}
{{$.locale.Tr "repo.diff.bin_not_shown"}} {{$.locale.Tr "repo.diff.bin_not_shown"}}

View File

@ -209,6 +209,8 @@ func (s *TestSession) MakeRequestNilResponseHashSumRecorder(t testing.TB, req *h
const userPassword = "password" const userPassword = "password"
var loginSessionCache = make(map[string]*TestSession, 10)
func emptyTestSession(t testing.TB) *TestSession { func emptyTestSession(t testing.TB) *TestSession {
t.Helper() t.Helper()
jar, err := cookiejar.New(nil) jar, err := cookiejar.New(nil)
@ -223,8 +225,12 @@ func getUserToken(t testing.TB, userName string) string {
func loginUser(t testing.TB, userName string) *TestSession { func loginUser(t testing.TB, userName string) *TestSession {
t.Helper() t.Helper()
if session, ok := loginSessionCache[userName]; ok {
return loginUserWithPassword(t, userName, userPassword) return session
}
session := loginUserWithPassword(t, userName, userPassword)
loginSessionCache[userName] = session
return session
} }
func loginUserWithPassword(t testing.TB, userName, password string) *TestSession { func loginUserWithPassword(t testing.TB, userName, password string) *TestSession {

View File

@ -22,4 +22,7 @@ func TestSignOut(t *testing.T) {
// try to view a private repo, should fail // try to view a private repo, should fail
req = NewRequest(t, "GET", "/user2/repo2") req = NewRequest(t, "GET", "/user2/repo2")
session.MakeRequest(t, req, http.StatusNotFound) session.MakeRequest(t, req, http.StatusNotFound)
// invalidate cached cookies for user2, for subsequent tests
delete(loginSessionCache, "user2")
} }

View File

@ -8,7 +8,7 @@
<DiffFileTreeItem v-for="item in fileTree" :key="item.name" :item="item" /> <DiffFileTreeItem v-for="item in fileTree" :key="item.name" :item="item" />
</div> </div>
<div v-if="isIncomplete" id="diff-too-many-files-stats" class="pt-2"> <div v-if="isIncomplete" id="diff-too-many-files-stats" class="pt-2">
<span class="mr-2">{{ tooManyFilesMessage }}</span><a :class="['ui', 'basic', 'tiny', 'button', isLoadingNewData === true ? 'disabled' : '']" id="diff-show-more-files-stats" @click.stop="loadMoreData">{{ showMoreMessage }}</a> <span>{{ tooManyFilesMessage }}</span><a :class="['ui', 'basic', 'tiny', 'button', isLoadingNewData === true ? 'disabled' : '']" id="diff-show-more-files-stats" @click.stop="loadMoreData">{{ showMoreMessage }}</a>
</div> </div>
</div> </div>
</template> </template>
@ -98,9 +98,6 @@ export default {
mounted() { mounted() {
// ensure correct buttons when we are mounted to the dom // ensure correct buttons when we are mounted to the dom
this.adjustToggleButton(this.fileTreeIsVisible); this.adjustToggleButton(this.fileTreeIsVisible);
// replace the pageData.diffFileInfo.files with our watched data so we get updates
pageData.diffFileInfo.files = this.files;
document.querySelector('.diff-toggle-file-tree-button').addEventListener('click', this.toggleVisibility); document.querySelector('.diff-toggle-file-tree-button').addEventListener('click', this.toggleVisibility);
}, },
unmounted() { unmounted() {

View File

@ -119,47 +119,26 @@ function onShowMoreFiles() {
export function doLoadMoreFiles(link, diffEnd, callback) { export function doLoadMoreFiles(link, diffEnd, callback) {
const url = `${link}?skip-to=${diffEnd}&file-only=true`; const url = `${link}?skip-to=${diffEnd}&file-only=true`;
loadMoreFiles(url, callback);
}
function loadMoreFiles(url, callback) {
const $target = $('a#diff-show-more-files');
if ($target.hasClass('disabled')) {
callback();
return;
}
$target.addClass('disabled');
$.ajax({ $.ajax({
type: 'GET', type: 'GET',
url, url,
}).done((resp) => { }).done((resp) => {
if (!resp) { if (!resp) {
$target.removeClass('disabled');
callback(resp); callback(resp);
return; return;
} }
$('#diff-incomplete').replaceWith($(resp).find('#diff-file-boxes').children());
// By simply rerunning the script we add the new data to our existing // By simply rerunning the script we add the new data to our existing
// pagedata object. this triggers vue and the filetree and filelist will // pagedata object. this triggers vue and the filetree and filelist will
// render the new elements. // render the new elements.
$('body').append($(resp).find('script#diff-data-script')); $('body').append($(resp).find('script#diff-data-script'));
onShowMoreFiles();
callback(resp); callback(resp);
}).fail(() => { }).fail(() => {
$target.removeClass('disabled');
callback(); callback();
}); });
} }
export function initRepoDiffShowMore() { export function initRepoDiffShowMore() {
$(document).on('click', 'a#diff-show-more-files', (e) => { $(document).on('click', 'a.diff-show-more-button', (e) => {
e.preventDefault();
const $target = $(e.target);
loadMoreFiles($target.data('href'), () => {});
});
$(document).on('click', 'a.diff-load-button', (e) => {
e.preventDefault(); e.preventDefault();
const $target = $(e.target); const $target = $(e.target);

View File

@ -1665,9 +1665,6 @@
background-color: var(--color-teal); background-color: var(--color-teal);
} }
} }
.button {
padding: 8px 12px;
}
} }
.diff-box .header:not(.resolved-placeholder) { .diff-box .header:not(.resolved-placeholder) {