mirror of
https://codeberg.org/forgejo/forgejo
synced 2024-11-25 11:16:11 +01:00
Compare commits
67 commits
848685d68d
...
2e43bd580d
Author | SHA1 | Date | |
---|---|---|---|
2e43bd580d | |||
e8021f281f | |||
cd26466622 | |||
ba3df01314 | |||
e00eb6d9b3 | |||
861c05c2f3 | |||
33b4f02d90 | |||
f817d97f85 | |||
e603cd3dcf | |||
805c72c9ce | |||
22e63701a8 | |||
69894fbc82 | |||
225d6f7ab7 | |||
7e6ccb52ff | |||
5d05f7f9f6 | |||
aa3a7249f7 | |||
df4099247f | |||
929b75ee39 | |||
a427f8dae5 | |||
984081f08d | |||
98dbce5e14 | |||
b4fb5f64c6 | |||
59d0824a3d | |||
57069811d1 | |||
b6ab473395 | |||
08da63cc4d | |||
43a54a64e3 | |||
77506c6f6c | |||
8e9b6817bc | |||
23efd9d278 | |||
692929b628 | |||
caad931385 | |||
b693611b35 | |||
5d09023f13 | |||
0e6fd0d1c1 | |||
49d7663929 | |||
1df06e3f39 | |||
14f6fcf448 | |||
80d48621cd | |||
6c771a311b | |||
7711db0a71 | |||
5574968ecb | |||
b9d91694af | |||
62f995203a | |||
d68a613ba8 | |||
07ba4d9f87 | |||
461d8b53c2 | |||
075c4c89ee | |||
1167d523c4 | |||
b60a7c3358 | |||
4674aea25b | |||
eba9c0ce48 | |||
c8ba17c73f | |||
2bdab948cb | |||
ad98ea63ee | |||
49eb168677 | |||
9c869b10b5 | |||
b8270240bf | |||
edfb57e699 | |||
c08d263a19 | |||
930e38d010 | |||
5374d29aa9 | |||
d971dfbae1 | |||
885cc32b14 | |||
2c3da59e27 | |||
2d343f8987 | |||
3793ec4d14 |
21
.forgejo/cascading-pr-end-to-end
Executable file
21
.forgejo/cascading-pr-end-to-end
Executable file
|
@ -0,0 +1,21 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
end_to_end=$1
|
||||||
|
end_to_end_pr=$2
|
||||||
|
forgejo=$3
|
||||||
|
forgejo_pr=$4
|
||||||
|
|
||||||
|
head_url=$(jq --raw-output .head.repo.html_url < $forgejo_pr)
|
||||||
|
test "$head_url" != null
|
||||||
|
branch=$(jq --raw-output .head.ref < $forgejo_pr)
|
||||||
|
test "$branch" != null
|
||||||
|
cd $end_to_end
|
||||||
|
echo $head_url $branch 7.0.0+0-gitea-1.22.0 > forgejo/sources/1.22
|
||||||
|
date > last-upgrade
|
||||||
|
|
||||||
|
base_url=$(jq --raw-output .base.repo.html_url < $forgejo_pr)
|
||||||
|
test "$base_url" != null
|
||||||
|
test "$GITHUB_RUN_NUMBER"
|
||||||
|
echo $base_url/actions/runs/$GITHUB_RUN_NUMBER/artifacts/forgejo > forgejo/binary-url
|
12
.forgejo/cascading-release-end-to-end
Executable file
12
.forgejo/cascading-release-end-to-end
Executable file
|
@ -0,0 +1,12 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
end_to_end=$1
|
||||||
|
end_to_end_pr=$2
|
||||||
|
forgejo=$3
|
||||||
|
forgejo_ref=$4
|
||||||
|
|
||||||
|
cd $end_to_end
|
||||||
|
date > last-upgrade
|
||||||
|
echo $FORGEJO_BINARY > forgejo/binary-url
|
3
.forgejo/testdata/build-release/Dockerfile
vendored
Normal file
3
.forgejo/testdata/build-release/Dockerfile
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
FROM public.ecr.aws/docker/library/alpine:3.18
|
||||||
|
RUN mkdir -p /app/gitea
|
||||||
|
RUN ( echo '#!/bin/sh' ; echo "echo forgejo v1.2.3" ) > /app/gitea/gitea ; chmod +x /app/gitea/gitea
|
5
.forgejo/testdata/build-release/Makefile
vendored
Normal file
5
.forgejo/testdata/build-release/Makefile
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
VERSION ?= $(shell cat VERSION 2>/dev/null)
|
||||||
|
sources-tarbal:
|
||||||
|
mkdir -p dist/release
|
||||||
|
echo $(VERSION) > VERSION
|
||||||
|
sources=forgejo-src-$(VERSION).tar.gz ; tar --transform 's|^./|forgejo-src-$(VERSION)/|' -czf dist/release/forgejo-src-$(VERSION).tar.gz . ; cd dist/release ; shasum -a 256 $$sources > $$sources.sha256
|
0
.forgejo/testdata/build-release/modules/public/bindata.go
vendored
Normal file
0
.forgejo/testdata/build-release/modules/public/bindata.go
vendored
Normal file
0
.forgejo/testdata/build-release/public/assets/css/placeholder
vendored
Normal file
0
.forgejo/testdata/build-release/public/assets/css/placeholder
vendored
Normal file
0
.forgejo/testdata/build-release/public/assets/fonts/placeholder
vendored
Normal file
0
.forgejo/testdata/build-release/public/assets/fonts/placeholder
vendored
Normal file
0
.forgejo/testdata/build-release/public/assets/js/placeholder
vendored
Normal file
0
.forgejo/testdata/build-release/public/assets/js/placeholder
vendored
Normal file
107
.forgejo/workflows/build-release-integration.yml
Normal file
107
.forgejo/workflows/build-release-integration.yml
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
name: Integration tests for the release process
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- Makefile
|
||||||
|
- Dockerfile
|
||||||
|
- Dockerfile.rootless
|
||||||
|
- docker/**
|
||||||
|
- .forgejo/workflows/build-release.yml
|
||||||
|
- .forgejo/workflows/build-release-integration.yml
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- Makefile
|
||||||
|
- Dockerfile
|
||||||
|
- Dockerfile.rootless
|
||||||
|
- docker/**
|
||||||
|
- .forgejo/workflows/build-release.yml
|
||||||
|
- .forgejo/workflows/build-release-integration.yml
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release-simulation:
|
||||||
|
if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
|
||||||
|
runs-on: self-hosted
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- id: forgejo
|
||||||
|
uses: https://code.forgejo.org/actions/setup-forgejo@v1
|
||||||
|
with:
|
||||||
|
user: root
|
||||||
|
password: admin1234
|
||||||
|
image-version: 1.21
|
||||||
|
lxc-ip-prefix: 10.0.9
|
||||||
|
|
||||||
|
- name: publish the forgejo release
|
||||||
|
run: |
|
||||||
|
set -x
|
||||||
|
|
||||||
|
version=1.2.3
|
||||||
|
cat > /etc/docker/daemon.json <<EOF
|
||||||
|
{
|
||||||
|
"insecure-registries" : ["${{ steps.forgejo.outputs.host-port }}"]
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
systemctl restart docker
|
||||||
|
|
||||||
|
apt-get install -qq -y xz-utils
|
||||||
|
|
||||||
|
dir=$(mktemp -d)
|
||||||
|
trap "rm -fr $dir" EXIT
|
||||||
|
|
||||||
|
url=http://root:admin1234@${{ steps.forgejo.outputs.host-port }}
|
||||||
|
export FORGEJO_RUNNER_LOGS="${{ steps.forgejo.outputs.runner-logs }}"
|
||||||
|
|
||||||
|
#
|
||||||
|
# Create a new project with a fake forgejo and the release workflow only
|
||||||
|
#
|
||||||
|
cp -a .forgejo/testdata/build-release/* $dir
|
||||||
|
mkdir -p $dir/.forgejo/workflows
|
||||||
|
cp .forgejo/workflows/build-release.yml $dir/.forgejo/workflows
|
||||||
|
cp $dir/Dockerfile $dir/Dockerfile.rootless
|
||||||
|
|
||||||
|
forgejo-test-helper.sh push $dir $url root forgejo
|
||||||
|
sha=$(forgejo-test-helper.sh branch_tip $url root/forgejo main)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Push a tag to trigger the release workflow and wait for it to complete
|
||||||
|
#
|
||||||
|
forgejo-curl.sh api_json --data-raw '{"tag_name": "v'$version'", "target": "'$sha'"}' $url/api/v1/repos/root/forgejo/tags
|
||||||
|
forgejo-curl.sh api_json -X PUT --data-raw '{"data":"${{ steps.forgejo.outputs.token }}"}' $url/api/v1/repos/root/forgejo/actions/secrets/TOKEN
|
||||||
|
forgejo-curl.sh api_json -X PUT --data-raw '{"data":"root"}' $url/api/v1/repos/root/forgejo/actions/secrets/DOER
|
||||||
|
LOOPS=180 forgejo-test-helper.sh wait_success "$url" root/forgejo $sha
|
||||||
|
|
||||||
|
#
|
||||||
|
# uncomment to see the logs even when everything is reported to be working ok
|
||||||
|
#
|
||||||
|
#cat $FORGEJO_RUNNER_LOGS
|
||||||
|
|
||||||
|
#
|
||||||
|
# Minimal sanity checks. e2e test is for the setup-forgejo
|
||||||
|
# action and the infrastructure playbook. Since the binary
|
||||||
|
# is a script shell it does not test the sanity of the cross
|
||||||
|
# build, only the sanity of the naming of the binaries.
|
||||||
|
#
|
||||||
|
for arch in amd64 arm64 arm-6 ; do
|
||||||
|
binary=forgejo-$version-linux-$arch
|
||||||
|
for suffix in '' '.xz' ; do
|
||||||
|
curl --fail -L -sS $url/root/forgejo/releases/download/v$version/$binary$suffix > $binary$suffix
|
||||||
|
if test "$suffix" = .xz ; then
|
||||||
|
unxz --keep $binary$suffix
|
||||||
|
fi
|
||||||
|
chmod +x $binary
|
||||||
|
./$binary --version | grep $version
|
||||||
|
curl --fail -L -sS $url/root/forgejo/releases/download/v$version/$binary$suffix.sha256 > $binary$suffix.sha256
|
||||||
|
shasum -a 256 --check $binary$suffix.sha256
|
||||||
|
rm $binary$suffix
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
sources=forgejo-src-$version.tar.gz
|
||||||
|
curl --fail -L -sS $url/root/forgejo/releases/download/v$version/$sources > $sources
|
||||||
|
curl --fail -L -sS $url/root/forgejo/releases/download/v$version/$sources.sha256 > $sources.sha256
|
||||||
|
shasum -a 256 --check $sources.sha256
|
||||||
|
|
||||||
|
docker pull ${{ steps.forgejo.outputs.host-port }}/root/forgejo:$version
|
||||||
|
docker pull ${{ steps.forgejo.outputs.host-port }}/root/forgejo:$version-rootless
|
169
.forgejo/workflows/build-release.yml
Normal file
169
.forgejo/workflows/build-release.yml
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
#
|
||||||
|
# See also https://forgejo.org/docs/next/developer/RELEASE/#release-process
|
||||||
|
#
|
||||||
|
# https://codeberg.org/forgejo-integration/forgejo
|
||||||
|
#
|
||||||
|
# Builds a release from a codeberg.org/forgejo-integration tag
|
||||||
|
#
|
||||||
|
# vars.ROLE: forgejo-integration
|
||||||
|
#
|
||||||
|
# secrets.DOER: forgejo-experimental-ci
|
||||||
|
# secrets.TOKEN: <generated from codeberg.org/forgejo-experimental-ci> scope read:user, write:repository, write:package
|
||||||
|
#
|
||||||
|
# secrets.CASCADE_ORIGIN_TOKEN: <generated from codeberg.org/forgejo-experimental-ci> scope read:user, write:repository, write:issue
|
||||||
|
# secrets.CASCADE_DESTINATION_TOKEN: <generated from code.forgejo.org/forgejo-ci> scope read:user, write:repository, write:issue
|
||||||
|
# vars.CASCADE_DESTINATION_DOER: forgejo-ci
|
||||||
|
#
|
||||||
|
name: Build release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags: 'v*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
runs-on: self-hosted
|
||||||
|
# root is used for testing, allow it
|
||||||
|
if: vars.ROLE == 'forgejo-integration' || github.repository_owner == 'root'
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Sanitize the name of the repository
|
||||||
|
id: repository
|
||||||
|
run: |
|
||||||
|
repository="${{ github.repository }}"
|
||||||
|
echo "value=${repository##*/}" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- uses: https://code.forgejo.org/actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
|
||||||
|
- uses: https://code.forgejo.org/actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
go-version: ">=1.21"
|
||||||
|
check-latest: true
|
||||||
|
|
||||||
|
- name: version from ref_name
|
||||||
|
id: tag-version
|
||||||
|
run: |
|
||||||
|
version="${{ github.ref_name }}"
|
||||||
|
version=${version##*v}
|
||||||
|
echo "value=$version" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: release notes
|
||||||
|
id: release-notes
|
||||||
|
run: |
|
||||||
|
anchor=${{ steps.tag-version.outputs.value }}
|
||||||
|
anchor=${anchor//./-}
|
||||||
|
cat >> "$GITHUB_OUTPUT" <<EOF
|
||||||
|
value<<ENDVAR
|
||||||
|
See https://codeberg.org/forgejo/forgejo/src/branch/forgejo/RELEASE-NOTES.md#$anchor
|
||||||
|
ENDVAR
|
||||||
|
EOF
|
||||||
|
|
||||||
|
- name: Build sources
|
||||||
|
run: |
|
||||||
|
set -x
|
||||||
|
apt-get -qq install -y make
|
||||||
|
version=${{ steps.tag-version.outputs.value }}
|
||||||
|
#
|
||||||
|
# Make sure all files are owned by the current user.
|
||||||
|
# When run as root `npx webpack` will assume the identity
|
||||||
|
# of the owner of the current working directory and may
|
||||||
|
# fail to create files if some sub-directories are not owned
|
||||||
|
# by the same user.
|
||||||
|
#
|
||||||
|
# Binaries:
|
||||||
|
# Node: 18.17.0 - /usr/local/node-v18.17.0-linux-x64/bin/node
|
||||||
|
# npm: 9.6.7 - /usr/local/node-v18.17.0-linux-x64/bin/npm
|
||||||
|
# Packages:
|
||||||
|
# add-asset-webpack-plugin: 2.0.1 => 2.0.1
|
||||||
|
# css-loader: 6.8.1 => 6.8.1
|
||||||
|
# esbuild-loader: 3.0.1 => 3.0.1
|
||||||
|
# license-checker-webpack-plugin: 0.2.1 => 0.2.1
|
||||||
|
# monaco-editor-webpack-plugin: 7.0.1 => 7.0.1
|
||||||
|
# vue-loader: 17.2.2 => 17.2.2
|
||||||
|
# webpack: 5.87.0 => 5.87.0
|
||||||
|
# webpack-cli: 5.1.4 => 5.1.4
|
||||||
|
#
|
||||||
|
chown -R $(id -u) .
|
||||||
|
make VERSION=$version TAGS=bindata sources-tarbal
|
||||||
|
mv dist/release release
|
||||||
|
|
||||||
|
(
|
||||||
|
tmp=$(mktemp -d)
|
||||||
|
tar --directory $tmp -zxvf release/*$version*.tar.gz
|
||||||
|
cd $tmp/*
|
||||||
|
#
|
||||||
|
# Verify `make frontend` files are available
|
||||||
|
#
|
||||||
|
test -d public/assets/css
|
||||||
|
test -d public/assets/fonts
|
||||||
|
test -d public/assets/js
|
||||||
|
#
|
||||||
|
# Verify `make generate` files are available
|
||||||
|
#
|
||||||
|
test -f modules/public/bindata.go
|
||||||
|
#
|
||||||
|
# Sanity check to verify that the source tarbal knows the
|
||||||
|
# version and is able to rebuild itself from it.
|
||||||
|
#
|
||||||
|
# When in sources the version is determined with git.
|
||||||
|
# When in the tarbal the version is determined from a VERSION file.
|
||||||
|
#
|
||||||
|
make sources-tarbal
|
||||||
|
tarbal=$(echo dist/release/*$version*.tar.gz)
|
||||||
|
if ! test -f $tarbal ; then
|
||||||
|
echo $tarbal does not exist
|
||||||
|
find dist release
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
)
|
||||||
|
|
||||||
|
- name: build container & release
|
||||||
|
if: ${{ secrets.TOKEN != '' }}
|
||||||
|
uses: https://code.forgejo.org/forgejo/forgejo-build-publish/build@v1
|
||||||
|
with:
|
||||||
|
forgejo: "${{ env.GITHUB_SERVER_URL }}"
|
||||||
|
owner: "${{ env.GITHUB_REPOSITORY_OWNER }}"
|
||||||
|
repository: "${{ steps.repository.outputs.value }}"
|
||||||
|
doer: "${{ secrets.DOER }}"
|
||||||
|
tag-version: "${{ steps.tag-version.outputs.value }}"
|
||||||
|
token: "${{ secrets.TOKEN }}"
|
||||||
|
platforms: linux/amd64,linux/arm64,linux/arm/v6
|
||||||
|
release-notes: "${{ steps.release-notes.outputs.value }}"
|
||||||
|
binary-name: forgejo
|
||||||
|
binary-path: /app/gitea/gitea
|
||||||
|
verbose: ${{ vars.VERBOSE || 'false' }}
|
||||||
|
|
||||||
|
- name: build rootless container
|
||||||
|
if: ${{ secrets.TOKEN != '' }}
|
||||||
|
uses: https://code.forgejo.org/forgejo/forgejo-build-publish/build@v1
|
||||||
|
with:
|
||||||
|
forgejo: "${{ env.GITHUB_SERVER_URL }}"
|
||||||
|
owner: "${{ env.GITHUB_REPOSITORY_OWNER }}"
|
||||||
|
repository: "${{ steps.repository.outputs.value }}"
|
||||||
|
doer: "${{ secrets.DOER }}"
|
||||||
|
tag-version: "${{ steps.tag-version.outputs.value }}"
|
||||||
|
token: "${{ secrets.TOKEN }}"
|
||||||
|
platforms: linux/amd64,linux/arm64,linux/arm/v6
|
||||||
|
suffix: -rootless
|
||||||
|
dockerfile: Dockerfile.rootless
|
||||||
|
verbose: ${{ vars.VERBOSE || 'false' }}
|
||||||
|
|
||||||
|
- name: end-to-end tests
|
||||||
|
if: ${{ secrets.TOKEN != '' && vars.ROLE == 'forgejo-integration' }}
|
||||||
|
uses: https://code.forgejo.org/actions/cascading-pr@v1
|
||||||
|
with:
|
||||||
|
origin-url: ${{ env.GITHUB_SERVER_URL }}
|
||||||
|
origin-repo: ${{ github.repository }}
|
||||||
|
origin-token: ${{ secrets.CASCADE_ORIGIN_TOKEN }}
|
||||||
|
origin-ref: refs/heads/forgejo
|
||||||
|
destination-url: https://code.forgejo.org
|
||||||
|
destination-fork-repo: ${{ vars.CASCADE_DESTINATION_DOER }}/end-to-end
|
||||||
|
destination-repo: forgejo/end-to-end
|
||||||
|
destination-branch: forgejo-pr
|
||||||
|
destination-token: ${{ secrets.CASCADE_DESTINATION_TOKEN }}
|
||||||
|
update: .forgejo/cascading-release-end-to-end
|
||||||
|
env:
|
||||||
|
FORGEJO_BINARY: "${{ env.GITHUB_SERVER_URL }}/${{ github.repository }}/releases/download/v${{ steps.tag-version.outputs.value }}/forgejo-${{ steps.tag-version.outputs.value }}-linux-amd64"
|
83
.forgejo/workflows/cascade-setup-end-to-end.yml
Normal file
83
.forgejo/workflows/cascade-setup-end-to-end.yml
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
on:
|
||||||
|
pull_request_target:
|
||||||
|
types:
|
||||||
|
- labeled
|
||||||
|
|
||||||
|
env:
|
||||||
|
FEATURE_BRANCHES: "privacy i18n moderation branding dependency"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
info:
|
||||||
|
if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
|
||||||
|
runs-on: docker
|
||||||
|
container:
|
||||||
|
image: node:20-bookworm
|
||||||
|
steps:
|
||||||
|
- name: event
|
||||||
|
run: |
|
||||||
|
echo github.event.pull_request.head.repo.fork = ${{ github.event.pull_request.head.repo.fork }}
|
||||||
|
echo github.event.action = ${{ github.event.action }}
|
||||||
|
echo github.event.pull_request.merged = ${{ github.event.pull_request.merged }}
|
||||||
|
echo github.event.pull_request.labels.*.name
|
||||||
|
cat <<'EOF'
|
||||||
|
${{ toJSON(github.event.pull_request.labels.*.name) }}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
build:
|
||||||
|
if: ${{ !startsWith(vars.ROLE, 'forgejo-') && github.event.action == 'label_updated' && contains(github.event.pull_request.labels.*.name, 'run-end-to-end-tests') }}
|
||||||
|
runs-on: docker
|
||||||
|
container:
|
||||||
|
image: 'docker.io/node:20-bookworm'
|
||||||
|
steps:
|
||||||
|
- uses: https://code.forgejo.org/actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: '0'
|
||||||
|
show-progress: 'false'
|
||||||
|
- name: adduser forgejo
|
||||||
|
run: |
|
||||||
|
git config --add safe.directory '*'
|
||||||
|
git config user.email "you@example.com"
|
||||||
|
git config user.name "Your Name"
|
||||||
|
adduser --quiet --comment forgejo --disabled-password forgejo
|
||||||
|
chown -R forgejo:forgejo .
|
||||||
|
- name: merge feature branches
|
||||||
|
run: |
|
||||||
|
su forgejo -c 'set -ex ; for b in ${{ env.FEATURE_BRANCHES }} ; do git merge -m $b origin/forgejo-$b ; done'
|
||||||
|
- uses: https://code.forgejo.org/actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
go-version: ">=1.21"
|
||||||
|
- name: make deps-backend
|
||||||
|
run: |
|
||||||
|
su forgejo -c 'make deps-backend'
|
||||||
|
- name: make forgejo
|
||||||
|
run: |
|
||||||
|
su forgejo -c 'make generate-backend static-executable && ln gitea forgejo'
|
||||||
|
env:
|
||||||
|
TAGS: bindata sqlite sqlite_unlock_notify
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: forgejo
|
||||||
|
path: forgejo
|
||||||
|
|
||||||
|
cascade:
|
||||||
|
if: ${{ !startsWith(vars.ROLE, 'forgejo-') && github.event.action == 'label_updated' && contains(github.event.pull_request.labels.*.name, 'run-end-to-end-tests') }}
|
||||||
|
needs: [build]
|
||||||
|
runs-on: docker
|
||||||
|
container:
|
||||||
|
image: node:20-bookworm
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/cascading-pr@v1
|
||||||
|
with:
|
||||||
|
origin-url: ${{ env.GITHUB_SERVER_URL }}
|
||||||
|
origin-repo: ${{ github.repository }}
|
||||||
|
origin-token: ${{ secrets.END_TO_END_CASCADING_PR_ORIGIN }}
|
||||||
|
origin-pr: ${{ github.event.pull_request.number }}
|
||||||
|
destination-url: https://code.forgejo.org
|
||||||
|
destination-fork-repo: cascading-pr/end-to-end
|
||||||
|
destination-repo: forgejo/end-to-end
|
||||||
|
destination-branch: forgejo-pr
|
||||||
|
destination-token: ${{ secrets.END_TO_END_CASCADING_PR_DESTINATION }}
|
||||||
|
close-merge: true
|
||||||
|
update: .forgejo/cascading-pr-end-to-end
|
37
.forgejo/workflows/e2e.yml
Normal file
37
.forgejo/workflows/e2e.yml
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
name: e2e
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- Makefile
|
||||||
|
- .forgejo/workflows/e2e.yml
|
||||||
|
- tests/e2e/**
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test-e2e:
|
||||||
|
if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
|
||||||
|
runs-on: docker
|
||||||
|
container:
|
||||||
|
image: 'docker.io/node:20-bookworm'
|
||||||
|
steps:
|
||||||
|
- uses: https://code.forgejo.org/actions/checkout@v4
|
||||||
|
- uses: https://code.forgejo.org/actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
go-version: "~1.21"
|
||||||
|
check-latest: true
|
||||||
|
- run: |
|
||||||
|
apt-get -qq update
|
||||||
|
apt-get -qq install -q sudo
|
||||||
|
sed -i -e 's/%sudo.*/%sudo ALL=(ALL:ALL) NOPASSWD:ALL/' /etc/sudoers
|
||||||
|
git config --add safe.directory '*'
|
||||||
|
adduser --quiet --comment forgejo --disabled-password forgejo
|
||||||
|
adduser forgejo sudo
|
||||||
|
chown -R forgejo:forgejo .
|
||||||
|
- run: |
|
||||||
|
su forgejo -c 'make deps-frontend frontend deps-backend'
|
||||||
|
- run: |
|
||||||
|
su forgejo -c 'make generate test-e2e-sqlite'
|
||||||
|
timeout-minutes: 40
|
||||||
|
env:
|
||||||
|
DEPS_PLAYWRIGHT: 1
|
||||||
|
USE_REPO_TEST_DIR: 1
|
27
.forgejo/workflows/mirror.yml
Normal file
27
.forgejo/workflows/mirror.yml
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
name: mirror
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'forgejo'
|
||||||
|
- 'v*/forgejo'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
mirror:
|
||||||
|
if: ${{ secrets.MIRROR_TOKEN != '' }}
|
||||||
|
runs-on: docker
|
||||||
|
container:
|
||||||
|
image: 'docker.io/node:20-bookworm'
|
||||||
|
steps:
|
||||||
|
- name: git push {v*/,}forgejo
|
||||||
|
run: |
|
||||||
|
git init --bare .
|
||||||
|
git remote add origin ${{ env.GITHUB_SERVER_URL }}/${{ env.GITHUB_REPOSITORY }}
|
||||||
|
git fetch origin refs/heads/forgejo:refs/mirror/forgejo
|
||||||
|
git ls-remote origin refs/heads/v*/forgejo | while read sha full_ref ; do
|
||||||
|
ref=${full_ref#refs/heads/}
|
||||||
|
echo git fetch origin $full_ref:refs/mirror/$ref
|
||||||
|
git fetch origin $full_ref:refs/mirror/$ref
|
||||||
|
done
|
||||||
|
echo git push --force https://${{ vars.MIRROR_DESTINATION }} refs/mirror/*:refs/heads/*
|
||||||
|
git push --force https://any:${{ secrets.MIRROR_TOKEN }}@${{ vars.MIRROR_DESTINATION }} refs/mirror/*:refs/heads/*
|
76
.forgejo/workflows/publish-release.yml
Normal file
76
.forgejo/workflows/publish-release.yml
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
#
|
||||||
|
# See also https://forgejo.org/docs/next/developer/RELEASE/#release-process
|
||||||
|
#
|
||||||
|
# https://codeberg.org/forgejo-experimental/forgejo
|
||||||
|
#
|
||||||
|
# Copies a release from codeberg.org/forgejo-integration to codeberg.org/forgejo-experimental
|
||||||
|
#
|
||||||
|
# vars.ROLE: forgejo-experimental
|
||||||
|
# vars.FORGEJO: https://codeberg.org
|
||||||
|
# vars.FROM_OWNER: forgejo-integration
|
||||||
|
# vars.TO_OWNER: forgejo-experimental
|
||||||
|
# vars.REPO: forgejo
|
||||||
|
# vars.DOER: forgejo-experimental-ci
|
||||||
|
# secrets.TOKEN: <generated from codeberg.org/forgejo-experimental-ci>
|
||||||
|
#
|
||||||
|
# http://private.forgejo.org/forgejo/forgejo
|
||||||
|
#
|
||||||
|
# Copies & sign a release from codeberg.org/forgejo-integration to codeberg.org/forgejo
|
||||||
|
#
|
||||||
|
# vars.ROLE: forgejo-release
|
||||||
|
# vars.FORGEJO: https://codeberg.org
|
||||||
|
# vars.FROM_OWNER: forgejo-integration
|
||||||
|
# vars.TO_OWNER: forgejo
|
||||||
|
# vars.REPO: forgejo
|
||||||
|
# vars.DOER: release-team
|
||||||
|
# secrets.TOKEN: <generated from codeberg.org/release-team>
|
||||||
|
# secrets.GPG_PRIVATE_KEY: <XYZ>
|
||||||
|
# secrets.GPG_PASSPHRASE: <ABC>
|
||||||
|
#
|
||||||
|
name: Pubish release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags: 'v*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
runs-on: self-hosted
|
||||||
|
if: vars.DOER != '' && vars.FORGEJO != '' && vars.TO_OWNER != '' && vars.FROM_OWNER != '' && secrets.TOKEN != ''
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: copy & sign
|
||||||
|
uses: https://code.forgejo.org/forgejo/forgejo-build-publish/publish@v1
|
||||||
|
with:
|
||||||
|
forgejo: ${{ vars.FORGEJO }}
|
||||||
|
from-owner: ${{ vars.FROM_OWNER }}
|
||||||
|
to-owner: ${{ vars.TO_OWNER }}
|
||||||
|
repo: ${{ vars.REPO }}
|
||||||
|
ref-name: ${{ github.ref_name }}
|
||||||
|
release-notes: "See https://codeberg.org/forgejo/forgejo/src/branch/forgejo/RELEASE-NOTES.md#{ANCHOR}"
|
||||||
|
doer: ${{ vars.DOER }}
|
||||||
|
token: ${{ secrets.TOKEN }}
|
||||||
|
gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||||
|
gpg-passphrase: ${{ secrets.GPG_PASSPHRASE }}
|
||||||
|
verbose: ${{ vars.VERBOSE }}
|
||||||
|
|
||||||
|
|
||||||
|
- name: set up go for the DNS update below
|
||||||
|
if: vars.ROLE == 'forgejo-experimental' && secrets.OVH_APP_KEY != ''
|
||||||
|
uses: https://code.forgejo.org/actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
go-version: ">=1.21"
|
||||||
|
check-latest: true
|
||||||
|
- name: update the _release.experimental DNS record
|
||||||
|
if: vars.ROLE == 'forgejo-experimental' && secrets.OVH_APP_KEY != ''
|
||||||
|
uses: https://code.forgejo.org/actions/ovh-dns-update@v1
|
||||||
|
with:
|
||||||
|
subdomain: _release.experimental
|
||||||
|
domain: forgejo.com # there is a CNAME from .org to .com (for security reasons)
|
||||||
|
record-id: 5283602601
|
||||||
|
value: v=${{ github.ref_name }}
|
||||||
|
ovh-app-key: ${{ secrets.OVH_APP_KEY }}
|
||||||
|
ovh-app-secret: ${{ secrets.OVH_APP_SECRET }}
|
||||||
|
ovh-consumer-key: ${{ secrets.OVH_CON_KEY }}
|
211
.forgejo/workflows/testing.yml
Normal file
211
.forgejo/workflows/testing.yml
Normal file
|
@ -0,0 +1,211 @@
|
||||||
|
name: testing
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'forgejo*'
|
||||||
|
- 'v*/forgejo*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint-backend:
|
||||||
|
if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
|
||||||
|
runs-on: docker
|
||||||
|
container:
|
||||||
|
image: 'docker.io/node:20-bookworm'
|
||||||
|
steps:
|
||||||
|
- uses: https://code.forgejo.org/actions/checkout@v3
|
||||||
|
- uses: https://code.forgejo.org/actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
go-version: ">=1.21"
|
||||||
|
check-latest: true
|
||||||
|
- run: make deps-backend deps-tools
|
||||||
|
- run: make lint-backend
|
||||||
|
env:
|
||||||
|
TAGS: bindata sqlite sqlite_unlock_notify
|
||||||
|
checks-backend:
|
||||||
|
if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
|
||||||
|
runs-on: docker
|
||||||
|
container:
|
||||||
|
image: 'docker.io/node:20-bookworm'
|
||||||
|
steps:
|
||||||
|
- uses: https://code.forgejo.org/actions/checkout@v3
|
||||||
|
- uses: https://code.forgejo.org/actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
go-version: ">=1.21"
|
||||||
|
check-latest: true
|
||||||
|
- run: make deps-backend deps-tools
|
||||||
|
- run: make --always-make checks-backend # ensure the "go-licenses" make target runs
|
||||||
|
test-unit:
|
||||||
|
if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
|
||||||
|
runs-on: docker
|
||||||
|
needs: [lint-backend, checks-backend]
|
||||||
|
container:
|
||||||
|
image: 'docker.io/node:20-bookworm'
|
||||||
|
services:
|
||||||
|
minio:
|
||||||
|
image: 'docker.io/bitnami/minio:2023.8.31'
|
||||||
|
env:
|
||||||
|
MINIO_ROOT_USER: 123456
|
||||||
|
MINIO_ROOT_PASSWORD: 12345678
|
||||||
|
steps:
|
||||||
|
- uses: https://code.forgejo.org/actions/checkout@v3
|
||||||
|
- uses: https://code.forgejo.org/actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
go-version: ">=1.21"
|
||||||
|
- run: |
|
||||||
|
git config --add safe.directory '*'
|
||||||
|
adduser --quiet --comment forgejo --disabled-password forgejo
|
||||||
|
chown -R forgejo:forgejo .
|
||||||
|
- name: install git >= 2.42
|
||||||
|
run: |
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
echo deb http://deb.debian.org/debian/ testing main > /etc/apt/sources.list.d/testing.list
|
||||||
|
apt-get update -qq
|
||||||
|
apt-get -q install -qq -y git
|
||||||
|
rm /etc/apt/sources.list.d/testing.list
|
||||||
|
apt-get update -qq
|
||||||
|
- run: |
|
||||||
|
su forgejo -c 'make deps-backend'
|
||||||
|
- run: |
|
||||||
|
su forgejo -c 'make backend'
|
||||||
|
env:
|
||||||
|
TAGS: bindata
|
||||||
|
- run: |
|
||||||
|
su forgejo -c 'make test-backend test-check'
|
||||||
|
timeout-minutes: 50
|
||||||
|
env:
|
||||||
|
RACE_ENABLED: 'true'
|
||||||
|
TAGS: bindata
|
||||||
|
test-mysql:
|
||||||
|
if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
|
||||||
|
runs-on: docker
|
||||||
|
needs: [lint-backend, checks-backend]
|
||||||
|
container:
|
||||||
|
image: 'docker.io/node:20-bookworm'
|
||||||
|
services:
|
||||||
|
mysql:
|
||||||
|
image: 'docker.io/mysql:8-debian'
|
||||||
|
env:
|
||||||
|
MYSQL_ALLOW_EMPTY_PASSWORD: yes
|
||||||
|
MYSQL_DATABASE: testgitea
|
||||||
|
#
|
||||||
|
# See also https://codeberg.org/forgejo/forgejo/issues/976
|
||||||
|
#
|
||||||
|
cmd: ['mysqld', '--innodb-adaptive-flushing=OFF', '--innodb-buffer-pool-size=4G', '--innodb-log-buffer-size=128M', '--innodb-flush-log-at-trx-commit=0', '--innodb-flush-log-at-timeout=30', '--innodb-flush-method=nosync', '--innodb-fsync-threshold=1000000000']
|
||||||
|
steps:
|
||||||
|
- uses: https://code.forgejo.org/actions/checkout@v3
|
||||||
|
- uses: https://code.forgejo.org/actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
go-version: "1.21"
|
||||||
|
- name: install dependencies & git >= 2.42
|
||||||
|
run: |
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
echo deb http://deb.debian.org/debian/ testing main > /etc/apt/sources.list.d/testing.list
|
||||||
|
apt-get update -qq
|
||||||
|
apt-get install --no-install-recommends -qq -y git git-lfs
|
||||||
|
rm /etc/apt/sources.list.d/testing.list
|
||||||
|
apt-get update -qq
|
||||||
|
- name: setup user and permissions
|
||||||
|
run: |
|
||||||
|
git config --add safe.directory '*'
|
||||||
|
adduser --quiet --comment forgejo --disabled-password forgejo
|
||||||
|
chown -R forgejo:forgejo .
|
||||||
|
- run: |
|
||||||
|
su forgejo -c 'make deps-backend'
|
||||||
|
- run: |
|
||||||
|
su forgejo -c 'make backend'
|
||||||
|
env:
|
||||||
|
TAGS: bindata
|
||||||
|
- run: |
|
||||||
|
su forgejo -c 'make test-mysql-migration test-mysql'
|
||||||
|
timeout-minutes: 50
|
||||||
|
env:
|
||||||
|
TAGS: bindata
|
||||||
|
USE_REPO_TEST_DIR: 1
|
||||||
|
test-pgsql:
|
||||||
|
if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
|
||||||
|
runs-on: docker
|
||||||
|
needs: [lint-backend, checks-backend]
|
||||||
|
container:
|
||||||
|
image: 'docker.io/node:20-bookworm'
|
||||||
|
services:
|
||||||
|
minio:
|
||||||
|
image: bitnami/minio:2021.3.17
|
||||||
|
env:
|
||||||
|
MINIO_ACCESS_KEY: 123456
|
||||||
|
MINIO_SECRET_KEY: 12345678
|
||||||
|
pgsql:
|
||||||
|
image: 'docker.io/postgres:15'
|
||||||
|
env:
|
||||||
|
POSTGRES_DB: test
|
||||||
|
POSTGRES_PASSWORD: postgres
|
||||||
|
steps:
|
||||||
|
- uses: https://code.forgejo.org/actions/checkout@v3
|
||||||
|
- uses: https://code.forgejo.org/actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
go-version: "1.21"
|
||||||
|
- name: install dependencies & git >= 2.42
|
||||||
|
run: |
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
echo deb http://deb.debian.org/debian/ testing main > /etc/apt/sources.list.d/testing.list
|
||||||
|
apt-get update -qq
|
||||||
|
apt-get install --no-install-recommends -qq -y git git-lfs
|
||||||
|
rm /etc/apt/sources.list.d/testing.list
|
||||||
|
apt-get update -qq
|
||||||
|
- name: setup user and permissions
|
||||||
|
run: |
|
||||||
|
git config --add safe.directory '*'
|
||||||
|
adduser --quiet --comment forgejo --disabled-password forgejo
|
||||||
|
chown -R forgejo:forgejo .
|
||||||
|
- run: |
|
||||||
|
su forgejo -c 'make deps-backend'
|
||||||
|
- run: |
|
||||||
|
su forgejo -c 'make backend'
|
||||||
|
env:
|
||||||
|
TAGS: bindata
|
||||||
|
- run: |
|
||||||
|
su forgejo -c 'make test-pgsql-migration test-pgsql'
|
||||||
|
timeout-minutes: 50
|
||||||
|
env:
|
||||||
|
TAGS: bindata
|
||||||
|
RACE_ENABLED: true
|
||||||
|
USE_REPO_TEST_DIR: 1
|
||||||
|
test-sqlite:
|
||||||
|
if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
|
||||||
|
runs-on: docker
|
||||||
|
needs: [lint-backend, checks-backend]
|
||||||
|
container:
|
||||||
|
image: 'docker.io/node:20-bookworm'
|
||||||
|
steps:
|
||||||
|
- uses: https://code.forgejo.org/actions/checkout@v3
|
||||||
|
- uses: https://code.forgejo.org/actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
go-version: "1.21"
|
||||||
|
- name: install dependencies & git >= 2.42
|
||||||
|
run: |
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
echo deb http://deb.debian.org/debian/ testing main > /etc/apt/sources.list.d/testing.list
|
||||||
|
apt-get update -qq
|
||||||
|
apt-get install --no-install-recommends -qq -y git git-lfs
|
||||||
|
rm /etc/apt/sources.list.d/testing.list
|
||||||
|
apt-get update -qq
|
||||||
|
- name: setup user and permissions
|
||||||
|
run: |
|
||||||
|
git config --add safe.directory '*'
|
||||||
|
adduser --quiet --comment forgejo --disabled-password forgejo
|
||||||
|
chown -R forgejo:forgejo .
|
||||||
|
- run: |
|
||||||
|
su forgejo -c 'make deps-backend'
|
||||||
|
- run: |
|
||||||
|
su forgejo -c 'make backend'
|
||||||
|
env:
|
||||||
|
TAGS: bindata sqlite sqlite_unlock_notify
|
||||||
|
- run: |
|
||||||
|
su forgejo -c 'make test-sqlite-migration test-sqlite'
|
||||||
|
timeout-minutes: 50
|
||||||
|
env:
|
||||||
|
TAGS: bindata sqlite sqlite_unlock_notify
|
||||||
|
RACE_ENABLED: true
|
||||||
|
TEST_TAGS: sqlite sqlite_unlock_notify
|
||||||
|
USE_REPO_TEST_DIR: 1
|
|
@ -1,42 +0,0 @@
|
||||||
<!-- NOTE: If your issue is a security concern, please send an email to security@gitea.io instead of opening a public issue -->
|
|
||||||
|
|
||||||
<!--
|
|
||||||
1. Please speak English, this is the language all maintainers can speak and write.
|
|
||||||
2. Please ask questions or configuration/deploy problems on our Discord
|
|
||||||
server (https://discord.gg/gitea) or forum (https://discourse.gitea.io).
|
|
||||||
3. Please take a moment to check that your issue doesn't already exist.
|
|
||||||
4. Make sure it's not mentioned in the FAQ (https://docs.gitea.com/help/faq)
|
|
||||||
5. Please give all relevant information below for bug reports, because
|
|
||||||
incomplete details will be handled as an invalid report.
|
|
||||||
-->
|
|
||||||
|
|
||||||
- Gitea version (or commit ref):
|
|
||||||
- Git version:
|
|
||||||
- Operating system:
|
|
||||||
<!-- Please include information on whether you built gitea yourself, used one of our downloads or are using some other package -->
|
|
||||||
<!-- Please also tell us how you are running gitea, e.g. if it is being run from docker, a command-line, systemd etc. --->
|
|
||||||
<!-- If you are using a package or systemd tell us what distribution you are using -->
|
|
||||||
- Database (use `[x]`):
|
|
||||||
- [ ] PostgreSQL
|
|
||||||
- [ ] MySQL
|
|
||||||
- [ ] MSSQL
|
|
||||||
- [ ] SQLite
|
|
||||||
- Can you reproduce the bug at https://try.gitea.io:
|
|
||||||
- [ ] Yes (provide example URL)
|
|
||||||
- [ ] No
|
|
||||||
- Log gist:
|
|
||||||
<!-- It really is important to provide pertinent logs -->
|
|
||||||
<!-- Please read https://docs.gitea.com/administration/logging-config#collecting-logs-for-help -->
|
|
||||||
<!-- In addition, if your problem relates to git commands set `RUN_MODE=dev` at the top of app.ini -->
|
|
||||||
|
|
||||||
## Description
|
|
||||||
<!-- If using a proxy or a CDN (e.g. CloudFlare) in front of gitea, please
|
|
||||||
disable the proxy/CDN fully and connect to gitea directly to confirm
|
|
||||||
the issue still persists without those services. -->
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
## Screenshots
|
|
||||||
|
|
||||||
<!-- **If this issue involves the Web Interface, please include a screenshot** -->
|
|
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
|
@ -1,2 +0,0 @@
|
||||||
open_collective: gitea
|
|
||||||
custom: https://www.bountysource.com/teams/gitea
|
|
91
.github/ISSUE_TEMPLATE/bug-report.yaml
vendored
91
.github/ISSUE_TEMPLATE/bug-report.yaml
vendored
|
@ -1,91 +0,0 @@
|
||||||
name: Bug Report
|
|
||||||
description: Found something you weren't expecting? Report it here!
|
|
||||||
labels: ["type/bug"]
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
NOTE: If your issue is a security concern, please send an email to security@gitea.io instead of opening a public issue.
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
1. Please speak English, this is the language all maintainers can speak and write.
|
|
||||||
2. Please ask questions or configuration/deploy problems on our Discord
|
|
||||||
server (https://discord.gg/gitea) or forum (https://discourse.gitea.io).
|
|
||||||
3. Make sure you are using the latest release and
|
|
||||||
take a moment to check that your issue hasn't been reported before.
|
|
||||||
4. Make sure it's not mentioned in the FAQ (https://docs.gitea.com/help/faq)
|
|
||||||
5. It's really important to provide pertinent details and logs (https://docs.gitea.com/help/support),
|
|
||||||
incomplete details will be handled as an invalid report.
|
|
||||||
- type: textarea
|
|
||||||
id: description
|
|
||||||
attributes:
|
|
||||||
label: Description
|
|
||||||
description: |
|
|
||||||
Please provide a description of your issue here, with a URL if you were able to reproduce the issue (see below)
|
|
||||||
If you are using a proxy or a CDN (e.g. Cloudflare) in front of Gitea, please disable the proxy/CDN fully and access Gitea directly to confirm the issue still persists without those services.
|
|
||||||
- type: input
|
|
||||||
id: gitea-ver
|
|
||||||
attributes:
|
|
||||||
label: Gitea Version
|
|
||||||
description: Gitea version (or commit reference) of your instance
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: dropdown
|
|
||||||
id: can-reproduce
|
|
||||||
attributes:
|
|
||||||
label: Can you reproduce the bug on the Gitea demo site?
|
|
||||||
description: |
|
|
||||||
If so, please provide a URL in the Description field
|
|
||||||
URL of Gitea demo: https://try.gitea.io
|
|
||||||
options:
|
|
||||||
- "Yes"
|
|
||||||
- "No"
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
It's really important to provide pertinent logs
|
|
||||||
Please read https://docs.gitea.com/administration/logging-config#collecting-logs-for-help
|
|
||||||
In addition, if your problem relates to git commands set `RUN_MODE=dev` at the top of app.ini
|
|
||||||
- type: input
|
|
||||||
id: logs
|
|
||||||
attributes:
|
|
||||||
label: Log Gist
|
|
||||||
description: Please provide a gist URL of your logs, with any sensitive information (e.g. API keys) removed/hidden
|
|
||||||
- type: textarea
|
|
||||||
id: screenshots
|
|
||||||
attributes:
|
|
||||||
label: Screenshots
|
|
||||||
description: If this issue involves the Web Interface, please provide one or more screenshots
|
|
||||||
- type: input
|
|
||||||
id: git-ver
|
|
||||||
attributes:
|
|
||||||
label: Git Version
|
|
||||||
description: The version of git running on the server
|
|
||||||
- type: input
|
|
||||||
id: os-ver
|
|
||||||
attributes:
|
|
||||||
label: Operating System
|
|
||||||
description: The operating system you are using to run Gitea
|
|
||||||
- type: textarea
|
|
||||||
id: run-info
|
|
||||||
attributes:
|
|
||||||
label: How are you running Gitea?
|
|
||||||
description: |
|
|
||||||
Please include information on whether you built Gitea yourself, used one of our downloads, are using https://try.gitea.io or are using some other package
|
|
||||||
Please also tell us how you are running Gitea, e.g. if it is being run from docker, a command-line, systemd etc.
|
|
||||||
If you are using a package or systemd tell us what distribution you are using
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: dropdown
|
|
||||||
id: database
|
|
||||||
attributes:
|
|
||||||
label: Database
|
|
||||||
description: What database system are you running?
|
|
||||||
options:
|
|
||||||
- PostgreSQL
|
|
||||||
- MySQL/MariaDB
|
|
||||||
- MSSQL
|
|
||||||
- SQLite
|
|
17
.github/ISSUE_TEMPLATE/config.yml
vendored
17
.github/ISSUE_TEMPLATE/config.yml
vendored
|
@ -1,17 +0,0 @@
|
||||||
blank_issues_enabled: false
|
|
||||||
contact_links:
|
|
||||||
- name: Security Concern
|
|
||||||
url: https://tinyurl.com/security-gitea
|
|
||||||
about: For security concerns, please send a mail to security@gitea.io instead of opening a public issue.
|
|
||||||
- name: Discord Server
|
|
||||||
url: https://discord.gg/Gitea
|
|
||||||
about: Please ask questions and discuss configuration or deployment problems here.
|
|
||||||
- name: Discourse Forum
|
|
||||||
url: https://discourse.gitea.io
|
|
||||||
about: Questions and configuration or deployment problems can also be discussed on our forum.
|
|
||||||
- name: Frequently Asked Questions
|
|
||||||
url: https://docs.gitea.com/help/faq
|
|
||||||
about: Please check if your question isn't mentioned here.
|
|
||||||
- name: Crowdin Translations
|
|
||||||
url: https://crowdin.com/project/gitea
|
|
||||||
about: Translations are managed here.
|
|
24
.github/ISSUE_TEMPLATE/feature-request.yaml
vendored
24
.github/ISSUE_TEMPLATE/feature-request.yaml
vendored
|
@ -1,24 +0,0 @@
|
||||||
name: Feature Request
|
|
||||||
description: Got an idea for a feature that Gitea doesn't have currently? Submit your idea here!
|
|
||||||
labels: ["type/proposal"]
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
1. Please speak English, this is the language all maintainers can speak and write.
|
|
||||||
2. Please ask questions or configuration/deploy problems on our Discord
|
|
||||||
server (https://discord.gg/gitea) or forum (https://discourse.gitea.io).
|
|
||||||
3. Please take a moment to check that your feature hasn't already been suggested.
|
|
||||||
- type: textarea
|
|
||||||
id: description
|
|
||||||
attributes:
|
|
||||||
label: Feature Description
|
|
||||||
placeholder: |
|
|
||||||
I think it would be great if Gitea had...
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
id: screenshots
|
|
||||||
attributes:
|
|
||||||
label: Screenshots
|
|
||||||
description: If you can, provide screenshots of an implementation on another site e.g. GitHub
|
|
66
.github/ISSUE_TEMPLATE/ui.bug-report.yaml
vendored
66
.github/ISSUE_TEMPLATE/ui.bug-report.yaml
vendored
|
@ -1,66 +0,0 @@
|
||||||
name: Web Interface Bug Report
|
|
||||||
description: Something doesn't look quite as it should? Report it here!
|
|
||||||
labels: ["type/bug", "topic/ui"]
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
NOTE: If your issue is a security concern, please send an email to security@gitea.io instead of opening a public issue.
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
1. Please speak English, this is the language all maintainers can speak and write.
|
|
||||||
2. Please ask questions or configuration/deploy problems on our Discord
|
|
||||||
server (https://discord.gg/gitea) or forum (https://discourse.gitea.io).
|
|
||||||
3. Please take a moment to check that your issue doesn't already exist.
|
|
||||||
4. Make sure it's not mentioned in the FAQ (https://docs.gitea.com/help/faq)
|
|
||||||
5. Please give all relevant information below for bug reports, because
|
|
||||||
incomplete details will be handled as an invalid report.
|
|
||||||
6. In particular it's really important to provide pertinent logs. If you are certain that this is a javascript
|
|
||||||
error, show us the javascript console. If the error appears to relate to Gitea the server you must also give us
|
|
||||||
DEBUG level logs. (See https://docs.gitea.com/administration/logging-config#collecting-logs-for-help)
|
|
||||||
- type: textarea
|
|
||||||
id: description
|
|
||||||
attributes:
|
|
||||||
label: Description
|
|
||||||
description: |
|
|
||||||
Please provide a description of your issue here, with a URL if you were able to reproduce the issue (see below)
|
|
||||||
If using a proxy or a CDN (e.g. CloudFlare) in front of gitea, please disable the proxy/CDN fully and connect to gitea directly to confirm the issue still persists without those services.
|
|
||||||
- type: textarea
|
|
||||||
id: screenshots
|
|
||||||
attributes:
|
|
||||||
label: Screenshots
|
|
||||||
description: Please provide at least 1 screenshot showing the issue.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: input
|
|
||||||
id: gitea-ver
|
|
||||||
attributes:
|
|
||||||
label: Gitea Version
|
|
||||||
description: Gitea version (or commit reference) your instance is running
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: dropdown
|
|
||||||
id: can-reproduce
|
|
||||||
attributes:
|
|
||||||
label: Can you reproduce the bug on the Gitea demo site?
|
|
||||||
description: |
|
|
||||||
If so, please provide a URL in the Description field
|
|
||||||
URL of Gitea demo: https://try.gitea.io
|
|
||||||
options:
|
|
||||||
- "Yes"
|
|
||||||
- "No"
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: input
|
|
||||||
id: os-ver
|
|
||||||
attributes:
|
|
||||||
label: Operating System
|
|
||||||
description: The operating system you are using to access Gitea
|
|
||||||
- type: input
|
|
||||||
id: browser-ver
|
|
||||||
attributes:
|
|
||||||
label: Browser Version
|
|
||||||
description: The browser and version that you are using to access Gitea
|
|
||||||
validations:
|
|
||||||
required: true
|
|
5
.github/actionlint.yaml
vendored
5
.github/actionlint.yaml
vendored
|
@ -1,5 +0,0 @@
|
||||||
self-hosted-runner:
|
|
||||||
labels:
|
|
||||||
- actuated-4cpu-8gb
|
|
||||||
- actuated-4cpu-16gb
|
|
||||||
- nscloud
|
|
36
.github/labeler.yml
vendored
36
.github/labeler.yml
vendored
|
@ -1,36 +0,0 @@
|
||||||
modifies/docs:
|
|
||||||
- "**/*.md"
|
|
||||||
- "docs/**"
|
|
||||||
|
|
||||||
modifies/frontend:
|
|
||||||
- "web_src/**/*"
|
|
||||||
|
|
||||||
modifies/templates:
|
|
||||||
- all: ["templates/**", "!templates/swagger/v1_json.tmpl"]
|
|
||||||
|
|
||||||
modifies/api:
|
|
||||||
- "routers/api/**"
|
|
||||||
- "templates/swagger/v1_json.tmpl"
|
|
||||||
|
|
||||||
modifies/cli:
|
|
||||||
- "cmd/**"
|
|
||||||
|
|
||||||
modifies/translation:
|
|
||||||
- "options/locale/*.ini"
|
|
||||||
|
|
||||||
modifies/migrations:
|
|
||||||
- "models/migrations/**/*"
|
|
||||||
|
|
||||||
modifies/internal:
|
|
||||||
- "Makefile"
|
|
||||||
- "Dockerfile"
|
|
||||||
- "Dockerfile.rootless"
|
|
||||||
- "docker/**"
|
|
||||||
- "webpack.config.js"
|
|
||||||
- ".eslintrc.yaml"
|
|
||||||
- ".golangci.yml"
|
|
||||||
- ".markdownlint.yaml"
|
|
||||||
- ".spectral.yaml"
|
|
||||||
- ".stylelintrc.yaml"
|
|
||||||
- ".yamllint.yaml"
|
|
||||||
- ".github/**"
|
|
9
.github/pull_request_template.md
vendored
9
.github/pull_request_template.md
vendored
|
@ -1,9 +0,0 @@
|
||||||
<!-- start tips -->
|
|
||||||
Please check the following:
|
|
||||||
1. Make sure you are targeting the `main` branch, pull requests on release branches are only allowed for backports.
|
|
||||||
2. Make sure you have read contributing guidelines: https://github.com/go-gitea/gitea/blob/main/CONTRIBUTING.md .
|
|
||||||
3. Describe what your pull request does and which issue you're targeting (if any).
|
|
||||||
4. It is recommended to enable "Allow edits by maintainers", so maintainers can help more easily.
|
|
||||||
5. Your input here will be included in the commit message when this PR has been merged. If you don't want some content to be included, please separate them with a line like `---`.
|
|
||||||
6. Delete all these tips before posting.
|
|
||||||
<!-- end tips -->
|
|
29
.github/workflows/cron-licenses.yml
vendored
29
.github/workflows/cron-licenses.yml
vendored
|
@ -1,29 +0,0 @@
|
||||||
name: cron-licenses
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: "7 0 * * 1" # every Monday at 00:07 UTC
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
cron-licenses:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: github.repository == 'go-gitea/gitea'
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version-file: go.mod
|
|
||||||
check-latest: true
|
|
||||||
- run: make generate-license generate-gitignore
|
|
||||||
timeout-minutes: 40
|
|
||||||
- name: push translations to repo
|
|
||||||
uses: appleboy/git-push-action@v0.0.3
|
|
||||||
with:
|
|
||||||
author_email: "teabot@gitea.io"
|
|
||||||
author_name: GiteaBot
|
|
||||||
branch: main
|
|
||||||
commit: true
|
|
||||||
commit_message: "[skip ci] Updated licenses and gitignores"
|
|
||||||
remote: "git@github.com:go-gitea/gitea.git"
|
|
||||||
ssh_key: ${{ secrets.DEPLOY_KEY }}
|
|
22
.github/workflows/cron-lock.yml
vendored
22
.github/workflows/cron-lock.yml
vendored
|
@ -1,22 +0,0 @@
|
||||||
name: cron-lock
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: "0 0 * * *" # every day at 00:00 UTC
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
issues: write
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: lock
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
action:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: github.repository == 'go-gitea/gitea'
|
|
||||||
steps:
|
|
||||||
- uses: dessant/lock-threads@v5
|
|
||||||
with:
|
|
||||||
issue-inactive-days: 45
|
|
49
.github/workflows/cron-translations.yml
vendored
49
.github/workflows/cron-translations.yml
vendored
|
@ -1,49 +0,0 @@
|
||||||
name: cron-translations
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: "7 0 * * *" # every day at 00:07 UTC
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
crowdin-pull:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: github.repository == 'go-gitea/gitea'
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: download from crowdin
|
|
||||||
uses: docker://jonasfranz/crowdin
|
|
||||||
env:
|
|
||||||
CROWDIN_KEY: ${{ secrets.CROWDIN_KEY }}
|
|
||||||
PLUGIN_DOWNLOAD: true
|
|
||||||
PLUGIN_EXPORT_DIR: options/locale/
|
|
||||||
PLUGIN_IGNORE_BRANCH: true
|
|
||||||
PLUGIN_PROJECT_IDENTIFIER: gitea
|
|
||||||
- name: update locales
|
|
||||||
run: ./build/update-locales.sh
|
|
||||||
- name: push translations to repo
|
|
||||||
uses: appleboy/git-push-action@v0.0.3
|
|
||||||
with:
|
|
||||||
author_email: "teabot@gitea.io"
|
|
||||||
author_name: GiteaBot
|
|
||||||
branch: main
|
|
||||||
commit: true
|
|
||||||
commit_message: "[skip ci] Updated translations via Crowdin"
|
|
||||||
remote: "git@github.com:go-gitea/gitea.git"
|
|
||||||
ssh_key: ${{ secrets.DEPLOY_KEY }}
|
|
||||||
crowdin-push:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: github.repository == 'go-gitea/gitea'
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: push translations to crowdin
|
|
||||||
uses: docker://jonasfranz/crowdin
|
|
||||||
env:
|
|
||||||
CROWDIN_KEY: ${{ secrets.CROWDIN_KEY }}
|
|
||||||
PLUGIN_UPLOAD: true
|
|
||||||
PLUGIN_EXPORT_DIR: options/locale/
|
|
||||||
PLUGIN_IGNORE_BRANCH: true
|
|
||||||
PLUGIN_PROJECT_IDENTIFIER: gitea
|
|
||||||
PLUGIN_FILES: |
|
|
||||||
locale_en-US.ini: options/locale/locale_en-US.ini
|
|
||||||
PLUGIN_BRANCH: main
|
|
25
.github/workflows/disk-clean.yml
vendored
25
.github/workflows/disk-clean.yml
vendored
|
@ -1,25 +0,0 @@
|
||||||
name: disk-clean
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_call:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
triage:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Free Disk Space (Ubuntu)
|
|
||||||
uses: jlumbroso/free-disk-space@main
|
|
||||||
with:
|
|
||||||
# this might remove tools that are actually needed,
|
|
||||||
# if set to "true" but frees about 6 GB
|
|
||||||
tool-cache: false
|
|
||||||
|
|
||||||
# all of these default to true, but feel free to set to
|
|
||||||
# "false" if necessary for your workflow
|
|
||||||
android: true
|
|
||||||
dotnet: true
|
|
||||||
haskell: true
|
|
||||||
large-packages: false
|
|
||||||
docker-images: false
|
|
||||||
swap-storage: true
|
|
97
.github/workflows/files-changed.yml
vendored
97
.github/workflows/files-changed.yml
vendored
|
@ -1,97 +0,0 @@
|
||||||
name: files-changed
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_call:
|
|
||||||
outputs:
|
|
||||||
backend:
|
|
||||||
value: ${{ jobs.detect.outputs.backend }}
|
|
||||||
frontend:
|
|
||||||
value: ${{ jobs.detect.outputs.frontend }}
|
|
||||||
docs:
|
|
||||||
value: ${{ jobs.detect.outputs.docs }}
|
|
||||||
actions:
|
|
||||||
value: ${{ jobs.detect.outputs.actions }}
|
|
||||||
templates:
|
|
||||||
value: ${{ jobs.detect.outputs.templates }}
|
|
||||||
docker:
|
|
||||||
value: ${{ jobs.detect.outputs.docker }}
|
|
||||||
swagger:
|
|
||||||
value: ${{ jobs.detect.outputs.swagger }}
|
|
||||||
yaml:
|
|
||||||
value: ${{ jobs.detect.outputs.yaml }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
detect:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 3
|
|
||||||
outputs:
|
|
||||||
backend: ${{ steps.changes.outputs.backend }}
|
|
||||||
frontend: ${{ steps.changes.outputs.frontend }}
|
|
||||||
docs: ${{ steps.changes.outputs.docs }}
|
|
||||||
actions: ${{ steps.changes.outputs.actions }}
|
|
||||||
templates: ${{ steps.changes.outputs.templates }}
|
|
||||||
docker: ${{ steps.changes.outputs.docker }}
|
|
||||||
swagger: ${{ steps.changes.outputs.swagger }}
|
|
||||||
yaml: ${{ steps.changes.outputs.yaml }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: dorny/paths-filter@v2
|
|
||||||
id: changes
|
|
||||||
with:
|
|
||||||
filters: |
|
|
||||||
backend:
|
|
||||||
- "**/*.go"
|
|
||||||
- "templates/**/*.tmpl"
|
|
||||||
- "assets/emoji.json"
|
|
||||||
- "go.mod"
|
|
||||||
- "go.sum"
|
|
||||||
- "Makefile"
|
|
||||||
- ".golangci.yml"
|
|
||||||
- ".editorconfig"
|
|
||||||
|
|
||||||
frontend:
|
|
||||||
- "**/*.js"
|
|
||||||
- "web_src/**"
|
|
||||||
- "assets/emoji.json"
|
|
||||||
- "package.json"
|
|
||||||
- "package-lock.json"
|
|
||||||
- "Makefile"
|
|
||||||
- ".eslintrc.yaml"
|
|
||||||
- ".stylelintrc.yaml"
|
|
||||||
- ".npmrc"
|
|
||||||
|
|
||||||
docs:
|
|
||||||
- "**/*.md"
|
|
||||||
- "docs/**"
|
|
||||||
- ".markdownlint.yaml"
|
|
||||||
- "package.json"
|
|
||||||
- "package-lock.json"
|
|
||||||
|
|
||||||
actions:
|
|
||||||
- ".github/workflows/*"
|
|
||||||
- "Makefile"
|
|
||||||
|
|
||||||
templates:
|
|
||||||
- "templates/**/*.tmpl"
|
|
||||||
- "pyproject.toml"
|
|
||||||
- "poetry.lock"
|
|
||||||
|
|
||||||
docker:
|
|
||||||
- "Dockerfile"
|
|
||||||
- "Dockerfile.rootless"
|
|
||||||
- "docker/**"
|
|
||||||
- "Makefile"
|
|
||||||
|
|
||||||
swagger:
|
|
||||||
- "templates/swagger/v1_json.tmpl"
|
|
||||||
- "Makefile"
|
|
||||||
- "package.json"
|
|
||||||
- "package-lock.json"
|
|
||||||
- ".spectral.yaml"
|
|
||||||
|
|
||||||
yaml:
|
|
||||||
- "**/*.yml"
|
|
||||||
- "**/*.yaml"
|
|
||||||
- ".yamllint.yaml"
|
|
||||||
- "pyproject.toml"
|
|
||||||
- "poetry.lock"
|
|
182
.github/workflows/pull-compliance.yml
vendored
182
.github/workflows/pull-compliance.yml
vendored
|
@ -1,182 +0,0 @@
|
||||||
name: compliance
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
files-changed:
|
|
||||||
uses: ./.github/workflows/files-changed.yml
|
|
||||||
|
|
||||||
lint-backend:
|
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == '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 deps-backend deps-tools
|
|
||||||
- run: make lint-backend
|
|
||||||
env:
|
|
||||||
TAGS: bindata sqlite sqlite_unlock_notify
|
|
||||||
|
|
||||||
lint-templates:
|
|
||||||
if: needs.files-changed.outputs.templates == 'true'
|
|
||||||
needs: files-changed
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: actions/setup-python@v4
|
|
||||||
with:
|
|
||||||
python-version: "3.11"
|
|
||||||
- run: pip install poetry
|
|
||||||
- run: make deps-py
|
|
||||||
- run: make lint-templates
|
|
||||||
|
|
||||||
lint-yaml:
|
|
||||||
if: needs.files-changed.outputs.yaml == 'true'
|
|
||||||
needs: files-changed
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: actions/setup-python@v4
|
|
||||||
with:
|
|
||||||
python-version: "3.11"
|
|
||||||
- run: pip install poetry
|
|
||||||
- run: make deps-py
|
|
||||||
- run: make lint-yaml
|
|
||||||
|
|
||||||
lint-swagger:
|
|
||||||
if: needs.files-changed.outputs.swagger == 'true'
|
|
||||||
needs: files-changed
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 20
|
|
||||||
- run: make deps-frontend
|
|
||||||
- run: make lint-swagger
|
|
||||||
|
|
||||||
lint-go-windows:
|
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == '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 deps-backend deps-tools
|
|
||||||
- run: make lint-go-windows lint-go-vet
|
|
||||||
env:
|
|
||||||
TAGS: bindata sqlite sqlite_unlock_notify
|
|
||||||
GOOS: windows
|
|
||||||
GOARCH: amd64
|
|
||||||
|
|
||||||
lint-go-gogit:
|
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == '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 deps-backend deps-tools
|
|
||||||
- run: make lint-go
|
|
||||||
env:
|
|
||||||
TAGS: bindata gogit sqlite sqlite_unlock_notify
|
|
||||||
|
|
||||||
checks-backend:
|
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == '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 deps-backend deps-tools
|
|
||||||
- run: make --always-make checks-backend # ensure the "go-licenses" make target runs
|
|
||||||
|
|
||||||
frontend:
|
|
||||||
if: needs.files-changed.outputs.frontend == 'true' || needs.files-changed.outputs.actions == 'true'
|
|
||||||
needs: files-changed
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 20
|
|
||||||
- run: make deps-frontend
|
|
||||||
- run: make lint-frontend
|
|
||||||
- run: make checks-frontend
|
|
||||||
- run: make test-frontend
|
|
||||||
- run: make frontend
|
|
||||||
|
|
||||||
backend:
|
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == '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
|
|
||||||
# no frontend build here as backend should be able to build
|
|
||||||
# even without any frontend files
|
|
||||||
- run: make deps-backend
|
|
||||||
- run: go build -o gitea_no_gcc # test if build succeeds without the sqlite tag
|
|
||||||
- name: build-backend-arm64
|
|
||||||
run: make backend # test cross compile
|
|
||||||
env:
|
|
||||||
GOOS: linux
|
|
||||||
GOARCH: arm64
|
|
||||||
TAGS: bindata gogit
|
|
||||||
- name: build-backend-windows
|
|
||||||
run: go build -o gitea_windows
|
|
||||||
env:
|
|
||||||
GOOS: windows
|
|
||||||
GOARCH: amd64
|
|
||||||
TAGS: bindata gogit
|
|
||||||
- name: build-backend-386
|
|
||||||
run: go build -o gitea_linux_386 # test if compatible with 32 bit
|
|
||||||
env:
|
|
||||||
GOOS: linux
|
|
||||||
GOARCH: 386
|
|
||||||
|
|
||||||
docs:
|
|
||||||
if: needs.files-changed.outputs.docs == 'true' || needs.files-changed.outputs.actions == 'true'
|
|
||||||
needs: files-changed
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 20
|
|
||||||
- run: make deps-frontend
|
|
||||||
- run: make lint-md
|
|
||||||
- run: make docs
|
|
||||||
|
|
||||||
actions:
|
|
||||||
if: needs.files-changed.outputs.actions == 'true' || needs.files-changed.outputs.actions == '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-actions
|
|
215
.github/workflows/pull-db-tests.yml
vendored
215
.github/workflows/pull-db-tests.yml
vendored
|
@ -1,215 +0,0 @@
|
||||||
name: db-tests
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
files-changed:
|
|
||||||
uses: ./.github/workflows/files-changed.yml
|
|
||||||
|
|
||||||
test-pgsql:
|
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
|
||||||
needs: files-changed
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
services:
|
|
||||||
pgsql:
|
|
||||||
image: postgres:12
|
|
||||||
env:
|
|
||||||
POSTGRES_DB: test
|
|
||||||
POSTGRES_PASSWORD: postgres
|
|
||||||
ports:
|
|
||||||
- "5432:5432"
|
|
||||||
ldap:
|
|
||||||
image: gitea/test-openldap:latest
|
|
||||||
ports:
|
|
||||||
- "389:389"
|
|
||||||
- "636:636"
|
|
||||||
minio:
|
|
||||||
# as github actions doesn't support "entrypoint", we need to use a non-official image
|
|
||||||
# that has a custom entrypoint set to "minio server /data"
|
|
||||||
image: bitnami/minio:2023.8.31
|
|
||||||
env:
|
|
||||||
MINIO_ROOT_USER: 123456
|
|
||||||
MINIO_ROOT_PASSWORD: 12345678
|
|
||||||
ports:
|
|
||||||
- "9000:9000"
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version-file: go.mod
|
|
||||||
check-latest: true
|
|
||||||
- name: Add hosts to /etc/hosts
|
|
||||||
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 pgsql ldap minio" | sudo tee -a /etc/hosts'
|
|
||||||
- run: make deps-backend
|
|
||||||
- run: make backend
|
|
||||||
env:
|
|
||||||
TAGS: bindata
|
|
||||||
- run: make test-pgsql-migration test-pgsql
|
|
||||||
timeout-minutes: 50
|
|
||||||
env:
|
|
||||||
TAGS: bindata gogit
|
|
||||||
RACE_ENABLED: true
|
|
||||||
TEST_TAGS: gogit
|
|
||||||
TEST_LDAP: 1
|
|
||||||
USE_REPO_TEST_DIR: 1
|
|
||||||
|
|
||||||
test-sqlite:
|
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == '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 deps-backend
|
|
||||||
- run: make backend
|
|
||||||
env:
|
|
||||||
TAGS: bindata gogit sqlite sqlite_unlock_notify
|
|
||||||
- run: make test-sqlite-migration test-sqlite
|
|
||||||
timeout-minutes: 50
|
|
||||||
env:
|
|
||||||
TAGS: bindata gogit sqlite sqlite_unlock_notify
|
|
||||||
RACE_ENABLED: true
|
|
||||||
TEST_TAGS: gogit sqlite sqlite_unlock_notify
|
|
||||||
USE_REPO_TEST_DIR: 1
|
|
||||||
|
|
||||||
test-unit:
|
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
|
||||||
needs: files-changed
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
services:
|
|
||||||
elasticsearch:
|
|
||||||
image: elasticsearch:7.5.0
|
|
||||||
env:
|
|
||||||
discovery.type: single-node
|
|
||||||
ports:
|
|
||||||
- "9200:9200"
|
|
||||||
meilisearch:
|
|
||||||
image: getmeili/meilisearch:v1.2.0
|
|
||||||
env:
|
|
||||||
MEILI_ENV: development # disable auth
|
|
||||||
ports:
|
|
||||||
- "7700:7700"
|
|
||||||
redis:
|
|
||||||
image: redis
|
|
||||||
options: >- # wait until redis has started
|
|
||||||
--health-cmd "redis-cli ping"
|
|
||||||
--health-interval 5s
|
|
||||||
--health-timeout 3s
|
|
||||||
--health-retries 10
|
|
||||||
ports:
|
|
||||||
- 6379:6379
|
|
||||||
minio:
|
|
||||||
image: bitnami/minio:2021.3.17
|
|
||||||
env:
|
|
||||||
MINIO_ACCESS_KEY: 123456
|
|
||||||
MINIO_SECRET_KEY: 12345678
|
|
||||||
ports:
|
|
||||||
- "9000:9000"
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version-file: go.mod
|
|
||||||
check-latest: true
|
|
||||||
- name: Add hosts to /etc/hosts
|
|
||||||
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 mysql elasticsearch meilisearch smtpimap" | sudo tee -a /etc/hosts'
|
|
||||||
- run: make deps-backend
|
|
||||||
- run: make backend
|
|
||||||
env:
|
|
||||||
TAGS: bindata
|
|
||||||
- name: unit-tests
|
|
||||||
run: make unit-test-coverage test-check
|
|
||||||
env:
|
|
||||||
TAGS: bindata
|
|
||||||
RACE_ENABLED: true
|
|
||||||
GITHUB_READ_TOKEN: ${{ secrets.GITHUB_READ_TOKEN }}
|
|
||||||
- name: unit-tests-gogit
|
|
||||||
run: make unit-test-coverage test-check
|
|
||||||
env:
|
|
||||||
TAGS: bindata gogit
|
|
||||||
RACE_ENABLED: true
|
|
||||||
GITHUB_READ_TOKEN: ${{ secrets.GITHUB_READ_TOKEN }}
|
|
||||||
|
|
||||||
test-mysql:
|
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
|
||||||
needs: files-changed
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
services:
|
|
||||||
mysql:
|
|
||||||
image: mysql:8.0
|
|
||||||
env:
|
|
||||||
MYSQL_ALLOW_EMPTY_PASSWORD: true
|
|
||||||
MYSQL_DATABASE: testgitea
|
|
||||||
ports:
|
|
||||||
- "3306:3306"
|
|
||||||
elasticsearch:
|
|
||||||
image: elasticsearch:7.5.0
|
|
||||||
env:
|
|
||||||
discovery.type: single-node
|
|
||||||
ports:
|
|
||||||
- "9200:9200"
|
|
||||||
smtpimap:
|
|
||||||
image: tabascoterrier/docker-imap-devel:latest
|
|
||||||
ports:
|
|
||||||
- "25:25"
|
|
||||||
- "143:143"
|
|
||||||
- "587:587"
|
|
||||||
- "993:993"
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version-file: go.mod
|
|
||||||
check-latest: true
|
|
||||||
- name: Add hosts to /etc/hosts
|
|
||||||
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 mysql elasticsearch smtpimap" | sudo tee -a /etc/hosts'
|
|
||||||
- run: make deps-backend
|
|
||||||
- run: make backend
|
|
||||||
env:
|
|
||||||
TAGS: bindata
|
|
||||||
- name: run tests
|
|
||||||
run: make test-mysql-migration integration-test-coverage
|
|
||||||
env:
|
|
||||||
TAGS: bindata
|
|
||||||
RACE_ENABLED: true
|
|
||||||
USE_REPO_TEST_DIR: 1
|
|
||||||
TEST_INDEXER_CODE_ES_URL: "http://elastic:changeme@elasticsearch:9200"
|
|
||||||
|
|
||||||
test-mssql:
|
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
|
||||||
needs: files-changed
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
services:
|
|
||||||
mssql:
|
|
||||||
image: mcr.microsoft.com/mssql/server:2017-latest
|
|
||||||
env:
|
|
||||||
ACCEPT_EULA: Y
|
|
||||||
MSSQL_PID: Standard
|
|
||||||
SA_PASSWORD: MwantsaSecurePassword1
|
|
||||||
ports:
|
|
||||||
- "1433:1433"
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version-file: go.mod
|
|
||||||
check-latest: true
|
|
||||||
- name: Add hosts to /etc/hosts
|
|
||||||
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 mssql" | sudo tee -a /etc/hosts'
|
|
||||||
- run: make deps-backend
|
|
||||||
- run: make backend
|
|
||||||
env:
|
|
||||||
TAGS: bindata
|
|
||||||
- run: make test-mssql-migration test-mssql
|
|
||||||
timeout-minutes: 50
|
|
||||||
env:
|
|
||||||
TAGS: bindata
|
|
||||||
USE_REPO_TEST_DIR: 1
|
|
35
.github/workflows/pull-docker-dryrun.yml
vendored
35
.github/workflows/pull-docker-dryrun.yml
vendored
|
@ -1,35 +0,0 @@
|
||||||
name: docker-dryrun
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
files-changed:
|
|
||||||
uses: ./.github/workflows/files-changed.yml
|
|
||||||
|
|
||||||
regular:
|
|
||||||
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
|
|
||||||
with:
|
|
||||||
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
|
|
||||||
with:
|
|
||||||
push: false
|
|
||||||
file: Dockerfile.rootless
|
|
||||||
tags: gitea/gitea:linux-amd64
|
|
32
.github/workflows/pull-e2e-tests.yml
vendored
32
.github/workflows/pull-e2e-tests.yml
vendored
|
@ -1,32 +0,0 @@
|
||||||
name: e2e-tests
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
files-changed:
|
|
||||||
uses: ./.github/workflows/files-changed.yml
|
|
||||||
|
|
||||||
test-e2e:
|
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.frontend == 'true' || needs.files-changed.outputs.actions == '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
|
|
||||||
- uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 20
|
|
||||||
- run: make deps-frontend frontend deps-backend
|
|
||||||
- run: npx playwright install --with-deps
|
|
||||||
- run: make test-e2e-sqlite
|
|
||||||
timeout-minutes: 40
|
|
||||||
env:
|
|
||||||
USE_REPO_TEST_DIR: 1
|
|
20
.github/workflows/pull-labeler.yml
vendored
20
.github/workflows/pull-labeler.yml
vendored
|
@ -1,20 +0,0 @@
|
||||||
name: labeler
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request_target:
|
|
||||||
types: [opened, synchronize, reopened]
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
label:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
pull-requests: write
|
|
||||||
steps:
|
|
||||||
- uses: actions/labeler@v4
|
|
||||||
with:
|
|
||||||
dot: true
|
|
134
.github/workflows/release-nightly.yml
vendored
134
.github/workflows/release-nightly.yml
vendored
|
@ -1,134 +0,0 @@
|
||||||
name: release-nightly
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [main, release/v*]
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
disk-clean:
|
|
||||||
uses: ./.github/workflows/disk-clean.yml
|
|
||||||
nightly-binary:
|
|
||||||
runs-on: nscloud
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
|
||||||
# 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@v5
|
|
||||||
with:
|
|
||||||
go-version-file: go.mod
|
|
||||||
check-latest: true
|
|
||||||
- uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 20
|
|
||||||
- run: make deps-frontend deps-backend
|
|
||||||
# xgo build
|
|
||||||
- run: make release
|
|
||||||
env:
|
|
||||||
TAGS: bindata sqlite sqlite_unlock_notify
|
|
||||||
- name: import gpg key
|
|
||||||
id: import_gpg
|
|
||||||
uses: crazy-max/ghaction-import-gpg@v6
|
|
||||||
with:
|
|
||||||
gpg_private_key: ${{ secrets.GPGSIGN_KEY }}
|
|
||||||
passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
|
|
||||||
- name: sign binaries
|
|
||||||
run: |
|
|
||||||
for f in dist/release/*; do
|
|
||||||
echo '${{ secrets.GPGSIGN_PASSPHRASE }}' | gpg --pinentry-mode loopback --passphrase-fd 0 --batch --yes --detach-sign -u ${{ steps.import_gpg.outputs.fingerprint }} --output "$f.asc" "$f"
|
|
||||||
done
|
|
||||||
# clean branch name to get the folder name in S3
|
|
||||||
- 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 "Cleaned name is ${REF_NAME}"
|
|
||||||
echo "branch=${REF_NAME}" >> "$GITHUB_OUTPUT"
|
|
||||||
- name: configure aws
|
|
||||||
uses: aws-actions/configure-aws-credentials@v4
|
|
||||||
with:
|
|
||||||
aws-region: ${{ secrets.AWS_REGION }}
|
|
||||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
||||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
||||||
- 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:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
|
||||||
# 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@v5
|
|
||||||
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: |
|
|
||||||
# if main then say nightly otherwise cleanup name
|
|
||||||
if [ "${{ github.ref }}" = "refs/heads/main" ]; then
|
|
||||||
echo "branch=nightly" >> "$GITHUB_OUTPUT"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
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: fetch go modules
|
|
||||||
run: make vendor
|
|
||||||
- name: build rootful docker image
|
|
||||||
uses: docker/build-push-action@v5
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
platforms: linux/amd64,linux/arm64
|
|
||||||
push: true
|
|
||||||
tags: gitea/gitea:${{ steps.clean_name.outputs.branch }}
|
|
||||||
nightly-docker-rootless:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
|
||||||
# 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@v5
|
|
||||||
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: |
|
|
||||||
# if main then say nightly otherwise cleanup name
|
|
||||||
if [ "${{ github.ref }}" = "refs/heads/main" ]; then
|
|
||||||
echo "branch=nightly" >> "$GITHUB_OUTPUT"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
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: fetch go modules
|
|
||||||
run: make vendor
|
|
||||||
- name: build rootless docker image
|
|
||||||
uses: docker/build-push-action@v5
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
platforms: linux/amd64,linux/arm64
|
|
||||||
push: true
|
|
||||||
file: Dockerfile.rootless
|
|
||||||
tags: gitea/gitea:${{ steps.clean_name.outputs.branch }}-rootless
|
|
132
.github/workflows/release-tag-rc.yml
vendored
132
.github/workflows/release-tag-rc.yml
vendored
|
@ -1,132 +0,0 @@
|
||||||
name: release-tag-rc
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- "v1*-rc*"
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: false
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
binary:
|
|
||||||
runs-on: nscloud
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
|
||||||
# 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@v5
|
|
||||||
with:
|
|
||||||
go-version-file: go.mod
|
|
||||||
check-latest: true
|
|
||||||
- uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 20
|
|
||||||
- run: make deps-frontend deps-backend
|
|
||||||
# xgo build
|
|
||||||
- run: make release
|
|
||||||
env:
|
|
||||||
TAGS: bindata sqlite sqlite_unlock_notify
|
|
||||||
- name: import gpg key
|
|
||||||
id: import_gpg
|
|
||||||
uses: crazy-max/ghaction-import-gpg@v6
|
|
||||||
with:
|
|
||||||
gpg_private_key: ${{ secrets.GPGSIGN_KEY }}
|
|
||||||
passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
|
|
||||||
- name: sign binaries
|
|
||||||
run: |
|
|
||||||
for f in dist/release/*; do
|
|
||||||
echo '${{ secrets.GPGSIGN_PASSPHRASE }}' | gpg --pinentry-mode loopback --passphrase-fd 0 --batch --yes --detach-sign -u ${{ steps.import_gpg.outputs.fingerprint }} --output "$f.asc" "$f"
|
|
||||||
done
|
|
||||||
# clean branch name to get the folder name in S3
|
|
||||||
- name: Get cleaned branch name
|
|
||||||
id: clean_name
|
|
||||||
run: |
|
|
||||||
REF_NAME=$(echo "${{ github.ref }}" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\/v//' -e 's/release\/v//')
|
|
||||||
echo "Cleaned name is ${REF_NAME}"
|
|
||||||
echo "branch=${REF_NAME}" >> "$GITHUB_OUTPUT"
|
|
||||||
- name: configure aws
|
|
||||||
uses: aws-actions/configure-aws-credentials@v4
|
|
||||||
with:
|
|
||||||
aws-region: ${{ secrets.AWS_REGION }}
|
|
||||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
||||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
||||||
- name: upload binaries to s3
|
|
||||||
run: |
|
|
||||||
aws s3 sync dist/release s3://${{ secrets.AWS_S3_BUCKET }}/gitea/${{ steps.clean_name.outputs.branch }} --no-progress
|
|
||||||
- name: Install GH CLI
|
|
||||||
uses: dev-hanz-ops/install-gh-cli-action@v0.1.0
|
|
||||||
with:
|
|
||||||
gh-cli-version: 2.39.1
|
|
||||||
- name: create github release
|
|
||||||
run: |
|
|
||||||
gh release create ${{ github.ref_name }} --title ${{ github.ref_name }} --draft --notes-from-tag dist/release/*
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
|
||||||
docker-rootful:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
|
||||||
# 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
|
|
||||||
- uses: docker/metadata-action@v5
|
|
||||||
id: meta
|
|
||||||
with:
|
|
||||||
images: gitea/gitea
|
|
||||||
flavor: |
|
|
||||||
latest=false
|
|
||||||
# 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: build rootful docker image
|
|
||||||
uses: docker/build-push-action@v5
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
platforms: linux/amd64,linux/arm64
|
|
||||||
push: true
|
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
|
||||||
docker-rootless:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
|
||||||
# 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
|
|
||||||
- uses: docker/metadata-action@v5
|
|
||||||
id: meta
|
|
||||||
with:
|
|
||||||
images: gitea/gitea
|
|
||||||
# each tag below will have the suffix of -rootless
|
|
||||||
flavor: |
|
|
||||||
latest=false
|
|
||||||
suffix=-rootless
|
|
||||||
# 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: build rootless docker image
|
|
||||||
uses: docker/build-push-action@v5
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
platforms: linux/amd64,linux/arm64
|
|
||||||
push: true
|
|
||||||
file: Dockerfile.rootless
|
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
|
143
.github/workflows/release-tag-version.yml
vendored
143
.github/workflows/release-tag-version.yml
vendored
|
@ -1,143 +0,0 @@
|
||||||
name: release-tag-version
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- "v1.*"
|
|
||||||
- "!v1*-rc*"
|
|
||||||
- "!v1*-dev"
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: false
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
binary:
|
|
||||||
runs-on: nscloud
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
|
||||||
# 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@v5
|
|
||||||
with:
|
|
||||||
go-version-file: go.mod
|
|
||||||
check-latest: true
|
|
||||||
- uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 20
|
|
||||||
- run: make deps-frontend deps-backend
|
|
||||||
# xgo build
|
|
||||||
- run: make release
|
|
||||||
env:
|
|
||||||
TAGS: bindata sqlite sqlite_unlock_notify
|
|
||||||
- name: import gpg key
|
|
||||||
id: import_gpg
|
|
||||||
uses: crazy-max/ghaction-import-gpg@v6
|
|
||||||
with:
|
|
||||||
gpg_private_key: ${{ secrets.GPGSIGN_KEY }}
|
|
||||||
passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
|
|
||||||
- name: sign binaries
|
|
||||||
run: |
|
|
||||||
for f in dist/release/*; do
|
|
||||||
echo '${{ secrets.GPGSIGN_PASSPHRASE }}' | gpg --pinentry-mode loopback --passphrase-fd 0 --batch --yes --detach-sign -u ${{ steps.import_gpg.outputs.fingerprint }} --output "$f.asc" "$f"
|
|
||||||
done
|
|
||||||
# clean branch name to get the folder name in S3
|
|
||||||
- name: Get cleaned branch name
|
|
||||||
id: clean_name
|
|
||||||
run: |
|
|
||||||
REF_NAME=$(echo "${{ github.ref }}" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\/v//' -e 's/release\/v//')
|
|
||||||
echo "Cleaned name is ${REF_NAME}"
|
|
||||||
echo "branch=${REF_NAME}" >> "$GITHUB_OUTPUT"
|
|
||||||
- name: configure aws
|
|
||||||
uses: aws-actions/configure-aws-credentials@v4
|
|
||||||
with:
|
|
||||||
aws-region: ${{ secrets.AWS_REGION }}
|
|
||||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
||||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
||||||
- name: upload binaries to s3
|
|
||||||
run: |
|
|
||||||
aws s3 sync dist/release s3://${{ secrets.AWS_S3_BUCKET }}/gitea/${{ steps.clean_name.outputs.branch }} --no-progress
|
|
||||||
- name: Install GH CLI
|
|
||||||
uses: dev-hanz-ops/install-gh-cli-action@v0.1.0
|
|
||||||
with:
|
|
||||||
gh-cli-version: 2.39.1
|
|
||||||
- name: create github release
|
|
||||||
run: |
|
|
||||||
gh release create ${{ github.ref_name }} --title ${{ github.ref_name }} --notes-from-tag dist/release/*
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
|
||||||
docker-rootful:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
|
||||||
# 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
|
|
||||||
- uses: docker/metadata-action@v5
|
|
||||||
id: meta
|
|
||||||
with:
|
|
||||||
images: gitea/gitea
|
|
||||||
# this will generate tags in the following format:
|
|
||||||
# latest
|
|
||||||
# 1
|
|
||||||
# 1.2
|
|
||||||
# 1.2.3
|
|
||||||
tags: |
|
|
||||||
type=semver,pattern={{major}}
|
|
||||||
type=semver,pattern={{major}}.{{minor}}
|
|
||||||
type=semver,pattern={{version}}
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
- name: build rootful docker image
|
|
||||||
uses: docker/build-push-action@v5
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
platforms: linux/amd64,linux/arm64
|
|
||||||
push: true
|
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
|
||||||
docker-rootless:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
|
||||||
# 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
|
|
||||||
- uses: docker/metadata-action@v5
|
|
||||||
id: meta
|
|
||||||
with:
|
|
||||||
images: gitea/gitea
|
|
||||||
# each tag below will have the suffix of -rootless
|
|
||||||
flavor: |
|
|
||||||
suffix=-rootless,onlatest=true
|
|
||||||
# this will generate tags in the following format (with -rootless suffix added):
|
|
||||||
# latest
|
|
||||||
# 1
|
|
||||||
# 1.2
|
|
||||||
# 1.2.3
|
|
||||||
tags: |
|
|
||||||
type=semver,pattern={{major}}
|
|
||||||
type=semver,pattern={{major}}.{{minor}}
|
|
||||||
type=semver,pattern={{version}}
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
- name: build rootless docker image
|
|
||||||
uses: docker/build-push-action@v5
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
platforms: linux/amd64,linux/arm64
|
|
||||||
push: true
|
|
||||||
file: Dockerfile.rootless
|
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,3 +1,6 @@
|
||||||
|
# Emacs
|
||||||
|
*~
|
||||||
|
|
||||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||||
*.o
|
*.o
|
||||||
*.a
|
*.a
|
||||||
|
|
45
Dockerfile
45
Dockerfile
|
@ -1,5 +1,6 @@
|
||||||
# Build stage
|
FROM --platform=$BUILDPLATFORM docker.io/tonistiigi/xx AS xx
|
||||||
FROM docker.io/library/golang:1.21-alpine3.19 AS build-env
|
|
||||||
|
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.21-alpine3.19 as build-env
|
||||||
|
|
||||||
ARG GOPROXY
|
ARG GOPROXY
|
||||||
ENV GOPROXY ${GOPROXY:-direct}
|
ENV GOPROXY ${GOPROXY:-direct}
|
||||||
|
@ -9,24 +10,33 @@ ARG TAGS="sqlite sqlite_unlock_notify"
|
||||||
ENV TAGS "bindata timetzdata $TAGS"
|
ENV TAGS "bindata timetzdata $TAGS"
|
||||||
ARG CGO_EXTRA_CFLAGS
|
ARG CGO_EXTRA_CFLAGS
|
||||||
|
|
||||||
# Build deps
|
#
|
||||||
RUN apk --no-cache add \
|
# Transparently cross compile for the target platform
|
||||||
build-base \
|
#
|
||||||
git \
|
COPY --from=xx / /
|
||||||
nodejs \
|
ARG TARGETPLATFORM
|
||||||
npm \
|
RUN apk --no-cache add clang lld
|
||||||
&& rm -rf /var/cache/apk/*
|
RUN xx-apk --no-cache add gcc musl-dev
|
||||||
|
ENV CGO_ENABLED=1
|
||||||
|
RUN xx-go --wrap
|
||||||
|
#
|
||||||
|
# for go generate and binfmt to find
|
||||||
|
# without it the generate phase will fail with
|
||||||
|
# #19 25.04 modules/public/public_bindata.go:8: running "go": exit status 1
|
||||||
|
# #19 25.39 aarch64-binfmt-P: Could not open '/lib/ld-musl-aarch64.so.1': No such file or directory
|
||||||
|
# why exactly is it needed? where is binfmt involved?
|
||||||
|
#
|
||||||
|
RUN cp /*-alpine-linux-musl*/lib/ld-musl-*.so.1 /lib || true
|
||||||
|
|
||||||
|
RUN apk --no-cache add build-base git nodejs npm
|
||||||
|
|
||||||
# Setup repo
|
|
||||||
COPY . ${GOPATH}/src/code.gitea.io/gitea
|
COPY . ${GOPATH}/src/code.gitea.io/gitea
|
||||||
WORKDIR ${GOPATH}/src/code.gitea.io/gitea
|
WORKDIR ${GOPATH}/src/code.gitea.io/gitea
|
||||||
|
|
||||||
# Checkout version if set
|
RUN make clean-all
|
||||||
RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \
|
RUN make frontend
|
||||||
&& make clean-all build
|
RUN go build contrib/environment-to-ini/environment-to-ini.go && xx-verify environment-to-ini
|
||||||
|
RUN make go-check generate-backend static-executable && xx-verify gitea
|
||||||
# Begin env-to-ini build
|
|
||||||
RUN go build contrib/environment-to-ini/environment-to-ini.go
|
|
||||||
|
|
||||||
# Copy local files
|
# Copy local files
|
||||||
COPY docker/root /tmp/local
|
COPY docker/root /tmp/local
|
||||||
|
@ -42,7 +52,7 @@ RUN chmod 755 /tmp/local/usr/bin/entrypoint \
|
||||||
RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete
|
RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete
|
||||||
|
|
||||||
FROM docker.io/library/alpine:3.19
|
FROM docker.io/library/alpine:3.19
|
||||||
LABEL maintainer="maintainers@gitea.io"
|
LABEL maintainer="contact@forgejo.org"
|
||||||
|
|
||||||
EXPOSE 22 3000
|
EXPOSE 22 3000
|
||||||
|
|
||||||
|
@ -81,6 +91,7 @@ ENTRYPOINT ["/usr/bin/entrypoint"]
|
||||||
CMD ["/bin/s6-svscan", "/etc/s6"]
|
CMD ["/bin/s6-svscan", "/etc/s6"]
|
||||||
|
|
||||||
COPY --from=build-env /tmp/local /
|
COPY --from=build-env /tmp/local /
|
||||||
|
RUN cd /usr/local/bin ; ln -s gitea forgejo
|
||||||
COPY --from=build-env /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
|
COPY --from=build-env /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
|
||||||
COPY --from=build-env /go/src/code.gitea.io/gitea/environment-to-ini /usr/local/bin/environment-to-ini
|
COPY --from=build-env /go/src/code.gitea.io/gitea/environment-to-ini /usr/local/bin/environment-to-ini
|
||||||
COPY --from=build-env /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete /etc/profile.d/gitea_bash_autocomplete.sh
|
COPY --from=build-env /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete /etc/profile.d/gitea_bash_autocomplete.sh
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
# Build stage
|
FROM --platform=$BUILDPLATFORM docker.io/tonistiigi/xx AS xx
|
||||||
FROM docker.io/library/golang:1.21-alpine3.19 AS build-env
|
|
||||||
|
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.21-alpine3.19 as build-env
|
||||||
|
|
||||||
ARG GOPROXY
|
ARG GOPROXY
|
||||||
ENV GOPROXY ${GOPROXY:-direct}
|
ENV GOPROXY ${GOPROXY:-direct}
|
||||||
|
@ -9,24 +10,33 @@ ARG TAGS="sqlite sqlite_unlock_notify"
|
||||||
ENV TAGS "bindata timetzdata $TAGS"
|
ENV TAGS "bindata timetzdata $TAGS"
|
||||||
ARG CGO_EXTRA_CFLAGS
|
ARG CGO_EXTRA_CFLAGS
|
||||||
|
|
||||||
#Build deps
|
#
|
||||||
RUN apk --no-cache add \
|
# Transparently cross compile for the target platform
|
||||||
build-base \
|
#
|
||||||
git \
|
COPY --from=xx / /
|
||||||
nodejs \
|
ARG TARGETPLATFORM
|
||||||
npm \
|
RUN apk --no-cache add clang lld
|
||||||
&& rm -rf /var/cache/apk/*
|
RUN xx-apk --no-cache add gcc musl-dev
|
||||||
|
ENV CGO_ENABLED=1
|
||||||
|
RUN xx-go --wrap
|
||||||
|
#
|
||||||
|
# for go generate and binfmt to find
|
||||||
|
# without it the generate phase will fail with
|
||||||
|
# #19 25.04 modules/public/public_bindata.go:8: running "go": exit status 1
|
||||||
|
# #19 25.39 aarch64-binfmt-P: Could not open '/lib/ld-musl-aarch64.so.1': No such file or directory
|
||||||
|
# why exactly is it needed? where is binfmt involved?
|
||||||
|
#
|
||||||
|
RUN cp /*-alpine-linux-musl*/lib/ld-musl-*.so.1 /lib || true
|
||||||
|
|
||||||
|
RUN apk --no-cache add build-base git nodejs npm
|
||||||
|
|
||||||
# Setup repo
|
|
||||||
COPY . ${GOPATH}/src/code.gitea.io/gitea
|
COPY . ${GOPATH}/src/code.gitea.io/gitea
|
||||||
WORKDIR ${GOPATH}/src/code.gitea.io/gitea
|
WORKDIR ${GOPATH}/src/code.gitea.io/gitea
|
||||||
|
|
||||||
# Checkout version if set
|
RUN make clean-all
|
||||||
RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \
|
RUN make frontend
|
||||||
&& make clean-all build
|
RUN go build contrib/environment-to-ini/environment-to-ini.go && xx-verify environment-to-ini
|
||||||
|
RUN make go-check generate-backend static-executable && xx-verify gitea
|
||||||
# Begin env-to-ini build
|
|
||||||
RUN go build contrib/environment-to-ini/environment-to-ini.go
|
|
||||||
|
|
||||||
# Copy local files
|
# Copy local files
|
||||||
COPY docker/rootless /tmp/local
|
COPY docker/rootless /tmp/local
|
||||||
|
@ -40,7 +50,7 @@ RUN chmod 755 /tmp/local/usr/local/bin/docker-entrypoint.sh \
|
||||||
RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete
|
RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete
|
||||||
|
|
||||||
FROM docker.io/library/alpine:3.19
|
FROM docker.io/library/alpine:3.19
|
||||||
LABEL maintainer="maintainers@gitea.io"
|
LABEL maintainer="contact@forgejo.org"
|
||||||
|
|
||||||
EXPOSE 2222 3000
|
EXPOSE 2222 3000
|
||||||
|
|
||||||
|
@ -69,18 +79,19 @@ RUN mkdir -p /var/lib/gitea /etc/gitea
|
||||||
RUN chown git:git /var/lib/gitea /etc/gitea
|
RUN chown git:git /var/lib/gitea /etc/gitea
|
||||||
|
|
||||||
COPY --from=build-env /tmp/local /
|
COPY --from=build-env /tmp/local /
|
||||||
|
RUN cd /usr/local/bin ; ln -s gitea forgejo
|
||||||
COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
|
COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
|
||||||
COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/environment-to-ini /usr/local/bin/environment-to-ini
|
COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/environment-to-ini /usr/local/bin/environment-to-ini
|
||||||
COPY --from=build-env /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete /etc/profile.d/gitea_bash_autocomplete.sh
|
COPY --from=build-env /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete /etc/profile.d/gitea_bash_autocomplete.sh
|
||||||
|
|
||||||
# git:git
|
#git:git
|
||||||
USER 1000:1000
|
USER 1000:1000
|
||||||
ENV GITEA_WORK_DIR /var/lib/gitea
|
ENV GITEA_WORK_DIR /var/lib/gitea
|
||||||
ENV GITEA_CUSTOM /var/lib/gitea/custom
|
ENV GITEA_CUSTOM /var/lib/gitea/custom
|
||||||
ENV GITEA_TEMP /tmp/gitea
|
ENV GITEA_TEMP /tmp/gitea
|
||||||
ENV TMPDIR /tmp/gitea
|
ENV TMPDIR /tmp/gitea
|
||||||
|
|
||||||
# TODO add to docs the ability to define the ini to load (useful to test and revert a config)
|
#TODO add to docs the ability to define the ini to load (useful to test and revert a config)
|
||||||
ENV GITEA_APP_INI /etc/gitea/app.ini
|
ENV GITEA_APP_INI /etc/gitea/app.ini
|
||||||
ENV HOME "/var/lib/gitea/git"
|
ENV HOME "/var/lib/gitea/git"
|
||||||
VOLUME ["/var/lib/gitea", "/etc/gitea"]
|
VOLUME ["/var/lib/gitea", "/etc/gitea"]
|
||||||
|
@ -88,3 +99,4 @@ WORKDIR /var/lib/gitea
|
||||||
|
|
||||||
ENTRYPOINT ["/usr/bin/dumb-init", "--", "/usr/local/bin/docker-entrypoint.sh"]
|
ENTRYPOINT ["/usr/bin/dumb-init", "--", "/usr/local/bin/docker-entrypoint.sh"]
|
||||||
CMD []
|
CMD []
|
||||||
|
|
||||||
|
|
49
Makefile
49
Makefile
|
@ -83,31 +83,14 @@ endif
|
||||||
STORED_VERSION_FILE := VERSION
|
STORED_VERSION_FILE := VERSION
|
||||||
HUGO_VERSION ?= 0.111.3
|
HUGO_VERSION ?= 0.111.3
|
||||||
|
|
||||||
GITHUB_REF_TYPE ?= branch
|
|
||||||
GITHUB_REF_NAME ?= $(shell git rev-parse --abbrev-ref HEAD)
|
|
||||||
|
|
||||||
ifneq ($(GITHUB_REF_TYPE),branch)
|
STORED_VERSION=$(shell cat $(STORED_VERSION_FILE) 2>/dev/null)
|
||||||
VERSION ?= $(subst v,,$(GITHUB_REF_NAME))
|
ifneq ($(STORED_VERSION),)
|
||||||
GITEA_VERSION ?= $(VERSION)
|
GITEA_VERSION ?= $(STORED_VERSION)
|
||||||
else
|
else
|
||||||
ifneq ($(GITHUB_REF_NAME),)
|
GITEA_VERSION ?= $(shell git describe --tags --always | sed 's/-/+/' | sed 's/^v//')
|
||||||
VERSION ?= $(subst release/v,,$(GITHUB_REF_NAME))
|
|
||||||
else
|
|
||||||
VERSION ?= main
|
|
||||||
endif
|
|
||||||
|
|
||||||
STORED_VERSION=$(shell cat $(STORED_VERSION_FILE) 2>/dev/null)
|
|
||||||
ifneq ($(STORED_VERSION),)
|
|
||||||
GITEA_VERSION ?= $(STORED_VERSION)
|
|
||||||
else
|
|
||||||
GITEA_VERSION ?= $(shell git describe --tags --always | sed 's/-/+/' | sed 's/^v//')
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
# if version = "main" then update version to "nightly"
|
|
||||||
ifeq ($(VERSION),main)
|
|
||||||
VERSION := main-nightly
|
|
||||||
endif
|
endif
|
||||||
|
VERSION = ${GITEA_VERSION}
|
||||||
|
|
||||||
LDFLAGS := $(LDFLAGS) -X "main.MakeVersion=$(MAKE_VERSION)" -X "main.Version=$(GITEA_VERSION)" -X "main.Tags=$(TAGS)"
|
LDFLAGS := $(LDFLAGS) -X "main.MakeVersion=$(MAKE_VERSION)" -X "main.Version=$(GITEA_VERSION)" -X "main.Tags=$(TAGS)"
|
||||||
|
|
||||||
|
@ -413,12 +396,11 @@ lint-go-windows:
|
||||||
.PHONY: lint-go-vet
|
.PHONY: lint-go-vet
|
||||||
lint-go-vet:
|
lint-go-vet:
|
||||||
@echo "Running go vet..."
|
@echo "Running go vet..."
|
||||||
@GOOS= GOARCH= $(GO) build code.gitea.io/gitea-vet
|
@$(GO) vet $(GO_PACKAGES)
|
||||||
@$(GO) vet -vettool=gitea-vet $(GO_PACKAGES)
|
|
||||||
|
|
||||||
.PHONY: lint-editorconfig
|
.PHONY: lint-editorconfig
|
||||||
lint-editorconfig:
|
lint-editorconfig:
|
||||||
$(GO) run $(EDITORCONFIG_CHECKER_PACKAGE) templates .github/workflows
|
$(GO) run $(EDITORCONFIG_CHECKER_PACKAGE) templates .forgejo/workflows
|
||||||
|
|
||||||
.PHONY: lint-actions
|
.PHONY: lint-actions
|
||||||
lint-actions:
|
lint-actions:
|
||||||
|
@ -788,8 +770,14 @@ security-check:
|
||||||
$(EXECUTABLE): $(GO_SOURCES) $(TAGS_PREREQ)
|
$(EXECUTABLE): $(GO_SOURCES) $(TAGS_PREREQ)
|
||||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' -o $@
|
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' -o $@
|
||||||
|
|
||||||
|
static-executable: $(GO_SOURCES) $(TAGS_PREREQ)
|
||||||
|
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags 'netgo osusergo $(TAGS)' -ldflags '-s -w -linkmode external -extldflags "-static" $(LDFLAGS)' -o $(EXECUTABLE)
|
||||||
|
|
||||||
.PHONY: release
|
.PHONY: release
|
||||||
release: frontend generate release-windows release-linux release-darwin release-freebsd release-copy release-compress vendor release-sources release-docs release-check
|
release: frontend generate release-linux release-copy release-compress vendor release-sources release-check
|
||||||
|
|
||||||
|
# just the sources, with all assets builtin and frontend resources generated
|
||||||
|
sources-tarbal: frontend generate vendor release-sources release-check
|
||||||
|
|
||||||
$(DIST_DIRS):
|
$(DIST_DIRS):
|
||||||
mkdir -p $(DIST_DIRS)
|
mkdir -p $(DIST_DIRS)
|
||||||
|
@ -803,7 +791,10 @@ endif
|
||||||
|
|
||||||
.PHONY: release-linux
|
.PHONY: release-linux
|
||||||
release-linux: | $(DIST_DIRS)
|
release-linux: | $(DIST_DIRS)
|
||||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out gitea-$(VERSION) .
|
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out forgejo-$(VERSION) .
|
||||||
|
ifeq ($(CI),true)
|
||||||
|
cp /build/* $(DIST)/binaries
|
||||||
|
endif
|
||||||
|
|
||||||
.PHONY: release-darwin
|
.PHONY: release-darwin
|
||||||
release-darwin: | $(DIST_DIRS)
|
release-darwin: | $(DIST_DIRS)
|
||||||
|
@ -831,8 +822,8 @@ release-sources: | $(DIST_DIRS)
|
||||||
# bsdtar needs a ^ to prevent matching subdirectories
|
# bsdtar needs a ^ to prevent matching subdirectories
|
||||||
$(eval EXCL := --exclude=$(shell tar --help | grep -q bsdtar && echo "^")./)
|
$(eval EXCL := --exclude=$(shell tar --help | grep -q bsdtar && echo "^")./)
|
||||||
# use transform to a add a release-folder prefix; in bsdtar the transform parameter equivalent is -s
|
# use transform to a add a release-folder prefix; in bsdtar the transform parameter equivalent is -s
|
||||||
$(eval TRANSFORM := $(shell tar --help | grep -q bsdtar && echo "-s '/^./gitea-src-$(VERSION)/'" || echo "--transform 's|^./|gitea-src-$(VERSION)/|'"))
|
$(eval TRANSFORM := $(shell tar --help | grep -q bsdtar && echo "-s '/^./forgejo-src-$(VERSION)/'" || echo "--transform 's|^./|forgejo-src-$(VERSION)/|'"))
|
||||||
tar $(addprefix $(EXCL),$(TAR_EXCLUDES)) $(TRANSFORM) -czf $(DIST)/release/gitea-src-$(VERSION).tar.gz .
|
tar $(addprefix $(EXCL),$(TAR_EXCLUDES)) $(TRANSFORM) -czf $(DIST)/release/forgejo-src-$(VERSION).tar.gz .
|
||||||
rm -f $(STORED_VERSION_FILE)
|
rm -f $(STORED_VERSION_FILE)
|
||||||
|
|
||||||
.PHONY: release-docs
|
.PHONY: release-docs
|
||||||
|
|
|
@ -50,6 +50,6 @@ func runGenerateActionsRunnerToken(c *cli.Context) error {
|
||||||
if extra.HasError() {
|
if extra.HasError() {
|
||||||
return handleCliResponseExtra(extra)
|
return handleCliResponseExtra(extra)
|
||||||
}
|
}
|
||||||
_, _ = fmt.Printf("%s\n", respText)
|
_, _ = fmt.Printf("%s\n", respText.Text)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,9 +15,9 @@ import (
|
||||||
"code.gitea.io/gitea/models/migrations"
|
"code.gitea.io/gitea/models/migrations"
|
||||||
migrate_base "code.gitea.io/gitea/models/migrations/base"
|
migrate_base "code.gitea.io/gitea/models/migrations/base"
|
||||||
"code.gitea.io/gitea/modules/container"
|
"code.gitea.io/gitea/modules/container"
|
||||||
"code.gitea.io/gitea/modules/doctor"
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/services/doctor"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
"xorm.io/xorm"
|
"xorm.io/xorm"
|
||||||
|
|
|
@ -7,8 +7,8 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/doctor"
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/services/doctor"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
243
cmd/forgejo/actions.go
Normal file
243
cmd/forgejo/actions.go
Normal file
|
@ -0,0 +1,243 @@
|
||||||
|
// Copyright The Forgejo Authors.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package forgejo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
actions_model "code.gitea.io/gitea/models/actions"
|
||||||
|
"code.gitea.io/gitea/modules/private"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
private_routers "code.gitea.io/gitea/routers/private"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CmdActions(ctx context.Context) *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
|
Name: "actions",
|
||||||
|
Usage: "Commands for managing Forgejo Actions",
|
||||||
|
Subcommands: []*cli.Command{
|
||||||
|
SubcmdActionsGenerateRunnerToken(ctx),
|
||||||
|
SubcmdActionsGenerateRunnerSecret(ctx),
|
||||||
|
SubcmdActionsRegister(ctx),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SubcmdActionsGenerateRunnerToken(ctx context.Context) *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
|
Name: "generate-runner-token",
|
||||||
|
Usage: "Generate a new token for a runner to use to register with the server",
|
||||||
|
Action: prepareWorkPathAndCustomConf(ctx, func(cliCtx *cli.Context) error { return RunGenerateActionsRunnerToken(ctx, cliCtx) }),
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "scope",
|
||||||
|
Aliases: []string{"s"},
|
||||||
|
Value: "",
|
||||||
|
Usage: "{owner}[/{repo}] - leave empty for a global runner",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SubcmdActionsGenerateRunnerSecret(ctx context.Context) *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
|
Name: "generate-secret",
|
||||||
|
Usage: "Generate a secret suitable for input to the register subcommand",
|
||||||
|
Action: func(cliCtx *cli.Context) error { return RunGenerateSecret(ctx, cliCtx) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SubcmdActionsRegister(ctx context.Context) *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
|
Name: "register",
|
||||||
|
Usage: "Idempotent registration of a runner using a shared secret",
|
||||||
|
Action: prepareWorkPathAndCustomConf(ctx, func(cliCtx *cli.Context) error { return RunRegister(ctx, cliCtx) }),
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "secret",
|
||||||
|
Usage: "the secret the runner will use to connect as a 40 character hexadecimal string",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "secret-stdin",
|
||||||
|
Usage: "the secret the runner will use to connect as a 40 character hexadecimal string, read from stdin",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "secret-file",
|
||||||
|
Usage: "path to the file containing the secret the runner will use to connect as a 40 character hexadecimal string",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "scope",
|
||||||
|
Aliases: []string{"s"},
|
||||||
|
Value: "",
|
||||||
|
Usage: "{owner}[/{repo}] - leave empty for a global runner",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "labels",
|
||||||
|
Value: "",
|
||||||
|
Usage: "comma separated list of labels supported by the runner (e.g. docker,ubuntu-latest,self-hosted) (not required since v1.21)",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "name",
|
||||||
|
Value: "runner",
|
||||||
|
Usage: "name of the runner (default runner)",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "version",
|
||||||
|
Value: "",
|
||||||
|
Usage: "version of the runner (not required since v1.21)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func readSecret(ctx context.Context, cliCtx *cli.Context) (string, error) {
|
||||||
|
if cliCtx.IsSet("secret") {
|
||||||
|
return cliCtx.String("secret"), nil
|
||||||
|
}
|
||||||
|
if cliCtx.IsSet("secret-stdin") {
|
||||||
|
buf, err := io.ReadAll(ContextGetStdin(ctx))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(buf), nil
|
||||||
|
}
|
||||||
|
if cliCtx.IsSet("secret-file") {
|
||||||
|
path := cliCtx.String("secret-file")
|
||||||
|
buf, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(buf), nil
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("at least one of the --secret, --secret-stdin, --secret-file options is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateSecret(secret string) error {
|
||||||
|
secretLen := len(secret)
|
||||||
|
if secretLen != 40 {
|
||||||
|
return fmt.Errorf("the secret must be exactly 40 characters long, not %d: generate-secret can provide a secret matching the requirements", secretLen)
|
||||||
|
}
|
||||||
|
if _, err := hex.DecodeString(secret); err != nil {
|
||||||
|
return fmt.Errorf("the secret must be an hexadecimal string: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func RunRegister(ctx context.Context, cliCtx *cli.Context) error {
|
||||||
|
if !ContextGetNoInit(ctx) {
|
||||||
|
var cancel context.CancelFunc
|
||||||
|
ctx, cancel = installSignals(ctx)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if err := initDB(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setting.MustInstalled()
|
||||||
|
|
||||||
|
secret, err := readSecret(ctx, cliCtx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := validateSecret(secret); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
scope := cliCtx.String("scope")
|
||||||
|
labels := cliCtx.String("labels")
|
||||||
|
name := cliCtx.String("name")
|
||||||
|
version := cliCtx.String("version")
|
||||||
|
|
||||||
|
//
|
||||||
|
// There are two kinds of tokens
|
||||||
|
//
|
||||||
|
// - "registration token" only used when a runner interacts to
|
||||||
|
// register
|
||||||
|
//
|
||||||
|
// - "token" obtained after a successful registration and stored by
|
||||||
|
// the runner to authenticate
|
||||||
|
//
|
||||||
|
// The register subcommand does not need a "registration token", it
|
||||||
|
// needs a "token". Using the same name is confusing and secret is
|
||||||
|
// preferred for this reason in the cli.
|
||||||
|
//
|
||||||
|
// The ActionsRunnerRegister argument is token to be consistent with
|
||||||
|
// the internal naming. It is still confusing to the developer but
|
||||||
|
// not to the user.
|
||||||
|
//
|
||||||
|
owner, repo, err := private_routers.ParseScope(ctx, scope)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
runner, err := actions_model.RegisterRunner(ctx, owner, repo, secret, strings.Split(labels, ","), name, version)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error while registering runner: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := fmt.Fprintf(ContextGetStdout(ctx), "%s", runner.UUID); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func RunGenerateSecret(ctx context.Context, cliCtx *cli.Context) error {
|
||||||
|
runner := actions_model.ActionRunner{}
|
||||||
|
if err := runner.GenerateToken(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := fmt.Fprintf(ContextGetStdout(ctx), "%s", runner.Token); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func RunGenerateActionsRunnerToken(ctx context.Context, cliCtx *cli.Context) error {
|
||||||
|
if !ContextGetNoInit(ctx) {
|
||||||
|
var cancel context.CancelFunc
|
||||||
|
ctx, cancel = installSignals(ctx)
|
||||||
|
defer cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
setting.MustInstalled()
|
||||||
|
|
||||||
|
scope := cliCtx.String("scope")
|
||||||
|
|
||||||
|
respText, extra := private.GenerateActionsRunnerToken(ctx, scope)
|
||||||
|
if extra.HasError() {
|
||||||
|
return handleCliResponseExtra(ctx, extra)
|
||||||
|
}
|
||||||
|
if _, err := fmt.Fprintf(ContextGetStdout(ctx), "%s", respText.Text); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func prepareWorkPathAndCustomConf(ctx context.Context, action cli.ActionFunc) func(cliCtx *cli.Context) error {
|
||||||
|
return func(cliCtx *cli.Context) error {
|
||||||
|
if !ContextGetNoInit(ctx) {
|
||||||
|
var args setting.ArgWorkPathAndCustomConf
|
||||||
|
// from children to parent, check the global flags
|
||||||
|
for _, curCtx := range cliCtx.Lineage() {
|
||||||
|
if curCtx.IsSet("work-path") && args.WorkPath == "" {
|
||||||
|
args.WorkPath = curCtx.String("work-path")
|
||||||
|
}
|
||||||
|
if curCtx.IsSet("custom-path") && args.CustomPath == "" {
|
||||||
|
args.CustomPath = curCtx.String("custom-path")
|
||||||
|
}
|
||||||
|
if curCtx.IsSet("config") && args.CustomConf == "" {
|
||||||
|
args.CustomConf = curCtx.String("config")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setting.InitWorkPathAndCommonConfig(os.Getenv, args)
|
||||||
|
}
|
||||||
|
return action(cliCtx)
|
||||||
|
}
|
||||||
|
}
|
147
cmd/forgejo/forgejo.go
Normal file
147
cmd/forgejo/forgejo.go
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
// Copyright The Forgejo Authors.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package forgejo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/private"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type key int
|
||||||
|
|
||||||
|
const (
|
||||||
|
noInitKey key = iota + 1
|
||||||
|
noExitKey
|
||||||
|
stdoutKey
|
||||||
|
stderrKey
|
||||||
|
stdinKey
|
||||||
|
)
|
||||||
|
|
||||||
|
func CmdForgejo(ctx context.Context) *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
|
Name: "forgejo-cli",
|
||||||
|
Usage: "Forgejo CLI",
|
||||||
|
Flags: []cli.Flag{},
|
||||||
|
Subcommands: []*cli.Command{
|
||||||
|
CmdActions(ctx),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ContextSetNoInit(ctx context.Context, value bool) context.Context {
|
||||||
|
return context.WithValue(ctx, noInitKey, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ContextGetNoInit(ctx context.Context) bool {
|
||||||
|
value, ok := ctx.Value(noInitKey).(bool)
|
||||||
|
return ok && value
|
||||||
|
}
|
||||||
|
|
||||||
|
func ContextSetNoExit(ctx context.Context, value bool) context.Context {
|
||||||
|
return context.WithValue(ctx, noExitKey, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ContextGetNoExit(ctx context.Context) bool {
|
||||||
|
value, ok := ctx.Value(noExitKey).(bool)
|
||||||
|
return ok && value
|
||||||
|
}
|
||||||
|
|
||||||
|
func ContextSetStderr(ctx context.Context, value io.Writer) context.Context {
|
||||||
|
return context.WithValue(ctx, stderrKey, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ContextGetStderr(ctx context.Context) io.Writer {
|
||||||
|
value, ok := ctx.Value(stderrKey).(io.Writer)
|
||||||
|
if !ok {
|
||||||
|
return os.Stderr
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
func ContextSetStdout(ctx context.Context, value io.Writer) context.Context {
|
||||||
|
return context.WithValue(ctx, stdoutKey, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ContextGetStdout(ctx context.Context) io.Writer {
|
||||||
|
value, ok := ctx.Value(stderrKey).(io.Writer)
|
||||||
|
if !ok {
|
||||||
|
return os.Stdout
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
func ContextSetStdin(ctx context.Context, value io.Reader) context.Context {
|
||||||
|
return context.WithValue(ctx, stdinKey, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ContextGetStdin(ctx context.Context) io.Reader {
|
||||||
|
value, ok := ctx.Value(stdinKey).(io.Reader)
|
||||||
|
if !ok {
|
||||||
|
return os.Stdin
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
// copied from ../cmd.go
|
||||||
|
func initDB(ctx context.Context) error {
|
||||||
|
setting.MustInstalled()
|
||||||
|
setting.LoadDBSetting()
|
||||||
|
setting.InitSQLLoggersForCli(log.INFO)
|
||||||
|
|
||||||
|
if setting.Database.Type == "" {
|
||||||
|
log.Fatal(`Database settings are missing from the configuration file: %q.
|
||||||
|
Ensure you are running in the correct environment or set the correct configuration file with -c.
|
||||||
|
If this is the intended configuration file complete the [database] section.`, setting.CustomConf)
|
||||||
|
}
|
||||||
|
if err := db.InitEngine(ctx); err != nil {
|
||||||
|
return fmt.Errorf("unable to initialize the database using the configuration in %q. Error: %w", setting.CustomConf, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// copied from ../cmd.go
|
||||||
|
func installSignals(ctx context.Context) (context.Context, context.CancelFunc) {
|
||||||
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
go func() {
|
||||||
|
// install notify
|
||||||
|
signalChannel := make(chan os.Signal, 1)
|
||||||
|
|
||||||
|
signal.Notify(
|
||||||
|
signalChannel,
|
||||||
|
syscall.SIGINT,
|
||||||
|
syscall.SIGTERM,
|
||||||
|
)
|
||||||
|
select {
|
||||||
|
case <-signalChannel:
|
||||||
|
case <-ctx.Done():
|
||||||
|
}
|
||||||
|
cancel()
|
||||||
|
signal.Reset()
|
||||||
|
}()
|
||||||
|
|
||||||
|
return ctx, cancel
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleCliResponseExtra(ctx context.Context, extra private.ResponseExtra) error {
|
||||||
|
if false && extra.UserMsg != "" {
|
||||||
|
if _, err := fmt.Fprintf(ContextGetStdout(ctx), "%s", extra.UserMsg); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ContextGetNoExit(ctx) {
|
||||||
|
return extra.Error
|
||||||
|
}
|
||||||
|
return cli.Exit(extra.Error, 1)
|
||||||
|
}
|
|
@ -78,6 +78,6 @@ func runKeys(c *cli.Context) error {
|
||||||
if extra.Error != nil {
|
if extra.Error != nil {
|
||||||
return extra.Error
|
return extra.Error
|
||||||
}
|
}
|
||||||
_, _ = fmt.Fprintln(c.App.Writer, strings.TrimSpace(authorizedString))
|
_, _ = fmt.Fprintln(c.App.Writer, strings.TrimSpace(authorizedString.Text))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,6 @@ func runSendMail(c *cli.Context) error {
|
||||||
if extra.HasError() {
|
if extra.HasError() {
|
||||||
return handleCliResponseExtra(extra)
|
return handleCliResponseExtra(extra)
|
||||||
}
|
}
|
||||||
_, _ = fmt.Printf("Sent %s email(s) to all users\n", respText)
|
_, _ = fmt.Printf("Sent %s email(s) to all users\n", respText.Text)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
37
cmd/main.go
37
cmd/main.go
|
@ -4,10 +4,13 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/cmd/forgejo"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
|
@ -113,6 +116,36 @@ func prepareWorkPathAndCustomConf(action cli.ActionFunc) func(ctx *cli.Context)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMainApp(version, versionExtra string) *cli.App {
|
func NewMainApp(version, versionExtra string) *cli.App {
|
||||||
|
path, err := os.Executable()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
executable := filepath.Base(path)
|
||||||
|
|
||||||
|
var subCmdsStandalone []*cli.Command = make([]*cli.Command, 0, 10)
|
||||||
|
var subCmdWithConfig []*cli.Command = make([]*cli.Command, 0, 10)
|
||||||
|
|
||||||
|
//
|
||||||
|
// If the executable is forgejo-cli, provide a Forgejo specific CLI
|
||||||
|
// that is NOT compatible with Gitea.
|
||||||
|
//
|
||||||
|
if executable == "forgejo-cli" {
|
||||||
|
subCmdsStandalone = append(subCmdsStandalone, forgejo.CmdActions(context.Background()))
|
||||||
|
} else {
|
||||||
|
//
|
||||||
|
// Otherwise provide a Gitea compatible CLI which includes Forgejo
|
||||||
|
// specific additions under the forgejo-cli subcommand. It allows
|
||||||
|
// admins to migration from Gitea to Forgejo by replacing the gitea
|
||||||
|
// binary and rename it to forgejo if they want.
|
||||||
|
//
|
||||||
|
subCmdsStandalone = append(subCmdsStandalone, forgejo.CmdForgejo(context.Background()))
|
||||||
|
subCmdWithConfig = append(subCmdWithConfig, CmdActions)
|
||||||
|
}
|
||||||
|
|
||||||
|
return innerNewMainApp(version, versionExtra, subCmdsStandalone, subCmdWithConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
func innerNewMainApp(version, versionExtra string, subCmdsStandaloneArgs, subCmdWithConfigArgs []*cli.Command) *cli.App {
|
||||||
app := cli.NewApp()
|
app := cli.NewApp()
|
||||||
app.Name = "Gitea"
|
app.Name = "Gitea"
|
||||||
app.HelpName = "gitea"
|
app.HelpName = "gitea"
|
||||||
|
@ -137,15 +170,17 @@ func NewMainApp(version, versionExtra string) *cli.App {
|
||||||
CmdMigrateStorage,
|
CmdMigrateStorage,
|
||||||
CmdDumpRepository,
|
CmdDumpRepository,
|
||||||
CmdRestoreRepository,
|
CmdRestoreRepository,
|
||||||
CmdActions,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
subCmdWithConfig = append(subCmdWithConfig, subCmdWithConfigArgs...)
|
||||||
|
|
||||||
// these sub-commands do not need the config file, and they do not depend on any path or environment variable.
|
// these sub-commands do not need the config file, and they do not depend on any path or environment variable.
|
||||||
subCmdStandalone := []*cli.Command{
|
subCmdStandalone := []*cli.Command{
|
||||||
CmdCert,
|
CmdCert,
|
||||||
CmdGenerate,
|
CmdGenerate,
|
||||||
CmdDocs,
|
CmdDocs,
|
||||||
}
|
}
|
||||||
|
subCmdStandalone = append(subCmdStandalone, subCmdsStandaloneArgs...)
|
||||||
|
|
||||||
app.DefaultCommand = CmdWeb.Name
|
app.DefaultCommand = CmdWeb.Name
|
||||||
|
|
||||||
|
|
|
@ -110,6 +110,9 @@ func migrateLFS(ctx context.Context, dstStorage storage.ObjectStorage) error {
|
||||||
|
|
||||||
func migrateAvatars(ctx context.Context, dstStorage storage.ObjectStorage) error {
|
func migrateAvatars(ctx context.Context, dstStorage storage.ObjectStorage) error {
|
||||||
return db.Iterate(ctx, nil, func(ctx context.Context, user *user_model.User) error {
|
return db.Iterate(ctx, nil, func(ctx context.Context, user *user_model.User) error {
|
||||||
|
if user.CustomAvatarRelativePath() == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
_, err := storage.Copy(dstStorage, user.CustomAvatarRelativePath(), storage.Avatars, user.CustomAvatarRelativePath())
|
_, err := storage.Copy(dstStorage, user.CustomAvatarRelativePath(), storage.Avatars, user.CustomAvatarRelativePath())
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
|
@ -117,6 +120,9 @@ func migrateAvatars(ctx context.Context, dstStorage storage.ObjectStorage) error
|
||||||
|
|
||||||
func migrateRepoAvatars(ctx context.Context, dstStorage storage.ObjectStorage) error {
|
func migrateRepoAvatars(ctx context.Context, dstStorage storage.ObjectStorage) error {
|
||||||
return db.Iterate(ctx, nil, func(ctx context.Context, repo *repo_model.Repository) error {
|
return db.Iterate(ctx, nil, func(ctx context.Context, repo *repo_model.Repository) error {
|
||||||
|
if repo.CustomAvatarRelativePath() == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
_, err := storage.Copy(dstStorage, repo.CustomAvatarRelativePath(), storage.RepoAvatars, repo.CustomAvatarRelativePath())
|
_, err := storage.Copy(dstStorage, repo.CustomAvatarRelativePath(), storage.RepoAvatars, repo.CustomAvatarRelativePath())
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
|
|
|
@ -1067,6 +1067,9 @@ LEVEL = Info
|
||||||
;;
|
;;
|
||||||
;; In addition to testing patches using the three-way merge method, re-test conflicting patches with git apply
|
;; In addition to testing patches using the three-way merge method, re-test conflicting patches with git apply
|
||||||
;TEST_CONFLICTING_PATCHES_WITH_GIT_APPLY = false
|
;TEST_CONFLICTING_PATCHES_WITH_GIT_APPLY = false
|
||||||
|
;;
|
||||||
|
;; Retarget child pull requests to the parent pull request branch target on merge of parent pull request. It only works on merged PRs where the head and base branch target the same repo.
|
||||||
|
;RETARGET_CHILDREN_ON_MERGE = true
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
@ -2579,10 +2582,9 @@ LEVEL = Info
|
||||||
; [actions]
|
; [actions]
|
||||||
;; Enable/Disable actions capabilities
|
;; Enable/Disable actions capabilities
|
||||||
;ENABLED = true
|
;ENABLED = true
|
||||||
;;
|
;; Default address to get action plugins, e.g. the default value means downloading from "https://code.forgejo.org/actions/checkout" for "uses: actions/checkout@v3"
|
||||||
;; Default platform to get action plugins, `github` for `https://github.com`, `self` for the current Gitea instance.
|
;DEFAULT_ACTIONS_URL = https://code.forgejo.org
|
||||||
;DEFAULT_ACTIONS_URL = github
|
;; Default artifact retention time in days, default is 90 days
|
||||||
;; Default artifact retention time in days. Artifacts could have their own retention periods by setting the `retention-days` option in `actions/upload-artifact` step.
|
|
||||||
;ARTIFACT_RETENTION_DAYS = 90
|
;ARTIFACT_RETENTION_DAYS = 90
|
||||||
;; Timeout to stop the task which have running status, but haven't been updated for a long time
|
;; Timeout to stop the task which have running status, but haven't been updated for a long time
|
||||||
;ZOMBIE_TASK_TIMEOUT = 10m
|
;ZOMBIE_TASK_TIMEOUT = 10m
|
||||||
|
|
|
@ -135,6 +135,7 @@ In addition, there is _`StaticRootPath`_ which can be set as a built-in at build
|
||||||
- `POPULATE_SQUASH_COMMENT_WITH_COMMIT_MESSAGES`: **false**: In default squash-merge messages include the commit message of all commits comprising the pull request.
|
- `POPULATE_SQUASH_COMMENT_WITH_COMMIT_MESSAGES`: **false**: In default squash-merge messages include the commit message of all commits comprising the pull request.
|
||||||
- `ADD_CO_COMMITTER_TRAILERS`: **true**: Add co-authored-by and co-committed-by trailers to merge commit messages if committer does not match author.
|
- `ADD_CO_COMMITTER_TRAILERS`: **true**: Add co-authored-by and co-committed-by trailers to merge commit messages if committer does not match author.
|
||||||
- `TEST_CONFLICTING_PATCHES_WITH_GIT_APPLY`: **false**: PR patches are tested using a three-way merge method to discover if there are conflicts. If this setting is set to **true**, conflicting patches will be retested using `git apply` - This was the previous behaviour in 1.18 (and earlier) but is somewhat inefficient. Please report if you find that this setting is required.
|
- `TEST_CONFLICTING_PATCHES_WITH_GIT_APPLY`: **false**: PR patches are tested using a three-way merge method to discover if there are conflicts. If this setting is set to **true**, conflicting patches will be retested using `git apply` - This was the previous behaviour in 1.18 (and earlier) but is somewhat inefficient. Please report if you find that this setting is required.
|
||||||
|
- `RETARGET_CHILDREN_ON_MERGE`: **true**: Retarget child pull requests to the parent pull request branch target on merge of parent pull request. It only works on merged PRs where the head and base branch target the same repo.
|
||||||
|
|
||||||
### Repository - Issue (`repository.issue`)
|
### Repository - Issue (`repository.issue`)
|
||||||
|
|
||||||
|
|
|
@ -27,14 +27,15 @@ GITEA_CUSTOM=/home/gitea/custom ./gitea web
|
||||||
|
|
||||||
## From Go language
|
## From Go language
|
||||||
|
|
||||||
As Gitea is written in Go, it uses some Go variables, such as:
|
As Gitea is written in Go, it uses some variables that influence the behaviour of Go's runtime, such as:
|
||||||
|
|
||||||
- `GOOS`
|
- `GOMEMLIMIT`
|
||||||
- `GOARCH`
|
- `GOGC`
|
||||||
- [`GOPATH`](https://golang.org/cmd/go/#hdr-GOPATH_environment_variable)
|
- `GOMAXPROCS`
|
||||||
|
- `GODEBUG`
|
||||||
|
|
||||||
For documentation about each of the variables available, refer to the
|
For documentation about each of the variables available, refer to the
|
||||||
[official Go documentation](https://golang.org/cmd/go/#hdr-Environment_variables).
|
[official Go documentation on runtime environment variables](https://pkg.go.dev/runtime#hdr-Environment_Variables).
|
||||||
|
|
||||||
## Gitea files
|
## Gitea files
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,7 @@ _Symbols used in table:_
|
||||||
| Markdown support | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
| Markdown support | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||||
| CSV support | ✓ | ✘ | ✓ | ✘ | ✘ | ✓ | ✘ | ✘ |
|
| CSV support | ✓ | ✘ | ✓ | ✘ | ✘ | ✓ | ✘ | ✘ |
|
||||||
| 'GitHub / GitLab pages' | [⚙️][gitea-pages-server], [⚙️][gitea-caddy-plugin] | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ |
|
| 'GitHub / GitLab pages' | [⚙️][gitea-pages-server], [⚙️][gitea-caddy-plugin] | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ |
|
||||||
|
| Gists / Snippets | [⚙️][opengist] | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||||
| Repo-specific wiki (as a repo itself) | ✓ | ✓ | ✓ | ✓ | ✓ | / | ✘ | ✘ |
|
| Repo-specific wiki (as a repo itself) | ✓ | ✓ | ✓ | ✓ | ✓ | / | ✘ | ✘ |
|
||||||
| Deploy Tokens | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
| Deploy Tokens | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||||
| Repository Tokens with write rights | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
| Repository Tokens with write rights | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||||
|
@ -147,3 +148,4 @@ _Symbols used in table:_
|
||||||
|
|
||||||
[gitea-caddy-plugin]: https://github.com/42wim/caddy-gitea
|
[gitea-caddy-plugin]: https://github.com/42wim/caddy-gitea
|
||||||
[gitea-pages-server]: https://codeberg.org/Codeberg/pages-server
|
[gitea-pages-server]: https://codeberg.org/Codeberg/pages-server
|
||||||
|
[opengist]: https://github.com/thomiceli/opengist
|
||||||
|
|
|
@ -24,16 +24,26 @@ The following examples use `dnf`.
|
||||||
|
|
||||||
## Configuring the package registry
|
## Configuring the package registry
|
||||||
|
|
||||||
To register the RPM registry add the url to the list of known apt sources:
|
To register the RPM registry add the url to the list of known sources:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
dnf config-manager --add-repo https://gitea.example.com/api/packages/{owner}/rpm/{group}.repo
|
dnf config-manager --add-repo https://gitea.example.com/api/packages/{owner}/rpm/{group}.repo
|
||||||
```
|
```
|
||||||
|
|
||||||
| Placeholder | Description |
|
| Placeholder | Description |
|
||||||
| ----------- |----------------------------------------------------|
|
| ----------- | ----------- |
|
||||||
| `owner` | The owner of the package. |
|
| `owner` | The owner of the package. |
|
||||||
| `group` | Everything, e.g. `el7`, `rocky/el9` , `test/fc38`.|
|
| `group` | Optional: Everything, e.g. empty, `el7`, `rocky/el9`, `test/fc38`. |
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# without a group
|
||||||
|
dnf config-manager --add-repo https://gitea.example.com/api/packages/testuser/rpm.repo
|
||||||
|
|
||||||
|
# with the group 'centos/el7'
|
||||||
|
dnf config-manager --add-repo https://gitea.example.com/api/packages/testuser/rpm/centos/el7.repo
|
||||||
|
```
|
||||||
|
|
||||||
If the registry is private, provide credentials in the url. You can use a password or a [personal access token](development/api-usage.md#authentication):
|
If the registry is private, provide credentials in the url. You can use a password or a [personal access token](development/api-usage.md#authentication):
|
||||||
|
|
||||||
|
@ -41,7 +51,7 @@ If the registry is private, provide credentials in the url. You can use a passwo
|
||||||
dnf config-manager --add-repo https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/rpm/{group}.repo
|
dnf config-manager --add-repo https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/rpm/{group}.repo
|
||||||
```
|
```
|
||||||
|
|
||||||
You have to add the credentials to the urls in the `rpm.repo` file in `/etc/yum.repos.d` too.
|
You have to add the credentials to the urls in the created `.repo` file in `/etc/yum.repos.d` too.
|
||||||
|
|
||||||
## Publish a package
|
## Publish a package
|
||||||
|
|
||||||
|
@ -54,11 +64,17 @@ PUT https://gitea.example.com/api/packages/{owner}/rpm/{group}/upload
|
||||||
| Parameter | Description |
|
| Parameter | Description |
|
||||||
| --------- | ----------- |
|
| --------- | ----------- |
|
||||||
| `owner` | The owner of the package. |
|
| `owner` | The owner of the package. |
|
||||||
| `group` | Everything, e.g. `el7`, `rocky/el9` , `test/fc38`.|
|
| `group` | Optional: Everything, e.g. empty, `el7`, `rocky/el9`, `test/fc38`. |
|
||||||
|
|
||||||
Example request using HTTP Basic authentication:
|
Example request using HTTP Basic authentication:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
# without a group
|
||||||
|
curl --user your_username:your_password_or_token \
|
||||||
|
--upload-file path/to/file.rpm \
|
||||||
|
https://gitea.example.com/api/packages/testuser/rpm/upload
|
||||||
|
|
||||||
|
# with the group 'centos/el7'
|
||||||
curl --user your_username:your_password_or_token \
|
curl --user your_username:your_password_or_token \
|
||||||
--upload-file path/to/file.rpm \
|
--upload-file path/to/file.rpm \
|
||||||
https://gitea.example.com/api/packages/testuser/rpm/centos/el7/upload
|
https://gitea.example.com/api/packages/testuser/rpm/centos/el7/upload
|
||||||
|
@ -83,17 +99,22 @@ To delete an RPM package perform a HTTP DELETE operation. This will delete the p
|
||||||
DELETE https://gitea.example.com/api/packages/{owner}/rpm/{group}/package/{package_name}/{package_version}/{architecture}
|
DELETE https://gitea.example.com/api/packages/{owner}/rpm/{group}/package/{package_name}/{package_version}/{architecture}
|
||||||
```
|
```
|
||||||
|
|
||||||
| Parameter | Description |
|
| Parameter | Description |
|
||||||
|-------------------|----------------------------|
|
| ----------------- | ----------- |
|
||||||
| `owner` | The owner of the package. |
|
| `owner` | The owner of the package. |
|
||||||
| `group` | The package group . |
|
| `group` | Optional: The package group. |
|
||||||
| `package_name` | The package name. |
|
| `package_name` | The package name. |
|
||||||
| `package_version` | The package version. |
|
| `package_version` | The package version. |
|
||||||
| `architecture` | The package architecture. |
|
| `architecture` | The package architecture. |
|
||||||
|
|
||||||
Example request using HTTP Basic authentication:
|
Example request using HTTP Basic authentication:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
# without a group
|
||||||
|
curl --user your_username:your_token_or_password -X DELETE \
|
||||||
|
https://gitea.example.com/api/packages/testuser/rpm/package/test-package/1.0.0/x86_64
|
||||||
|
|
||||||
|
# with the group 'centos/el7'
|
||||||
curl --user your_username:your_token_or_password -X DELETE \
|
curl --user your_username:your_token_or_password -X DELETE \
|
||||||
https://gitea.example.com/api/packages/testuser/rpm/centos/el7/package/test-package/1.0.0/x86_64
|
https://gitea.example.com/api/packages/testuser/rpm/centos/el7/package/test-package/1.0.0/x86_64
|
||||||
```
|
```
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -306,6 +306,8 @@ replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142
|
||||||
|
|
||||||
replace github.com/nektos/act => gitea.com/gitea/act v0.2.51
|
replace github.com/nektos/act => gitea.com/gitea/act v0.2.51
|
||||||
|
|
||||||
|
replace github.com/gorilla/feeds => github.com/yardenshoham/feeds v0.0.0-20240110072658-f3d0c21c0bd5
|
||||||
|
|
||||||
exclude github.com/gofrs/uuid v3.2.0+incompatible
|
exclude github.com/gofrs/uuid v3.2.0+incompatible
|
||||||
|
|
||||||
exclude github.com/gofrs/uuid v4.0.0+incompatible
|
exclude github.com/gofrs/uuid v4.0.0+incompatible
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -501,8 +501,6 @@ github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8
|
||||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||||
github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
|
github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
|
||||||
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
|
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
|
||||||
github.com/gorilla/feeds v1.1.2 h1:pxzZ5PD3RJdhFH2FsJJ4x6PqMqbgFk1+Vez4XWBW8Iw=
|
|
||||||
github.com/gorilla/feeds v1.1.2/go.mod h1:WMib8uJP3BbY+X8Szd1rA5Pzhdfh+HCCAYT2z7Fza6Y=
|
|
||||||
github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE=
|
github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE=
|
||||||
github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w=
|
github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w=
|
||||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
|
@ -904,6 +902,8 @@ github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMx
|
||||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||||
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e h1:+SOyEddqYF09QP7vr7CgJ1eti3pY9Fn3LHO1M1r/0sI=
|
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e h1:+SOyEddqYF09QP7vr7CgJ1eti3pY9Fn3LHO1M1r/0sI=
|
||||||
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||||
|
github.com/yardenshoham/feeds v0.0.0-20240110072658-f3d0c21c0bd5 h1:3seWKGVhGoc66Ht5QlhQsr4xT2caDnFegsnh2NqvENU=
|
||||||
|
github.com/yardenshoham/feeds v0.0.0-20240110072658-f3d0c21c0bd5/go.mod h1:WMib8uJP3BbY+X8Szd1rA5Pzhdfh+HCCAYT2z7Fza6Y=
|
||||||
github.com/yohcop/openid-go v1.0.1 h1:DPRd3iPO5F6O5zX2e62XpVAbPT6wV51cuucH0z9g3js=
|
github.com/yohcop/openid-go v1.0.1 h1:DPRd3iPO5F6O5zX2e62XpVAbPT6wV51cuucH0z9g3js=
|
||||||
github.com/yohcop/openid-go v1.0.1/go.mod h1:b/AvD03P0KHj4yuihb+VtLD6bYYgsy0zqBzPCRjkCNs=
|
github.com/yohcop/openid-go v1.0.1/go.mod h1:b/AvD03P0KHj4yuihb+VtLD6bYYgsy0zqBzPCRjkCNs=
|
||||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
|
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
|
||||||
|
|
68
models/actions/forgejo.go
Normal file
68
models/actions/forgejo.go
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package actions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
auth_model "code.gitea.io/gitea/models/auth"
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
|
gouuid "github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
func RegisterRunner(ctx context.Context, ownerID, repoID int64, token string, labels []string, name, version string) (*ActionRunner, error) {
|
||||||
|
uuid, err := gouuid.FromBytes([]byte(token[:16]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("gouuid.FromBytes %v", err)
|
||||||
|
}
|
||||||
|
uuidString := uuid.String()
|
||||||
|
|
||||||
|
var runner ActionRunner
|
||||||
|
|
||||||
|
has, err := db.GetEngine(ctx).Where("uuid=?", uuidString).Get(&runner)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("GetRunner %v", err)
|
||||||
|
} else if !has {
|
||||||
|
//
|
||||||
|
// The runner does not exist yet, create it
|
||||||
|
//
|
||||||
|
saltBytes, err := util.CryptoRandomBytes(16)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("CryptoRandomBytes %v", err)
|
||||||
|
}
|
||||||
|
salt := hex.EncodeToString(saltBytes)
|
||||||
|
|
||||||
|
hash := auth_model.HashToken(token, salt)
|
||||||
|
|
||||||
|
runner = ActionRunner{
|
||||||
|
UUID: uuidString,
|
||||||
|
TokenHash: hash,
|
||||||
|
TokenSalt: salt,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := CreateRunner(ctx, &runner); err != nil {
|
||||||
|
return &runner, fmt.Errorf("can't create new runner %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Update the existing runner
|
||||||
|
//
|
||||||
|
name, _ = util.SplitStringAtByteN(name, 255)
|
||||||
|
|
||||||
|
runner.Name = name
|
||||||
|
runner.OwnerID = ownerID
|
||||||
|
runner.RepoID = repoID
|
||||||
|
runner.Version = version
|
||||||
|
runner.AgentLabels = labels
|
||||||
|
|
||||||
|
if err := UpdateRunner(ctx, &runner, "name", "owner_id", "repo_id", "version", "agent_labels"); err != nil {
|
||||||
|
return &runner, fmt.Errorf("can't update the runner %+v %w", runner, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &runner, nil
|
||||||
|
}
|
29
models/actions/forgejo_test.go
Normal file
29
models/actions/forgejo_test.go
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package actions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/subtle"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
auth_model "code.gitea.io/gitea/models/auth"
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestActions_RegisterRunner(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
ownerID := int64(0)
|
||||||
|
repoID := int64(0)
|
||||||
|
token := "0123456789012345678901234567890123456789"
|
||||||
|
labels := []string{}
|
||||||
|
name := "runner"
|
||||||
|
version := "v1.2.3"
|
||||||
|
runner, err := RegisterRunner(db.DefaultContext, ownerID, repoID, token, labels, name, version)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, name, runner.Name)
|
||||||
|
|
||||||
|
assert.EqualValues(t, 1, subtle.ConstantTimeCompare([]byte(runner.TokenHash), []byte(auth_model.HashToken(token, runner.TokenSalt))), "the token cannot be verified with the same method as routers/api/actions/runner/interceptor.go as of 8228751c55d6a4263f0fec2932ca16181c09c97d")
|
||||||
|
}
|
|
@ -46,10 +46,13 @@ type ActionRun struct {
|
||||||
TriggerEvent string // the trigger event defined in the `on` configuration of the triggered workflow
|
TriggerEvent string // the trigger event defined in the `on` configuration of the triggered workflow
|
||||||
Status Status `xorm:"index"`
|
Status Status `xorm:"index"`
|
||||||
Version int `xorm:"version default 0"` // Status could be updated concomitantly, so an optimistic lock is needed
|
Version int `xorm:"version default 0"` // Status could be updated concomitantly, so an optimistic lock is needed
|
||||||
Started timeutil.TimeStamp
|
// Started and Stopped is used for recording last run time, if rerun happened, they will be reset to 0
|
||||||
Stopped timeutil.TimeStamp
|
Started timeutil.TimeStamp
|
||||||
Created timeutil.TimeStamp `xorm:"created"`
|
Stopped timeutil.TimeStamp
|
||||||
Updated timeutil.TimeStamp `xorm:"updated"`
|
// PreviousDuration is used for recording previous duration
|
||||||
|
PreviousDuration time.Duration
|
||||||
|
Created timeutil.TimeStamp `xorm:"created"`
|
||||||
|
Updated timeutil.TimeStamp `xorm:"updated"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -118,7 +121,7 @@ func (run *ActionRun) LoadAttributes(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (run *ActionRun) Duration() time.Duration {
|
func (run *ActionRun) Duration() time.Duration {
|
||||||
return calculateDuration(run.Started, run.Stopped, run.Status)
|
return calculateDuration(run.Started, run.Stopped, run.Status) + run.PreviousDuration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (run *ActionRun) GetPushEventPayload() (*api.PushPayload, error) {
|
func (run *ActionRun) GetPushEventPayload() (*api.PushPayload, error) {
|
||||||
|
|
|
@ -669,3 +669,10 @@
|
||||||
type: 10
|
type: 10
|
||||||
config: "{}"
|
config: "{}"
|
||||||
created_unix: 946684810
|
created_unix: 946684810
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 101
|
||||||
|
repo_id: 59
|
||||||
|
type: 1
|
||||||
|
config: "{}"
|
||||||
|
created_unix: 946684810
|
||||||
|
|
|
@ -1693,3 +1693,16 @@
|
||||||
size: 0
|
size: 0
|
||||||
is_fsck_enabled: true
|
is_fsck_enabled: true
|
||||||
close_issues_via_commit_in_any_branch: false
|
close_issues_via_commit_in_any_branch: false
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 59
|
||||||
|
owner_id: 2
|
||||||
|
owner_name: user2
|
||||||
|
lower_name: test_commit_revert
|
||||||
|
name: test_commit_revert
|
||||||
|
default_branch: main
|
||||||
|
is_empty: false
|
||||||
|
is_archived: false
|
||||||
|
is_private: true
|
||||||
|
status: 0
|
||||||
|
num_issues: 0
|
||||||
|
|
|
@ -66,7 +66,7 @@
|
||||||
num_followers: 2
|
num_followers: 2
|
||||||
num_following: 1
|
num_following: 1
|
||||||
num_stars: 2
|
num_stars: 2
|
||||||
num_repos: 14
|
num_repos: 15
|
||||||
num_teams: 0
|
num_teams: 0
|
||||||
num_members: 0
|
num_members: 0
|
||||||
visibility: 0
|
visibility: 0
|
||||||
|
|
|
@ -25,7 +25,6 @@ import (
|
||||||
"code.gitea.io/gitea/modules/translation"
|
"code.gitea.io/gitea/modules/translation"
|
||||||
|
|
||||||
"xorm.io/builder"
|
"xorm.io/builder"
|
||||||
"xorm.io/xorm"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// CommitStatus holds a single Status of a single Commit
|
// CommitStatus holds a single Status of a single Commit
|
||||||
|
@ -38,7 +37,7 @@ type CommitStatus struct {
|
||||||
SHA string `xorm:"VARCHAR(64) NOT NULL INDEX UNIQUE(repo_sha_index)"`
|
SHA string `xorm:"VARCHAR(64) NOT NULL INDEX UNIQUE(repo_sha_index)"`
|
||||||
TargetURL string `xorm:"TEXT"`
|
TargetURL string `xorm:"TEXT"`
|
||||||
Description string `xorm:"TEXT"`
|
Description string `xorm:"TEXT"`
|
||||||
ContextHash string `xorm:"char(40) index"`
|
ContextHash string `xorm:"VARCHAR(64) index"`
|
||||||
Context string `xorm:"TEXT"`
|
Context string `xorm:"TEXT"`
|
||||||
Creator *user_model.User `xorm:"-"`
|
Creator *user_model.User `xorm:"-"`
|
||||||
CreatorID int64
|
CreatorID int64
|
||||||
|
@ -221,57 +220,42 @@ func CalcCommitStatus(statuses []*CommitStatus) *CommitStatus {
|
||||||
// CommitStatusOptions holds the options for query commit statuses
|
// CommitStatusOptions holds the options for query commit statuses
|
||||||
type CommitStatusOptions struct {
|
type CommitStatusOptions struct {
|
||||||
db.ListOptions
|
db.ListOptions
|
||||||
|
RepoID int64
|
||||||
|
SHA string
|
||||||
State string
|
State string
|
||||||
SortType string
|
SortType string
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCommitStatuses returns all statuses for a given commit.
|
func (opts *CommitStatusOptions) ToConds() builder.Cond {
|
||||||
func GetCommitStatuses(ctx context.Context, repo *repo_model.Repository, sha string, opts *CommitStatusOptions) ([]*CommitStatus, int64, error) {
|
var cond builder.Cond = builder.Eq{
|
||||||
if opts.Page <= 0 {
|
"repo_id": opts.RepoID,
|
||||||
opts.Page = 1
|
"sha": opts.SHA,
|
||||||
}
|
|
||||||
if opts.PageSize <= 0 {
|
|
||||||
opts.Page = setting.ItemsPerPage
|
|
||||||
}
|
}
|
||||||
|
|
||||||
countSession := listCommitStatusesStatement(ctx, repo, sha, opts)
|
|
||||||
countSession = db.SetSessionPagination(countSession, opts)
|
|
||||||
maxResults, err := countSession.Count(new(CommitStatus))
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Count PRs: %v", err)
|
|
||||||
return nil, maxResults, err
|
|
||||||
}
|
|
||||||
|
|
||||||
statuses := make([]*CommitStatus, 0, opts.PageSize)
|
|
||||||
findSession := listCommitStatusesStatement(ctx, repo, sha, opts)
|
|
||||||
findSession = db.SetSessionPagination(findSession, opts)
|
|
||||||
sortCommitStatusesSession(findSession, opts.SortType)
|
|
||||||
return statuses, maxResults, findSession.Find(&statuses)
|
|
||||||
}
|
|
||||||
|
|
||||||
func listCommitStatusesStatement(ctx context.Context, repo *repo_model.Repository, sha string, opts *CommitStatusOptions) *xorm.Session {
|
|
||||||
sess := db.GetEngine(ctx).Where("repo_id = ?", repo.ID).And("sha = ?", sha)
|
|
||||||
switch opts.State {
|
switch opts.State {
|
||||||
case "pending", "success", "error", "failure", "warning":
|
case "pending", "success", "error", "failure", "warning":
|
||||||
sess.And("state = ?", opts.State)
|
cond = cond.And(builder.Eq{
|
||||||
|
"state": opts.State,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return sess
|
|
||||||
|
return cond
|
||||||
}
|
}
|
||||||
|
|
||||||
func sortCommitStatusesSession(sess *xorm.Session, sortType string) {
|
func (opts *CommitStatusOptions) ToOrders() string {
|
||||||
switch sortType {
|
switch opts.SortType {
|
||||||
case "oldest":
|
case "oldest":
|
||||||
sess.Asc("created_unix")
|
return "created_unix ASC"
|
||||||
case "recentupdate":
|
case "recentupdate":
|
||||||
sess.Desc("updated_unix")
|
return "updated_unix DESC"
|
||||||
case "leastupdate":
|
case "leastupdate":
|
||||||
sess.Asc("updated_unix")
|
return "updated_unix ASC"
|
||||||
case "leastindex":
|
case "leastindex":
|
||||||
sess.Desc("index")
|
return "`index` DESC"
|
||||||
case "highestindex":
|
case "highestindex":
|
||||||
sess.Asc("index")
|
return "`index` ASC"
|
||||||
default:
|
default:
|
||||||
sess.Desc("created_unix")
|
return "created_unix DESC"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,11 @@ func TestGetCommitStatuses(t *testing.T) {
|
||||||
|
|
||||||
sha1 := "1234123412341234123412341234123412341234"
|
sha1 := "1234123412341234123412341234123412341234"
|
||||||
|
|
||||||
statuses, maxResults, err := git_model.GetCommitStatuses(db.DefaultContext, repo1, sha1, &git_model.CommitStatusOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 50}})
|
statuses, maxResults, err := db.FindAndCount[git_model.CommitStatus](db.DefaultContext, &git_model.CommitStatusOptions{
|
||||||
|
ListOptions: db.ListOptions{Page: 1, PageSize: 50},
|
||||||
|
RepoID: repo1.ID,
|
||||||
|
SHA: sha1,
|
||||||
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, int(maxResults), 5)
|
assert.Equal(t, int(maxResults), 5)
|
||||||
assert.Len(t, statuses, 5)
|
assert.Len(t, statuses, 5)
|
||||||
|
@ -46,4 +50,128 @@ func TestGetCommitStatuses(t *testing.T) {
|
||||||
assert.Equal(t, "deploy/awesomeness", statuses[4].Context)
|
assert.Equal(t, "deploy/awesomeness", statuses[4].Context)
|
||||||
assert.Equal(t, structs.CommitStatusError, statuses[4].State)
|
assert.Equal(t, structs.CommitStatusError, statuses[4].State)
|
||||||
assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[4].APIURL(db.DefaultContext))
|
assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[4].APIURL(db.DefaultContext))
|
||||||
|
|
||||||
|
statuses, maxResults, err = db.FindAndCount[git_model.CommitStatus](db.DefaultContext, &git_model.CommitStatusOptions{
|
||||||
|
ListOptions: db.ListOptions{Page: 2, PageSize: 50},
|
||||||
|
RepoID: repo1.ID,
|
||||||
|
SHA: sha1,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, int(maxResults), 5)
|
||||||
|
assert.Empty(t, statuses)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_CalcCommitStatus(t *testing.T) {
|
||||||
|
kases := []struct {
|
||||||
|
statuses []*git_model.CommitStatus
|
||||||
|
expected *git_model.CommitStatus
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
statuses: []*git_model.CommitStatus{
|
||||||
|
{
|
||||||
|
State: structs.CommitStatusPending,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: &git_model.CommitStatus{
|
||||||
|
State: structs.CommitStatusPending,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
statuses: []*git_model.CommitStatus{
|
||||||
|
{
|
||||||
|
State: structs.CommitStatusSuccess,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
State: structs.CommitStatusPending,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: &git_model.CommitStatus{
|
||||||
|
State: structs.CommitStatusPending,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
statuses: []*git_model.CommitStatus{
|
||||||
|
{
|
||||||
|
State: structs.CommitStatusSuccess,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
State: structs.CommitStatusPending,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
State: structs.CommitStatusSuccess,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: &git_model.CommitStatus{
|
||||||
|
State: structs.CommitStatusPending,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
statuses: []*git_model.CommitStatus{
|
||||||
|
{
|
||||||
|
State: structs.CommitStatusError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
State: structs.CommitStatusPending,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
State: structs.CommitStatusSuccess,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: &git_model.CommitStatus{
|
||||||
|
State: structs.CommitStatusError,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
statuses: []*git_model.CommitStatus{
|
||||||
|
{
|
||||||
|
State: structs.CommitStatusWarning,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
State: structs.CommitStatusPending,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
State: structs.CommitStatusSuccess,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: &git_model.CommitStatus{
|
||||||
|
State: structs.CommitStatusWarning,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
statuses: []*git_model.CommitStatus{
|
||||||
|
{
|
||||||
|
State: structs.CommitStatusSuccess,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
State: structs.CommitStatusSuccess,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
State: structs.CommitStatusSuccess,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: &git_model.CommitStatus{
|
||||||
|
State: structs.CommitStatusSuccess,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
statuses: []*git_model.CommitStatus{
|
||||||
|
{
|
||||||
|
State: structs.CommitStatusFailure,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
State: structs.CommitStatusError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
State: structs.CommitStatusWarning,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: &git_model.CommitStatus{
|
||||||
|
State: structs.CommitStatusError,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, kase := range kases {
|
||||||
|
assert.Equal(t, kase.expected, git_model.CalcCommitStatus(kase.statuses))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -270,7 +270,7 @@ type Comment struct {
|
||||||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
|
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
|
||||||
|
|
||||||
// Reference issue in commit message
|
// Reference issue in commit message
|
||||||
CommitSHA string `xorm:"VARCHAR(40)"`
|
CommitSHA string `xorm:"VARCHAR(64)"`
|
||||||
|
|
||||||
Attachments []*repo_model.Attachment `xorm:"-"`
|
Attachments []*repo_model.Attachment `xorm:"-"`
|
||||||
Reactions ReactionList `xorm:"-"`
|
Reactions ReactionList `xorm:"-"`
|
||||||
|
|
|
@ -171,11 +171,11 @@ type PullRequest struct {
|
||||||
HeadBranch string
|
HeadBranch string
|
||||||
HeadCommitID string `xorm:"-"`
|
HeadCommitID string `xorm:"-"`
|
||||||
BaseBranch string
|
BaseBranch string
|
||||||
MergeBase string `xorm:"VARCHAR(40)"`
|
MergeBase string `xorm:"VARCHAR(64)"`
|
||||||
AllowMaintainerEdit bool `xorm:"NOT NULL DEFAULT false"`
|
AllowMaintainerEdit bool `xorm:"NOT NULL DEFAULT false"`
|
||||||
|
|
||||||
HasMerged bool `xorm:"INDEX"`
|
HasMerged bool `xorm:"INDEX"`
|
||||||
MergedCommitID string `xorm:"VARCHAR(40)"`
|
MergedCommitID string `xorm:"VARCHAR(64)"`
|
||||||
MergerID int64 `xorm:"INDEX"`
|
MergerID int64 `xorm:"INDEX"`
|
||||||
Merger *user_model.User `xorm:"-"`
|
Merger *user_model.User `xorm:"-"`
|
||||||
MergedUnix timeutil.TimeStamp `xorm:"updated INDEX"`
|
MergedUnix timeutil.TimeStamp `xorm:"updated INDEX"`
|
||||||
|
|
|
@ -116,7 +116,7 @@ type Review struct {
|
||||||
Content string `xorm:"TEXT"`
|
Content string `xorm:"TEXT"`
|
||||||
// Official is a review made by an assigned approver (counts towards approval)
|
// Official is a review made by an assigned approver (counts towards approval)
|
||||||
Official bool `xorm:"NOT NULL DEFAULT false"`
|
Official bool `xorm:"NOT NULL DEFAULT false"`
|
||||||
CommitID string `xorm:"VARCHAR(40)"`
|
CommitID string `xorm:"VARCHAR(64)"`
|
||||||
Stale bool `xorm:"NOT NULL DEFAULT false"`
|
Stale bool `xorm:"NOT NULL DEFAULT false"`
|
||||||
Dismissed bool `xorm:"NOT NULL DEFAULT false"`
|
Dismissed bool `xorm:"NOT NULL DEFAULT false"`
|
||||||
|
|
||||||
|
|
|
@ -340,7 +340,7 @@ func GetTrackedTimeByID(ctx context.Context, id int64) (*TrackedTime, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetIssueTotalTrackedTime returns the total tracked time for issues by given conditions.
|
// GetIssueTotalTrackedTime returns the total tracked time for issues by given conditions.
|
||||||
func GetIssueTotalTrackedTime(ctx context.Context, opts *IssuesOptions, isClosed bool) (int64, error) {
|
func GetIssueTotalTrackedTime(ctx context.Context, opts *IssuesOptions, isClosed util.OptionalBool) (int64, error) {
|
||||||
if len(opts.IssueIDs) <= MaxQueryParameters {
|
if len(opts.IssueIDs) <= MaxQueryParameters {
|
||||||
return getIssueTotalTrackedTimeChunk(ctx, opts, isClosed, opts.IssueIDs)
|
return getIssueTotalTrackedTimeChunk(ctx, opts, isClosed, opts.IssueIDs)
|
||||||
}
|
}
|
||||||
|
@ -363,7 +363,7 @@ func GetIssueTotalTrackedTime(ctx context.Context, opts *IssuesOptions, isClosed
|
||||||
return accum, nil
|
return accum, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getIssueTotalTrackedTimeChunk(ctx context.Context, opts *IssuesOptions, isClosed bool, issueIDs []int64) (int64, error) {
|
func getIssueTotalTrackedTimeChunk(ctx context.Context, opts *IssuesOptions, isClosed util.OptionalBool, issueIDs []int64) (int64, error) {
|
||||||
sumSession := func(opts *IssuesOptions, issueIDs []int64) *xorm.Session {
|
sumSession := func(opts *IssuesOptions, issueIDs []int64) *xorm.Session {
|
||||||
sess := db.GetEngine(ctx).
|
sess := db.GetEngine(ctx).
|
||||||
Table("tracked_time").
|
Table("tracked_time").
|
||||||
|
@ -377,7 +377,9 @@ func getIssueTotalTrackedTimeChunk(ctx context.Context, opts *IssuesOptions, isC
|
||||||
Time int64
|
Time int64
|
||||||
}
|
}
|
||||||
|
|
||||||
return sumSession(opts, issueIDs).
|
session := sumSession(opts, issueIDs)
|
||||||
And("issue.is_closed = ?", isClosed).
|
if !isClosed.IsNone() {
|
||||||
SumInt(new(trackedTime), "tracked_time.time")
|
session = session.And("issue.is_closed = ?", isClosed.IsTrue())
|
||||||
|
}
|
||||||
|
return session.SumInt(new(trackedTime), "tracked_time.time")
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
issues_model "code.gitea.io/gitea/models/issues"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
@ -119,11 +120,15 @@ func TestTotalTimesForEachUser(t *testing.T) {
|
||||||
func TestGetIssueTotalTrackedTime(t *testing.T) {
|
func TestGetIssueTotalTrackedTime(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
ttt, err := issues_model.GetIssueTotalTrackedTime(db.DefaultContext, &issues_model.IssuesOptions{MilestoneIDs: []int64{1}}, false)
|
ttt, err := issues_model.GetIssueTotalTrackedTime(db.DefaultContext, &issues_model.IssuesOptions{MilestoneIDs: []int64{1}}, util.OptionalBoolFalse)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, 3682, ttt)
|
assert.EqualValues(t, 3682, ttt)
|
||||||
|
|
||||||
ttt, err = issues_model.GetIssueTotalTrackedTime(db.DefaultContext, &issues_model.IssuesOptions{MilestoneIDs: []int64{1}}, true)
|
ttt, err = issues_model.GetIssueTotalTrackedTime(db.DefaultContext, &issues_model.IssuesOptions{MilestoneIDs: []int64{1}}, util.OptionalBoolTrue)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, 0, ttt)
|
assert.EqualValues(t, 0, ttt)
|
||||||
|
|
||||||
|
ttt, err = issues_model.GetIssueTotalTrackedTime(db.DefaultContext, &issues_model.IssuesOptions{MilestoneIDs: []int64{1}}, util.OptionalBoolNone)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 3682, ttt)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
# type Repository struct {
|
||||||
|
# ID int64 `xorm:"pk autoincr"`
|
||||||
|
# }
|
||||||
|
-
|
||||||
|
id: 1
|
||||||
|
-
|
||||||
|
id: 2
|
||||||
|
-
|
||||||
|
id: 3
|
||||||
|
-
|
||||||
|
id: 10
|
|
@ -552,6 +552,12 @@ var migrations = []Migration{
|
||||||
NewMigration("Add Index to pull_auto_merge.doer_id", v1_22.AddIndexToPullAutoMergeDoerID),
|
NewMigration("Add Index to pull_auto_merge.doer_id", v1_22.AddIndexToPullAutoMergeDoerID),
|
||||||
// v283 -> v284
|
// v283 -> v284
|
||||||
NewMigration("Add combined Index to issue_user.uid and issue_id", v1_22.AddCombinedIndexToIssueUser),
|
NewMigration("Add combined Index to issue_user.uid and issue_id", v1_22.AddCombinedIndexToIssueUser),
|
||||||
|
// v284 -> v285
|
||||||
|
NewMigration("Add ignore stale approval column on branch table", v1_22.AddIgnoreStaleApprovalsColumnToProtectedBranchTable),
|
||||||
|
// v285 -> v286
|
||||||
|
NewMigration("Add PreviousDuration to ActionRun", v1_22.AddPreviousDurationToActionRun),
|
||||||
|
// v286 -> v287
|
||||||
|
NewMigration("Add support for SHA256 git repositories", v1_22.AdjustDBForSha256),
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCurrentDBVersion returns the current db version
|
// GetCurrentDBVersion returns the current db version
|
||||||
|
|
18
models/migrations/v1_22/v285.go
Normal file
18
models/migrations/v1_22/v285.go
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package v1_22 //nolint
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"xorm.io/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AddPreviousDurationToActionRun(x *xorm.Engine) error {
|
||||||
|
type ActionRun struct {
|
||||||
|
PreviousDuration time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
return x.Sync(&ActionRun{})
|
||||||
|
}
|
104
models/migrations/v1_22/v286.go
Normal file
104
models/migrations/v1_22/v286.go
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
package v1_22 //nolint
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
|
"xorm.io/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func expandHashReferencesToSha256(x *xorm.Engine) error {
|
||||||
|
alteredTables := [][2]string{
|
||||||
|
{"commit_status", "context_hash"},
|
||||||
|
{"comment", "commit_sha"},
|
||||||
|
{"pull_request", "merge_base"},
|
||||||
|
{"pull_request", "merged_commit_id"},
|
||||||
|
{"review", "commit_id"},
|
||||||
|
{"review_state", "commit_sha"},
|
||||||
|
{"repo_archiver", "commit_id"},
|
||||||
|
{"release", "sha1"},
|
||||||
|
{"repo_indexer_status", "commit_sha"},
|
||||||
|
}
|
||||||
|
|
||||||
|
db := x.NewSession()
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
if err := db.Begin(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !setting.Database.Type.IsSQLite3() {
|
||||||
|
if setting.Database.Type.IsMSSQL() {
|
||||||
|
// drop indexes that need to be re-created afterwards
|
||||||
|
droppedIndexes := []string{
|
||||||
|
"DROP INDEX commit_status.IDX_commit_status_context_hash",
|
||||||
|
"DROP INDEX review_state.UQE_review_state_pull_commit_user",
|
||||||
|
"DROP INDEX repo_archiver.UQE_repo_archiver_s",
|
||||||
|
}
|
||||||
|
for _, s := range droppedIndexes {
|
||||||
|
_, err := db.Exec(s)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New(s + " " + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, alts := range alteredTables {
|
||||||
|
var err error
|
||||||
|
if setting.Database.Type.IsMySQL() {
|
||||||
|
_, err = db.Exec(fmt.Sprintf("ALTER TABLE `%s` MODIFY COLUMN `%s` VARCHAR(64)", alts[0], alts[1]))
|
||||||
|
} else if setting.Database.Type.IsMSSQL() {
|
||||||
|
_, err = db.Exec(fmt.Sprintf("ALTER TABLE `%s` ALTER COLUMN `%s` VARCHAR(64)", alts[0], alts[1]))
|
||||||
|
} else {
|
||||||
|
_, err = db.Exec(fmt.Sprintf("ALTER TABLE `%s` ALTER COLUMN `%s` TYPE VARCHAR(64)", alts[0], alts[1]))
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("alter column '%s' of table '%s' failed: %w", alts[1], alts[0], err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if setting.Database.Type.IsMSSQL() {
|
||||||
|
recreateIndexes := []string{
|
||||||
|
"CREATE INDEX IDX_commit_status_context_hash ON commit_status(context_hash)",
|
||||||
|
"CREATE UNIQUE INDEX UQE_review_state_pull_commit_user ON review_state(user_id, pull_id, commit_sha)",
|
||||||
|
"CREATE UNIQUE INDEX UQE_repo_archiver_s ON repo_archiver(repo_id, type, commit_id)",
|
||||||
|
}
|
||||||
|
for _, s := range recreateIndexes {
|
||||||
|
_, err := db.Exec(s)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New(s + " " + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Debug("Updated database tables to hold SHA256 git hash references")
|
||||||
|
|
||||||
|
return db.Commit()
|
||||||
|
}
|
||||||
|
|
||||||
|
func addObjectFormatNameToRepository(x *xorm.Engine) error {
|
||||||
|
type Repository struct {
|
||||||
|
ObjectFormatName string `xorm:"VARCHAR(6) NOT NULL DEFAULT 'sha1'"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := x.Sync(new(Repository)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Here to catch weird edge-cases where column constraints above are
|
||||||
|
// not applied by the DB backend
|
||||||
|
_, err := x.Exec("UPDATE repository set object_format_name = 'sha1' WHERE object_format_name = '' or object_format_name IS NULL")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func AdjustDBForSha256(x *xorm.Engine) error {
|
||||||
|
if err := expandHashReferencesToSha256(x); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return addObjectFormatNameToRepository(x)
|
||||||
|
}
|
62
models/migrations/v1_22/v286_test.go
Normal file
62
models/migrations/v1_22/v286_test.go
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package v1_22 //nolint
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/migrations/base"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"xorm.io/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func PrepareOldRepository(t *testing.T) (*xorm.Engine, func()) {
|
||||||
|
type Repository struct { // old struct
|
||||||
|
ID int64 `xorm:"pk autoincr"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare and load the testing database
|
||||||
|
return base.PrepareTestEnv(t, 0, new(Repository))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_RepositoryFormat(t *testing.T) {
|
||||||
|
x, deferable := PrepareOldRepository(t)
|
||||||
|
defer deferable()
|
||||||
|
|
||||||
|
type Repository struct {
|
||||||
|
ID int64 `xorm:"pk autoincr"`
|
||||||
|
ObjectFormatName string `xorg:"not null default('sha1')"`
|
||||||
|
}
|
||||||
|
|
||||||
|
repo := new(Repository)
|
||||||
|
|
||||||
|
// check we have some records to migrate
|
||||||
|
count, err := x.Count(new(Repository))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 4, count)
|
||||||
|
|
||||||
|
assert.NoError(t, AdjustDBForSha256(x))
|
||||||
|
|
||||||
|
repo.ID = 20
|
||||||
|
repo.ObjectFormatName = "sha256"
|
||||||
|
_, err = x.Insert(repo)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
count, err = x.Count(new(Repository))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 5, count)
|
||||||
|
|
||||||
|
repo = new(Repository)
|
||||||
|
ok, err := x.ID(2).Get(repo)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, true, ok)
|
||||||
|
assert.EqualValues(t, "sha1", repo.ObjectFormatName)
|
||||||
|
|
||||||
|
repo = new(Repository)
|
||||||
|
ok, err = x.ID(20).Get(repo)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, true, ok)
|
||||||
|
assert.EqualValues(t, "sha256", repo.ObjectFormatName)
|
||||||
|
}
|
|
@ -191,18 +191,18 @@ type Package struct {
|
||||||
func TryInsertPackage(ctx context.Context, p *Package) (*Package, error) {
|
func TryInsertPackage(ctx context.Context, p *Package) (*Package, error) {
|
||||||
e := db.GetEngine(ctx)
|
e := db.GetEngine(ctx)
|
||||||
|
|
||||||
key := &Package{
|
existing := &Package{}
|
||||||
OwnerID: p.OwnerID,
|
|
||||||
Type: p.Type,
|
|
||||||
LowerName: p.LowerName,
|
|
||||||
}
|
|
||||||
|
|
||||||
has, err := e.Get(key)
|
has, err := e.Where(builder.Eq{
|
||||||
|
"owner_id": p.OwnerID,
|
||||||
|
"type": p.Type,
|
||||||
|
"lower_name": p.LowerName,
|
||||||
|
}).Get(existing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if has {
|
if has {
|
||||||
return key, ErrDuplicatePackage
|
return existing, ErrDuplicatePackage
|
||||||
}
|
}
|
||||||
if _, err = e.Insert(p); err != nil {
|
if _, err = e.Insert(p); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -41,12 +41,20 @@ type PackageBlob struct {
|
||||||
func GetOrInsertBlob(ctx context.Context, pb *PackageBlob) (*PackageBlob, bool, error) {
|
func GetOrInsertBlob(ctx context.Context, pb *PackageBlob) (*PackageBlob, bool, error) {
|
||||||
e := db.GetEngine(ctx)
|
e := db.GetEngine(ctx)
|
||||||
|
|
||||||
has, err := e.Get(pb)
|
existing := &PackageBlob{}
|
||||||
|
|
||||||
|
has, err := e.Where(builder.Eq{
|
||||||
|
"size": pb.Size,
|
||||||
|
"hash_md5": pb.HashMD5,
|
||||||
|
"hash_sha1": pb.HashSHA1,
|
||||||
|
"hash_sha256": pb.HashSHA256,
|
||||||
|
"hash_sha512": pb.HashSHA512,
|
||||||
|
}).Get(existing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
if has {
|
if has {
|
||||||
return pb, true, nil
|
return existing, true, nil
|
||||||
}
|
}
|
||||||
if _, err = e.Insert(pb); err != nil {
|
if _, err = e.Insert(pb); err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
|
|
|
@ -46,18 +46,18 @@ type PackageFile struct {
|
||||||
func TryInsertFile(ctx context.Context, pf *PackageFile) (*PackageFile, error) {
|
func TryInsertFile(ctx context.Context, pf *PackageFile) (*PackageFile, error) {
|
||||||
e := db.GetEngine(ctx)
|
e := db.GetEngine(ctx)
|
||||||
|
|
||||||
key := &PackageFile{
|
existing := &PackageFile{}
|
||||||
VersionID: pf.VersionID,
|
|
||||||
LowerName: pf.LowerName,
|
|
||||||
CompositeKey: pf.CompositeKey,
|
|
||||||
}
|
|
||||||
|
|
||||||
has, err := e.Get(key)
|
has, err := e.Where(builder.Eq{
|
||||||
|
"version_id": pf.VersionID,
|
||||||
|
"lower_name": pf.LowerName,
|
||||||
|
"composite_key": pf.CompositeKey,
|
||||||
|
}).Get(existing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if has {
|
if has {
|
||||||
return pf, ErrDuplicatePackageFile
|
return existing, ErrDuplicatePackageFile
|
||||||
}
|
}
|
||||||
if _, err = e.Insert(pf); err != nil {
|
if _, err = e.Insert(pf); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -93,13 +93,13 @@ func GetFileForVersionByName(ctx context.Context, versionID int64, name, key str
|
||||||
return nil, ErrPackageFileNotExist
|
return nil, ErrPackageFileNotExist
|
||||||
}
|
}
|
||||||
|
|
||||||
pf := &PackageFile{
|
pf := &PackageFile{}
|
||||||
VersionID: versionID,
|
|
||||||
LowerName: strings.ToLower(name),
|
|
||||||
CompositeKey: key,
|
|
||||||
}
|
|
||||||
|
|
||||||
has, err := db.GetEngine(ctx).Get(pf)
|
has, err := db.GetEngine(ctx).Where(builder.Eq{
|
||||||
|
"version_id": versionID,
|
||||||
|
"lower_name": strings.ToLower(name),
|
||||||
|
"composite_key": key,
|
||||||
|
}).Get(pf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,17 +39,17 @@ type PackageVersion struct {
|
||||||
func GetOrInsertVersion(ctx context.Context, pv *PackageVersion) (*PackageVersion, error) {
|
func GetOrInsertVersion(ctx context.Context, pv *PackageVersion) (*PackageVersion, error) {
|
||||||
e := db.GetEngine(ctx)
|
e := db.GetEngine(ctx)
|
||||||
|
|
||||||
key := &PackageVersion{
|
existing := &PackageVersion{}
|
||||||
PackageID: pv.PackageID,
|
|
||||||
LowerVersion: pv.LowerVersion,
|
|
||||||
}
|
|
||||||
|
|
||||||
has, err := e.Get(key)
|
has, err := e.Where(builder.Eq{
|
||||||
|
"package_id": pv.PackageID,
|
||||||
|
"lower_version": pv.LowerVersion,
|
||||||
|
}).Get(existing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if has {
|
if has {
|
||||||
return key, ErrDuplicatePackageVersion
|
return existing, ErrDuplicatePackageVersion
|
||||||
}
|
}
|
||||||
if _, err = e.Insert(pv); err != nil {
|
if _, err = e.Insert(pv); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
23
models/packages/rpm/search.go
Normal file
23
models/packages/rpm/search.go
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package rpm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
|
rpm_module "code.gitea.io/gitea/modules/packages/rpm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetGroups gets all available groups
|
||||||
|
func GetGroups(ctx context.Context, ownerID int64) ([]string, error) {
|
||||||
|
return packages_model.GetDistinctPropertyValues(
|
||||||
|
ctx,
|
||||||
|
packages_model.TypeRpm,
|
||||||
|
ownerID,
|
||||||
|
packages_model.PropertyTypeFile,
|
||||||
|
rpm_module.PropertyGroup,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
}
|
|
@ -39,7 +39,7 @@ type ReviewState struct {
|
||||||
ID int64 `xorm:"pk autoincr"`
|
ID int64 `xorm:"pk autoincr"`
|
||||||
UserID int64 `xorm:"NOT NULL UNIQUE(pull_commit_user)"`
|
UserID int64 `xorm:"NOT NULL UNIQUE(pull_commit_user)"`
|
||||||
PullID int64 `xorm:"NOT NULL INDEX UNIQUE(pull_commit_user) DEFAULT 0"` // Which PR was the review on?
|
PullID int64 `xorm:"NOT NULL INDEX UNIQUE(pull_commit_user) DEFAULT 0"` // Which PR was the review on?
|
||||||
CommitSHA string `xorm:"NOT NULL VARCHAR(40) UNIQUE(pull_commit_user)"` // Which commit was the head commit for the review?
|
CommitSHA string `xorm:"NOT NULL VARCHAR(64) UNIQUE(pull_commit_user)"` // Which commit was the head commit for the review?
|
||||||
UpdatedFiles map[string]ViewedState `xorm:"NOT NULL LONGTEXT JSON"` // Stores for each of the changed files of a PR whether they have been viewed, changed since last viewed, or not viewed
|
UpdatedFiles map[string]ViewedState `xorm:"NOT NULL LONGTEXT JSON"` // Stores for each of the changed files of a PR whether they have been viewed, changed since last viewed, or not viewed
|
||||||
UpdatedUnix timeutil.TimeStamp `xorm:"updated"` // Is an accurate indicator of the order of commits as we do not expect it to be possible to make reviews on previous commits
|
UpdatedUnix timeutil.TimeStamp `xorm:"updated"` // Is an accurate indicator of the order of commits as we do not expect it to be possible to make reviews on previous commits
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ type RepoArchiver struct { //revive:disable-line:exported
|
||||||
RepoID int64 `xorm:"index unique(s)"`
|
RepoID int64 `xorm:"index unique(s)"`
|
||||||
Type git.ArchiveType `xorm:"unique(s)"`
|
Type git.ArchiveType `xorm:"unique(s)"`
|
||||||
Status ArchiverStatus
|
Status ArchiverStatus
|
||||||
CommitID string `xorm:"VARCHAR(40) unique(s)"`
|
CommitID string `xorm:"VARCHAR(64) unique(s)"`
|
||||||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX NOT NULL created"`
|
CreatedUnix timeutil.TimeStamp `xorm:"INDEX NOT NULL created"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ type Release struct {
|
||||||
Target string
|
Target string
|
||||||
TargetBehind string `xorm:"-"` // to handle non-existing or empty target
|
TargetBehind string `xorm:"-"` // to handle non-existing or empty target
|
||||||
Title string
|
Title string
|
||||||
Sha1 string `xorm:"VARCHAR(40)"`
|
Sha1 string `xorm:"VARCHAR(64)"`
|
||||||
NumCommits int64
|
NumCommits int64
|
||||||
NumCommitsBehind int64 `xorm:"-"`
|
NumCommitsBehind int64 `xorm:"-"`
|
||||||
Note string `xorm:"TEXT"`
|
Note string `xorm:"TEXT"`
|
||||||
|
|
|
@ -180,7 +180,7 @@ type Repository struct {
|
||||||
IsFsckEnabled bool `xorm:"NOT NULL DEFAULT true"`
|
IsFsckEnabled bool `xorm:"NOT NULL DEFAULT true"`
|
||||||
CloseIssuesViaCommitInAnyBranch bool `xorm:"NOT NULL DEFAULT false"`
|
CloseIssuesViaCommitInAnyBranch bool `xorm:"NOT NULL DEFAULT false"`
|
||||||
Topics []string `xorm:"TEXT JSON"`
|
Topics []string `xorm:"TEXT JSON"`
|
||||||
ObjectFormatName string `xorm:"-"`
|
ObjectFormatName string `xorm:"VARCHAR(6) NOT NULL DEFAULT 'sha1'"`
|
||||||
|
|
||||||
TrustModel TrustModelType
|
TrustModel TrustModelType
|
||||||
|
|
||||||
|
@ -276,10 +276,6 @@ func (repo *Repository) AfterLoad() {
|
||||||
repo.NumOpenMilestones = repo.NumMilestones - repo.NumClosedMilestones
|
repo.NumOpenMilestones = repo.NumMilestones - repo.NumClosedMilestones
|
||||||
repo.NumOpenProjects = repo.NumProjects - repo.NumClosedProjects
|
repo.NumOpenProjects = repo.NumProjects - repo.NumClosedProjects
|
||||||
repo.NumOpenActionRuns = repo.NumActionRuns - repo.NumClosedActionRuns
|
repo.NumOpenActionRuns = repo.NumActionRuns - repo.NumClosedActionRuns
|
||||||
|
|
||||||
// this is a temporary behaviour to support old repos, next step is to store the object format in the database
|
|
||||||
// and read from database so this line could be removed. To not depend on git module, we use a constant variable here
|
|
||||||
repo.ObjectFormatName = "sha1"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadAttributes loads attributes of the repository.
|
// LoadAttributes loads attributes of the repository.
|
||||||
|
|
|
@ -27,7 +27,7 @@ const (
|
||||||
type RepoIndexerStatus struct { //revive:disable-line:exported
|
type RepoIndexerStatus struct { //revive:disable-line:exported
|
||||||
ID int64 `xorm:"pk autoincr"`
|
ID int64 `xorm:"pk autoincr"`
|
||||||
RepoID int64 `xorm:"INDEX(s)"`
|
RepoID int64 `xorm:"INDEX(s)"`
|
||||||
CommitSha string `xorm:"VARCHAR(40)"`
|
CommitSha string `xorm:"VARCHAR(64)"`
|
||||||
IndexerType RepoIndexerType `xorm:"INDEX(s) NOT NULL DEFAULT 0"`
|
IndexerType RepoIndexerType `xorm:"INDEX(s) NOT NULL DEFAULT 0"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,11 +40,14 @@ func IsWorkflow(path string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.HasPrefix(path, ".gitea/workflows") || strings.HasPrefix(path, ".github/workflows")
|
return strings.HasPrefix(path, ".forgejo/workflows") || strings.HasPrefix(path, ".gitea/workflows") || strings.HasPrefix(path, ".github/workflows")
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListWorkflows(commit *git.Commit) (git.Entries, error) {
|
func ListWorkflows(commit *git.Commit) (git.Entries, error) {
|
||||||
tree, err := commit.SubTree(".gitea/workflows")
|
tree, err := commit.SubTree(".forgejo/workflows")
|
||||||
|
if _, ok := err.(git.ErrNotExist); ok {
|
||||||
|
tree, err = commit.SubTree(".gitea/workflows")
|
||||||
|
}
|
||||||
if _, ok := err.(git.ErrNotExist); ok {
|
if _, ok := err.(git.ErrNotExist); ok {
|
||||||
tree, err = commit.SubTree(".github/workflows")
|
tree, err = commit.SubTree(".github/workflows")
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,7 +93,7 @@ func packageAssignment(ctx *packageAssignmentCtx, errCb func(int, string, any))
|
||||||
}
|
}
|
||||||
|
|
||||||
func determineAccessMode(ctx *Base, pkg *Package, doer *user_model.User) (perm.AccessMode, error) {
|
func determineAccessMode(ctx *Base, pkg *Package, doer *user_model.User) (perm.AccessMode, error) {
|
||||||
if setting.Service.RequireSignInView && doer == nil {
|
if setting.Service.RequireSignInView && (doer == nil || doer.IsGhost()) {
|
||||||
return perm.AccessModeNone, nil
|
return perm.AccessModeNone, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
144
modules/git/blame_sha256_test.go
Normal file
144
modules/git/blame_sha256_test.go
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package git
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestReadingBlameOutputSha256(t *testing.T) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
t.Run("Without .git-blame-ignore-revs", func(t *testing.T) {
|
||||||
|
repo, err := OpenRepository(ctx, "./tests/repos/repo5_pulls_sha256")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer repo.Close()
|
||||||
|
|
||||||
|
commit, err := repo.GetCommit("0b69b7bb649b5d46e14cabb6468685e5dd721290acc7ffe604d37cde57927345")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
parts := []*BlamePart{
|
||||||
|
{
|
||||||
|
Sha: "1e35a51dc00fd7de730344c07061acfe80e8117e075ac979b6a29a3a045190ca",
|
||||||
|
Lines: []string{
|
||||||
|
"# test_repo",
|
||||||
|
"Test repository for testing migration from github to gitea",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Sha: "0b69b7bb649b5d46e14cabb6468685e5dd721290acc7ffe604d37cde57927345",
|
||||||
|
Lines: []string{"", "Do not make any changes to this repo it is used for unit testing"},
|
||||||
|
PreviousSha: "1e35a51dc00fd7de730344c07061acfe80e8117e075ac979b6a29a3a045190ca",
|
||||||
|
PreviousPath: "README.md",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, bypass := range []bool{false, true} {
|
||||||
|
blameReader, err := CreateBlameReader(ctx, Sha256ObjectFormat, "./tests/repos/repo5_pulls_sha256", commit, "README.md", bypass)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, blameReader)
|
||||||
|
defer blameReader.Close()
|
||||||
|
|
||||||
|
assert.False(t, blameReader.UsesIgnoreRevs())
|
||||||
|
|
||||||
|
for _, part := range parts {
|
||||||
|
actualPart, err := blameReader.NextPart()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, part, actualPart)
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure all parts have been read
|
||||||
|
actualPart, err := blameReader.NextPart()
|
||||||
|
assert.Nil(t, actualPart)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("With .git-blame-ignore-revs", func(t *testing.T) {
|
||||||
|
repo, err := OpenRepository(ctx, "./tests/repos/repo6_blame_sha256")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer repo.Close()
|
||||||
|
|
||||||
|
full := []*BlamePart{
|
||||||
|
{
|
||||||
|
Sha: "ab2b57a4fa476fb2edb74dafa577caf918561abbaa8fba0c8dc63c412e17a7cc",
|
||||||
|
Lines: []string{"line", "line"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Sha: "9347b0198cd1f25017579b79d0938fa89dba34ad2514f0dd92f6bc975ed1a2fe",
|
||||||
|
Lines: []string{"changed line"},
|
||||||
|
PreviousSha: "ab2b57a4fa476fb2edb74dafa577caf918561abbaa8fba0c8dc63c412e17a7cc",
|
||||||
|
PreviousPath: "blame.txt",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Sha: "ab2b57a4fa476fb2edb74dafa577caf918561abbaa8fba0c8dc63c412e17a7cc",
|
||||||
|
Lines: []string{"line", "line", ""},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
CommitID string
|
||||||
|
UsesIgnoreRevs bool
|
||||||
|
Bypass bool
|
||||||
|
Parts []*BlamePart
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
CommitID: "e2f5660e15159082902960af0ed74fc144921d2b0c80e069361853b3ece29ba3",
|
||||||
|
UsesIgnoreRevs: true,
|
||||||
|
Bypass: false,
|
||||||
|
Parts: []*BlamePart{
|
||||||
|
{
|
||||||
|
Sha: "ab2b57a4fa476fb2edb74dafa577caf918561abbaa8fba0c8dc63c412e17a7cc",
|
||||||
|
Lines: []string{"line", "line", "changed line", "line", "line", ""},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
CommitID: "e2f5660e15159082902960af0ed74fc144921d2b0c80e069361853b3ece29ba3",
|
||||||
|
UsesIgnoreRevs: false,
|
||||||
|
Bypass: true,
|
||||||
|
Parts: full,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
CommitID: "9347b0198cd1f25017579b79d0938fa89dba34ad2514f0dd92f6bc975ed1a2fe",
|
||||||
|
UsesIgnoreRevs: false,
|
||||||
|
Bypass: false,
|
||||||
|
Parts: full,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
CommitID: "9347b0198cd1f25017579b79d0938fa89dba34ad2514f0dd92f6bc975ed1a2fe",
|
||||||
|
UsesIgnoreRevs: false,
|
||||||
|
Bypass: false,
|
||||||
|
Parts: full,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range cases {
|
||||||
|
commit, err := repo.GetCommit(c.CommitID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
blameReader, err := CreateBlameReader(ctx, repo.objectFormat, "./tests/repos/repo6_blame_sha256", commit, "blame.txt", c.Bypass)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, blameReader)
|
||||||
|
defer blameReader.Close()
|
||||||
|
|
||||||
|
assert.Equal(t, c.UsesIgnoreRevs, blameReader.UsesIgnoreRevs())
|
||||||
|
|
||||||
|
for _, part := range c.Parts {
|
||||||
|
actualPart, err := blameReader.NextPart()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, part, actualPart)
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure all parts have been read
|
||||||
|
actualPart, err := blameReader.NextPart()
|
||||||
|
assert.Nil(t, actualPart)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
|
@ -85,6 +85,8 @@ readLoop:
|
||||||
commit.Committer.Decode(data)
|
commit.Committer.Decode(data)
|
||||||
_, _ = payloadSB.Write(line)
|
_, _ = payloadSB.Write(line)
|
||||||
case "gpgsig":
|
case "gpgsig":
|
||||||
|
fallthrough
|
||||||
|
case "gpgsig-sha256": // FIXME: no intertop, so only 1 exists at present.
|
||||||
_, _ = signatureSB.Write(data)
|
_, _ = signatureSB.Write(data)
|
||||||
_ = signatureSB.WriteByte('\n')
|
_ = signatureSB.WriteByte('\n')
|
||||||
pgpsig = true
|
pgpsig = true
|
||||||
|
|
195
modules/git/commit_sha256_test.go
Normal file
195
modules/git/commit_sha256_test.go
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
//go:build !gogit
|
||||||
|
|
||||||
|
package git
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCommitsCountSha256(t *testing.T) {
|
||||||
|
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare_sha256")
|
||||||
|
|
||||||
|
commitsCount, err := CommitsCount(DefaultContext,
|
||||||
|
CommitsCountOptions{
|
||||||
|
RepoPath: bareRepo1Path,
|
||||||
|
Revision: []string{"f004f41359117d319dedd0eaab8c5259ee2263da839dcba33637997458627fdc"},
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, int64(3), commitsCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCommitsCountWithoutBaseSha256(t *testing.T) {
|
||||||
|
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare_sha256")
|
||||||
|
|
||||||
|
commitsCount, err := CommitsCount(DefaultContext,
|
||||||
|
CommitsCountOptions{
|
||||||
|
RepoPath: bareRepo1Path,
|
||||||
|
Not: "main",
|
||||||
|
Revision: []string{"branch1"},
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, int64(2), commitsCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetFullCommitIDSha256(t *testing.T) {
|
||||||
|
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare_sha256")
|
||||||
|
|
||||||
|
id, err := GetFullCommitID(DefaultContext, bareRepo1Path, "f004f4")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "f004f41359117d319dedd0eaab8c5259ee2263da839dcba33637997458627fdc", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetFullCommitIDErrorSha256(t *testing.T) {
|
||||||
|
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare_sha256")
|
||||||
|
|
||||||
|
id, err := GetFullCommitID(DefaultContext, bareRepo1Path, "unknown")
|
||||||
|
assert.Empty(t, id)
|
||||||
|
if assert.Error(t, err) {
|
||||||
|
assert.EqualError(t, err, "object does not exist [id: unknown, rel_path: ]")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCommitFromReaderSha256(t *testing.T) {
|
||||||
|
commitString := `9433b2a62b964c17a4485ae180f45f595d3e69d31b786087775e28c6b6399df0 commit 1114
|
||||||
|
tree e7f9e96dd79c09b078cac8b303a7d3b9d65ff9b734e86060a4d20409fd379f9e
|
||||||
|
parent 26e9ccc29fad747e9c5d9f4c9ddeb7eff61cc45ef6a8dc258cbeb181afc055e8
|
||||||
|
author Adam Majer <amajer@suse.de> 1698676906 +0100
|
||||||
|
committer Adam Majer <amajer@suse.de> 1698676906 +0100
|
||||||
|
gpgsig-sha256 -----BEGIN PGP SIGNATURE-----
|
||||||
|
` + " " + `
|
||||||
|
iQIrBAABCgAtFiEES+fB08xlgTrzSdQvhkUIsBsmec8FAmU/wKoPHGFtYWplckBz
|
||||||
|
dXNlLmRlAAoJEIZFCLAbJnnP4s4PQIJATa++WPzR6/H4etT7bsOGoMyguEJYyWOd
|
||||||
|
aTybplzT7QAL7h2to0QszGabtzMJPIA39xSFZNYNN30voK5YyyYibXluPKgjemfK
|
||||||
|
WNXwF+gkwgZI38gSvKf+vlqI+EYyIFe19wOhiju0m8SIlB5NEPiWHa17q2mqmqqx
|
||||||
|
1FWa2JdqLPYjAtSLFXeSZegrY5V1FxdemyMUONkg8YO9OSIMZiE0GsnnOXQ3xcT4
|
||||||
|
JTCnmlUxIKw689UiEY80JopUIq+Wl7+qq9507IYYSUCyB6JazL42AKMzVCbD+qBP
|
||||||
|
oOzh/hafYgk9H9qCQXaLbmvs17zXRpicig1bAzqgAy1FDelvpERyRTydEajSLIG6
|
||||||
|
U1cRCkgXCZ0NfsYNPPmBa8b3+rnstypXYTbyMwTln7FfUAaGo6o9JYiPMkzxlmsy
|
||||||
|
zfp/tcaY8+LlBL9aOJjtv+a0p+HrpCGd6CCa4ARfphTLq8QRSSh8uzlB9N+6HnRI
|
||||||
|
VAEUo6ecdDxSpyt2naeg9pKus/BRi7P6g4B1hkk/zZstUX/QP4IQuAJbXjkvsC+X
|
||||||
|
HKRr3NlRM/DygzTyj0gN74uoa0goCIbyAQhiT42nm0cuhM7uN/W0ayrlZjGF1cbR
|
||||||
|
8NCJUL2Nwj0ywKIavC99Ipkb8AsFwpVT6U6effs6
|
||||||
|
=xybZ
|
||||||
|
-----END PGP SIGNATURE-----
|
||||||
|
|
||||||
|
signed commit`
|
||||||
|
|
||||||
|
sha := &Sha256Hash{
|
||||||
|
0x94, 0x33, 0xb2, 0xa6, 0x2b, 0x96, 0x4c, 0x17, 0xa4, 0x48, 0x5a, 0xe1, 0x80, 0xf4, 0x5f, 0x59,
|
||||||
|
0x5d, 0x3e, 0x69, 0xd3, 0x1b, 0x78, 0x60, 0x87, 0x77, 0x5e, 0x28, 0xc6, 0xb6, 0x39, 0x9d, 0xf0,
|
||||||
|
}
|
||||||
|
gitRepo, err := openRepositoryWithDefaultContext(filepath.Join(testReposDir, "repo1_bare_sha256"))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, gitRepo)
|
||||||
|
defer gitRepo.Close()
|
||||||
|
|
||||||
|
commitFromReader, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if !assert.NotNil(t, commitFromReader) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
assert.EqualValues(t, sha, commitFromReader.ID)
|
||||||
|
assert.EqualValues(t, `-----BEGIN PGP SIGNATURE-----
|
||||||
|
|
||||||
|
iQIrBAABCgAtFiEES+fB08xlgTrzSdQvhkUIsBsmec8FAmU/wKoPHGFtYWplckBz
|
||||||
|
dXNlLmRlAAoJEIZFCLAbJnnP4s4PQIJATa++WPzR6/H4etT7bsOGoMyguEJYyWOd
|
||||||
|
aTybplzT7QAL7h2to0QszGabtzMJPIA39xSFZNYNN30voK5YyyYibXluPKgjemfK
|
||||||
|
WNXwF+gkwgZI38gSvKf+vlqI+EYyIFe19wOhiju0m8SIlB5NEPiWHa17q2mqmqqx
|
||||||
|
1FWa2JdqLPYjAtSLFXeSZegrY5V1FxdemyMUONkg8YO9OSIMZiE0GsnnOXQ3xcT4
|
||||||
|
JTCnmlUxIKw689UiEY80JopUIq+Wl7+qq9507IYYSUCyB6JazL42AKMzVCbD+qBP
|
||||||
|
oOzh/hafYgk9H9qCQXaLbmvs17zXRpicig1bAzqgAy1FDelvpERyRTydEajSLIG6
|
||||||
|
U1cRCkgXCZ0NfsYNPPmBa8b3+rnstypXYTbyMwTln7FfUAaGo6o9JYiPMkzxlmsy
|
||||||
|
zfp/tcaY8+LlBL9aOJjtv+a0p+HrpCGd6CCa4ARfphTLq8QRSSh8uzlB9N+6HnRI
|
||||||
|
VAEUo6ecdDxSpyt2naeg9pKus/BRi7P6g4B1hkk/zZstUX/QP4IQuAJbXjkvsC+X
|
||||||
|
HKRr3NlRM/DygzTyj0gN74uoa0goCIbyAQhiT42nm0cuhM7uN/W0ayrlZjGF1cbR
|
||||||
|
8NCJUL2Nwj0ywKIavC99Ipkb8AsFwpVT6U6effs6
|
||||||
|
=xybZ
|
||||||
|
-----END PGP SIGNATURE-----
|
||||||
|
`, commitFromReader.Signature.Signature)
|
||||||
|
assert.EqualValues(t, `tree e7f9e96dd79c09b078cac8b303a7d3b9d65ff9b734e86060a4d20409fd379f9e
|
||||||
|
parent 26e9ccc29fad747e9c5d9f4c9ddeb7eff61cc45ef6a8dc258cbeb181afc055e8
|
||||||
|
author Adam Majer <amajer@suse.de> 1698676906 +0100
|
||||||
|
committer Adam Majer <amajer@suse.de> 1698676906 +0100
|
||||||
|
|
||||||
|
signed commit`, commitFromReader.Signature.Payload)
|
||||||
|
assert.EqualValues(t, "Adam Majer <amajer@suse.de>", commitFromReader.Author.String())
|
||||||
|
|
||||||
|
commitFromReader2, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString+"\n\n"))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
commitFromReader.CommitMessage += "\n\n"
|
||||||
|
commitFromReader.Signature.Payload += "\n\n"
|
||||||
|
assert.EqualValues(t, commitFromReader, commitFromReader2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHasPreviousCommitSha256(t *testing.T) {
|
||||||
|
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare_sha256")
|
||||||
|
|
||||||
|
repo, err := openRepositoryWithDefaultContext(bareRepo1Path)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer repo.Close()
|
||||||
|
|
||||||
|
commit, err := repo.GetCommit("f004f41359117d319dedd0eaab8c5259ee2263da839dcba33637997458627fdc")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
parentSHA := MustIDFromString("b0ec7af4547047f12d5093e37ef8f1b3b5415ed8ee17894d43a34d7d34212e9c")
|
||||||
|
notParentSHA := MustIDFromString("42e334efd04cd36eea6da0599913333c26116e1a537ca76e5b6e4af4dda00236")
|
||||||
|
assert.Equal(t, repo.objectFormat, parentSHA.Type())
|
||||||
|
assert.Equal(t, repo.objectFormat.Name(), "sha256")
|
||||||
|
|
||||||
|
haz, err := commit.HasPreviousCommit(parentSHA)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, haz)
|
||||||
|
|
||||||
|
hazNot, err := commit.HasPreviousCommit(notParentSHA)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.False(t, hazNot)
|
||||||
|
|
||||||
|
selfNot, err := commit.HasPreviousCommit(commit.ID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.False(t, selfNot)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetCommitFileStatusMergesSha256(t *testing.T) {
|
||||||
|
bareRepo1Path := filepath.Join(testReposDir, "repo6_merge_sha256")
|
||||||
|
|
||||||
|
commitFileStatus, err := GetCommitFileStatus(DefaultContext, bareRepo1Path, "d2e5609f630dd8db500f5298d05d16def282412e3e66ed68cc7d0833b29129a1")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
expected := CommitFileStatus{
|
||||||
|
[]string{
|
||||||
|
"add_file.txt",
|
||||||
|
},
|
||||||
|
[]string{},
|
||||||
|
[]string{
|
||||||
|
"to_modify.txt",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, expected.Added, commitFileStatus.Added)
|
||||||
|
assert.Equal(t, expected.Removed, commitFileStatus.Removed)
|
||||||
|
assert.Equal(t, expected.Modified, commitFileStatus.Modified)
|
||||||
|
|
||||||
|
expected = CommitFileStatus{
|
||||||
|
[]string{},
|
||||||
|
[]string{
|
||||||
|
"to_remove.txt",
|
||||||
|
},
|
||||||
|
[]string{},
|
||||||
|
}
|
||||||
|
|
||||||
|
commitFileStatus, err = GetCommitFileStatus(DefaultContext, bareRepo1Path, "da1ded40dc8e5b7c564171f4bf2fc8370487decfb1cb6a99ef28f3ed73d09172")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, expected.Added, commitFileStatus.Added)
|
||||||
|
assert.Equal(t, expected.Removed, commitFileStatus.Removed)
|
||||||
|
assert.Equal(t, expected.Modified, commitFileStatus.Modified)
|
||||||
|
}
|
|
@ -49,9 +49,9 @@ func TestFormat_Flag(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "multiple fields",
|
name: "multiple fields",
|
||||||
|
|
||||||
givenFormat: foreachref.NewFormat("refname:short", "objecttype", "objectname"),
|
givenFormat: foreachref.NewFormat("refname:lstrip=2", "objecttype", "objectname"),
|
||||||
|
|
||||||
wantFlag: "refname:short %(refname:short)%00objecttype %(objecttype)%00objectname %(objectname)%00%00",
|
wantFlag: "refname:lstrip=2 %(refname:lstrip=2)%00objecttype %(objecttype)%00objectname %(objectname)%00%00",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -166,10 +166,6 @@ func InitSimple(ctx context.Context) error {
|
||||||
// InitFull initializes git module with version check and change global variables, sync gitconfig.
|
// InitFull initializes git module with version check and change global variables, sync gitconfig.
|
||||||
// It should only be called once at the beginning of the program initialization (TestMain/GlobalInitInstalled) as this code makes unsynchronized changes to variables.
|
// It should only be called once at the beginning of the program initialization (TestMain/GlobalInitInstalled) as this code makes unsynchronized changes to variables.
|
||||||
func InitFull(ctx context.Context) (err error) {
|
func InitFull(ctx context.Context) (err error) {
|
||||||
if err = checkInit(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = InitSimple(ctx); err != nil {
|
if err = InitSimple(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -189,7 +185,13 @@ func InitFull(ctx context.Context) (err error) {
|
||||||
globalCommandArgs = append(globalCommandArgs, "-c", "credential.helper=")
|
globalCommandArgs = append(globalCommandArgs, "-c", "credential.helper=")
|
||||||
}
|
}
|
||||||
SupportProcReceive = CheckGitVersionAtLeast("2.29") == nil
|
SupportProcReceive = CheckGitVersionAtLeast("2.29") == nil
|
||||||
SupportHashSha256 = CheckGitVersionAtLeast("2.42") == nil
|
SupportHashSha256 = CheckGitVersionAtLeast("2.42") == nil && !isGogit
|
||||||
|
if SupportHashSha256 {
|
||||||
|
SupportedObjectFormats = append(SupportedObjectFormats, Sha256ObjectFormat)
|
||||||
|
} else {
|
||||||
|
log.Warn("sha256 hash support is disabled - requires Git >= 2.42. Gogit is currently unsupported")
|
||||||
|
}
|
||||||
|
|
||||||
if setting.LFS.StartServer {
|
if setting.LFS.StartServer {
|
||||||
if CheckGitVersionAtLeast("2.1.2") != nil {
|
if CheckGitVersionAtLeast("2.1.2") != nil {
|
||||||
return errors.New("LFS server support requires Git >= 2.1.2")
|
return errors.New("LFS server support requires Git >= 2.1.2")
|
||||||
|
|
|
@ -5,6 +5,7 @@ package git
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
|
"crypto/sha256"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
@ -12,6 +13,9 @@ import (
|
||||||
// sha1Pattern can be used to determine if a string is an valid sha
|
// sha1Pattern can be used to determine if a string is an valid sha
|
||||||
var sha1Pattern = regexp.MustCompile(`^[0-9a-f]{4,40}$`)
|
var sha1Pattern = regexp.MustCompile(`^[0-9a-f]{4,40}$`)
|
||||||
|
|
||||||
|
// sha256Pattern can be used to determine if a string is an valid sha
|
||||||
|
var sha256Pattern = regexp.MustCompile(`^[0-9a-f]{4,64}$`)
|
||||||
|
|
||||||
type ObjectFormat interface {
|
type ObjectFormat interface {
|
||||||
// Name returns the name of the object format
|
// Name returns the name of the object format
|
||||||
Name() string
|
Name() string
|
||||||
|
@ -29,11 +33,12 @@ type ObjectFormat interface {
|
||||||
ComputeHash(t ObjectType, content []byte) ObjectID
|
ComputeHash(t ObjectType, content []byte) ObjectID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* SHA1 Type */
|
||||||
type Sha1ObjectFormatImpl struct{}
|
type Sha1ObjectFormatImpl struct{}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
emptyObjectID = &Sha1Hash{}
|
emptySha1ObjectID = &Sha1Hash{}
|
||||||
emptyTree = &Sha1Hash{
|
emptySha1Tree = &Sha1Hash{
|
||||||
0x4b, 0x82, 0x5d, 0xc6, 0x42, 0xcb, 0x6e, 0xb9, 0xa0, 0x60,
|
0x4b, 0x82, 0x5d, 0xc6, 0x42, 0xcb, 0x6e, 0xb9, 0xa0, 0x60,
|
||||||
0xe5, 0x4b, 0xf8, 0xd6, 0x92, 0x88, 0xfb, 0xee, 0x49, 0x04,
|
0xe5, 0x4b, 0xf8, 0xd6, 0x92, 0x88, 0xfb, 0xee, 0x49, 0x04,
|
||||||
}
|
}
|
||||||
|
@ -41,11 +46,11 @@ var (
|
||||||
|
|
||||||
func (Sha1ObjectFormatImpl) Name() string { return "sha1" }
|
func (Sha1ObjectFormatImpl) Name() string { return "sha1" }
|
||||||
func (Sha1ObjectFormatImpl) EmptyObjectID() ObjectID {
|
func (Sha1ObjectFormatImpl) EmptyObjectID() ObjectID {
|
||||||
return emptyObjectID
|
return emptySha1ObjectID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Sha1ObjectFormatImpl) EmptyTree() ObjectID {
|
func (Sha1ObjectFormatImpl) EmptyTree() ObjectID {
|
||||||
return emptyTree
|
return emptySha1Tree
|
||||||
}
|
}
|
||||||
func (Sha1ObjectFormatImpl) FullLength() int { return 40 }
|
func (Sha1ObjectFormatImpl) FullLength() int { return 40 }
|
||||||
func (Sha1ObjectFormatImpl) IsValid(input string) bool {
|
func (Sha1ObjectFormatImpl) IsValid(input string) bool {
|
||||||
|
@ -72,11 +77,59 @@ func (h Sha1ObjectFormatImpl) ComputeHash(t ObjectType, content []byte) ObjectID
|
||||||
return &sha1
|
return &sha1
|
||||||
}
|
}
|
||||||
|
|
||||||
var Sha1ObjectFormat ObjectFormat = Sha1ObjectFormatImpl{}
|
/* SHA256 Type */
|
||||||
|
type Sha256ObjectFormatImpl struct{}
|
||||||
|
|
||||||
|
var (
|
||||||
|
emptySha256ObjectID = &Sha256Hash{}
|
||||||
|
emptySha256Tree = &Sha256Hash{
|
||||||
|
0x6e, 0xf1, 0x9b, 0x41, 0x22, 0x5c, 0x53, 0x69, 0xf1, 0xc1,
|
||||||
|
0x04, 0xd4, 0x5d, 0x8d, 0x85, 0xef, 0xa9, 0xb0, 0x57, 0xb5,
|
||||||
|
0x3b, 0x14, 0xb4, 0xb9, 0xb9, 0x39, 0xdd, 0x74, 0xde, 0xcc,
|
||||||
|
0x53, 0x21,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (Sha256ObjectFormatImpl) Name() string { return "sha256" }
|
||||||
|
func (Sha256ObjectFormatImpl) EmptyObjectID() ObjectID {
|
||||||
|
return emptySha256ObjectID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Sha256ObjectFormatImpl) EmptyTree() ObjectID {
|
||||||
|
return emptySha256Tree
|
||||||
|
}
|
||||||
|
func (Sha256ObjectFormatImpl) FullLength() int { return 64 }
|
||||||
|
func (Sha256ObjectFormatImpl) IsValid(input string) bool {
|
||||||
|
return sha256Pattern.MatchString(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Sha256ObjectFormatImpl) MustID(b []byte) ObjectID {
|
||||||
|
var id Sha256Hash
|
||||||
|
copy(id[0:32], b)
|
||||||
|
return &id
|
||||||
|
}
|
||||||
|
|
||||||
|
// ComputeHash compute the hash for a given ObjectType and content
|
||||||
|
func (h Sha256ObjectFormatImpl) ComputeHash(t ObjectType, content []byte) ObjectID {
|
||||||
|
hasher := sha256.New()
|
||||||
|
_, _ = hasher.Write(t.Bytes())
|
||||||
|
_, _ = hasher.Write([]byte(" "))
|
||||||
|
_, _ = hasher.Write([]byte(strconv.FormatInt(int64(len(content)), 10)))
|
||||||
|
_, _ = hasher.Write([]byte{0})
|
||||||
|
|
||||||
|
// HashSum generates a SHA256 for the provided hash
|
||||||
|
var sha256 Sha1Hash
|
||||||
|
copy(sha256[:], hasher.Sum(nil))
|
||||||
|
return &sha256
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
Sha1ObjectFormat ObjectFormat = Sha1ObjectFormatImpl{}
|
||||||
|
Sha256ObjectFormat ObjectFormat = Sha256ObjectFormatImpl{}
|
||||||
|
)
|
||||||
|
|
||||||
var SupportedObjectFormats = []ObjectFormat{
|
var SupportedObjectFormats = []ObjectFormat{
|
||||||
Sha1ObjectFormat,
|
Sha1ObjectFormat,
|
||||||
// TODO: add sha256
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ObjectFormatFromName(name string) ObjectFormat {
|
func ObjectFormatFromName(name string) ObjectFormat {
|
||||||
|
|
|
@ -16,6 +16,7 @@ type ObjectID interface {
|
||||||
Type() ObjectFormat
|
Type() ObjectFormat
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* SHA1 */
|
||||||
type Sha1Hash [20]byte
|
type Sha1Hash [20]byte
|
||||||
|
|
||||||
func (h *Sha1Hash) String() string {
|
func (h *Sha1Hash) String() string {
|
||||||
|
@ -39,6 +40,21 @@ func MustIDFromString(hexHash string) ObjectID {
|
||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* SHA256 */
|
||||||
|
type Sha256Hash [32]byte
|
||||||
|
|
||||||
|
func (h *Sha256Hash) String() string {
|
||||||
|
return hex.EncodeToString(h[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Sha256Hash) IsZero() bool {
|
||||||
|
empty := Sha256Hash{}
|
||||||
|
return bytes.Equal(empty[:], h[:])
|
||||||
|
}
|
||||||
|
func (h *Sha256Hash) RawValue() []byte { return h[:] }
|
||||||
|
func (*Sha256Hash) Type() ObjectFormat { return Sha256ObjectFormat }
|
||||||
|
|
||||||
|
/* utility */
|
||||||
func NewIDFromString(hexHash string) (ObjectID, error) {
|
func NewIDFromString(hexHash string) (ObjectID, error) {
|
||||||
var theObjectFormat ObjectFormat
|
var theObjectFormat ObjectFormat
|
||||||
for _, objectFormat := range SupportedObjectFormats {
|
for _, objectFormat := range SupportedObjectFormats {
|
||||||
|
|
|
@ -13,6 +13,8 @@ func ParseGogitHash(h plumbing.Hash) ObjectID {
|
||||||
switch hash.Size {
|
switch hash.Size {
|
||||||
case 20:
|
case 20:
|
||||||
return Sha1ObjectFormat.MustID(h[:])
|
return Sha1ObjectFormat.MustID(h[:])
|
||||||
|
case 32:
|
||||||
|
return Sha256ObjectFormat.MustID(h[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -97,15 +97,12 @@ func InitRepository(ctx context.Context, repoPath string, bare bool, objectForma
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := NewCommand(ctx, "init")
|
cmd := NewCommand(ctx, "init")
|
||||||
if SupportHashSha256 {
|
|
||||||
if objectFormatName == "" {
|
if !IsValidObjectFormat(objectFormatName) {
|
||||||
objectFormatName = Sha1ObjectFormat.Name()
|
return fmt.Errorf("invalid object format: %s", objectFormatName)
|
||||||
}
|
|
||||||
if !IsValidObjectFormat(objectFormatName) {
|
|
||||||
return fmt.Errorf("invalid object format: %s", objectFormatName)
|
|
||||||
}
|
|
||||||
cmd.AddOptionValues("--object-format", objectFormatName)
|
|
||||||
}
|
}
|
||||||
|
cmd.AddOptionValues("--object-format", objectFormatName)
|
||||||
|
|
||||||
if bare {
|
if bare {
|
||||||
cmd.AddArguments("--bare")
|
cmd.AddArguments("--bare")
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
@ -62,11 +63,15 @@ func (repo *Repository) CreateArchive(ctx context.Context, format ArchiveType, t
|
||||||
cmd.AddOptionFormat("--format=%s", format.String())
|
cmd.AddOptionFormat("--format=%s", format.String())
|
||||||
cmd.AddDynamicArguments(commitID)
|
cmd.AddDynamicArguments(commitID)
|
||||||
|
|
||||||
|
// Avoid LFS hooks getting installed because of /etc/gitconfig, which can break pull requests.
|
||||||
|
env := append(os.Environ(), "GIT_CONFIG_NOSYSTEM=1")
|
||||||
|
|
||||||
var stderr strings.Builder
|
var stderr strings.Builder
|
||||||
err := cmd.Run(&RunOpts{
|
err := cmd.Run(&RunOpts{
|
||||||
Dir: repo.Path,
|
Dir: repo.Path,
|
||||||
Stdout: target,
|
Stdout: target,
|
||||||
Stderr: &stderr,
|
Stderr: &stderr,
|
||||||
|
Env: env,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ConcatenateError(err, stderr.String())
|
return ConcatenateError(err, stderr.String())
|
||||||
|
|
|
@ -8,6 +8,8 @@ import (
|
||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var isGogit bool
|
||||||
|
|
||||||
// contextKey is a value for use with context.WithValue.
|
// contextKey is a value for use with context.WithValue.
|
||||||
type contextKey struct {
|
type contextKey struct {
|
||||||
name string
|
name string
|
||||||
|
|
|
@ -21,6 +21,10 @@ import (
|
||||||
"github.com/go-git/go-git/v5/storage/filesystem"
|
"github.com/go-git/go-git/v5/storage/filesystem"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
isGogit = true
|
||||||
|
}
|
||||||
|
|
||||||
// Repository represents a Git repository.
|
// Repository represents a Git repository.
|
||||||
type Repository struct {
|
type Repository struct {
|
||||||
Path string
|
Path string
|
||||||
|
|
|
@ -15,6 +15,10 @@ import (
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
isGogit = false
|
||||||
|
}
|
||||||
|
|
||||||
// Repository represents a Git repository.
|
// Repository represents a Git repository.
|
||||||
type Repository struct {
|
type Repository struct {
|
||||||
Path string
|
Path string
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue