mirror of https://github.com/go-gitea/gitea.git
Merge branch 'main' into lunny/project_workflow
commit
c6bd967966
|
|
@ -74,6 +74,9 @@ cpu.out
|
|||
/VERSION
|
||||
/.air
|
||||
/.go-licenses
|
||||
/Dockerfile
|
||||
/Dockerfile.rootless
|
||||
/.venv
|
||||
|
||||
# Files and folders that were previously generated
|
||||
/public/assets/img/webpack
|
||||
|
|
|
|||
|
|
@ -11,25 +11,23 @@ jobs:
|
|||
files-changed:
|
||||
uses: ./.github/workflows/files-changed.yml
|
||||
|
||||
regular:
|
||||
container:
|
||||
if: needs.files-changed.outputs.docker == 'true' || needs.files-changed.outputs.actions == 'true'
|
||||
needs: files-changed
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
- uses: docker/build-push-action@v5
|
||||
- name: Build regular container image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
push: false
|
||||
tags: gitea/gitea:linux-amd64
|
||||
|
||||
rootless:
|
||||
if: needs.files-changed.outputs.docker == 'true' || needs.files-changed.outputs.actions == 'true'
|
||||
needs: files-changed
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
- uses: docker/build-push-action@v5
|
||||
- name: Build rootless container image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
push: false
|
||||
file: Dockerfile.rootless
|
||||
tags: gitea/gitea:linux-amd64
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ jobs:
|
|||
- name: upload binaries to s3
|
||||
run: |
|
||||
aws s3 sync dist/release s3://${{ secrets.AWS_S3_BUCKET }}/gitea/${{ steps.clean_name.outputs.branch }} --no-progress
|
||||
nightly-docker-rootful:
|
||||
nightly-container:
|
||||
runs-on: namespace-profile-gitea-release-docker
|
||||
permissions:
|
||||
packages: write # to publish to ghcr.io
|
||||
|
|
@ -65,10 +65,6 @@ jobs:
|
|||
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
||||
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
|
||||
- run: git fetch --unshallow --quiet --tags --force
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
check-latest: true
|
||||
- uses: docker/setup-qemu-action@v3
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
- name: Get cleaned branch name
|
||||
|
|
@ -76,6 +72,29 @@ jobs:
|
|||
run: |
|
||||
REF_NAME=$(echo "${{ github.ref }}" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\///' -e 's/release\/v//')
|
||||
echo "branch=${REF_NAME}-nightly" >> "$GITHUB_OUTPUT"
|
||||
- uses: docker/metadata-action@v5
|
||||
id: meta
|
||||
with:
|
||||
images: |-
|
||||
gitea/gitea
|
||||
ghcr.io/go-gitea/gitea
|
||||
tags: |
|
||||
type=raw,value=${{ steps.clean_name.outputs.branch }}
|
||||
annotations: |
|
||||
org.opencontainers.image.authors="maintainers@gitea.io"
|
||||
- uses: docker/metadata-action@v5
|
||||
id: meta_rootless
|
||||
with:
|
||||
images: |-
|
||||
gitea/gitea
|
||||
ghcr.io/go-gitea/gitea
|
||||
# each tag below will have the suffix of -rootless
|
||||
flavor: |
|
||||
suffix=-rootless
|
||||
tags: |
|
||||
type=raw,value=${{ steps.clean_name.outputs.branch }}
|
||||
annotations: |
|
||||
org.opencontainers.image.authors="maintainers@gitea.io"
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
|
|
@ -87,57 +106,20 @@ jobs:
|
|||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: fetch go modules
|
||||
run: make vendor
|
||||
- name: build rootful docker image
|
||||
- name: build regular docker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64,linux/riscv64
|
||||
push: true
|
||||
tags: |-
|
||||
gitea/gitea:${{ steps.clean_name.outputs.branch }}
|
||||
ghcr.io/go-gitea/gitea:${{ steps.clean_name.outputs.branch }}
|
||||
nightly-docker-rootless:
|
||||
runs-on: namespace-profile-gitea-release-docker
|
||||
permissions:
|
||||
packages: write # to publish to ghcr.io
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
||||
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
|
||||
- run: git fetch --unshallow --quiet --tags --force
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
check-latest: true
|
||||
- uses: docker/setup-qemu-action@v3
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
- name: Get cleaned branch name
|
||||
id: clean_name
|
||||
run: |
|
||||
REF_NAME=$(echo "${{ github.ref }}" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\///' -e 's/release\/v//')
|
||||
echo "branch=${REF_NAME}-nightly" >> "$GITHUB_OUTPUT"
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Login to GHCR using PAT
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: fetch go modules
|
||||
run: make vendor
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
annotations: ${{ steps.meta.outputs.annotations }}
|
||||
- name: build rootless docker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
platforms: linux/amd64,linux/arm64,linux/riscv64
|
||||
push: true
|
||||
file: Dockerfile.rootless
|
||||
tags: |-
|
||||
gitea/gitea:${{ steps.clean_name.outputs.branch }}-rootless
|
||||
ghcr.io/go-gitea/gitea:${{ steps.clean_name.outputs.branch }}-rootless
|
||||
tags: ${{ steps.meta_rootless.outputs.tags }}
|
||||
annotations: ${{ steps.meta_rootless.outputs.annotations }}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ jobs:
|
|||
gh release create ${{ github.ref_name }} --title ${{ github.ref_name }} --draft --notes-from-tag dist/release/*
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
docker-rootful:
|
||||
container:
|
||||
runs-on: namespace-profile-gitea-release-docker
|
||||
permissions:
|
||||
packages: write # to publish to ghcr.io
|
||||
|
|
@ -88,38 +88,10 @@ jobs:
|
|||
# 1.2.3-rc0
|
||||
tags: |
|
||||
type=semver,pattern={{version}}
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Login to GHCR using PAT
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: build rootful docker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64,linux/riscv64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
docker-rootless:
|
||||
runs-on: namespace-profile-gitea-release-docker
|
||||
permissions:
|
||||
packages: write # to publish to ghcr.io
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
||||
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
|
||||
- run: git fetch --unshallow --quiet --tags --force
|
||||
- uses: docker/setup-qemu-action@v3
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
annotations: |
|
||||
org.opencontainers.image.authors="maintainers@gitea.io"
|
||||
- uses: docker/metadata-action@v5
|
||||
id: meta
|
||||
id: meta_rootless
|
||||
with:
|
||||
images: |-
|
||||
gitea/gitea
|
||||
|
|
@ -131,6 +103,8 @@ jobs:
|
|||
# 1.2.3-rc0
|
||||
tags: |
|
||||
type=semver,pattern={{version}}
|
||||
annotations: |
|
||||
org.opencontainers.image.authors="maintainers@gitea.io"
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
|
|
@ -142,12 +116,20 @@ jobs:
|
|||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: build rootless docker image
|
||||
- name: build regular container image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64,linux/riscv64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
annotations: ${{ steps.meta.outputs.annotations }}
|
||||
- name: build rootless container image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64,linux/riscv64
|
||||
push: true
|
||||
file: Dockerfile.rootless
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
tags: ${{ steps.meta_rootless.outputs.tags }}
|
||||
annotations: ${{ steps.meta_rootless.outputs.annotations }}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ jobs:
|
|||
gh release create ${{ github.ref_name }} --title ${{ github.ref_name }} --notes-from-tag dist/release/*
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
docker-rootful:
|
||||
container:
|
||||
runs-on: namespace-profile-gitea-release-docker
|
||||
permissions:
|
||||
packages: write # to publish to ghcr.io
|
||||
|
|
@ -96,36 +96,10 @@ jobs:
|
|||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Login to GHCR using PAT
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: build rootful docker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64,linux/riscv64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
docker-rootless:
|
||||
runs-on: namespace-profile-gitea-release-docker
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
||||
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
|
||||
- run: git fetch --unshallow --quiet --tags --force
|
||||
- uses: docker/setup-qemu-action@v3
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
annotations: |
|
||||
org.opencontainers.image.authors="maintainers@gitea.io"
|
||||
- uses: docker/metadata-action@v5
|
||||
id: meta
|
||||
id: meta_rootless
|
||||
with:
|
||||
images: |-
|
||||
gitea/gitea
|
||||
|
|
@ -142,6 +116,8 @@ jobs:
|
|||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
annotations: |
|
||||
org.opencontainers.image.authors="maintainers@gitea.io"
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
|
|
@ -153,12 +129,20 @@ jobs:
|
|||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: build rootless docker image
|
||||
- name: build regular container image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64,linux/riscv64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
annotations: ${{ steps.meta.outputs.annotations }}
|
||||
- name: build rootless container image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64,linux/riscv64
|
||||
push: true
|
||||
file: Dockerfile.rootless
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
tags: ${{ steps.meta_rootless.outputs.tags }}
|
||||
annotations: ${{ steps.meta_rootless.outputs.annotations }}
|
||||
|
|
|
|||
|
|
@ -124,3 +124,6 @@ prime/
|
|||
/AGENT.md
|
||||
/CLAUDE.md
|
||||
/llms.txt
|
||||
|
||||
# Ignore worktrees when working on multiple branches
|
||||
.worktrees/
|
||||
|
|
|
|||
38
Dockerfile
38
Dockerfile
|
|
@ -1,8 +1,8 @@
|
|||
# syntax=docker/dockerfile:1
|
||||
# Build stage
|
||||
FROM docker.io/library/golang:1.25-alpine3.22 AS build-env
|
||||
|
||||
ARG GOPROXY
|
||||
ENV GOPROXY=${GOPROXY:-direct}
|
||||
ARG GOPROXY=direct
|
||||
|
||||
ARG GITEA_VERSION
|
||||
ARG TAGS="sqlite sqlite_unlock_notify"
|
||||
|
|
@ -14,22 +14,24 @@ RUN apk --no-cache add \
|
|||
build-base \
|
||||
git \
|
||||
nodejs \
|
||||
npm \
|
||||
&& npm install -g pnpm@10 \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
pnpm
|
||||
|
||||
# Setup repo
|
||||
COPY . ${GOPATH}/src/code.gitea.io/gitea
|
||||
WORKDIR ${GOPATH}/src/code.gitea.io/gitea
|
||||
# Use COPY but not "mount" because some directories like "node_modules" contain platform-depended contents and these directories need to be ignored.
|
||||
# ".git" directory will be mounted later separately for getting version data.
|
||||
# TODO: in the future, maybe we can pre-build the frontend assets on one platform and share them for different platforms, the benefit is that it won't be affected by webpack plugin compatibility problems, then the working directory can be fully mounted and the COPY is not needed.
|
||||
COPY --exclude=.git/ . .
|
||||
|
||||
# Checkout version if set
|
||||
RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \
|
||||
&& make clean-all build
|
||||
# Build gitea, .git mount is required for version data
|
||||
RUN --mount=type=cache,target=/go/pkg/mod \
|
||||
--mount=type=cache,target="/root/.cache/go-build" \
|
||||
--mount=type=cache,target=/root/.local/share/pnpm/store \
|
||||
--mount=type=bind,source=".git/",target=".git/" \
|
||||
make
|
||||
|
||||
# Copy local files
|
||||
COPY docker/root /tmp/local
|
||||
|
||||
# Set permissions
|
||||
# Set permissions for builds that made under windows which strips the executable bit from file
|
||||
RUN chmod 755 /tmp/local/usr/bin/entrypoint \
|
||||
/tmp/local/usr/local/bin/* \
|
||||
/tmp/local/etc/s6/gitea/* \
|
||||
|
|
@ -37,8 +39,7 @@ RUN chmod 755 /tmp/local/usr/bin/entrypoint \
|
|||
/tmp/local/etc/s6/.s6-svscan/* \
|
||||
/go/src/code.gitea.io/gitea/gitea
|
||||
|
||||
FROM docker.io/library/alpine:3.22
|
||||
LABEL maintainer="maintainers@gitea.io"
|
||||
FROM docker.io/library/alpine:3.22 AS gitea
|
||||
|
||||
EXPOSE 22 3000
|
||||
|
||||
|
|
@ -53,8 +54,7 @@ RUN apk --no-cache add \
|
|||
s6 \
|
||||
sqlite \
|
||||
su-exec \
|
||||
gnupg \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
gnupg
|
||||
|
||||
RUN addgroup \
|
||||
-S -g 1000 \
|
||||
|
|
@ -68,6 +68,9 @@ RUN addgroup \
|
|||
git && \
|
||||
echo "git:*" | chpasswd -e
|
||||
|
||||
COPY --from=build-env /tmp/local /
|
||||
COPY --from=build-env /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
|
||||
|
||||
ENV USER=git
|
||||
ENV GITEA_CUSTOM=/data/gitea
|
||||
|
||||
|
|
@ -75,6 +78,3 @@ VOLUME ["/data"]
|
|||
|
||||
ENTRYPOINT ["/usr/bin/entrypoint"]
|
||||
CMD ["/usr/bin/s6-svscan", "/etc/s6"]
|
||||
|
||||
COPY --from=build-env /tmp/local /
|
||||
COPY --from=build-env /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
|
||||
|
|
|
|||
|
|
@ -1,40 +1,39 @@
|
|||
# syntax=docker/dockerfile:1
|
||||
# Build stage
|
||||
FROM docker.io/library/golang:1.25-alpine3.22 AS build-env
|
||||
|
||||
ARG GOPROXY
|
||||
ENV GOPROXY=${GOPROXY:-direct}
|
||||
ARG GOPROXY=direct
|
||||
|
||||
ARG GITEA_VERSION
|
||||
ARG TAGS="sqlite sqlite_unlock_notify"
|
||||
ENV TAGS="bindata timetzdata $TAGS"
|
||||
ARG CGO_EXTRA_CFLAGS
|
||||
|
||||
#Build deps
|
||||
# Build deps
|
||||
RUN apk --no-cache add \
|
||||
build-base \
|
||||
git \
|
||||
nodejs \
|
||||
npm \
|
||||
&& npm install -g pnpm@10 \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
pnpm
|
||||
|
||||
# Setup repo
|
||||
COPY . ${GOPATH}/src/code.gitea.io/gitea
|
||||
WORKDIR ${GOPATH}/src/code.gitea.io/gitea
|
||||
# See the comments in Dockerfile
|
||||
COPY --exclude=.git/ . .
|
||||
|
||||
# Checkout version if set
|
||||
RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \
|
||||
&& make clean-all build
|
||||
# Build gitea, .git mount is required for version data
|
||||
RUN --mount=type=cache,target=/go/pkg/mod \
|
||||
--mount=type=cache,target="/root/.cache/go-build" \
|
||||
--mount=type=cache,target=/root/.local/share/pnpm/store \
|
||||
--mount=type=bind,source=".git/",target=".git/" \
|
||||
make
|
||||
|
||||
# Copy local files
|
||||
COPY docker/rootless /tmp/local
|
||||
|
||||
# Set permissions
|
||||
# Set permissions for builds that made under windows which strips the executable bit from file
|
||||
RUN chmod 755 /tmp/local/usr/local/bin/* \
|
||||
/go/src/code.gitea.io/gitea/gitea
|
||||
|
||||
FROM docker.io/library/alpine:3.22
|
||||
LABEL maintainer="maintainers@gitea.io"
|
||||
FROM docker.io/library/alpine:3.22 AS gitea-rootless
|
||||
|
||||
EXPOSE 2222 3000
|
||||
|
||||
|
|
@ -46,8 +45,7 @@ RUN apk --no-cache add \
|
|||
git \
|
||||
curl \
|
||||
gnupg \
|
||||
openssh-keygen \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
openssh-keygen
|
||||
|
||||
RUN addgroup \
|
||||
-S -g 1000 \
|
||||
|
|
|
|||
14
cmd/serv.go
14
cmd/serv.go
|
|
@ -18,7 +18,7 @@ import (
|
|||
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
||||
git_model "code.gitea.io/gitea/models/git"
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
"code.gitea.io/gitea/models/repo"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
|
|
@ -207,7 +207,7 @@ func runServ(ctx context.Context, c *cli.Command) error {
|
|||
username := repoPathFields[0]
|
||||
reponame := strings.TrimSuffix(repoPathFields[1], ".git") // “the-repo-name" or "the-repo-name.wiki"
|
||||
|
||||
if !repo.IsValidSSHAccessRepoName(reponame) {
|
||||
if !repo_model.IsValidSSHAccessRepoName(reponame) {
|
||||
return fail(ctx, "Invalid repo name", "Invalid repo name: %s", reponame)
|
||||
}
|
||||
|
||||
|
|
@ -253,10 +253,12 @@ func runServ(ctx context.Context, c *cli.Command) error {
|
|||
return fail(ctx, extra.UserMsg, "ServCommand failed: %s", extra.Error)
|
||||
}
|
||||
|
||||
// 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(results.OwnerName + "/" + results.RepoName + ".git")
|
||||
// because the original repoPath maybe redirected, we need to use the returned actual repository information
|
||||
if results.IsWiki {
|
||||
repoPath = repo_model.RelativeWikiPath(results.OwnerName, results.RepoName)
|
||||
} else {
|
||||
repoPath = repo_model.RelativePath(results.OwnerName, results.RepoName)
|
||||
}
|
||||
|
||||
// LFS SSH protocol
|
||||
if verb == git.CmdVerbLfsTransfer {
|
||||
|
|
|
|||
|
|
@ -3914,6 +3914,14 @@ variables.update.success=変数を更新しました。
|
|||
logs.always_auto_scroll=常にログを自動スクロール
|
||||
logs.always_expand_running=常に実行中のログを展開
|
||||
|
||||
general=一般
|
||||
general.enable_actions=Actionsの有効化
|
||||
general.collaborative_owners_management=協力オーナーの管理
|
||||
general.collaborative_owners_management_help=協力オーナーとは、このリポジトリのActionやワークフローに、自身のプライベートリポジトリからアクセスできるユーザーまたは組織のことです。
|
||||
general.add_collaborative_owner=協力オーナーを追加
|
||||
general.collaborative_owner_not_exist=協力オーナーが存在しません。
|
||||
general.remove_collaborative_owner=協力オーナーの削除
|
||||
general.remove_collaborative_owner_desc=協力オーナーを削除すると、そのオーナーのリポジトリはこのリポジトリのActionにアクセスできなくなります。 続行しますか?
|
||||
|
||||
[projects]
|
||||
deleted.display_name=削除されたプロジェクト
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ func (s *SMTPSender) Send(from string, to []string, msg io.WriterTo) error {
|
|||
return fmt.Errorf("failed to issue MAIL command: %w", err)
|
||||
}
|
||||
} else {
|
||||
if err = client.Mail(from); err != nil {
|
||||
if err = client.Mail(fmt.Sprintf("<%s>", from)); err != nil {
|
||||
return fmt.Errorf("failed to issue MAIL command: %w", err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ export default {
|
|||
'./{build,models,modules,routers,services}/**/*.go',
|
||||
'./templates/**/*.tmpl',
|
||||
'./web_src/js/**/*.{ts,js,vue}',
|
||||
].filter(Boolean),
|
||||
].filter(Boolean as unknown as <T>(x: T | boolean) => x is T),
|
||||
blocklist: [
|
||||
// classes that don't work without CSS variables from "@tailwind base" which we don't use
|
||||
'transform', 'shadow', 'ring', 'blur', 'grayscale', 'invert', '!invert', 'filter', '!filter',
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
{{else if eq .status "blocked"}}
|
||||
{{svg "octicon-blocked" $size (printf "text yellow %s" $className)}}
|
||||
{{else if eq .status "running"}}
|
||||
{{svg "gitea-running" $size (printf "text yellow circular-spin %s" $className)}}
|
||||
{{svg "gitea-running" $size (printf "text yellow rotate-clockwise %s" $className)}}
|
||||
{{else}}{{/*failure, unknown*/}}
|
||||
{{svg "octicon-x-circle-fill" $size (printf "text red %s" $className)}}
|
||||
{{end}}
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@
|
|||
{{template "repo/issue/view_content/update_branch_by_merge" $}}
|
||||
{{else if .Issue.PullRequest.IsChecking}}
|
||||
<div class="item">
|
||||
{{svg "octicon-sync" 16 "circular-spin"}}
|
||||
{{svg "gitea-running" 16 "rotate-clockwise"}}
|
||||
{{ctx.Locale.Tr "repo.pulls.is_checking"}}
|
||||
</div>
|
||||
{{else if .Issue.PullRequest.IsAncestor}}
|
||||
|
|
|
|||
|
|
@ -33,15 +33,15 @@ export async function login_user(browser: Browser, workerInfo: WorkerInfo, user:
|
|||
}
|
||||
|
||||
export async function load_logged_in_context(browser: Browser, workerInfo: WorkerInfo, user: string) {
|
||||
let context;
|
||||
try {
|
||||
context = await browser.newContext({storageState: `${ARTIFACTS_PATH}/state-${user}-${workerInfo.workerIndex}.json`});
|
||||
return await browser.newContext({storageState: `${ARTIFACTS_PATH}/state-${user}-${workerInfo.workerIndex}.json`});
|
||||
} catch (err) {
|
||||
if (err.code === 'ENOENT') {
|
||||
throw new Error(`Could not find state for '${user}'. Did you call login_user(browser, workerInfo, '${user}') in test.beforeAll()?`);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
export async function save_visual(page: Page) {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,9 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
auth_model "code.gitea.io/gitea/models/auth"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
|
|
@ -71,3 +73,46 @@ func Test_RepoWikiPages(t *testing.T) {
|
|||
assert.Equal(t, expectedPagePaths[i], pagePath)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_WikiClone(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
username := "user2"
|
||||
reponame := "repo1"
|
||||
wikiPath := username + "/" + reponame + ".wiki.git"
|
||||
keyname := "my-testing-key"
|
||||
baseAPITestContext := NewAPITestContext(t, username, "repo1", auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
|
||||
|
||||
u.Path = wikiPath
|
||||
|
||||
t.Run("Clone HTTP", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
dstLocalPath := t.TempDir()
|
||||
assert.NoError(t, git.Clone(t.Context(), u.String(), dstLocalPath, git.CloneRepoOptions{}))
|
||||
content, err := os.ReadFile(filepath.Join(dstLocalPath, "Home.md"))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "# Home page\n\nThis is the home page!\n", string(content))
|
||||
})
|
||||
|
||||
t.Run("Clone SSH", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
dstLocalPath := t.TempDir()
|
||||
sshURL := createSSHUrl(wikiPath, u)
|
||||
|
||||
withKeyFile(t, keyname, func(keyFile string) {
|
||||
var keyID int64
|
||||
t.Run("CreateUserKey", doAPICreateUserKey(baseAPITestContext, "test-key", keyFile, func(t *testing.T, key api.PublicKey) {
|
||||
keyID = key.ID
|
||||
}))
|
||||
assert.NotZero(t, keyID)
|
||||
|
||||
// Setup clone folder
|
||||
assert.NoError(t, git.Clone(t.Context(), sshURL.String(), dstLocalPath, git.CloneRepoOptions{}))
|
||||
content, err := os.ReadFile(filepath.Join(dstLocalPath, "Home.md"))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "# Home page\n\nThis is the home page!\n", string(content))
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,10 @@ function processAssetsSvgFiles(pattern: string, opts: Opts = {}) {
|
|||
return glob(pattern).map((path) => processAssetsSvgFile(path, opts));
|
||||
}
|
||||
|
||||
function lowercaseKeys(obj: Record<string, any>) {
|
||||
return Object.fromEntries(Object.entries(obj).map(([key, value]) => [key.toLowerCase(), value]));
|
||||
}
|
||||
|
||||
async function processMaterialFileIcons() {
|
||||
const paths = glob('node_modules/material-icon-theme/icons/*.svg');
|
||||
const svgSymbols: Record<string, string> = {};
|
||||
|
|
@ -76,18 +80,30 @@ async function processMaterialFileIcons() {
|
|||
// * https://code.visualstudio.com/docs/languages/identifiers#_known-language-identifiers
|
||||
// * https://github.com/microsoft/vscode/tree/1.98.0/extensions
|
||||
delete iconRules.iconDefinitions;
|
||||
for (const [k, v] of Object.entries(iconRules.fileNames)) iconRules.fileNames[k.toLowerCase()] = v;
|
||||
for (const [k, v] of Object.entries(iconRules.folderNames)) iconRules.folderNames[k.toLowerCase()] = v;
|
||||
for (const [k, v] of Object.entries(iconRules.fileExtensions)) iconRules.fileExtensions[k.toLowerCase()] = v;
|
||||
|
||||
if (iconRules.fileNames) {
|
||||
iconRules.fileNames = lowercaseKeys(iconRules.fileNames);
|
||||
}
|
||||
if (iconRules.folderNames) {
|
||||
iconRules.folderNames = lowercaseKeys(iconRules.folderNames);
|
||||
}
|
||||
if (iconRules.fileExtensions) {
|
||||
iconRules.fileExtensions = lowercaseKeys(iconRules.fileExtensions);
|
||||
}
|
||||
|
||||
// Use VSCode's "Language ID" mapping from its extensions
|
||||
for (const [_, langIdExtMap] of Object.entries(vscodeExtensions)) {
|
||||
for (const [langId, names] of Object.entries(langIdExtMap)) {
|
||||
for (const name of names) {
|
||||
const nameLower = name.toLowerCase();
|
||||
if (nameLower[0] === '.') {
|
||||
iconRules.fileExtensions[nameLower.substring(1)] ??= langId;
|
||||
if (iconRules.fileExtensions) {
|
||||
iconRules.fileExtensions[nameLower.substring(1)] ??= langId;
|
||||
}
|
||||
} else {
|
||||
iconRules.fileNames[nameLower] ??= langId;
|
||||
if (iconRules.fileNames) {
|
||||
iconRules.fileNames[nameLower] ??= langId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
"strictBindCallApply": true,
|
||||
"strictBuiltinIteratorReturn": true,
|
||||
"strictFunctionTypes": true,
|
||||
"strictNullChecks": false,
|
||||
"stripInternal": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"types": [
|
||||
|
|
|
|||
|
|
@ -116,14 +116,12 @@ code.language-math.is-loading::after {
|
|||
animation-timing-function: ease-in-out;
|
||||
}
|
||||
|
||||
/* FIXME: `octicon-sync` is counterclockwise, so this animation is also counterclockwise, it looks somewhat strange.
|
||||
Ideally in the future we should use a better image for clockwise animation. */
|
||||
.circular-spin {
|
||||
animation: circular-spin-keyframes 1s linear infinite;
|
||||
.rotate-clockwise {
|
||||
animation: rotate-clockwise-keyframes 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes circular-spin-keyframes {
|
||||
@keyframes rotate-clockwise-keyframes {
|
||||
100% {
|
||||
transform: rotate(-360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ withDefaults(defineProps<{
|
|||
<SvgIcon name="octicon-stop" class="text grey" :size="size" :class="className" v-else-if="status === 'cancelled'"/>
|
||||
<SvgIcon name="octicon-circle" class="text grey" :size="size" :class="className" v-else-if="status === 'waiting'"/>
|
||||
<SvgIcon name="octicon-blocked" class="text yellow" :size="size" :class="className" v-else-if="status === 'blocked'"/>
|
||||
<SvgIcon name="gitea-running" class="text yellow" :size="size" :class="'circular-spin ' + className" v-else-if="status === 'running'"/>
|
||||
<SvgIcon name="gitea-running" class="text yellow" :size="size" :class="'rotate-clockwise ' + className" v-else-if="status === 'running'"/>
|
||||
<SvgIcon name="octicon-x-circle-fill" class="text red" :size="size" v-else/><!-- failure, unknown -->
|
||||
</span>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -608,7 +608,7 @@ export default defineComponent({
|
|||
<!-- If the job is done and the job step log is loaded for the first time, show the loading icon
|
||||
currentJobStepsStates[i].cursor === null means the log is loaded for the first time
|
||||
-->
|
||||
<SvgIcon v-if="isDone(run.status) && currentJobStepsStates[i].expanded && currentJobStepsStates[i].cursor === null" name="octicon-sync" class="tw-mr-2 circular-spin"/>
|
||||
<SvgIcon v-if="isDone(run.status) && currentJobStepsStates[i].expanded && currentJobStepsStates[i].cursor === null" name="gitea-running" class="tw-mr-2 rotate-clockwise"/>
|
||||
<SvgIcon v-else :name="currentJobStepsStates[i].expanded ? 'octicon-chevron-down': 'octicon-chevron-right'" :class="['tw-mr-2', !isExpandable(jobStep.status) && 'tw-invisible']"/>
|
||||
<ActionRunStatus :status="jobStep.status" class="tw-mr-2"/>
|
||||
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ const options: ChartOptions<'line'> = {
|
|||
<div class="tw-flex ui segment main-graph">
|
||||
<div v-if="isLoading || errorText !== ''" class="tw-m-auto">
|
||||
<div v-if="isLoading">
|
||||
<SvgIcon name="octicon-sync" class="tw-mr-2 circular-spin"/>
|
||||
<SvgIcon name="gitea-running" class="tw-mr-2 rotate-clockwise"/>
|
||||
{{ locale.loadingInfo }}
|
||||
</div>
|
||||
<div v-else class="text red">
|
||||
|
|
|
|||
|
|
@ -381,7 +381,7 @@ export default defineComponent({
|
|||
<div class="tw-flex ui segment main-graph">
|
||||
<div v-if="isLoading || errorText !== ''" class="tw-m-auto">
|
||||
<div v-if="isLoading">
|
||||
<SvgIcon name="octicon-sync" class="tw-mr-2 circular-spin"/>
|
||||
<SvgIcon name="gitea-running" class="tw-mr-2 rotate-clockwise"/>
|
||||
{{ locale.loadingInfo }}
|
||||
</div>
|
||||
<div v-else class="text red">
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ const options: ChartOptions<'bar'> = {
|
|||
<div class="tw-flex ui segment main-graph">
|
||||
<div v-if="isLoading || errorText !== ''" class="tw-m-auto">
|
||||
<div v-if="isLoading">
|
||||
<SvgIcon name="octicon-sync" class="tw-mr-2 circular-spin"/>
|
||||
<SvgIcon name="gitea-running" class="tw-mr-2 rotate-clockwise"/>
|
||||
{{ locale.loadingInfo }}
|
||||
</div>
|
||||
<div v-else class="text red">
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ const onItemClick = (e: MouseEvent) => {
|
|||
@click.stop="onItemClick"
|
||||
>
|
||||
<div v-if="item.entryMode === 'tree'" class="item-toggle">
|
||||
<SvgIcon v-if="isLoading" name="octicon-sync" class="circular-spin"/>
|
||||
<SvgIcon v-if="isLoading" name="gitea-running" class="rotate-clockwise"/>
|
||||
<SvgIcon v-else :name="collapsed ? 'octicon-chevron-right' : 'octicon-chevron-down'" @click.stop.prevent="doLoadChildren"/>
|
||||
</div>
|
||||
<div class="item-content">
|
||||
|
|
|
|||
|
|
@ -261,7 +261,7 @@ export function initRepoPullRequestReview() {
|
|||
if (commentDiv) {
|
||||
// get the name of the parent id
|
||||
const groupID = commentDiv.closest('div[id^="code-comments-"]')?.getAttribute('id');
|
||||
if (groupID && groupID.startsWith('code-comments-')) {
|
||||
if (groupID?.startsWith('code-comments-')) {
|
||||
const id = groupID.slice(14);
|
||||
const ancestorDiffBox = commentDiv.closest<HTMLElement>('.diff-file-box');
|
||||
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ function initRepoSettingsBranches() {
|
|||
// show the `Matched` mark for the status checks that match the pattern
|
||||
const markMatchedStatusChecks = () => {
|
||||
const patterns = (document.querySelector<HTMLTextAreaElement>('#status_check_contexts').value || '').split(/[\r\n]+/);
|
||||
const validPatterns = patterns.map((item) => item.trim()).filter(Boolean);
|
||||
const validPatterns = patterns.map((item) => item.trim()).filter(Boolean as unknown as <T>(x: T | boolean) => x is T);
|
||||
const marks = document.querySelectorAll('.status-check-matched-mark');
|
||||
|
||||
for (const el of marks) {
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ export function svg(name: SvgName, size = 16, classNames?: string | string[]): s
|
|||
svgNode.setAttribute('width', String(size));
|
||||
svgNode.setAttribute('height', String(size));
|
||||
}
|
||||
if (className) svgNode.classList.add(...className.split(/\s+/).filter(Boolean));
|
||||
if (className) svgNode.classList.add(...className.split(/\s+/).filter(Boolean as unknown as <T>(x: T | boolean) => x is T));
|
||||
return serializeXml(svgNode);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ const isProduction = env.NODE_ENV !== 'development';
|
|||
// false - all disabled
|
||||
let sourceMaps;
|
||||
if ('ENABLE_SOURCEMAP' in env) {
|
||||
sourceMaps = ['true', 'false'].includes(env.ENABLE_SOURCEMAP) ? env.ENABLE_SOURCEMAP : 'reduced';
|
||||
sourceMaps = ['true', 'false'].includes(env.ENABLE_SOURCEMAP || '') ? env.ENABLE_SOURCEMAP : 'reduced';
|
||||
} else {
|
||||
sourceMaps = isProduction ? 'reduced' : 'true';
|
||||
}
|
||||
|
|
@ -95,7 +95,7 @@ export default {
|
|||
path: fileURLToPath(new URL('public/assets', import.meta.url)),
|
||||
filename: () => 'js/[name].js',
|
||||
chunkFilename: ({chunk}) => {
|
||||
const language = (/monaco.*languages?_.+?_(.+?)_/.exec(String(chunk.id)) || [])[1];
|
||||
const language = (/monaco.*languages?_.+?_(.+?)_/.exec(String(chunk?.id)) || [])[1];
|
||||
return `js/${language ? `monaco-language-${language.toLowerCase()}` : `[name]`}.[contenthash:8].js`;
|
||||
},
|
||||
},
|
||||
|
|
@ -270,7 +270,7 @@ export default {
|
|||
excludeAssets: [
|
||||
/^js\/monaco-language-.+\.js$/,
|
||||
!isProduction && /^licenses.txt$/,
|
||||
].filter(Boolean),
|
||||
].filter(Boolean as unknown as <T>(x: T | boolean) => x is T),
|
||||
groupAssetsByChunk: false,
|
||||
groupAssetsByEmitStatus: false,
|
||||
groupAssetsByInfo: false,
|
||||
|
|
|
|||
Loading…
Reference in New Issue