Skip to content

Commit

Permalink
Merge remote-tracking branch 'giteaofficial/main'
Browse files Browse the repository at this point in the history
* giteaofficial/main: (38 commits)
  Document how the TOC election process works (go-gitea#29135)
  Runner tokens are multi use (go-gitea#29153)
  Fix Gitpod logic of setting ROOT_URL (go-gitea#29162)
  Remove jQuery from the user search form in admin page (go-gitea#29151)
  Dont load Review if Comment is CommentTypeReviewRequest (go-gitea#28551)
  Show `View at this point in history` for every commit (go-gitea#29122)
  [skip ci] Updated translations via Crowdin
  Add merge style `fast-forward-only` (go-gitea#28954)
  Use Markdown alert syntax for notes in README (go-gitea#29150)
  Refactor issue template parsing and fix API endpoint (go-gitea#29069)
  [skip ci] Updated translations via Crowdin
  Update some translations and fix markdown formatting (go-gitea#29099)
  Show more settings for empty repositories (go-gitea#29130)
  Update JS and PY dependencies (go-gitea#29127)
  Add alert blocks in markdown (go-gitea#29121)
  Remove obsolete border-radius on comment content (go-gitea#29128)
  Make blockquote border size less aggressive (go-gitea#29124)
  Drop "@" from email sender to avoid spam filters (go-gitea#29109)
  [skip ci] Updated translations via Crowdin
  Disallow duplicate storage paths (go-gitea#26484)
  ...
  • Loading branch information
zjjhot committed Feb 14, 2024
2 parents f3b61f2 + 4feb91f commit 82aedae
Show file tree
Hide file tree
Showing 107 changed files with 1,458 additions and 892 deletions.
3 changes: 1 addition & 2 deletions .eslintrc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,6 @@ rules:
prefer-rest-params: [2]
prefer-spread: [2]
prefer-template: [2]
quotes: [2, single, {avoidEscape: true, allowTemplateLiterals: true}]
radix: [2, as-needed]
regexp/confusing-quantifier: [2]
regexp/control-character-escape: [2]
Expand Down Expand Up @@ -811,7 +810,7 @@ rules:
wc/no-constructor-params: [2]
wc/no-constructor: [2]
wc/no-customized-built-in-elements: [2]
wc/no-exports-with-element: [2]
wc/no-exports-with-element: [0]
wc/no-invalid-element-name: [2]
wc/no-invalid-extends: [2]
wc/no-method-prefixed-with-on: [2]
Expand Down
12 changes: 12 additions & 0 deletions .github/workflows/pull-compliance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,18 @@ jobs:
- run: make deps-frontend
- run: make lint-swagger

lint-spell:
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.frontend == 'true' || needs.files-changed.outputs.actions == 'true' || needs.files-changed.outputs.docs == 'true' || needs.files-changed.outputs.templates == 'true'
needs: files-changed
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
check-latest: true
- run: make lint-spell

lint-go-windows:
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
needs: files-changed
Expand Down
15 changes: 12 additions & 3 deletions .gitpod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,19 @@ tasks:
- name: Run backend
command: |
gp sync-await setup
if [ ! -f custom/conf/app.ini ]
then
# Get the URL and extract the domain
url=$(gp url 3000)
domain=$(echo $url | awk -F[/:] '{print $4}')
if [ -f custom/conf/app.ini ]; then
sed -i "s|^ROOT_URL =.*|ROOT_URL = ${url}/|" custom/conf/app.ini
sed -i "s|^DOMAIN =.*|DOMAIN = ${domain}|" custom/conf/app.ini
sed -i "s|^SSH_DOMAIN =.*|SSH_DOMAIN = ${domain}|" custom/conf/app.ini
sed -i "s|^NO_REPLY_ADDRESS =.*|SSH_DOMAIN = noreply.${domain}|" custom/conf/app.ini
else
mkdir -p custom/conf/
echo -e "[server]\nROOT_URL=$(gp url 3000)/" > custom/conf/app.ini
echo -e "[server]\nROOT_URL = ${url}/" > custom/conf/app.ini
echo -e "\n[database]\nDB_TYPE = sqlite3\nPATH = $GITPOD_REPO_ROOT/data/gitea.db" >> custom/conf/app.ini
fi
export TAGS="sqlite sqlite_unlock_notify"
Expand Down
36 changes: 27 additions & 9 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
- [Release Cycle](#release-cycle)
- [Maintainers](#maintainers)
- [Technical Oversight Committee (TOC)](#technical-oversight-committee-toc)
- [TOC election process](#toc-election-process)
- [Current TOC members](#current-toc-members)
- [Previous TOC/owners members](#previous-tocowners-members)
- [Governance Compensation](#governance-compensation)
Expand Down Expand Up @@ -486,36 +487,53 @@ if possible provide GPG signed commits.
https://help.github.com/articles/securing-your-account-with-two-factor-authentication-2fa/
https://help.github.com/articles/signing-commits-with-gpg/

Furthermore, any account with write access (like bots and TOC members) **must** use 2FA.
https://help.github.com/articles/securing-your-account-with-two-factor-authentication-2fa/

## Technical Oversight Committee (TOC)

At the start of 2023, the `Owners` team was dissolved. Instead, the governance charter proposed a technical oversight committee (TOC) which expands the ownership team of the Gitea project from three elected positions to six positions. Three positions would be elected as it has been over the past years, and the other three would consist of appointed members from the Gitea company.
At the start of 2023, the `Owners` team was dissolved. Instead, the governance charter proposed a technical oversight committee (TOC) which expands the ownership team of the Gitea project from three elected positions to six positions. Three positions are elected as it has been over the past years, and the other three consist of appointed members from the Gitea company.
https://blog.gitea.com/quarterly-23q1/

When the new community members have been elected, the old members will give up ownership to the newly elected members. For security reasons, TOC members or any account with write access (like a bot) must use 2FA.
https://help.github.com/articles/securing-your-account-with-two-factor-authentication-2fa/
### TOC election process

Any maintainer is eligible to be part of the community TOC if they are not associated with the Gitea company.
A maintainer can either nominate themselves, or can be nominated by other maintainers to be a candidate for the TOC election.
If you are nominated by someone else, you must first accept your nomination before the vote starts to be a candidate.

The TOC is elected for one year, the TOC election happens yearly.
After the announcement of the results of the TOC election, elected members have two weeks time to confirm or refuse the seat.
If an elected member does not answer within this timeframe, they are automatically assumed to refuse the seat.
Refusals result in the person with the next highest vote getting the same choice.
As long as seats are empty in the TOC, members of the previous TOC can fill them until an elected member accepts the seat.

If an elected member that accepts the seat does not have 2FA configured yet, they will be temporarily counted as `answer pending` until they manage to configure 2FA, thus leaving their seat empty for this duration.

### Current TOC members

- 2023-01-01 ~ 2023-12-31 - https://blog.gitea.com/quarterly-23q1/
- 2024-01-01 ~ 2024-12-31
- Company
- [Jason Song](https://gitea.com/wolfogre) <i@wolfogre.com>
- [Lunny Xiao](https://gitea.com/lunny) <xiaolunwen@gmail.com>
- [Matti Ranta](https://gitea.com/techknowlogick) <techknowlogick@gitea.io>
- [Matti Ranta](https://gitea.com/techknowlogick) <techknowlogick@gitea.com>
- Community
- [6543](https://gitea.com/6543) <6543@obermui.de>
- [Andrew Thornton](https://gitea.com/zeripath) <art27@cantab.net>
- [delvh](https://gitea.com/delvh) <dev.lh@web.de>
- [John Olheiser](https://gitea.com/jolheiser) <john.olheiser@gmail.com>

### Previous TOC/owners members

Here's the history of the owners and the time they served:

- [Lunny Xiao](https://gitea.com/lunny) - 2016, 2017, [2018](https://github.com/go-gitea/gitea/issues/3255), [2019](https://github.com/go-gitea/gitea/issues/5572), [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872)
- [Lunny Xiao](https://gitea.com/lunny) - 2016, 2017, [2018](https://github.com/go-gitea/gitea/issues/3255), [2019](https://github.com/go-gitea/gitea/issues/5572), [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872), 2023
- [Kim Carlbäcker](https://github.com/bkcsoft) - 2016, 2017
- [Thomas Boerger](https://gitea.com/tboerger) - 2016, 2017
- [Lauris Bukšis-Haberkorns](https://gitea.com/lafriks) - [2018](https://github.com/go-gitea/gitea/issues/3255), [2019](https://github.com/go-gitea/gitea/issues/5572), [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801)
- [Matti Ranta](https://gitea.com/techknowlogick) - [2019](https://github.com/go-gitea/gitea/issues/5572), [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872)
- [Andrew Thornton](https://gitea.com/zeripath) - [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872)
- [Matti Ranta](https://gitea.com/techknowlogick) - [2019](https://github.com/go-gitea/gitea/issues/5572), [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872), 2023
- [Andrew Thornton](https://gitea.com/zeripath) - [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872), 2023
- [6543](https://gitea.com/6543) - 2023
- [John Olheiser](https://gitea.com/jolheiser) - 2023
- [Jason Song](https://gitea.com/wolfogre) - 2023

## Governance Compensation

Expand Down
24 changes: 16 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-che
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.6.0
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.55.2
GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11
MISSPELL_PACKAGE ?= github.com/client9/misspell/cmd/misspell@v0.3.4
MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.4.1
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.30.5
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1.6.0
Expand Down Expand Up @@ -146,6 +146,8 @@ TAR_EXCLUDES := .git data indexers queues log node_modules $(EXECUTABLE) $(FOMAN
GO_DIRS := build cmd models modules routers services tests
WEB_DIRS := web_src/js web_src/css

SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) docs/content templates options/locale/locale_en-US.ini .github

GO_SOURCES := $(wildcard *.go)
GO_SOURCES += $(shell find $(GO_DIRS) -type f -name "*.go" ! -path modules/options/bindata.go ! -path modules/public/bindata.go ! -path modules/templates/bindata.go)
GO_SOURCES += $(GENERATED_GO_DEST)
Expand Down Expand Up @@ -219,6 +221,8 @@ help:
@echo " - lint-swagger lint swagger files"
@echo " - lint-templates lint template files"
@echo " - lint-yaml lint yaml files"
@echo " - lint-spell lint spelling"
@echo " - lint-spell-fix lint spelling and fix issues"
@echo " - checks run various consistency checks"
@echo " - checks-frontend check frontend files"
@echo " - checks-backend check backend files"
Expand Down Expand Up @@ -308,10 +312,6 @@ fmt-check: fmt
exit 1; \
fi

.PHONY: misspell-check
misspell-check:
go run $(MISSPELL_PACKAGE) -error $(GO_DIRS) $(WEB_DIRS)

.PHONY: $(TAGS_EVIDENCE)
$(TAGS_EVIDENCE):
@mkdir -p $(MAKE_EVIDENCE_DIR)
Expand Down Expand Up @@ -351,13 +351,13 @@ checks: checks-frontend checks-backend
checks-frontend: lockfile-check svg-check

.PHONY: checks-backend
checks-backend: tidy-check swagger-check fmt-check misspell-check swagger-validate security-check
checks-backend: tidy-check swagger-check fmt-check swagger-validate security-check

.PHONY: lint
lint: lint-frontend lint-backend
lint: lint-frontend lint-backend lint-spell

.PHONY: lint-fix
lint-fix: lint-frontend-fix lint-backend-fix
lint-fix: lint-frontend-fix lint-backend-fix lint-spell-fix

.PHONY: lint-frontend
lint-frontend: lint-js lint-css
Expand Down Expand Up @@ -395,6 +395,14 @@ lint-swagger: node_modules
lint-md: node_modules
npx markdownlint docs *.md

.PHONY: lint-spell
lint-spell:
@go run $(MISSPELL_PACKAGE) -error $(SPELLCHECK_FILES)

.PHONY: lint-spell-fix
lint-spell-fix:
@go run $(MISSPELL_PACKAGE) -w $(SPELLCHECK_FILES)

.PHONY: lint-go
lint-go:
$(GO) run $(GOLANGCI_LINT_PACKAGE) run
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,17 +97,17 @@ More info: https://docs.gitea.com/installation/install-from-source

./gitea web

NOTE: If you're interested in using our APIs, we have experimental
support with [documentation](https://try.gitea.io/api/swagger).
> [!NOTE]
> If you're interested in using our APIs, we have experimental support with [documentation](https://try.gitea.io/api/swagger).
## Contributing

Expected workflow is: Fork -> Patch -> Push -> Pull Request

NOTES:

1. **YOU MUST READ THE [CONTRIBUTORS GUIDE](CONTRIBUTING.md) BEFORE STARTING TO WORK ON A PULL REQUEST.**
2. If you have found a vulnerability in the project, please write privately to **security@gitea.io**. Thanks!
> [!NOTE]
>
> 1. **YOU MUST READ THE [CONTRIBUTORS GUIDE](CONTRIBUTING.md) BEFORE STARTING TO WORK ON A PULL REQUEST.**
> 2. If you have found a vulnerability in the project, please write privately to **security@gitea.io**. Thanks!
## Translating

Expand Down
12 changes: 7 additions & 5 deletions cmd/serv.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,16 +216,18 @@ func runServ(c *cli.Context) error {
}
}

// LowerCase and trim the repoPath as that's how they are stored.
repoPath = strings.ToLower(strings.TrimSpace(repoPath))

rr := strings.SplitN(repoPath, "/", 2)
if len(rr) != 2 {
return fail(ctx, "Invalid repository path", "Invalid repository path: %v", repoPath)
}

username := strings.ToLower(rr[0])
reponame := strings.ToLower(strings.TrimSuffix(rr[1], ".git"))
username := rr[0]
reponame := strings.TrimSuffix(rr[1], ".git")

// LowerCase and trim the repoPath as that's how they are stored.
// This should be done after splitting the repoPath into username and reponame
// so that username and reponame are not affected.
repoPath = strings.ToLower(strings.TrimSpace(repoPath))

if alphaDashDotPattern.MatchString(reponame) {
return fail(ctx, "Invalid repo name", "Invalid repo name: %s", reponame)
Expand Down
2 changes: 1 addition & 1 deletion custom/conf/app.example.ini
Original file line number Diff line number Diff line change
Expand Up @@ -1044,7 +1044,7 @@ LEVEL = Info
;; List of keywords used in Pull Request comments to automatically reopen a related issue
;REOPEN_KEYWORDS = reopen,reopens,reopened
;;
;; Set default merge style for repository creating, valid options: merge, rebase, rebase-merge, squash
;; Set default merge style for repository creating, valid options: merge, rebase, rebase-merge, squash, fast-forward-only
;DEFAULT_MERGE_STYLE = merge
;;
;; In the default merge message for squash commits include at most this many commits
Expand Down
98 changes: 92 additions & 6 deletions docs/content/administration/backup-and-restore.zh-cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ menu:

Gitea 已经实现了 `dump` 命令可以用来备份所有需要的文件到一个zip压缩文件。该压缩文件可以被用来进行数据恢复。

## 备份一致性

为了确保 Gitea 实例的一致性,在备份期间必须关闭它。

Gitea 包括数据库、文件和 Git 仓库,当它被使用时所有这些都会发生变化。例如,当迁移正在进行时,在数据库中创建一个事务,而 Git 仓库正在被复制。如果备份发生在迁移的中间,Git 仓库可能是不完整的,尽管数据库声称它是完整的,因为它是在之后被转储的。避免这种竞争条件的唯一方法是在备份期间停止 Gitea 实例。

## 备份命令 (`dump`)

先转到git用户的权限: `su git`. 再Gitea目录运行 `./gitea dump`。一般会显示类似如下的输出:
Expand All @@ -34,15 +40,43 @@ Gitea 已经实现了 `dump` 命令可以用来备份所有需要的文件到一

最后生成的 `gitea-dump-1482906742.zip` 文件将会包含如下内容:

* `custom` - 所有保存在 `custom/` 目录下的配置和自定义的文件。
* `data` - 数据目录下的所有内容不包含使用文件session的文件。该目录包含 `attachments`, `avatars`, `lfs`, `indexers`, 如果使用sqlite 还会包含 sqlite 数据库文件。
* `app.ini` - 如果原先存储在默认的 custom/ 目录之外,则是配置文件的可选副本
* `custom/` - 所有保存在 `custom/` 目录下的配置和自定义的文件。
* `data/` - 数据目录(APP_DATA_PATH),如果使用文件会话,则不包括会话。该目录包括 `attachments``avatars``lfs``indexers`、如果使用 SQLite 则包括 SQLite 文件。
* `repos/` - 仓库目录的完整副本。
* `gitea-db.sql` - 数据库dump出来的 SQL。
* `gitea-repo.zip` - Git仓库压缩文件。
* `log/` - Logs文件,如果用作迁移不是必须的。

中间备份文件将会在临时目录进行创建,如果您要重新指定临时目录,可以用 `--tempdir` 参数,或者用 `TMPDIR` 环境变量。

## Restore Command (`restore`)
## 备份数据库

`gitea dump` 创建的 SQL 转储使用 XORM,Gitea 管理员可能更喜欢使用本地的 MySQL 和 PostgreSQL 转储工具。使用 XORM 转储数据库时仍然存在一些问题,可能会导致在尝试恢复时出现问题。

```sh
# mysql
mysqldump -u$USER -p$PASS --database $DATABASE > gitea-db.sql
# postgres
pg_dump -U $USER $DATABASE > gitea-db.sql
```

### 使用Docker (`dump`

在使用 Docker 时,使用 `dump` 命令有一些注意事项。

必须以 `gitea/conf/app.ini` 中指定的 `RUN_USER = <OS_USERNAME>` 执行该命令;并且,为了让备份文件夹的压缩过程能够顺利执行,`docker exec` 命令必须在 `--tempdir` 内部执行。

示例:

```none
docker exec -u <OS_USERNAME> -it -w <--tempdir> $(docker ps -qf 'name=^<NAME_OF_DOCKER_CONTAINER>$') bash -c '/usr/local/bin/gitea dump -c </path/to/app.ini>'
```

\*注意:`--tempdir` 指的是 Gitea 使用的 Docker 环境的临时目录;如果您没有指定自定义的 `--tempdir`,那么 Gitea 将使用 `/tmp` 或 Docker 容器的 `TMPDIR` 环境变量。对于 `--tempdir`,请相应调整您的 `docker exec` 命令选项。

结果应该是一个文件,存储在指定的 `--tempdir` 中,类似于:`gitea-dump-1482906742.zip`

## 恢复命令 (`restore`)

当前还没有恢复命令,恢复需要人工进行。主要是把文件和数据库进行恢复。

Expand All @@ -51,10 +85,10 @@ Gitea 已经实现了 `dump` 命令可以用来备份所有需要的文件到一
```sh
unzip gitea-dump-1610949662.zip
cd gitea-dump-1610949662
mv data/conf/app.ini /etc/gitea/conf/app.ini
mv app.ini /etc/gitea/conf/app.ini
mv data/* /var/lib/gitea/data/
mv log/* /var/lib/gitea/log/
mv repos/* /var/lib/gitea/repositories/
mv repos/* /var/lib/gitea/gitea-repositories/
chown -R gitea:gitea /etc/gitea/conf/app.ini /var/lib/gitea

# mysql
Expand All @@ -66,3 +100,55 @@ psql -U $USER -d $DATABASE < gitea-db.sql

service gitea restart
```

如果安装方式发生了变化(例如 二进制 -> Docker),或者 Gitea 安装到了与之前安装不同的目录,则需要重新生成仓库 Git 钩子。

在 Gitea 运行时,并从 Gitea 二进制文件所在的目录执行:`./gitea admin regenerate hooks`

这样可以确保仓库 Git 钩子中的应用程序和配置文件路径与当前安装一致。如果这些路径没有更新,仓库的 `push` 操作将失败。

### 使用 Docker (`restore`)

在基于 Docker 的 Gitea 实例中,也没有恢复命令的支持。恢复过程与前面描述的步骤相同,但路径不同。

示例:

```sh
# 在容器中打开 bash 会话
docker exec --user git -it 2a83b293548e bash
# 在容器内解压您的备份文件
unzip gitea-dump-1610949662.zip
cd gitea-dump-1610949662
# 恢复 Gitea 数据
mv data/* /data/gitea
# 恢复仓库本身
mv repos/* /data/git/gitea-repositories/
# 调整文件权限
chown -R git:git /data
# 重新生成 Git 钩子
/usr/local/bin/gitea -c '/data/gitea/conf/app.ini' admin regenerate hooks
```

Gitea 容器中的默认用户是 `git`(1000:1000)。请用您的 Gitea 容器 ID 或名称替换 `2a83b293548e`

### 使用 Docker-rootless (`restore`)

在 Docker-rootless 容器中的恢复工作流程只是要使用的目录不同:

```sh
# 在容器中打开 bash 会话
docker exec --user git -it 2a83b293548e bash
# 在容器内解压您的备份文件
unzip gitea-dump-1610949662.zip
cd gitea-dump-1610949662
# 恢复 app.ini
mv data/conf/app.ini /etc/gitea/app.ini
# 恢复 Gitea 数据
mv data/* /var/lib/gitea
# 恢复仓库本身
mv repos/* /var/lib/gitea/git/gitea-repositories
# 调整文件权限
chown -R git:git /etc/gitea/app.ini /var/lib/gitea
# 重新生成 Git 钩子
/usr/local/bin/gitea -c '/etc/gitea/app.ini' admin regenerate hooks
```
Loading

0 comments on commit 82aedae

Please sign in to comment.