mirror of
https://github.com/go-gitea/gitea.git
synced 2025-02-27 20:02:27 +08:00
Merge branch 'main' into main
This commit is contained in:
commit
abc5d12590
@ -324,6 +324,10 @@ RUN_USER = ; git
|
|||||||
;; Maximum number of locks returned per page
|
;; Maximum number of locks returned per page
|
||||||
;LFS_LOCKS_PAGING_NUM = 50
|
;LFS_LOCKS_PAGING_NUM = 50
|
||||||
;;
|
;;
|
||||||
|
;; When clients make lfs batch requests, reject them if there are more pointers than this number
|
||||||
|
;; zero means 'unlimited'
|
||||||
|
;LFS_MAX_BATCH_SIZE = 0
|
||||||
|
;;
|
||||||
;; Allow graceful restarts using SIGHUP to fork
|
;; Allow graceful restarts using SIGHUP to fork
|
||||||
;ALLOW_GRACEFUL_RESTARTS = true
|
;ALLOW_GRACEFUL_RESTARTS = true
|
||||||
;;
|
;;
|
||||||
@ -2638,6 +2642,10 @@ LEVEL = Info
|
|||||||
;; override the azure blob base path if storage type is azureblob
|
;; override the azure blob base path if storage type is azureblob
|
||||||
;AZURE_BLOB_BASE_PATH = lfs/
|
;AZURE_BLOB_BASE_PATH = lfs/
|
||||||
|
|
||||||
|
;[lfs_client]
|
||||||
|
;; When mirroring an upstream lfs endpoint, limit the number of pointers in each batch request to this number
|
||||||
|
;BATCH_SIZE = 20
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; settings for packages, will override storage setting
|
;; settings for packages, will override storage setting
|
||||||
|
@ -16,10 +16,9 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/proxy"
|
"code.gitea.io/gitea/modules/proxy"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
const httpBatchSize = 20
|
|
||||||
|
|
||||||
// HTTPClient is used to communicate with the LFS server
|
// HTTPClient is used to communicate with the LFS server
|
||||||
// https://github.com/git-lfs/git-lfs/blob/main/docs/api/batch.md
|
// https://github.com/git-lfs/git-lfs/blob/main/docs/api/batch.md
|
||||||
type HTTPClient struct {
|
type HTTPClient struct {
|
||||||
@ -30,7 +29,7 @@ type HTTPClient struct {
|
|||||||
|
|
||||||
// BatchSize returns the preferred size of batchs to process
|
// BatchSize returns the preferred size of batchs to process
|
||||||
func (c *HTTPClient) BatchSize() int {
|
func (c *HTTPClient) BatchSize() int {
|
||||||
return httpBatchSize
|
return setting.LFSClient.BatchSize
|
||||||
}
|
}
|
||||||
|
|
||||||
func newHTTPClient(endpoint *url.URL, httpTransport *http.Transport) *HTTPClient {
|
func newHTTPClient(endpoint *url.URL, httpTransport *http.Transport) *HTTPClient {
|
||||||
|
@ -10,7 +10,10 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/generate"
|
"code.gitea.io/gitea/modules/generate"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LFS represents the configuration for Git LFS
|
// LFS represents the server-side configuration for Git LFS.
|
||||||
|
// Ideally these options should be in a section like "[lfs_server]",
|
||||||
|
// but they are in "[server]" section due to historical reasons.
|
||||||
|
// Could be refactored in the future while keeping backwards compatibility.
|
||||||
var LFS = struct {
|
var LFS = struct {
|
||||||
StartServer bool `ini:"LFS_START_SERVER"`
|
StartServer bool `ini:"LFS_START_SERVER"`
|
||||||
AllowPureSSH bool `ini:"LFS_ALLOW_PURE_SSH"`
|
AllowPureSSH bool `ini:"LFS_ALLOW_PURE_SSH"`
|
||||||
@ -18,15 +21,21 @@ var LFS = struct {
|
|||||||
HTTPAuthExpiry time.Duration `ini:"LFS_HTTP_AUTH_EXPIRY"`
|
HTTPAuthExpiry time.Duration `ini:"LFS_HTTP_AUTH_EXPIRY"`
|
||||||
MaxFileSize int64 `ini:"LFS_MAX_FILE_SIZE"`
|
MaxFileSize int64 `ini:"LFS_MAX_FILE_SIZE"`
|
||||||
LocksPagingNum int `ini:"LFS_LOCKS_PAGING_NUM"`
|
LocksPagingNum int `ini:"LFS_LOCKS_PAGING_NUM"`
|
||||||
|
MaxBatchSize int `ini:"LFS_MAX_BATCH_SIZE"`
|
||||||
|
|
||||||
Storage *Storage
|
Storage *Storage
|
||||||
}{}
|
}{}
|
||||||
|
|
||||||
|
// LFSClient represents configuration for Gitea's LFS clients, for example: mirroring upstream Git LFS
|
||||||
|
var LFSClient = struct {
|
||||||
|
BatchSize int `ini:"BATCH_SIZE"`
|
||||||
|
}{}
|
||||||
|
|
||||||
func loadLFSFrom(rootCfg ConfigProvider) error {
|
func loadLFSFrom(rootCfg ConfigProvider) error {
|
||||||
|
mustMapSetting(rootCfg, "lfs_client", &LFSClient)
|
||||||
|
|
||||||
|
mustMapSetting(rootCfg, "server", &LFS)
|
||||||
sec := rootCfg.Section("server")
|
sec := rootCfg.Section("server")
|
||||||
if err := sec.MapTo(&LFS); err != nil {
|
|
||||||
return fmt.Errorf("failed to map LFS settings: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
lfsSec, _ := rootCfg.GetSection("lfs")
|
lfsSec, _ := rootCfg.GetSection("lfs")
|
||||||
|
|
||||||
@ -53,6 +62,10 @@ func loadLFSFrom(rootCfg ConfigProvider) error {
|
|||||||
LFS.LocksPagingNum = 50
|
LFS.LocksPagingNum = 50
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if LFSClient.BatchSize < 1 {
|
||||||
|
LFSClient.BatchSize = 20
|
||||||
|
}
|
||||||
|
|
||||||
LFS.HTTPAuthExpiry = sec.Key("LFS_HTTP_AUTH_EXPIRY").MustDuration(24 * time.Hour)
|
LFS.HTTPAuthExpiry = sec.Key("LFS_HTTP_AUTH_EXPIRY").MustDuration(24 * time.Hour)
|
||||||
|
|
||||||
if !LFS.StartServer || !InstallLock {
|
if !LFS.StartServer || !InstallLock {
|
||||||
|
@ -99,3 +99,19 @@ STORAGE_TYPE = minio
|
|||||||
assert.EqualValues(t, "gitea", LFS.Storage.MinioConfig.Bucket)
|
assert.EqualValues(t, "gitea", LFS.Storage.MinioConfig.Bucket)
|
||||||
assert.EqualValues(t, "lfs/", LFS.Storage.MinioConfig.BasePath)
|
assert.EqualValues(t, "lfs/", LFS.Storage.MinioConfig.BasePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_LFSClientServerConfigs(t *testing.T) {
|
||||||
|
iniStr := `
|
||||||
|
[server]
|
||||||
|
LFS_MAX_BATCH_SIZE = 100
|
||||||
|
[lfs_client]
|
||||||
|
# will default to 20
|
||||||
|
BATCH_SIZE = 0
|
||||||
|
`
|
||||||
|
cfg, err := NewConfigProviderFromData(iniStr)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.NoError(t, loadLFSFrom(cfg))
|
||||||
|
assert.EqualValues(t, 100, LFS.MaxBatchSize)
|
||||||
|
assert.EqualValues(t, 20, LFSClient.BatchSize)
|
||||||
|
}
|
||||||
|
16
package-lock.json
generated
16
package-lock.json
generated
@ -47,7 +47,6 @@
|
|||||||
"sortablejs": "1.15.2",
|
"sortablejs": "1.15.2",
|
||||||
"swagger-ui-dist": "5.17.14",
|
"swagger-ui-dist": "5.17.14",
|
||||||
"tailwindcss": "3.4.10",
|
"tailwindcss": "3.4.10",
|
||||||
"temporal-polyfill": "0.2.5",
|
|
||||||
"throttle-debounce": "5.0.2",
|
"throttle-debounce": "5.0.2",
|
||||||
"tinycolor2": "1.6.0",
|
"tinycolor2": "1.6.0",
|
||||||
"tippy.js": "6.3.7",
|
"tippy.js": "6.3.7",
|
||||||
@ -14748,21 +14747,6 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/temporal-polyfill": {
|
|
||||||
"version": "0.2.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/temporal-polyfill/-/temporal-polyfill-0.2.5.tgz",
|
|
||||||
"integrity": "sha512-ye47xp8Cb0nDguAhrrDS1JT1SzwEV9e26sSsrWzVu+yPZ7LzceEcH0i2gci9jWfOfSCCgM3Qv5nOYShVUUFUXA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"temporal-spec": "^0.2.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/temporal-spec": {
|
|
||||||
"version": "0.2.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/temporal-spec/-/temporal-spec-0.2.4.tgz",
|
|
||||||
"integrity": "sha512-lDMFv4nKQrSjlkHKAlHVqKrBG4DyFfa9F74cmBZ3Iy3ed8yvWnlWSIdi4IKfSqwmazAohBNwiN64qGx4y5Q3IQ==",
|
|
||||||
"license": "ISC"
|
|
||||||
},
|
|
||||||
"node_modules/terser": {
|
"node_modules/terser": {
|
||||||
"version": "5.31.6",
|
"version": "5.31.6",
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.31.6.tgz",
|
"resolved": "https://registry.npmjs.org/terser/-/terser-5.31.6.tgz",
|
||||||
|
@ -46,7 +46,6 @@
|
|||||||
"sortablejs": "1.15.2",
|
"sortablejs": "1.15.2",
|
||||||
"swagger-ui-dist": "5.17.14",
|
"swagger-ui-dist": "5.17.14",
|
||||||
"tailwindcss": "3.4.10",
|
"tailwindcss": "3.4.10",
|
||||||
"temporal-polyfill": "0.2.5",
|
|
||||||
"throttle-debounce": "5.0.2",
|
"throttle-debounce": "5.0.2",
|
||||||
"tinycolor2": "1.6.0",
|
"tinycolor2": "1.6.0",
|
||||||
"tippy.js": "6.3.7",
|
"tippy.js": "6.3.7",
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/container"
|
"code.gitea.io/gitea/modules/container"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/structs"
|
"code.gitea.io/gitea/modules/structs"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/services/context"
|
"code.gitea.io/gitea/services/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -39,7 +40,7 @@ func Organizations(ctx *context.Context) {
|
|||||||
)
|
)
|
||||||
sortOrder := ctx.FormString("sort")
|
sortOrder := ctx.FormString("sort")
|
||||||
if sortOrder == "" {
|
if sortOrder == "" {
|
||||||
sortOrder = "newest"
|
sortOrder = util.Iif(supportedSortOrders.Contains(setting.UI.ExploreDefaultSort), setting.UI.ExploreDefaultSort, "newest")
|
||||||
ctx.SetFormString("sort", sortOrder)
|
ctx.SetFormString("sort", sortOrder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/sitemap"
|
"code.gitea.io/gitea/modules/sitemap"
|
||||||
"code.gitea.io/gitea/modules/structs"
|
"code.gitea.io/gitea/modules/structs"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/services/context"
|
"code.gitea.io/gitea/services/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -149,7 +150,7 @@ func Users(ctx *context.Context) {
|
|||||||
)
|
)
|
||||||
sortOrder := ctx.FormString("sort")
|
sortOrder := ctx.FormString("sort")
|
||||||
if sortOrder == "" {
|
if sortOrder == "" {
|
||||||
sortOrder = "newest"
|
sortOrder = util.Iif(supportedSortOrders.Contains(setting.UI.ExploreDefaultSort), setting.UI.ExploreDefaultSort, "newest")
|
||||||
ctx.SetFormString("sort", sortOrder)
|
ctx.SetFormString("sort", sortOrder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,6 +179,11 @@ func BatchHandler(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if setting.LFS.MaxBatchSize != 0 && len(br.Objects) > setting.LFS.MaxBatchSize {
|
||||||
|
writeStatus(ctx, http.StatusRequestEntityTooLarge)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
contentStore := lfs_module.NewContentStore()
|
contentStore := lfs_module.NewContentStore()
|
||||||
|
|
||||||
var responseObjects []*lfs_module.ObjectResponse
|
var responseObjects []*lfs_module.ObjectResponse
|
||||||
|
@ -102,7 +102,7 @@
|
|||||||
{{$sameBase := ne $.BaseName $.HeadUserName}}
|
{{$sameBase := ne $.BaseName $.HeadUserName}}
|
||||||
{{$differentBranch := ne . $.HeadBranch}}
|
{{$differentBranch := ne . $.HeadBranch}}
|
||||||
{{if or $sameBase $differentBranch}}
|
{{if or $sameBase $differentBranch}}
|
||||||
<div class="item {{if eq $.BaseBranch .}}selected{{end}}" data-branch="{{.}}">{{$.BaseName}}{{if $.HeadRepo}}/{{$.HeadRepo}}{{end}}:{{.}}</div>
|
<div class="item {{if eq $.BaseBranch .}}selected{{end}}" data-branch="{{.}}">{{$.BaseName}}:{{.}}</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
@ -17,7 +17,7 @@ const colors = ref({
|
|||||||
const activityTopAuthors = window.config.pageData.repoActivityTopAuthors || [];
|
const activityTopAuthors = window.config.pageData.repoActivityTopAuthors || [];
|
||||||
|
|
||||||
const graphPoints = computed(() => {
|
const graphPoints = computed(() => {
|
||||||
return activityTopAuthors.value.map((item) => {
|
return activityTopAuthors.map((item) => {
|
||||||
return {
|
return {
|
||||||
value: item.commits,
|
value: item.commits,
|
||||||
label: item.name,
|
label: item.name,
|
||||||
@ -26,7 +26,7 @@ const graphPoints = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const graphAuthors = computed(() => {
|
const graphAuthors = computed(() => {
|
||||||
return activityTopAuthors.value.map((item, idx) => {
|
return activityTopAuthors.map((item, idx) => {
|
||||||
return {
|
return {
|
||||||
position: idx + 1,
|
position: idx + 1,
|
||||||
...item,
|
...item,
|
||||||
@ -35,7 +35,7 @@ const graphAuthors = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const graphWidth = computed(() => {
|
const graphWidth = computed(() => {
|
||||||
return activityTopAuthors.value.length * 40;
|
return activityTopAuthors.length * 40;
|
||||||
});
|
});
|
||||||
|
|
||||||
const styleElement = ref<HTMLElement | null>(null);
|
const styleElement = ref<HTMLElement | null>(null);
|
||||||
|
@ -7,9 +7,15 @@ test('toAbsoluteLocaleDate', () => {
|
|||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
})).toEqual('March 15, 2024');
|
})).toEqual('March 15, 2024');
|
||||||
|
|
||||||
expect(toAbsoluteLocaleDate('2024-03-15', 'de-DE', {
|
expect(toAbsoluteLocaleDate('2024-03-15T01:02:03', 'de-DE', {
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
month: 'long',
|
month: 'long',
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
})).toEqual('15. März 2024');
|
})).toEqual('15. März 2024');
|
||||||
|
|
||||||
|
expect(toAbsoluteLocaleDate('12345-03-15 01:02:03', '', {
|
||||||
|
year: 'numeric',
|
||||||
|
month: 'short',
|
||||||
|
day: 'numeric',
|
||||||
|
})).toEqual('Mar 15, 12345');
|
||||||
});
|
});
|
||||||
|
@ -1,30 +1,28 @@
|
|||||||
import {Temporal} from 'temporal-polyfill';
|
export function toAbsoluteLocaleDate(date: string, lang: string, opts: Intl.DateTimeFormatOptions) {
|
||||||
|
return new Date(date).toLocaleString(lang || [], opts);
|
||||||
export function toAbsoluteLocaleDate(dateStr, lang, opts) {
|
|
||||||
return Temporal.PlainDate.from(dateStr).toLocaleString(lang ?? [], opts);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
window.customElements.define('absolute-date', class extends HTMLElement {
|
window.customElements.define('absolute-date', class extends HTMLElement {
|
||||||
static observedAttributes = ['date', 'year', 'month', 'weekday', 'day'];
|
static observedAttributes = ['date', 'year', 'month', 'weekday', 'day'];
|
||||||
|
|
||||||
|
initialized = false;
|
||||||
|
|
||||||
update = () => {
|
update = () => {
|
||||||
const year = this.getAttribute('year') ?? '';
|
const opt: Intl.DateTimeFormatOptions = {};
|
||||||
const month = this.getAttribute('month') ?? '';
|
for (const attr of ['year', 'month', 'weekday', 'day']) {
|
||||||
const weekday = this.getAttribute('weekday') ?? '';
|
if (this.getAttribute(attr)) opt[attr] = this.getAttribute(attr);
|
||||||
const day = this.getAttribute('day') ?? '';
|
}
|
||||||
const lang = this.closest('[lang]')?.getAttribute('lang') ||
|
const lang = this.closest('[lang]')?.getAttribute('lang') ||
|
||||||
this.ownerDocument.documentElement.getAttribute('lang') || '';
|
this.ownerDocument.documentElement.getAttribute('lang') || '';
|
||||||
|
|
||||||
// only use the first 10 characters, e.g. the `yyyy-mm-dd` part
|
// only use the date part, it is guaranteed to be in ISO format (YYYY-MM-DDTHH:mm:ss.sssZ)
|
||||||
const dateStr = this.getAttribute('date').substring(0, 10);
|
let date = this.getAttribute('date');
|
||||||
|
let dateSep = date.indexOf('T');
|
||||||
|
dateSep = dateSep === -1 ? date.indexOf(' ') : dateSep;
|
||||||
|
date = dateSep === -1 ? date : date.substring(0, dateSep);
|
||||||
|
|
||||||
if (!this.shadowRoot) this.attachShadow({mode: 'open'});
|
if (!this.shadowRoot) this.attachShadow({mode: 'open'});
|
||||||
this.shadowRoot.textContent = toAbsoluteLocaleDate(dateStr, lang, {
|
this.shadowRoot.textContent = toAbsoluteLocaleDate(date, lang, opt);
|
||||||
...(year && {year}),
|
|
||||||
...(month && {month}),
|
|
||||||
...(weekday && {weekday}),
|
|
||||||
...(day && {day}),
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
attributeChangedCallback(_name, oldValue, newValue) {
|
attributeChangedCallback(_name, oldValue, newValue) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user