1
1
mirror of https://github.com/go-gitea/gitea synced 2025-01-20 14:44:27 +00:00

Merge branch 'main' into lunny/refactor_getpatch

This commit is contained in:
Lunny Xiao 2024-12-12 15:25:54 -08:00
commit 27b67534e3
20 changed files with 129 additions and 38 deletions

View File

@ -3,3 +3,5 @@ self-hosted-runner:
- actuated-4cpu-8gb
- actuated-4cpu-16gb
- nscloud
- namespace-profile-gitea-release-docker
- namespace-profile-gitea-release-binary

View File

@ -10,7 +10,7 @@ concurrency:
jobs:
nightly-binary:
runs-on: nscloud
runs-on: namespace-profile-gitea-release-binary
steps:
- uses: actions/checkout@v4
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
@ -58,7 +58,7 @@ jobs:
run: |
aws s3 sync dist/release s3://${{ secrets.AWS_S3_BUCKET }}/gitea/${{ steps.clean_name.outputs.branch }} --no-progress
nightly-docker-rootful:
runs-on: ubuntu-latest
runs-on: namespace-profile-gitea-release-docker
steps:
- uses: actions/checkout@v4
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
@ -95,7 +95,7 @@ jobs:
push: true
tags: gitea/gitea:${{ steps.clean_name.outputs.branch }}
nightly-docker-rootless:
runs-on: ubuntu-latest
runs-on: namespace-profile-gitea-release-docker
steps:
- uses: actions/checkout@v4
# fetch all commits instead of only the last as some branches are long lived and could have many between versions

View File

@ -11,7 +11,7 @@ concurrency:
jobs:
binary:
runs-on: nscloud
runs-on: namespace-profile-gitea-release-binary
steps:
- uses: actions/checkout@v4
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
@ -68,7 +68,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
docker-rootful:
runs-on: ubuntu-latest
runs-on: namespace-profile-gitea-release-docker
steps:
- uses: actions/checkout@v4
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
@ -99,7 +99,7 @@ jobs:
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
docker-rootless:
runs-on: ubuntu-latest
runs-on: namespace-profile-gitea-release-docker
steps:
- uses: actions/checkout@v4
# fetch all commits instead of only the last as some branches are long lived and could have many between versions

View File

@ -13,7 +13,7 @@ concurrency:
jobs:
binary:
runs-on: nscloud
runs-on: namespace-profile-gitea-release-binary
steps:
- uses: actions/checkout@v4
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
@ -70,7 +70,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
docker-rootful:
runs-on: ubuntu-latest
runs-on: namespace-profile-gitea-release-docker
steps:
- uses: actions/checkout@v4
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
@ -105,7 +105,7 @@ jobs:
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
docker-rootless:
runs-on: ubuntu-latest
runs-on: namespace-profile-gitea-release-docker
steps:
- uses: actions/checkout@v4
# fetch all commits instead of only the last as some branches are long lived and could have many between versions

View File

@ -37,6 +37,7 @@ type ActionRun struct {
TriggerUser *user_model.User `xorm:"-"`
ScheduleID int64
Ref string `xorm:"index"` // the commit/tag/… that caused the run
IsRefDeleted bool `xorm:"-"`
CommitSHA string
IsForkPullRequest bool // If this is triggered by a PR from a forked repository or an untrusted user, we need to check if it is approved and limit permissions when running the workflow.
NeedApproval bool // may need approval if it's a fork pull request

View File

@ -12,6 +12,7 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/optional"
@ -169,9 +170,22 @@ func GetBranch(ctx context.Context, repoID int64, branchName string) (*Branch, e
return &branch, nil
}
func GetBranches(ctx context.Context, repoID int64, branchNames []string) ([]*Branch, error) {
func GetBranches(ctx context.Context, repoID int64, branchNames []string, includeDeleted bool) ([]*Branch, error) {
branches := make([]*Branch, 0, len(branchNames))
return branches, db.GetEngine(ctx).Where("repo_id=?", repoID).In("name", branchNames).Find(&branches)
sess := db.GetEngine(ctx).Where("repo_id=?", repoID).In("name", branchNames)
if !includeDeleted {
sess.And("is_deleted=?", false)
}
return branches, sess.Find(&branches)
}
func BranchesToNamesSet(branches []*Branch) container.Set[string] {
names := make(container.Set[string], len(branches))
for _, branch := range branches {
names.Add(branch.Name)
}
return names
}
func AddBranches(ctx context.Context, branches []*Branch) error {

View File

@ -236,6 +236,7 @@ func createRequest(ctx context.Context, method, url string, headers map[string]s
req.Header.Set(key, value)
}
req.Header.Set("Accept", AcceptHeader)
req.Header.Set("User-Agent", UserAgentHeader)
return req, nil
}

View File

@ -15,7 +15,8 @@ const (
// MediaType contains the media type for LFS server requests
MediaType = "application/vnd.git-lfs+json"
// Some LFS servers offer content with other types, so fallback to '*/*' if application/vnd.git-lfs+json cannot be served
AcceptHeader = "application/vnd.git-lfs+json;q=0.9, */*;q=0.8"
AcceptHeader = "application/vnd.git-lfs+json;q=0.9, */*;q=0.8"
UserAgentHeader = "git-lfs"
)
// BatchRequest contains multiple requests processed in one batch operation.

View File

@ -245,6 +245,10 @@ func List(ctx *context.Context) {
return
}
if err := loadIsRefDeleted(ctx, runs); err != nil {
log.Error("LoadIsRefDeleted", err)
}
ctx.Data["Runs"] = runs
actors, err := actions_model.GetActors(ctx, ctx.Repo.Repository.ID)
@ -267,6 +271,34 @@ func List(ctx *context.Context) {
ctx.HTML(http.StatusOK, tplListActions)
}
// loadIsRefDeleted loads the IsRefDeleted field for each run in the list.
// TODO: move this function to models/actions/run_list.go but now it will result in a circular import.
func loadIsRefDeleted(ctx *context.Context, runs actions_model.RunList) error {
branches := make(container.Set[string], len(runs))
for _, run := range runs {
refName := git.RefName(run.Ref)
if refName.IsBranch() {
branches.Add(refName.ShortName())
}
}
if len(branches) == 0 {
return nil
}
branchInfos, err := git_model.GetBranches(ctx, ctx.Repo.Repository.ID, branches.Values(), false)
if err != nil {
return err
}
branchSet := git_model.BranchesToNamesSet(branchInfos)
for _, run := range runs {
refName := git.RefName(run.Ref)
if refName.IsBranch() && !branchSet.Contains(run.Ref) {
run.IsRefDeleted = true
}
}
return nil
}
type WorkflowDispatchInput struct {
Name string `yaml:"name"`
Description string `yaml:"description"`

View File

@ -19,6 +19,7 @@ import (
actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git"
"code.gitea.io/gitea/models/perm"
access_model "code.gitea.io/gitea/models/perm/access"
repo_model "code.gitea.io/gitea/models/repo"
@ -136,8 +137,9 @@ type ViewUser struct {
}
type ViewBranch struct {
Name string `json:"name"`
Link string `json:"link"`
Name string `json:"name"`
Link string `json:"link"`
IsDeleted bool `json:"isDeleted"`
}
type ViewJobStep struct {
@ -236,6 +238,16 @@ func ViewPost(ctx *context_module.Context) {
Name: run.PrettyRef(),
Link: run.RefLink(),
}
refName := git.RefName(run.Ref)
if refName.IsBranch() {
b, err := git_model.GetBranch(ctx, ctx.Repo.Repository.ID, refName.ShortName())
if err != nil && !git_model.IsErrBranchNotExist(err) {
log.Error("GetBranch: %v", err)
} else if git_model.IsErrBranchNotExist(err) || (b != nil && b.IsDeleted) {
branch.IsDeleted = true
}
}
resp.State.Run.Commit = ViewCommit{
ShortSha: base.ShortSha(run.CommitSHA),
Link: fmt.Sprintf("%s/commit/%s", run.Repo.Link(), run.CommitSHA),

View File

@ -305,7 +305,7 @@ func SyncBranchesToDB(ctx context.Context, repoID, pusherID int64, branchNames,
}
return db.WithTx(ctx, func(ctx context.Context) error {
branches, err := git_model.GetBranches(ctx, repoID, branchNames)
branches, err := git_model.GetBranches(ctx, repoID, branchNames, true)
if err != nil {
return fmt.Errorf("git_model.GetBranches: %v", err)
}

View File

@ -27,10 +27,10 @@
</div>
</div>
<div class="flex-item-trailing">
{{if .RefLink}}
<a class="ui label run-list-ref gt-ellipsis" href="{{.RefLink}}">{{.PrettyRef}}</a>
{{if .IsRefDeleted}}
<span class="ui label run-list-ref gt-ellipsis tw-line-through" data-tooltip-content="{{.PrettyRef}}">{{.PrettyRef}}</span>
{{else}}
<span class="ui label run-list-ref gt-ellipsis">{{.PrettyRef}}</span>
<a class="ui label run-list-ref gt-ellipsis" href="{{.RefLink}}" data-tooltip-content="{{.PrettyRef}}">{{.PrettyRef}}</a>
{{end}}
<div class="run-list-item-right">
<div class="run-list-meta">{{svg "octicon-calendar" 16}}{{DateUtils.TimeSince .Updated}}</div>

View File

@ -1,6 +1,7 @@
{{if .Permission.CanRead ctx.Consts.RepoUnitTypeCode}}
<div id="repo-contributors-chart"
data-repo-link="{{.RepoLink}}"
data-repo-default-branch-name="{{.Repository.DefaultBranch}}"
data-locale-filter-label="{{ctx.Locale.Tr "repo.contributors.contribution_type.filter_label"}}"
data-locale-contribution-type-commits="{{ctx.Locale.Tr "repo.contributors.contribution_type.commits"}}"
data-locale-contribution-type-additions="{{ctx.Locale.Tr "repo.contributors.contribution_type.additions"}}"

View File

@ -167,8 +167,8 @@
<button class="btn diff-header-popup-btn tw-p-1">{{svg "octicon-kebab-horizontal" 18}}</button>
<div class="tippy-target">
{{if not (or $file.IsIncomplete $file.IsBin $file.IsSubmodule)}}
<button class="unescape-button item" data-file-content-elem-id="diff-{{$file.NameHash}}">{{ctx.Locale.Tr "repo.unescape_control_characters"}}</button>
<button class="escape-button tw-hidden item" data-file-content-elem-id="diff-{{$file.NameHash}}">{{ctx.Locale.Tr "repo.escape_control_characters"}}</button>
<button class="unescape-button item" data-unicode-content-selector="#diff-{{$file.NameHash}}">{{ctx.Locale.Tr "repo.unescape_control_characters"}}</button>
<button class="escape-button tw-hidden item" data-unicode-content-selector="#diff-{{$file.NameHash}}">{{ctx.Locale.Tr "repo.escape_control_characters"}}</button>
{{end}}
{{if and (not $file.IsSubmodule) (not $.PageIsWiki)}}
{{if $file.IsDeleted}}

View File

@ -44,13 +44,13 @@
</div>
<div class="repo-button-row">
{{if .EscapeStatus.Escaped}}
<a class="ui small button unescape-button tw-m-0 tw-hidden">{{ctx.Locale.Tr "repo.unescape_control_characters"}}</a>
<a class="ui small button escape-button tw-m-0">{{ctx.Locale.Tr "repo.escape_control_characters"}}</a>
<a class="ui small button unescape-button tw-hidden" data-unicode-content-selector=".wiki-content-parts">{{ctx.Locale.Tr "repo.unescape_control_characters"}}</a>
<a class="ui small button escape-button" data-unicode-content-selector=".wiki-content-parts">{{ctx.Locale.Tr "repo.escape_control_characters"}}</a>
{{end}}
{{if and .CanWriteWiki (not .Repository.IsMirror)}}
<a class="ui small button" href="{{.RepoLink}}/wiki/{{.PageURL}}?action=_edit">{{ctx.Locale.Tr "repo.wiki.edit_page_button"}}</a>
<a class="ui small primary button" href="{{.RepoLink}}/wiki?action=_new">{{ctx.Locale.Tr "repo.wiki.new_page_button"}}</a>
<a class="ui small red button tw-m-0 delete-button" href="" data-url="{{.RepoLink}}/wiki/{{.PageURL}}?action=_delete" data-id="{{.PageURL}}">{{ctx.Locale.Tr "repo.wiki.delete_page_button"}}</a>
<a class="ui small red button delete-button" href="" data-url="{{.RepoLink}}/wiki/{{.PageURL}}?action=_delete" data-id="{{.PageURL}}">{{ctx.Locale.Tr "repo.wiki.delete_page_button"}}</a>
{{end}}
</div>
</div>

View File

@ -95,6 +95,11 @@ func TestMain(m *testing.M) {
os.Unsetenv("GIT_COMMITTER_EMAIL")
os.Unsetenv("GIT_COMMITTER_DATE")
// Avoid loading the default system config. On MacOS, this config
// sets the osxkeychain credential helper, which will cause tests
// to freeze with a dialog.
os.Setenv("GIT_CONFIG_NOSYSTEM", "true")
err := unittest.InitFixtures(
unittest.FixturesOptions{
Dir: filepath.Join(filepath.Dir(setting.AppPath), "models/fixtures/"),

View File

@ -429,7 +429,8 @@ export function initRepositoryActionView() {
<a class="muted" :href="run.commit.pusher.link">{{ run.commit.pusher.displayName }}</a>
</template>
<span class="ui label tw-max-w-full" v-if="run.commit.shortSHA">
<a class="gt-ellipsis" :href="run.commit.branch.link">{{ run.commit.branch.name }}</a>
<span v-if="run.commit.branch.isDeleted" class="gt-ellipsis tw-line-through" :data-tooltip-content="run.commit.branch.name">{{ run.commit.branch.name }}</span>
<a v-else class="gt-ellipsis" :href="run.commit.branch.link" :data-tooltip-content="run.commit.branch.name">{{ run.commit.branch.name }}</a>
</span>
</div>
</div>

View File

@ -1,5 +1,6 @@
<script lang="ts">
import {SvgIcon} from '../svg.ts';
import dayjs from 'dayjs';
import {
Chart,
Title,
@ -26,6 +27,7 @@ import {sleep} from '../utils.ts';
import 'chartjs-adapter-dayjs-4/dist/chartjs-adapter-dayjs-4.esm';
import {fomanticQuery} from '../modules/fomantic/base.ts';
import type {Entries} from 'type-fest';
import {pathEscapeSegments} from '../utils/url.ts';
const customEventListener: Plugin = {
id: 'customEventListener',
@ -65,6 +67,10 @@ export default {
type: String,
required: true,
},
repoDefaultBranchName: {
type: String,
required: true,
},
},
data: () => ({
isLoading: false,
@ -100,6 +106,15 @@ export default {
.slice(0, 100);
},
getContributorSearchQuery(contributorEmail: string) {
const min = dayjs(this.xAxisMin).format('YYYY-MM-DD');
const max = dayjs(this.xAxisMax).format('YYYY-MM-DD');
const params = new URLSearchParams({
'q': `after:${min}, before:${max}, author:${contributorEmail}`,
});
return `${this.repoLink}/commits/branch/${pathEscapeSegments(this.repoDefaultBranchName)}/search?${params.toString()}`;
},
async fetchGraphData() {
this.isLoading = true;
try {
@ -167,7 +182,7 @@ export default {
// for details.
user.max_contribution_type += 1;
filteredData[key] = {...user, weeks: filteredWeeks};
filteredData[key] = {...user, weeks: filteredWeeks, email: key};
}
return filteredData;
@ -215,7 +230,7 @@ export default {
};
},
updateOtherCharts({chart}: {chart: Chart}, reset?: boolean = false) {
updateOtherCharts({chart}: {chart: Chart}, reset: boolean = false) {
const minVal = chart.options.scales.x.min;
const maxVal = chart.options.scales.x.max;
if (reset) {
@ -381,7 +396,7 @@ export default {
<div class="ui top attached header tw-flex tw-flex-1">
<b class="ui right">#{{ index + 1 }}</b>
<a :href="contributor.home_link">
<img class="ui avatar tw-align-middle" height="40" width="40" :src="contributor.avatar_link">
<img class="ui avatar tw-align-middle" height="40" width="40" :src="contributor.avatar_link" alt="">
</a>
<div class="tw-ml-2">
<a v-if="contributor.home_link !== ''" :href="contributor.home_link"><h4>{{ contributor.name }}</h4></a>
@ -389,7 +404,11 @@ export default {
{{ contributor.name }}
</h4>
<p class="tw-text-12 tw-flex tw-gap-1">
<strong v-if="contributor.total_commits">{{ contributor.total_commits.toLocaleString() }} {{ locale.contributionType.commits }}</strong>
<strong v-if="contributor.total_commits">
<a class="silenced" :href="getContributorSearchQuery(contributor.email)">
{{ contributor.total_commits.toLocaleString() }} {{ locale.contributionType.commits }}
</a>
</strong>
<strong v-if="contributor.total_additions" class="text green">{{ contributor.total_additions.toLocaleString() }}++ </strong>
<strong v-if="contributor.total_deletions" class="text red">
{{ contributor.total_deletions.toLocaleString() }}--</strong>

View File

@ -8,6 +8,7 @@ export async function initRepoContributors() {
try {
const View = createApp(RepoContributors, {
repoLink: el.getAttribute('data-repo-link'),
repoDefaultBranchName: el.getAttribute('data-repo-default-branch-name'),
locale: {
filterLabel: el.getAttribute('data-locale-filter-label'),
contributionType: {

View File

@ -1,27 +1,28 @@
import {addDelegatedEventListener, hideElem, queryElemSiblings, showElem, toggleElem} from '../utils/dom.ts';
export function initUnicodeEscapeButton() {
// buttons might appear on these pages: file view (code, rendered markdown), diff (commit, pr conversation, pr diff), blame, wiki
addDelegatedEventListener(document, 'click', '.escape-button, .unescape-button, .toggle-escape-button', (btn, e) => {
e.preventDefault();
const fileContentElemId = btn.getAttribute('data-file-content-elem-id');
const fileContent = fileContentElemId ?
document.querySelector(`#${fileContentElemId}`) :
const unicodeContentSelector = btn.getAttribute('data-unicode-content-selector');
const container = unicodeContentSelector ?
document.querySelector(unicodeContentSelector) :
btn.closest('.file-content, .non-diff-file-content');
const fileView = fileContent?.querySelectorAll('.file-code, .file-view');
const fileView = container.querySelector('.file-code, .file-view') ?? container;
if (btn.matches('.escape-button')) {
for (const el of fileView) el.classList.add('unicode-escaped');
fileView.classList.add('unicode-escaped');
hideElem(btn);
showElem(queryElemSiblings(btn, '.unescape-button'));
} else if (btn.matches('.unescape-button')) {
for (const el of fileView) el.classList.remove('unicode-escaped');
fileView.classList.remove('unicode-escaped');
hideElem(btn);
showElem(queryElemSiblings(btn, '.escape-button'));
} else if (btn.matches('.toggle-escape-button')) {
const isEscaped = fileView[0]?.classList.contains('unicode-escaped');
for (const el of fileView) el.classList.toggle('unicode-escaped', !isEscaped);
toggleElem(fileContent.querySelectorAll('.unescape-button'), !isEscaped);
toggleElem(fileContent.querySelectorAll('.escape-button'), isEscaped);
const isEscaped = fileView.classList.contains('unicode-escaped');
fileView.classList.toggle('unicode-escaped', !isEscaped);
toggleElem(container.querySelectorAll('.unescape-button'), !isEscaped);
toggleElem(container.querySelectorAll('.escape-button'), isEscaped);
}
});
}