Merge pull request '[gitea] week 2024-24 cherry pick (gitea/main -> forgejo)' (#4083) from earl-warren/wcp/2024-24 into forgejo
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/4083 Reviewed-by: twenty-panda <twenty-panda@noreply.codeberg.org>
This commit is contained in:
commit
df373c9f7e
53 changed files with 532 additions and 226 deletions
|
@ -10,7 +10,8 @@
|
|||
"ghcr.io/devcontainers-contrib/features/poetry:2": {},
|
||||
"ghcr.io/devcontainers/features/python:1": {
|
||||
"version": "3.12"
|
||||
}
|
||||
},
|
||||
"ghcr.io/warrenbuckley/codespace-features/sqlite:1": {}
|
||||
},
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
|
@ -25,8 +26,9 @@
|
|||
"Vue.volar",
|
||||
"ms-azuretools.vscode-docker",
|
||||
"vitest.explorer",
|
||||
"qwtel.sqlite-viewer",
|
||||
"GitHub.vscode-pull-request-github"
|
||||
"cweijan.vscode-database-client2",
|
||||
"GitHub.vscode-pull-request-github",
|
||||
"Azurite.azurite"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
|
|
@ -43,7 +43,7 @@ vscode:
|
|||
- Vue.volar
|
||||
- ms-azuretools.vscode-docker
|
||||
- vitest.explorer
|
||||
- qwtel.sqlite-viewer
|
||||
- cweijan.vscode-database-client2
|
||||
- GitHub.vscode-pull-request-github
|
||||
|
||||
ports:
|
||||
|
|
10
Makefile
10
Makefile
|
@ -38,6 +38,7 @@ GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1.6.0 # renovate: datasour
|
|||
GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1 # renovate: datasource=go
|
||||
DEADCODE_PACKAGE ?= golang.org/x/tools/cmd/deadcode@v0.22.0 # renovate: datasource=go
|
||||
GOMOCK_PACKAGE ?= go.uber.org/mock/mockgen@v0.4.0 # renovate: datasource=go
|
||||
GOPLS_PACKAGE ?= golang.org/x/tools/gopls@v0.15.3 # renovate: datasource=go
|
||||
|
||||
DOCKER_IMAGE ?= gitea/gitea
|
||||
DOCKER_TAG ?= latest
|
||||
|
@ -228,6 +229,7 @@ help:
|
|||
@echo " - lint-go lint go files"
|
||||
@echo " - lint-go-fix lint go files and fix issues"
|
||||
@echo " - lint-go-vet lint go files with vet"
|
||||
@echo " - lint-go-gopls lint go files with gopls"
|
||||
@echo " - lint-js lint js files"
|
||||
@echo " - lint-js-fix lint js files and fix issues"
|
||||
@echo " - lint-css lint css files"
|
||||
|
@ -468,6 +470,11 @@ lint-go-vet:
|
|||
@echo "Running go vet..."
|
||||
@$(GO) vet ./...
|
||||
|
||||
.PHONY: lint-go-gopls
|
||||
lint-go-gopls:
|
||||
@echo "Running gopls check..."
|
||||
@GO=$(GO) GOPLS_PACKAGE=$(GOPLS_PACKAGE) tools/lint-go-gopls.sh $(GO_SOURCES_NO_BINDATA)
|
||||
|
||||
.PHONY: lint-editorconfig
|
||||
lint-editorconfig:
|
||||
$(GO) run $(EDITORCONFIG_CHECKER_PACKAGE) templates .forgejo/workflows
|
||||
|
@ -879,13 +886,14 @@ deps-tools:
|
|||
$(GO) install $(GO_LICENSES_PACKAGE)
|
||||
$(GO) install $(GOVULNCHECK_PACKAGE)
|
||||
$(GO) install $(GOMOCK_PACKAGE)
|
||||
$(GO) install $(GOPLS_PACKAGE)
|
||||
|
||||
node_modules: package-lock.json
|
||||
npm install --no-save
|
||||
@touch node_modules
|
||||
|
||||
.venv: poetry.lock
|
||||
poetry install --no-root
|
||||
poetry install
|
||||
@touch .venv
|
||||
|
||||
.PHONY: fomantic
|
||||
|
|
|
@ -1387,6 +1387,9 @@ LEVEL = Info
|
|||
;;
|
||||
;; Maximum allowed file size in bytes to render CSV files as table. (Set to 0 for no limit).
|
||||
;MAX_FILE_SIZE = 524288
|
||||
;;
|
||||
;; Maximum allowed rows to render CSV files. (Set to 0 for no limit)
|
||||
;MAX_ROWS = 2500
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -1746,6 +1749,16 @@ LEVEL = Info
|
|||
;; convert \r\n to \n for Sendmail
|
||||
;SENDMAIL_CONVERT_CRLF = true
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;[mailer.override_header]
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; This is empty by default, use it only if you know what you need it for.
|
||||
;Reply-To = test@example.com, test2@example.com
|
||||
;Content-Type = text/html; charset=utf-8
|
||||
;In-Reply-To =
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;[email.incoming]
|
||||
|
|
|
@ -5,8 +5,6 @@ package markup
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html"
|
||||
"io"
|
||||
"regexp"
|
||||
|
@ -15,6 +13,8 @@ import (
|
|||
"code.gitea.io/gitea/modules/csv"
|
||||
"code.gitea.io/gitea/modules/markup"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -81,86 +81,38 @@ func writeField(w io.Writer, element, class, field string) error {
|
|||
func (r Renderer) Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error {
|
||||
tmpBlock := bufio.NewWriter(output)
|
||||
maxSize := setting.UI.CSV.MaxFileSize
|
||||
maxRows := setting.UI.CSV.MaxRows
|
||||
|
||||
if maxSize == 0 {
|
||||
return r.tableRender(ctx, input, tmpBlock)
|
||||
if maxSize != 0 {
|
||||
input = io.LimitReader(input, maxSize+1)
|
||||
}
|
||||
|
||||
rawBytes, err := io.ReadAll(io.LimitReader(input, maxSize+1))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if int64(len(rawBytes)) <= maxSize {
|
||||
return r.tableRender(ctx, bytes.NewReader(rawBytes), tmpBlock)
|
||||
}
|
||||
return r.fallbackRender(io.MultiReader(bytes.NewReader(rawBytes), input), tmpBlock)
|
||||
}
|
||||
|
||||
func (Renderer) fallbackRender(input io.Reader, tmpBlock *bufio.Writer) error {
|
||||
_, err := tmpBlock.WriteString("<pre>")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
scan := bufio.NewScanner(input)
|
||||
scan.Split(bufio.ScanRunes)
|
||||
for scan.Scan() {
|
||||
switch scan.Text() {
|
||||
case `&`:
|
||||
_, err = tmpBlock.WriteString("&")
|
||||
case `'`:
|
||||
_, err = tmpBlock.WriteString("'") // "'" is shorter than "'" and apos was not in HTML until HTML5.
|
||||
case `<`:
|
||||
_, err = tmpBlock.WriteString("<")
|
||||
case `>`:
|
||||
_, err = tmpBlock.WriteString(">")
|
||||
case `"`:
|
||||
_, err = tmpBlock.WriteString(""") // """ is shorter than """.
|
||||
default:
|
||||
_, err = tmpBlock.Write(scan.Bytes())
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err = scan.Err(); err != nil {
|
||||
return fmt.Errorf("fallbackRender scan: %w", err)
|
||||
}
|
||||
|
||||
_, err = tmpBlock.WriteString("</pre>")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return tmpBlock.Flush()
|
||||
}
|
||||
|
||||
func (Renderer) tableRender(ctx *markup.RenderContext, input io.Reader, tmpBlock *bufio.Writer) error {
|
||||
rd, err := csv.CreateReaderAndDetermineDelimiter(ctx, input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := tmpBlock.WriteString(`<table class="data-table">`); err != nil {
|
||||
return err
|
||||
}
|
||||
row := 1
|
||||
|
||||
row := 0
|
||||
for {
|
||||
fields, err := rd.Read()
|
||||
if err == io.EOF {
|
||||
if err == io.EOF || (row >= maxRows && maxRows != 0) {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, err := tmpBlock.WriteString("<tr>"); err != nil {
|
||||
return err
|
||||
}
|
||||
element := "td"
|
||||
if row == 1 {
|
||||
if row == 0 {
|
||||
element = "th"
|
||||
}
|
||||
if err := writeField(tmpBlock, element, "line-num", strconv.Itoa(row)); err != nil {
|
||||
if err := writeField(tmpBlock, element, "line-num", strconv.Itoa(row+1)); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, field := range fields {
|
||||
|
@ -174,8 +126,32 @@ func (Renderer) tableRender(ctx *markup.RenderContext, input io.Reader, tmpBlock
|
|||
|
||||
row++
|
||||
}
|
||||
|
||||
if _, err = tmpBlock.WriteString("</table>"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check if maxRows or maxSize is reached, and if true, warn.
|
||||
if (row >= maxRows && maxRows != 0) || (rd.InputOffset() >= maxSize && maxSize != 0) {
|
||||
warn := `<table class="data-table"><tr><td>`
|
||||
rawLink := ` <a href="` + ctx.Links.RawLink() + `/` + util.PathEscapeSegments(ctx.RelativePath) + `">`
|
||||
|
||||
// Try to get the user translation
|
||||
if locale, ok := ctx.Ctx.Value(translation.ContextKey).(translation.Locale); ok {
|
||||
warn += locale.TrString("repo.file_too_large")
|
||||
rawLink += locale.TrString("repo.file_view_raw")
|
||||
} else {
|
||||
warn += "The file is too large to be shown."
|
||||
rawLink += "View Raw"
|
||||
}
|
||||
|
||||
warn += rawLink + `</a></td></tr></table>`
|
||||
|
||||
// Write the HTML string to the output
|
||||
if _, err := tmpBlock.WriteString(warn); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return tmpBlock.Flush()
|
||||
}
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
package markup
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
|
@ -31,12 +29,4 @@ func TestRenderCSV(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, v, buf.String())
|
||||
}
|
||||
|
||||
t.Run("fallbackRender", func(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
err := render.fallbackRender(strings.NewReader("1,<a>\n2,<b>"), bufio.NewWriter(&buf))
|
||||
assert.NoError(t, err)
|
||||
want := "<pre>1,<a>\n2,<b></pre>"
|
||||
assert.Equal(t, want, buf.String())
|
||||
})
|
||||
}
|
||||
|
|
|
@ -18,14 +18,15 @@ import (
|
|||
// Mailer represents mail service.
|
||||
type Mailer struct {
|
||||
// Mailer
|
||||
Name string `ini:"NAME"`
|
||||
From string `ini:"FROM"`
|
||||
EnvelopeFrom string `ini:"ENVELOPE_FROM"`
|
||||
OverrideEnvelopeFrom bool `ini:"-"`
|
||||
FromName string `ini:"-"`
|
||||
FromEmail string `ini:"-"`
|
||||
SendAsPlainText bool `ini:"SEND_AS_PLAIN_TEXT"`
|
||||
SubjectPrefix string `ini:"SUBJECT_PREFIX"`
|
||||
Name string `ini:"NAME"`
|
||||
From string `ini:"FROM"`
|
||||
EnvelopeFrom string `ini:"ENVELOPE_FROM"`
|
||||
OverrideEnvelopeFrom bool `ini:"-"`
|
||||
FromName string `ini:"-"`
|
||||
FromEmail string `ini:"-"`
|
||||
SendAsPlainText bool `ini:"SEND_AS_PLAIN_TEXT"`
|
||||
SubjectPrefix string `ini:"SUBJECT_PREFIX"`
|
||||
OverrideHeader map[string][]string `ini:"-"`
|
||||
|
||||
// SMTP sender
|
||||
Protocol string `ini:"PROTOCOL"`
|
||||
|
@ -159,6 +160,12 @@ func loadMailerFrom(rootCfg ConfigProvider) {
|
|||
log.Fatal("Unable to map [mailer] section on to MailService. Error: %v", err)
|
||||
}
|
||||
|
||||
overrideHeader := rootCfg.Section("mailer.override_header").Keys()
|
||||
MailService.OverrideHeader = make(map[string][]string)
|
||||
for _, key := range overrideHeader {
|
||||
MailService.OverrideHeader[key.Name()] = key.Strings(",")
|
||||
}
|
||||
|
||||
// Infer SMTPPort if not set
|
||||
if MailService.SMTPPort == "" {
|
||||
switch MailService.Protocol {
|
||||
|
|
|
@ -53,6 +53,7 @@ var UI = struct {
|
|||
|
||||
CSV struct {
|
||||
MaxFileSize int64
|
||||
MaxRows int
|
||||
} `ini:"ui.csv"`
|
||||
|
||||
Admin struct {
|
||||
|
@ -110,8 +111,10 @@ var UI = struct {
|
|||
},
|
||||
CSV: struct {
|
||||
MaxFileSize int64
|
||||
MaxRows int
|
||||
}{
|
||||
MaxFileSize: 524288,
|
||||
MaxRows: 2500,
|
||||
},
|
||||
Admin: struct {
|
||||
UserPagingNum int
|
||||
|
|
|
@ -6,8 +6,11 @@ package structs
|
|||
import "time"
|
||||
|
||||
type Activity struct {
|
||||
ID int64 `json:"id"`
|
||||
UserID int64 `json:"user_id"` // Receiver user
|
||||
ID int64 `json:"id"`
|
||||
UserID int64 `json:"user_id"` // Receiver user
|
||||
// the type of action
|
||||
//
|
||||
// enum: create_repo,rename_repo,star_repo,watch_repo,commit_repo,create_issue,create_pull_request,transfer_repo,push_tag,comment_issue,merge_pull_request,close_issue,reopen_issue,close_pull_request,reopen_pull_request,delete_tag,delete_branch,mirror_sync_push,mirror_sync_create,mirror_sync_delete,approve_pull_request,reject_pull_request,comment_pull,publish_release,pull_review_dismissed,pull_request_ready_for_review,auto_merge_pull_request
|
||||
OpType string `json:"op_type"`
|
||||
ActUserID int64 `json:"act_user_id"`
|
||||
ActUser *User `json:"act_user"`
|
||||
|
|
44
options/gitignore/Alteryx
Normal file
44
options/gitignore/Alteryx
Normal file
|
@ -0,0 +1,44 @@
|
|||
# gitignore template for Alteryx Designer
|
||||
# website: https://www.alteryx.com/
|
||||
# website: https://help.alteryx.com/current/designer/alteryx-file-types
|
||||
|
||||
# Alteryx Data Files
|
||||
*.yxdb
|
||||
*.cydb
|
||||
*.cyidx
|
||||
*.rptx
|
||||
*.vvf
|
||||
*.aws
|
||||
|
||||
# Alteryx Special Files
|
||||
*.yxwv
|
||||
*.yxft
|
||||
*.yxbe
|
||||
*.bak
|
||||
*.pcxml
|
||||
*.log
|
||||
*.bin
|
||||
*.yxlang
|
||||
CASS.ini
|
||||
|
||||
# Alteryx License Files
|
||||
*.yxlc
|
||||
*.slc
|
||||
*.cylc
|
||||
*.alc
|
||||
*.gzlc
|
||||
|
||||
## gitignore reference sites
|
||||
# https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository#Ignoring-Files
|
||||
# https://git-scm.com/docs/gitignore
|
||||
# https://help.github.com/articles/ignoring-files/
|
||||
|
||||
## Useful knowledge from stackoverflow
|
||||
# Even if you haven't tracked the files so far, git seems to be able to "know" about them even after you add them to .gitignore.
|
||||
# WARNING: First commit your current changes, or you will lose them.
|
||||
# Then run the following commands from the top folder of your git repo:
|
||||
# git rm -r --cached .
|
||||
# git add .
|
||||
# git commit -m "fixed untracked files"
|
||||
|
||||
# author: Kacper Ksieski
|
|
@ -14,6 +14,8 @@
|
|||
*.lzma
|
||||
*.cab
|
||||
*.xar
|
||||
*.zst
|
||||
*.tzst
|
||||
|
||||
# Packing-only formats
|
||||
*.iso
|
||||
|
|
11
options/gitignore/Ballerina
Normal file
11
options/gitignore/Ballerina
Normal file
|
@ -0,0 +1,11 @@
|
|||
# generated files
|
||||
target/
|
||||
generated/
|
||||
|
||||
# dependencies
|
||||
Dependencies.toml
|
||||
|
||||
# config files
|
||||
Config.toml
|
||||
# the config files used for testing, Uncomment the following line if you want to commit the test config files
|
||||
#!**/tests/Config.toml
|
|
@ -9,3 +9,4 @@ install_manifest.txt
|
|||
compile_commands.json
|
||||
CTestTestfile.cmake
|
||||
_deps
|
||||
CMakeUserPresets.json
|
||||
|
|
|
@ -26,6 +26,18 @@
|
|||
#*.obj
|
||||
#
|
||||
|
||||
# Default Delphi compiler directories
|
||||
# Content of this directories are generated with each Compile/Construct of a project.
|
||||
# Most of the time, files here have not there place in a code repository.
|
||||
#Win32/
|
||||
#Win64/
|
||||
#OSX64/
|
||||
#OSXARM64/
|
||||
#Android/
|
||||
#Android64/
|
||||
#iOSDevice64/
|
||||
#Linux64/
|
||||
|
||||
# Delphi compiler-generated binaries (safe to delete)
|
||||
*.exe
|
||||
*.dll
|
||||
|
|
18
options/gitignore/GitHubPages
Normal file
18
options/gitignore/GitHubPages
Normal file
|
@ -0,0 +1,18 @@
|
|||
# This .gitignore is appropriate for repositories deployed to GitHub Pages and using
|
||||
# a Gemfile as specified at https://github.com/github/pages-gem#conventional
|
||||
|
||||
# Basic Jekyll gitignores (synchronize to Jekyll.gitignore)
|
||||
_site/
|
||||
.sass-cache/
|
||||
.jekyll-cache/
|
||||
.jekyll-metadata
|
||||
|
||||
# Additional Ruby/bundler ignore for when you run: bundle install
|
||||
/vendor
|
||||
|
||||
# Specific ignore for GitHub Pages
|
||||
# GitHub Pages will always use its own deployed version of pages-gem
|
||||
# This means GitHub Pages will NOT use your Gemfile.lock and therefore it is
|
||||
# counterproductive to check this file into the repository.
|
||||
# Details at https://github.com/github/pages-gem/issues/768
|
||||
Gemfile.lock
|
|
@ -20,3 +20,6 @@
|
|||
# Go workspace file
|
||||
go.work
|
||||
go.work.sum
|
||||
|
||||
# env file
|
||||
.env
|
||||
|
|
|
@ -5,23 +5,6 @@
|
|||
## User settings
|
||||
xcuserdata/
|
||||
|
||||
## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
|
||||
*.xcscmblueprint
|
||||
*.xccheckout
|
||||
|
||||
## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
|
||||
build/
|
||||
DerivedData/
|
||||
*.moved-aside
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
*.mode1v3
|
||||
!default.mode1v3
|
||||
*.mode2v3
|
||||
!default.mode2v3
|
||||
*.perspectivev3
|
||||
!default.perspectivev3
|
||||
|
||||
## Obj-C/Swift specific
|
||||
*.hmap
|
||||
|
||||
|
|
|
@ -12,3 +12,10 @@ Cargo.lock
|
|||
|
||||
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||
*.pdb
|
||||
|
||||
# RustRover
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
|
@ -5,23 +5,6 @@
|
|||
## User settings
|
||||
xcuserdata/
|
||||
|
||||
## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
|
||||
*.xcscmblueprint
|
||||
*.xccheckout
|
||||
|
||||
## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
|
||||
build/
|
||||
DerivedData/
|
||||
*.moved-aside
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
*.mode1v3
|
||||
!default.mode1v3
|
||||
*.mode2v3
|
||||
!default.mode2v3
|
||||
*.perspectivev3
|
||||
!default.perspectivev3
|
||||
|
||||
## Obj-C/Swift specific
|
||||
*.hmap
|
||||
|
||||
|
@ -66,10 +49,6 @@ playground.xcworkspace
|
|||
|
||||
Carthage/Build/
|
||||
|
||||
# Accio dependency management
|
||||
Dependencies/
|
||||
.accio/
|
||||
|
||||
# fastlane
|
||||
#
|
||||
# It is recommended to not store the screenshots in the git repo.
|
||||
|
@ -81,10 +60,3 @@ fastlane/report.xml
|
|||
fastlane/Preview.html
|
||||
fastlane/screenshots/**/*.png
|
||||
fastlane/test_output
|
||||
|
||||
# Code Injection
|
||||
#
|
||||
# After new code Injection tools there's a generated folder /iOSInjectionProject
|
||||
# https://github.com/johnno1962/injectionforxcode
|
||||
|
||||
iOSInjectionProject/
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
*.synctex.gz
|
||||
*.synctex.gz(busy)
|
||||
*.pdfsync
|
||||
*.rubbercache
|
||||
rubber.cache
|
||||
|
||||
## Build tool directories for auxiliary files
|
||||
# latexrun
|
||||
|
@ -138,6 +140,9 @@ acs-*.bib
|
|||
*.trc
|
||||
*.xref
|
||||
|
||||
# hypdoc
|
||||
*.hd
|
||||
|
||||
# hyperref
|
||||
*.brf
|
||||
|
||||
|
|
|
@ -23,6 +23,9 @@ override.tf.json
|
|||
*_override.tf
|
||||
*_override.tf.json
|
||||
|
||||
# Ignore transient lock info files created by terraform apply
|
||||
.terraform.tfstate.lock.info
|
||||
|
||||
# Include override files you do wish to add to version control using negated pattern
|
||||
# !example_override.tf
|
||||
|
||||
|
@ -32,3 +35,6 @@ override.tf.json
|
|||
# Ignore CLI configuration files
|
||||
.terraformrc
|
||||
terraform.rc
|
||||
|
||||
# Ignore hcl file
|
||||
.terraform.lock.hcl
|
||||
|
|
11
options/gitignore/UiPath
Normal file
11
options/gitignore/UiPath
Normal file
|
@ -0,0 +1,11 @@
|
|||
# gitignore template for RPA development using UiPath Studio
|
||||
# website: https://www.uipath.com/product/studio
|
||||
#
|
||||
# Recommended: n/a
|
||||
|
||||
# Ignore folders that could cause issues if accidentally tracked
|
||||
**/.local/**
|
||||
**/.settings/**
|
||||
**/.objects/**
|
||||
**/.tmh/**
|
||||
**/*.log
|
|
@ -47,7 +47,7 @@ SourceArt/**/*.tga
|
|||
|
||||
# Binary Files
|
||||
Binaries/*
|
||||
Plugins/*/Binaries/*
|
||||
Plugins/**/Binaries/*
|
||||
|
||||
# Builds
|
||||
Build/*
|
||||
|
@ -68,7 +68,7 @@ Saved/*
|
|||
|
||||
# Compiled source files for the engine to use
|
||||
Intermediate/*
|
||||
Plugins/*/Intermediate/*
|
||||
Plugins/**/Intermediate/*
|
||||
|
||||
# Cache files for the editor to use
|
||||
DerivedDataCache/*
|
||||
|
|
|
@ -1,6 +1,2 @@
|
|||
## User settings
|
||||
xcuserdata/
|
||||
|
||||
## Xcode 8 and earlier
|
||||
*.xcscmblueprint
|
||||
*.xccheckout
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
[tool.poetry]
|
||||
name = "forgejo"
|
||||
version = "0.0.0"
|
||||
description = ""
|
||||
authors = []
|
||||
package-mode = false
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.10"
|
||||
|
|
3
release-notes/8.0.0/feat/4083.md
Normal file
3
release-notes/8.0.0/feat/4083.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
- add [Reviewed-on and Reviewed-by variables](https://codeberg.org/forgejo/forgejo/commit/4ddd9af50fbfcfb2ebf629697a803b3bce56c4af) to the merge template
|
||||
- [add the `[ui.csv].MAX_ROWS` setting](https://codeberg.org/forgejo/forgejo/commit/433b6c6910f8699dc41787ef8f5148b122b4677e) to avoid displaying a large number of lines (defaults to 2500)
|
||||
- [add a setting to override or add headers of all outgoing emails](https://codeberg.org/forgejo/forgejo/commit/1d4bff4f65d5e4a3969871ef91d3612daf272b45), for instance `Reply-To` or `In-Reply-To`
|
1
release-notes/8.0.0/fix/4083.md
Normal file
1
release-notes/8.0.0/fix/4083.md
Normal file
|
@ -0,0 +1 @@
|
|||
- [NuGet Package fails `choco info pkgname` when `pkgname` is also a substring of another package Id](https://codeberg.org/forgejo/forgejo/commit/c6e04c3c9eddfa6c4bec541f681c8d300b157cdb)
|
|
@ -96,20 +96,34 @@ func FeedCapabilityResource(ctx *context.Context) {
|
|||
xmlResponse(ctx, http.StatusOK, Metadata)
|
||||
}
|
||||
|
||||
var searchTermExtract = regexp.MustCompile(`'([^']+)'`)
|
||||
var (
|
||||
searchTermExtract = regexp.MustCompile(`'([^']+)'`)
|
||||
searchTermExact = regexp.MustCompile(`\s+eq\s+'`)
|
||||
)
|
||||
|
||||
func getSearchTerm(ctx *context.Context) string {
|
||||
func getSearchTerm(ctx *context.Context) packages_model.SearchValue {
|
||||
searchTerm := strings.Trim(ctx.FormTrim("searchTerm"), "'")
|
||||
if searchTerm == "" {
|
||||
// $filter contains a query like:
|
||||
// (((Id ne null) and substringof('microsoft',tolower(Id)))
|
||||
// We don't support these queries, just extract the search term.
|
||||
match := searchTermExtract.FindStringSubmatch(ctx.FormTrim("$filter"))
|
||||
if len(match) == 2 {
|
||||
searchTerm = strings.TrimSpace(match[1])
|
||||
if searchTerm != "" {
|
||||
return packages_model.SearchValue{
|
||||
Value: searchTerm,
|
||||
ExactMatch: false,
|
||||
}
|
||||
}
|
||||
return searchTerm
|
||||
|
||||
// $filter contains a query like:
|
||||
// (((Id ne null) and substringof('microsoft',tolower(Id)))
|
||||
// https://www.odata.org/documentation/odata-version-2-0/uri-conventions/ section 4.5
|
||||
// We don't support these queries, just extract the search term.
|
||||
filter := ctx.FormTrim("$filter")
|
||||
match := searchTermExtract.FindStringSubmatch(filter)
|
||||
if len(match) == 2 {
|
||||
return packages_model.SearchValue{
|
||||
Value: strings.TrimSpace(match[1]),
|
||||
ExactMatch: searchTermExact.MatchString(filter),
|
||||
}
|
||||
}
|
||||
|
||||
return packages_model.SearchValue{}
|
||||
}
|
||||
|
||||
// https://github.com/NuGet/NuGet.Client/blob/dev/src/NuGet.Core/NuGet.Protocol/LegacyFeed/V2FeedQueryBuilder.cs
|
||||
|
@ -118,11 +132,9 @@ func SearchServiceV2(ctx *context.Context) {
|
|||
paginator := db.NewAbsoluteListOptions(skip, take)
|
||||
|
||||
pvs, total, err := packages_model.SearchLatestVersions(ctx, &packages_model.PackageSearchOptions{
|
||||
OwnerID: ctx.Package.Owner.ID,
|
||||
Type: packages_model.TypeNuGet,
|
||||
Name: packages_model.SearchValue{
|
||||
Value: getSearchTerm(ctx),
|
||||
},
|
||||
OwnerID: ctx.Package.Owner.ID,
|
||||
Type: packages_model.TypeNuGet,
|
||||
Name: getSearchTerm(ctx),
|
||||
IsInternal: optional.Some(false),
|
||||
Paginator: paginator,
|
||||
})
|
||||
|
@ -169,10 +181,8 @@ func SearchServiceV2(ctx *context.Context) {
|
|||
// http://docs.oasis-open.org/odata/odata/v4.0/errata03/os/complete/part2-url-conventions/odata-v4.0-errata03-os-part2-url-conventions-complete.html#_Toc453752351
|
||||
func SearchServiceV2Count(ctx *context.Context) {
|
||||
count, err := nuget_model.CountPackages(ctx, &packages_model.PackageSearchOptions{
|
||||
OwnerID: ctx.Package.Owner.ID,
|
||||
Name: packages_model.SearchValue{
|
||||
Value: getSearchTerm(ctx),
|
||||
},
|
||||
OwnerID: ctx.Package.Owner.ID,
|
||||
Name: getSearchTerm(ctx),
|
||||
IsInternal: optional.Some(false),
|
||||
})
|
||||
if err != nil {
|
||||
|
|
|
@ -158,7 +158,7 @@ func GetContentHistoryDetail(ctx *context.Context) {
|
|||
|
||||
// use chroma to render the diff html
|
||||
diffHTMLBuf := bytes.Buffer{}
|
||||
diffHTMLBuf.WriteString("<pre class='chroma' style='tab-size: 4'>")
|
||||
diffHTMLBuf.WriteString("<pre class='chroma'>")
|
||||
for _, it := range diff {
|
||||
if it.Type == diffmatchpatch.DiffInsert {
|
||||
diffHTMLBuf.WriteString("<span class='gi'>")
|
||||
|
|
|
@ -57,7 +57,7 @@ func (m *Message) ToMessage() *gomail.Message {
|
|||
msg.SetHeader(header, m.Headers[header]...)
|
||||
}
|
||||
|
||||
if len(setting.MailService.SubjectPrefix) > 0 {
|
||||
if setting.MailService.SubjectPrefix != "" {
|
||||
msg.SetHeader("Subject", setting.MailService.SubjectPrefix+" "+m.Subject)
|
||||
} else {
|
||||
msg.SetHeader("Subject", m.Subject)
|
||||
|
@ -79,6 +79,14 @@ func (m *Message) ToMessage() *gomail.Message {
|
|||
if len(msg.GetHeader("Message-ID")) == 0 {
|
||||
msg.SetHeader("Message-ID", m.generateAutoMessageID())
|
||||
}
|
||||
|
||||
for k, v := range setting.MailService.OverrideHeader {
|
||||
if len(msg.GetHeader(k)) != 0 {
|
||||
log.Debug("Mailer override header '%s' as per config", k)
|
||||
}
|
||||
msg.SetHeader(k, v...)
|
||||
}
|
||||
|
||||
return msg
|
||||
}
|
||||
|
||||
|
|
|
@ -4,22 +4,22 @@
|
|||
package mailer
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGenerateMessageID(t *testing.T) {
|
||||
mailService := setting.Mailer{
|
||||
defer test.MockVariableValue(&setting.MailService, &setting.Mailer{
|
||||
From: "test@gitea.com",
|
||||
}
|
||||
|
||||
setting.MailService = &mailService
|
||||
setting.Domain = "localhost"
|
||||
})()
|
||||
defer test.MockVariableValue(&setting.Domain, "localhost")()
|
||||
|
||||
date := time.Date(2000, 1, 2, 3, 4, 5, 6, time.UTC)
|
||||
m := NewMessageFrom("", "display-name", "from-address", "subject", "body")
|
||||
|
@ -39,7 +39,7 @@ func TestGenerateMessageID(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestGenerateMessageIDForRelease(t *testing.T) {
|
||||
setting.Domain = "localhost"
|
||||
defer test.MockVariableValue(&setting.Domain, "localhost")()
|
||||
|
||||
rel := repo_model.Release{
|
||||
ID: 42,
|
||||
|
@ -51,3 +51,77 @@ func TestGenerateMessageIDForRelease(t *testing.T) {
|
|||
m := createMessageIDForRelease(&rel)
|
||||
assert.Equal(t, "<test/tag-test/releases/42@localhost>", m)
|
||||
}
|
||||
|
||||
func TestToMessage(t *testing.T) {
|
||||
defer test.MockVariableValue(&setting.MailService, &setting.Mailer{
|
||||
From: "test@gitea.com",
|
||||
})()
|
||||
defer test.MockVariableValue(&setting.Domain, "localhost")()
|
||||
|
||||
m1 := Message{
|
||||
Info: "info",
|
||||
FromAddress: "test@gitea.com",
|
||||
FromDisplayName: "Test Gitea",
|
||||
To: "a@b.com",
|
||||
Subject: "Issue X Closed",
|
||||
Body: "Some Issue got closed by Y-Man",
|
||||
}
|
||||
|
||||
buf := &strings.Builder{}
|
||||
_, err := m1.ToMessage().WriteTo(buf)
|
||||
assert.NoError(t, err)
|
||||
header, _ := extractMailHeaderAndContent(t, buf.String())
|
||||
assert.EqualValues(t, map[string]string{
|
||||
"Content-Type": "multipart/alternative;",
|
||||
"Date": "Mon, 01 Jan 0001 00:00:00 +0000",
|
||||
"From": "\"Test Gitea\" <test@gitea.com>",
|
||||
"Message-ID": "<autogen--6795364578871-69c000786adc60dc@localhost>",
|
||||
"Mime-Version": "1.0",
|
||||
"Subject": "Issue X Closed",
|
||||
"To": "a@b.com",
|
||||
"X-Auto-Response-Suppress": "All",
|
||||
}, header)
|
||||
|
||||
setting.MailService.OverrideHeader = map[string][]string{
|
||||
"Message-ID": {""}, // delete message id
|
||||
"Auto-Submitted": {"auto-generated"}, // suppress auto replay
|
||||
}
|
||||
|
||||
buf = &strings.Builder{}
|
||||
_, err = m1.ToMessage().WriteTo(buf)
|
||||
assert.NoError(t, err)
|
||||
header, _ = extractMailHeaderAndContent(t, buf.String())
|
||||
assert.EqualValues(t, map[string]string{
|
||||
"Content-Type": "multipart/alternative;",
|
||||
"Date": "Mon, 01 Jan 0001 00:00:00 +0000",
|
||||
"From": "\"Test Gitea\" <test@gitea.com>",
|
||||
"Message-ID": "",
|
||||
"Mime-Version": "1.0",
|
||||
"Subject": "Issue X Closed",
|
||||
"To": "a@b.com",
|
||||
"X-Auto-Response-Suppress": "All",
|
||||
"Auto-Submitted": "auto-generated",
|
||||
}, header)
|
||||
}
|
||||
|
||||
func extractMailHeaderAndContent(t *testing.T, mail string) (map[string]string, string) {
|
||||
header := make(map[string]string)
|
||||
|
||||
parts := strings.SplitN(mail, "boundary=", 2)
|
||||
if !assert.Len(t, parts, 2) {
|
||||
return nil, ""
|
||||
}
|
||||
content := strings.TrimSpace("boundary=" + parts[1])
|
||||
|
||||
hParts := strings.Split(parts[0], "\n")
|
||||
|
||||
for _, hPart := range hParts {
|
||||
parts := strings.SplitN(hPart, ":", 2)
|
||||
hk := strings.TrimSpace(parts[0])
|
||||
if hk != "" {
|
||||
header[hk] = strings.TrimSpace(parts[1])
|
||||
}
|
||||
}
|
||||
|
||||
return header, content
|
||||
}
|
||||
|
|
|
@ -183,7 +183,7 @@ func newDownloader(ctx context.Context, ownerName string, opts base.MigrateOptio
|
|||
// migrateRepository will download information and then upload it to Uploader, this is a simple
|
||||
// process for small repository. For a big repository, save all the data to disk
|
||||
// before upload is better
|
||||
func migrateRepository(ctx context.Context, doer *user_model.User, downloader base.Downloader, uploader base.Uploader, opts base.MigrateOptions, messenger base.Messenger) error {
|
||||
func migrateRepository(_ context.Context, doer *user_model.User, downloader base.Downloader, uploader base.Uploader, opts base.MigrateOptions, messenger base.Messenger) error {
|
||||
if messenger == nil {
|
||||
messenger = base.NilMessenger
|
||||
}
|
||||
|
|
|
@ -46,6 +46,9 @@ func getMergeMessage(ctx context.Context, baseGitRepo *git.Repository, pr *issue
|
|||
if err := pr.Issue.LoadPoster(ctx); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
if err := pr.Issue.LoadRepo(ctx); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
isExternalTracker := pr.BaseRepo.UnitEnabled(ctx, unit.TypeExternalTracker)
|
||||
issueReference := "#"
|
||||
|
@ -53,6 +56,9 @@ func getMergeMessage(ctx context.Context, baseGitRepo *git.Repository, pr *issue
|
|||
issueReference = "!"
|
||||
}
|
||||
|
||||
reviewedOn := fmt.Sprintf("Reviewed-on: %s/%s", setting.AppURL, pr.Issue.Link())
|
||||
reviewedBy := pr.GetApprovers(ctx)
|
||||
|
||||
if mergeStyle != "" {
|
||||
commit, err := baseGitRepo.GetBranchCommit(pr.BaseRepo.DefaultBranch)
|
||||
if err != nil {
|
||||
|
@ -83,6 +89,8 @@ func getMergeMessage(ctx context.Context, baseGitRepo *git.Repository, pr *issue
|
|||
"PullRequestPosterName": pr.Issue.Poster.Name,
|
||||
"PullRequestIndex": strconv.FormatInt(pr.Index, 10),
|
||||
"PullRequestReference": fmt.Sprintf("%s%d", issueReference, pr.Index),
|
||||
"ReviewedOn": reviewedOn,
|
||||
"ReviewedBy": reviewedBy,
|
||||
}
|
||||
if pr.HeadRepo != nil {
|
||||
vars["HeadRepoOwnerName"] = pr.HeadRepo.OwnerName
|
||||
|
@ -122,20 +130,22 @@ func getMergeMessage(ctx context.Context, baseGitRepo *git.Repository, pr *issue
|
|||
return "", "", nil
|
||||
}
|
||||
|
||||
body = fmt.Sprintf("%s\n%s", reviewedOn, reviewedBy)
|
||||
|
||||
// Squash merge has a different from other styles.
|
||||
if mergeStyle == repo_model.MergeStyleSquash {
|
||||
return fmt.Sprintf("%s (%s%d)", pr.Issue.Title, issueReference, pr.Issue.Index), "", nil
|
||||
return fmt.Sprintf("%s (%s%d)", pr.Issue.Title, issueReference, pr.Issue.Index), body, nil
|
||||
}
|
||||
|
||||
if pr.BaseRepoID == pr.HeadRepoID {
|
||||
return fmt.Sprintf("Merge pull request '%s' (%s%d) from %s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadBranch, pr.BaseBranch), "", nil
|
||||
return fmt.Sprintf("Merge pull request '%s' (%s%d) from %s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadBranch, pr.BaseBranch), body, nil
|
||||
}
|
||||
|
||||
if pr.HeadRepo == nil {
|
||||
return fmt.Sprintf("Merge pull request '%s' (%s%d) from <deleted>:%s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadBranch, pr.BaseBranch), "", nil
|
||||
return fmt.Sprintf("Merge pull request '%s' (%s%d) from <deleted>:%s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadBranch, pr.BaseBranch), body, nil
|
||||
}
|
||||
|
||||
return fmt.Sprintf("Merge pull request '%s' (%s%d) from %s:%s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseBranch), "", nil
|
||||
return fmt.Sprintf("Merge pull request '%s' (%s%d) from %s:%s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseBranch), body, nil
|
||||
}
|
||||
|
||||
func expandDefaultMergeMessage(template string, vars map[string]string) (message, body string) {
|
||||
|
|
|
@ -285,7 +285,7 @@ func transferOwnership(ctx context.Context, doer *user_model.User, newOwnerName
|
|||
}
|
||||
|
||||
// changeRepositoryName changes all corresponding setting from old repository name to new one.
|
||||
func changeRepositoryName(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, newRepoName string) (err error) {
|
||||
func changeRepositoryName(ctx context.Context, repo *repo_model.Repository, newRepoName string) (err error) {
|
||||
oldRepoName := repo.Name
|
||||
newRepoName = strings.ToLower(newRepoName)
|
||||
if err = repo_model.IsUsableRepoName(newRepoName); err != nil {
|
||||
|
@ -347,7 +347,7 @@ func ChangeRepositoryName(ctx context.Context, doer *user_model.User, repo *repo
|
|||
// local copy's origin accordingly.
|
||||
|
||||
repoWorkingPool.CheckIn(fmt.Sprint(repo.ID))
|
||||
if err := changeRepositoryName(ctx, doer, repo, newRepoName); err != nil {
|
||||
if err := changeRepositoryName(ctx, repo, newRepoName); err != nil {
|
||||
repoWorkingPool.CheckOut(fmt.Sprint(repo.ID))
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import {readFileSync} from 'node:fs';
|
||||
import {env} from 'node:process';
|
||||
import {parse} from 'postcss';
|
||||
import plugin from 'tailwindcss/plugin.js';
|
||||
|
||||
const isProduction = env.NODE_ENV !== 'development';
|
||||
|
||||
|
@ -98,4 +99,26 @@ export default {
|
|||
})),
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
plugin(({addUtilities}) => {
|
||||
addUtilities({
|
||||
// tw-hidden must win all other "display: xxx !important" classes to get the chance to "hide" an element.
|
||||
// do not use:
|
||||
// * "[hidden]" attribute: it's too weak, can not be applied to an element with "display: flex"
|
||||
// * ".hidden" class: it has been polluted by Fomantic UI in many cases
|
||||
// * inline style="display: none": it's difficult to tweak
|
||||
// * jQuery's show/hide/toggle: it can not show/hide elements with "display: xxx !important"
|
||||
// only use:
|
||||
// * this ".tw-hidden" class
|
||||
// * showElem/hideElem/toggleElem functions in "utils/dom.js"
|
||||
'.hidden.hidden': {
|
||||
'display': 'none',
|
||||
},
|
||||
// proposed class from https://github.com/tailwindlabs/tailwindcss/pull/12128
|
||||
'.break-anywhere': {
|
||||
'overflow-wrap': 'anywhere',
|
||||
},
|
||||
});
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
{{ctx.Locale.Tr "admin.packages.total_size" (ctx.Locale.TrSize .TotalBlobSize)}},
|
||||
{{ctx.Locale.Tr "admin.packages.unreferenced_size" (ctx.Locale.TrSize .TotalUnreferencedBlobSize)}})
|
||||
<div class="ui right">
|
||||
<form method="post" action="/admin/packages/cleanup">
|
||||
<form method="post" action="{{AppSubUrl}}/admin/packages/cleanup">
|
||||
{{.CsrfTokenHtml}}
|
||||
<button class="ui primary tiny button">{{ctx.Locale.Tr "admin.packages.cleanup"}}</button>
|
||||
</form>
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
<div><label><input name="check" type="checkbox"> check</label></div>
|
||||
<div><button name="btn">submit post</button></div>
|
||||
</form>
|
||||
<form method="post" action="/no-such-uri" class="form-fetch-action">
|
||||
<form method="post" action="no-such-uri" class="form-fetch-action">
|
||||
<div class="tw-py-8">bad action url</div>
|
||||
<div><button name="btn">submit test</button></div>
|
||||
</form>
|
||||
|
|
|
@ -66,7 +66,7 @@
|
|||
<div id="project-board">
|
||||
<div class="board {{if .CanWriteProjects}}sortable{{end}}"{{if .CanWriteProjects}} data-url="{{$.Link}}/move"{{end}}>
|
||||
{{range .Columns}}
|
||||
<div class="ui segment project-column"{{if .Color}} style="background: {{.Color}} !important; color: {{ContrastColor .Color}} !important"{{end}} data-id="{{.ID}}" data-sorting="{{.Sorting}}" data-url="{{$.Link}}/{{.ID}}">
|
||||
<div class="project-column"{{if .Color}} style="background: {{.Color}} !important; color: {{ContrastColor .Color}} !important"{{end}} data-id="{{.ID}}" data-sorting="{{.Sorting}}" data-url="{{$.Link}}/{{.ID}}">
|
||||
<div class="project-column-header{{if $canWriteProject}} tw-cursor-grab{{end}}">
|
||||
<div class="ui large label project-column-title tw-py-1">
|
||||
<div class="ui small circular grey label project-column-issue-count">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{{range .RecentlyPushedNewBranches}}
|
||||
<div class="ui positive message tw-flex tw-items-center">
|
||||
<div class="tw-flex-1">
|
||||
<div class="ui positive message tw-flex tw-items-center tw-gap-2">
|
||||
<div class="tw-flex-1 tw-break-anywhere">
|
||||
{{$timeSince := TimeSince .CommitTime.AsTime ctx.Locale}}
|
||||
{{$repo := .GetRepo $.Context}}
|
||||
{{$name := .Name}}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
<div class="issue-card-icon">
|
||||
{{template "shared/issueicon" .}}
|
||||
</div>
|
||||
<a class="issue-card-title muted issue-title" href="{{.Link}}">{{.Title | RenderEmoji ctx | RenderCodeBlock}}</a>
|
||||
<a class="issue-card-title muted issue-title tw-break-anywhere" href="{{.Link}}">{{.Title | RenderEmoji ctx | RenderCodeBlock}}</a>
|
||||
{{if and $.isPinnedIssueCard $.Page.IsRepoAdmin}}
|
||||
<a role="button" class="issue-card-unpin muted tw-flex tw-items-center" data-tooltip-content={{ctx.Locale.Tr "repo.issues.unpin_issue"}} data-issue-id="{{.ID}}" data-unpin-url="{{$.Page.Link}}/unpin/{{.Index}}">
|
||||
{{svg "octicon-x" 16}}
|
||||
|
|
|
@ -199,7 +199,6 @@
|
|||
|
||||
{{if .AllowMerge}} {{/* user is allowed to merge */}}
|
||||
{{$prUnit := .Repository.MustGetUnit $.Context $.UnitTypePullRequests}}
|
||||
{{$approvers := (.Issue.PullRequest.GetApprovers ctx)}}
|
||||
{{if or $prUnit.PullRequestsConfig.AllowMerge $prUnit.PullRequestsConfig.AllowRebase $prUnit.PullRequestsConfig.AllowRebaseMerge $prUnit.PullRequestsConfig.AllowSquash $prUnit.PullRequestsConfig.AllowFastForwardOnly}}
|
||||
{{$hasPendingPullRequestMergeTip := ""}}
|
||||
{{if .HasPendingPullRequestMerge}}
|
||||
|
@ -208,11 +207,10 @@
|
|||
{{end}}
|
||||
<div class="divider"></div>
|
||||
<script type="module">
|
||||
const issueUrl = window.location.origin + {{$.Issue.Link}};
|
||||
const defaultMergeTitle = {{.DefaultMergeMessage}};
|
||||
const defaultSquashMergeTitle = {{.DefaultSquashMergeMessage}};
|
||||
const defaultMergeMessage = {{if .DefaultMergeBody}}{{.DefaultMergeBody}}{{else}}`Reviewed-on: ${issueUrl}\n` + {{$approvers}}{{end}};
|
||||
const defaultSquashMergeMessage = {{if .DefaultSquashMergeBody}}{{.DefaultSquashMergeBody}}{{else}}`Reviewed-on: ${issueUrl}\n` + {{$approvers}}{{end}};
|
||||
const defaultMergeMessage = {{.DefaultMergeBody}};
|
||||
const defaultSquashMergeMessage = {{.DefaultSquashMergeBody}};
|
||||
const mergeForm = {
|
||||
'baseLink': {{.Link}},
|
||||
'textCancel': {{ctx.Locale.Tr "cancel"}},
|
||||
|
|
|
@ -70,7 +70,7 @@
|
|||
<td><p data-tooltip-content="{{.Description}}">{{.Name}}</p></td>
|
||||
<td>{{if .Version}}{{.Version}}{{else}}{{ctx.Locale.Tr "unknown"}}{{end}}</td>
|
||||
<td><span data-tooltip-content="{{.BelongsToOwnerName}}">{{.BelongsToOwnerType.LocaleString ctx.Locale}}</span></td>
|
||||
<td class="runner-tags">
|
||||
<td class="tw-flex tw-flex-wrap tw-gap-2 runner-tags">
|
||||
{{range .AgentLabels}}<span class="ui label">{{.}}</span>{{end}}
|
||||
</td>
|
||||
<td>{{if .LastOnline}}{{TimeSinceUnix .LastOnline ctx.Locale}}{{else}}{{ctx.Locale.Tr "never"}}{{end}}</td>
|
||||
|
|
30
templates/swagger/v1_json.tmpl
generated
30
templates/swagger/v1_json.tmpl
generated
|
@ -18537,7 +18537,37 @@
|
|||
"x-go-name": "IsPrivate"
|
||||
},
|
||||
"op_type": {
|
||||
"description": "the type of action",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"create_repo",
|
||||
"rename_repo",
|
||||
"star_repo",
|
||||
"watch_repo",
|
||||
"commit_repo",
|
||||
"create_issue",
|
||||
"create_pull_request",
|
||||
"transfer_repo",
|
||||
"push_tag",
|
||||
"comment_issue",
|
||||
"merge_pull_request",
|
||||
"close_issue",
|
||||
"reopen_issue",
|
||||
"close_pull_request",
|
||||
"reopen_pull_request",
|
||||
"delete_tag",
|
||||
"delete_branch",
|
||||
"mirror_sync_push",
|
||||
"mirror_sync_create",
|
||||
"mirror_sync_delete",
|
||||
"approve_pull_request",
|
||||
"reject_pull_request",
|
||||
"comment_pull",
|
||||
"publish_release",
|
||||
"pull_review_dismissed",
|
||||
"pull_request_ready_for_review",
|
||||
"auto_merge_pull_request"
|
||||
],
|
||||
"x-go-name": "OpType"
|
||||
},
|
||||
"ref_name": {
|
||||
|
|
|
@ -49,14 +49,14 @@
|
|||
{{end}}
|
||||
</div>
|
||||
<a class="notifications-link tw-flex tw-flex-1 tw-flex-col silenced" href="{{.Link ctx}}">
|
||||
<div class="notifications-top-row tw-text-13">
|
||||
<div class="notifications-top-row tw-text-13 tw-break-anywhere">
|
||||
{{.Repository.FullName}} {{if .Issue}}<span class="text light-3">#{{.Issue.Index}}</span>{{end}}
|
||||
{{if eq .Status 3}}
|
||||
{{svg "octicon-pin" 13 "text blue tw-mt-0.5 tw-ml-1"}}
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="notifications-bottom-row tw-text-16 tw-py-0.5">
|
||||
<span class="issue-title">
|
||||
<span class="issue-title tw-break-anywhere">
|
||||
{{if .Issue}}
|
||||
{{.Issue.Title | RenderEmoji $.Context | RenderCodeBlock}}
|
||||
{{else}}
|
||||
|
|
|
@ -75,7 +75,7 @@
|
|||
{{ctx.Locale.Tr "settings.select_permissions"}}
|
||||
</summary>
|
||||
<p class="activity meta">
|
||||
<p>{{ctx.Locale.Tr "settings.access_token_desc" (`href="/api/swagger" target="_blank"`|SafeHTML) (`href="https://forgejo.org/docs/latest/user/token-scope/" target="_blank"`|SafeHTML)}}</p>
|
||||
<p>{{ctx.Locale.Tr "settings.access_token_desc" (HTMLFormat `href="%s/api/swagger" target="_blank"` AppSubUrl) (`href="https://forgejo.org/docs/latest/user/token-scope/" target="_blank"`|SafeHTML)}}</p>
|
||||
</p>
|
||||
<div class="scoped-access-token-mount">
|
||||
<scoped-access-token-selector
|
||||
|
|
|
@ -431,22 +431,33 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`)
|
|||
|
||||
t.Run("SearchService", func(t *testing.T) {
|
||||
cases := []struct {
|
||||
Query string
|
||||
Skip int
|
||||
Take int
|
||||
ExpectedTotal int64
|
||||
ExpectedResults int
|
||||
Query string
|
||||
Skip int
|
||||
Take int
|
||||
ExpectedTotal int64
|
||||
ExpectedResults int
|
||||
ExpectedExactMatch bool
|
||||
}{
|
||||
{"", 0, 0, 1, 1},
|
||||
{"", 0, 10, 1, 1},
|
||||
{"gitea", 0, 10, 0, 0},
|
||||
{"test", 0, 10, 1, 1},
|
||||
{"test", 1, 10, 1, 0},
|
||||
{"", 0, 0, 4, 4, false},
|
||||
{"", 0, 10, 4, 4, false},
|
||||
{"gitea", 0, 10, 0, 0, false},
|
||||
{"test", 0, 10, 1, 1, false},
|
||||
{"test", 1, 10, 1, 0, false},
|
||||
{"almost.similar", 0, 0, 3, 3, true},
|
||||
}
|
||||
|
||||
req := NewRequestWithBody(t, "PUT", url, createPackage(packageName, "1.0.99")).
|
||||
AddBasicAuth(user.Name)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
fakePackages := []string{
|
||||
packageName,
|
||||
"almost.similar.dependency",
|
||||
"almost.similar",
|
||||
"almost.similar.dependant",
|
||||
}
|
||||
|
||||
for _, fakePackageName := range fakePackages {
|
||||
req := NewRequestWithBody(t, "PUT", url, createPackage(fakePackageName, "1.0.99")).
|
||||
AddBasicAuth(user.Name)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
}
|
||||
|
||||
t.Run("v2", func(t *testing.T) {
|
||||
t.Run("Search()", func(t *testing.T) {
|
||||
|
@ -493,6 +504,63 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`)
|
|||
}
|
||||
})
|
||||
|
||||
t.Run("Packages()", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
t.Run("substringof", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
for i, c := range cases {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/Packages()?$filter=substringof('%s',tolower(Id))&$skip=%d&$top=%d", url, c.Query, c.Skip, c.Take)).
|
||||
AddBasicAuth(user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result FeedResponse
|
||||
decodeXML(t, resp, &result)
|
||||
|
||||
assert.Equal(t, c.ExpectedTotal, result.Count, "case %d: unexpected total hits", i)
|
||||
assert.Len(t, result.Entries, c.ExpectedResults, "case %d: unexpected result count", i)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/Packages()/$count?$filter=substringof('%s',tolower(Id))&$skip=%d&$top=%d", url, c.Query, c.Skip, c.Take)).
|
||||
AddBasicAuth(user.Name)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, strconv.FormatInt(c.ExpectedTotal, 10), resp.Body.String(), "case %d: unexpected total hits", i)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("IdEq", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
for i, c := range cases {
|
||||
if c.Query == "" {
|
||||
// Ignore the `tolower(Id) eq ''` as it's unlikely to happen
|
||||
continue
|
||||
}
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/Packages()?$filter=(tolower(Id) eq '%s')&$skip=%d&$top=%d", url, c.Query, c.Skip, c.Take)).
|
||||
AddBasicAuth(user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var result FeedResponse
|
||||
decodeXML(t, resp, &result)
|
||||
|
||||
expectedCount := 0
|
||||
if c.ExpectedExactMatch {
|
||||
expectedCount = 1
|
||||
}
|
||||
|
||||
assert.Equal(t, int64(expectedCount), result.Count, "case %d: unexpected total hits", i)
|
||||
assert.Len(t, result.Entries, expectedCount, "case %d: unexpected result count", i)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/Packages()/$count?$filter=(tolower(Id) eq '%s')&$skip=%d&$top=%d", url, c.Query, c.Skip, c.Take)).
|
||||
AddBasicAuth(user.Name)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
assert.Equal(t, strconv.FormatInt(int64(expectedCount), 10), resp.Body.String(), "case %d: unexpected total hits", i)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Next", func(t *testing.T) {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/Search()?searchTerm='test'&$skip=0&$top=1", url)).
|
||||
AddBasicAuth(user.Name)
|
||||
|
@ -550,9 +618,11 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`)
|
|||
})
|
||||
})
|
||||
|
||||
req = NewRequest(t, "DELETE", fmt.Sprintf("%s/%s/%s", url, packageName, "1.0.99")).
|
||||
AddBasicAuth(user.Name)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
for _, fakePackageName := range fakePackages {
|
||||
req := NewRequest(t, "DELETE", fmt.Sprintf("%s/%s/%s", url, fakePackageName, "1.0.99")).
|
||||
AddBasicAuth(user.Name)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("RegistrationService", func(t *testing.T) {
|
||||
|
|
|
@ -42,7 +42,7 @@ func TestAPIRepoTags(t *testing.T) {
|
|||
assert.Equal(t, setting.AppURL+"user2/repo1/archive/v1.1.zip", tags[0].ZipballURL)
|
||||
assert.Equal(t, setting.AppURL+"user2/repo1/archive/v1.1.tar.gz", tags[0].TarballURL)
|
||||
|
||||
newTag := createNewTagUsingAPI(t, session, token, user.Name, repoName, "gitea/22", "", "nice!\nand some text")
|
||||
newTag := createNewTagUsingAPI(t, token, user.Name, repoName, "gitea/22", "", "nice!\nand some text")
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &tags)
|
||||
assert.Len(t, tags, 2)
|
||||
|
@ -72,7 +72,7 @@ func TestAPIRepoTags(t *testing.T) {
|
|||
MakeRequest(t, req, http.StatusNotFound)
|
||||
}
|
||||
|
||||
func createNewTagUsingAPI(t *testing.T, session *TestSession, token, ownerName, repoName, name, target, msg string) *api.Tag {
|
||||
func createNewTagUsingAPI(t *testing.T, token, ownerName, repoName, name, target, msg string) *api.Tag {
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/tags", ownerName, repoName)
|
||||
req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateTagOption{
|
||||
TagName: name,
|
||||
|
@ -96,7 +96,7 @@ func TestAPIGetTagArchiveDownloadCount(t *testing.T) {
|
|||
repoName := "repo1"
|
||||
tagName := "TagDownloadCount"
|
||||
|
||||
createNewTagUsingAPI(t, session, token, user.Name, repoName, tagName, "", "")
|
||||
createNewTagUsingAPI(t, token, user.Name, repoName, tagName, "", "")
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/tags/%s?token=%s", user.Name, repoName, tagName, token)
|
||||
|
||||
|
|
|
@ -237,7 +237,7 @@ func (c *compareDump) assertLoadFiles(beforeFilename, afterFilename string, t re
|
|||
//
|
||||
// Given []Something{} create afterPtr, beforePtr []*Something{}
|
||||
//
|
||||
sliceType := reflect.SliceOf(reflect.PtrTo(t.Elem()))
|
||||
sliceType := reflect.SliceOf(reflect.PointerTo(t.Elem()))
|
||||
beforeSlice := reflect.MakeSlice(sliceType, 0, 10)
|
||||
beforePtr = reflect.New(beforeSlice.Type())
|
||||
beforePtr.Elem().Set(beforeSlice)
|
||||
|
|
|
@ -36,7 +36,7 @@ func TestGPGGit(t *testing.T) {
|
|||
defer os.Setenv("GNUPGHOME", oldGNUPGHome)
|
||||
|
||||
// Need to create a root key
|
||||
rootKeyPair, err := importTestingKey(tmpDir, "gitea", "gitea@fake.local")
|
||||
rootKeyPair, err := importTestingKey()
|
||||
if !assert.NoError(t, err, "importTestingKey") {
|
||||
return
|
||||
}
|
||||
|
@ -263,7 +263,7 @@ func TestGPGGit(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func crudActionCreateFile(t *testing.T, ctx APITestContext, user *user_model.User, from, to, path string, callback ...func(*testing.T, api.FileResponse)) func(*testing.T) {
|
||||
func crudActionCreateFile(_ *testing.T, ctx APITestContext, user *user_model.User, from, to, path string, callback ...func(*testing.T, api.FileResponse)) func(*testing.T) {
|
||||
return doAPICreateFile(ctx, path, &api.CreateFileOptions{
|
||||
FileOptions: api.FileOptions{
|
||||
BranchName: from,
|
||||
|
@ -282,7 +282,7 @@ func crudActionCreateFile(t *testing.T, ctx APITestContext, user *user_model.Use
|
|||
}, callback...)
|
||||
}
|
||||
|
||||
func importTestingKey(tmpDir, name, email string) (*openpgp.Entity, error) {
|
||||
func importTestingKey() (*openpgp.Entity, error) {
|
||||
if _, _, err := process.GetManager().Exec("gpg --import tests/integration/private-testing.key", "gpg", "--import", "tests/integration/private-testing.key"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
23
tools/lint-go-gopls.sh
Executable file
23
tools/lint-go-gopls.sh
Executable file
|
@ -0,0 +1,23 @@
|
|||
#!/bin/bash
|
||||
set -uo pipefail
|
||||
|
||||
cd "$(dirname -- "${BASH_SOURCE[0]}")" && cd ..
|
||||
|
||||
IGNORE_PATTERNS=(
|
||||
"is deprecated" # TODO: fix these
|
||||
)
|
||||
|
||||
# lint all go files with 'gopls check' and look for lines starting with the
|
||||
# current absolute path, indicating a error was found. This is neccessary
|
||||
# because the tool does not set non-zero exit code when errors are found.
|
||||
# ref: https://github.com/golang/go/issues/67078
|
||||
ERROR_LINES=$("$GO" run "$GOPLS_PACKAGE" check "$@" 2>/dev/null | grep -E "^$PWD" | grep -vFf <(printf '%s\n' "${IGNORE_PATTERNS[@]}"));
|
||||
NUM_ERRORS=$(echo -n "$ERROR_LINES" | wc -l)
|
||||
|
||||
if [ "$NUM_ERRORS" -eq "0" ]; then
|
||||
exit 0;
|
||||
else
|
||||
echo "$ERROR_LINES"
|
||||
echo "Found $NUM_ERRORS 'gopls check' errors"
|
||||
exit 1;
|
||||
fi
|
|
@ -9,6 +9,7 @@
|
|||
.project-column {
|
||||
background-color: var(--color-project-column-bg) !important;
|
||||
border: 1px solid var(--color-secondary) !important;
|
||||
border-radius: var(--border-radius);
|
||||
margin: 0 0.5rem !important;
|
||||
padding: 0.5rem !important;
|
||||
width: 320px;
|
||||
|
|
|
@ -35,22 +35,6 @@ Gitea's private styles use `g-` prefix.
|
|||
.interact-bg:hover { background: var(--color-hover) !important; }
|
||||
.interact-bg:active { background: var(--color-active) !important; }
|
||||
|
||||
/*
|
||||
tw-hidden must win all other "display: xxx !important" classes to get the chance to "hide" an element.
|
||||
do not use:
|
||||
* "[hidden]" attribute: it's too weak, can not be applied to an element with "display: flex"
|
||||
* ".hidden" class: it has been polluted by Fomantic UI in many cases
|
||||
* inline style="display: none": it's difficult to tweak
|
||||
* jQuery's show/hide/toggle: it can not show/hide elements with "display: xxx !important"
|
||||
only use:
|
||||
* this ".tw-hidden" class
|
||||
* showElem/hideElem/toggleElem functions in "utils/dom.js"
|
||||
*/
|
||||
.tw-hidden.tw-hidden { display: none !important; }
|
||||
|
||||
/* proposed class from https://github.com/tailwindlabs/tailwindcss/pull/12128 */
|
||||
.tw-break-anywhere { overflow-wrap: anywhere !important; }
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
/* double selector so it wins over .tw-flex (old .gt-df) etc */
|
||||
.not-mobile.not-mobile {
|
||||
|
|
|
@ -2489,6 +2489,7 @@ tbody.commit-list {
|
|||
min-height: 12em;
|
||||
max-height: calc(100vh - 10.5rem);
|
||||
overflow-y: auto;
|
||||
tab-size: 4;
|
||||
}
|
||||
|
||||
.comment-diff-data pre {
|
||||
|
|
Loading…
Add table
Reference in a new issue