mirror of
https://github.com/go-gitea/gitea.git
synced 2025-07-20 00:00:55 -04:00
Compare commits
10 Commits
ae2794c958
...
3c131307ac
Author | SHA1 | Date | |
---|---|---|---|
|
3c131307ac | ||
|
ac4ae35542 | ||
|
e2e0280108 | ||
|
28ead9ea62 | ||
|
5283ce9650 | ||
|
65eea1d536 | ||
|
d1527dac3d | ||
|
43632d9d34 | ||
|
79e8865aae | ||
|
e94a4ad28d |
16
.github/workflows/release-nightly.yml
vendored
16
.github/workflows/release-nightly.yml
vendored
@ -48,15 +48,15 @@ jobs:
|
|||||||
REF_NAME=$(echo "${{ github.ref }}" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\///' -e 's/release\/v//')
|
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 "Cleaned name is ${REF_NAME}"
|
||||||
echo "branch=${REF_NAME}" >> "$GITHUB_OUTPUT"
|
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
|
- name: upload binaries to s3
|
||||||
uses: jakejarvis/s3-sync-action@master
|
run: |
|
||||||
env:
|
aws s3 sync dist/release s3://${{ secrets.AWS_S3_BUCKET }}/gitea/${{ steps.clean_name.outputs.branch }} --no-progress
|
||||||
AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
|
|
||||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
||||||
AWS_REGION: ${{ secrets.AWS_REGION }}
|
|
||||||
SOURCE_DIR: dist/release
|
|
||||||
DEST_DIR: gitea/${{ steps.clean_name.outputs.branch }}
|
|
||||||
nightly-docker-rootful:
|
nightly-docker-rootful:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
@ -7,7 +7,6 @@ package main
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@ -19,11 +18,8 @@ import (
|
|||||||
|
|
||||||
"github.com/google/go-github/v53/github"
|
"github.com/google/go-github/v53/github"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultVersion = "v1.18" // to backport to
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
app := cli.NewApp()
|
app := cli.NewApp()
|
||||||
app.Name = "backport"
|
app.Name = "backport"
|
||||||
@ -54,16 +50,6 @@ func main() {
|
|||||||
Name: "backport-branch",
|
Name: "backport-branch",
|
||||||
Usage: "Backport branch to backport on to (default: backport-<pr>-<version>",
|
Usage: "Backport branch to backport on to (default: backport-<pr>-<version>",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "remote",
|
|
||||||
Value: "",
|
|
||||||
Usage: "Remote for your fork of the Gitea upstream",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "fork-user",
|
|
||||||
Value: "",
|
|
||||||
Usage: "Forked user name on Github",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "no-fetch",
|
Name: "no-fetch",
|
||||||
Usage: "Set this flag to prevent fetch of remote branches",
|
Usage: "Set this flag to prevent fetch of remote branches",
|
||||||
@ -72,18 +58,6 @@ func main() {
|
|||||||
Name: "no-amend-message",
|
Name: "no-amend-message",
|
||||||
Usage: "Set this flag to prevent automatic amendment of the commit message",
|
Usage: "Set this flag to prevent automatic amendment of the commit message",
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "no-push",
|
|
||||||
Usage: "Set this flag to prevent pushing the backport up to your fork",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "no-xdg-open",
|
|
||||||
Usage: "Set this flag to not use xdg-open to open the PR URL",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "continue",
|
|
||||||
Usage: "Set this flag to continue from a git cherry-pick that has broken",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
cli.AppHelpTemplate = `NAME:
|
cli.AppHelpTemplate = `NAME:
|
||||||
{{.Name}} - {{.Usage}}
|
{{.Name}} - {{.Usage}}
|
||||||
@ -101,7 +75,7 @@ OPTIONS:
|
|||||||
app.Action = runBackport
|
app.Action = runBackport
|
||||||
|
|
||||||
if err := app.Run(os.Args); err != nil {
|
if err := app.Run(os.Args); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Unable to backport: %v\n", err)
|
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,24 +83,9 @@ func runBackport(c *cli.Context) error {
|
|||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
continuing := c.Bool("continue")
|
|
||||||
|
|
||||||
var pr string
|
|
||||||
|
|
||||||
version := c.String("version")
|
version := c.String("version")
|
||||||
if version == "" && continuing {
|
|
||||||
// determine version from current branch name
|
|
||||||
var err error
|
|
||||||
pr, version, err = readCurrentBranch(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if version == "" {
|
if version == "" {
|
||||||
version = readVersion()
|
return fmt.Errorf("Provide a version to backport to")
|
||||||
}
|
|
||||||
if version == "" {
|
|
||||||
version = defaultVersion
|
|
||||||
}
|
}
|
||||||
|
|
||||||
upstream := c.String("upstream")
|
upstream := c.String("upstream")
|
||||||
@ -134,16 +93,6 @@ func runBackport(c *cli.Context) error {
|
|||||||
upstream = "origin"
|
upstream = "origin"
|
||||||
}
|
}
|
||||||
|
|
||||||
forkUser := c.String("fork-user")
|
|
||||||
remote := c.String("remote")
|
|
||||||
if remote == "" && !c.Bool("--no-push") {
|
|
||||||
var err error
|
|
||||||
remote, forkUser, err = determineRemote(ctx, forkUser)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
upstreamReleaseBranch := c.String("release-branch")
|
upstreamReleaseBranch := c.String("release-branch")
|
||||||
if upstreamReleaseBranch == "" {
|
if upstreamReleaseBranch == "" {
|
||||||
upstreamReleaseBranch = path.Join("release", version)
|
upstreamReleaseBranch = path.Join("release", version)
|
||||||
@ -152,14 +101,12 @@ func runBackport(c *cli.Context) error {
|
|||||||
localReleaseBranch := path.Join(upstream, upstreamReleaseBranch)
|
localReleaseBranch := path.Join(upstream, upstreamReleaseBranch)
|
||||||
|
|
||||||
args := c.Args().Slice()
|
args := c.Args().Slice()
|
||||||
if len(args) == 0 && pr == "" {
|
if len(args) == 0 {
|
||||||
return fmt.Errorf("no PR number provided\nProvide a PR number to backport")
|
return fmt.Errorf("Provide a PR number to backport")
|
||||||
} else if len(args) != 1 && pr == "" {
|
} else if len(args) != 1 {
|
||||||
return fmt.Errorf("multiple PRs provided %v\nOnly a single PR can be backported at a time", args)
|
return fmt.Errorf("Only a single PR can be backported at a time")
|
||||||
}
|
|
||||||
if pr == "" {
|
|
||||||
pr = args[0]
|
|
||||||
}
|
}
|
||||||
|
pr := args[0]
|
||||||
|
|
||||||
backportBranch := c.String("backport-branch")
|
backportBranch := c.String("backport-branch")
|
||||||
if backportBranch == "" {
|
if backportBranch == "" {
|
||||||
@ -186,10 +133,8 @@ func runBackport(c *cli.Context) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !continuing {
|
if err := checkoutBackportBranch(ctx, backportBranch, localReleaseBranch); err != nil {
|
||||||
if err := checkoutBackportBranch(ctx, backportBranch, localReleaseBranch); err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := cherrypick(ctx, sha); err != nil {
|
if err := cherrypick(ctx, sha); err != nil {
|
||||||
@ -202,41 +147,8 @@ func runBackport(c *cli.Context) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !c.Bool("no-push") {
|
fmt.Printf("Backport done! You can now push it with `git push <your remote> %s`\n", backportBranch)
|
||||||
url := "https://github.com/go-gitea/gitea/compare/" + upstreamReleaseBranch + "..." + forkUser + ":" + backportBranch
|
|
||||||
|
|
||||||
if err := gitPushUp(ctx, remote, backportBranch); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !c.Bool("no-xdg-open") {
|
|
||||||
if err := xdgOpen(ctx, url); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fmt.Printf("* Navigate to %s to open PR\n", url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func xdgOpen(ctx context.Context, url string) error {
|
|
||||||
fmt.Printf("* `xdg-open %s`\n", url)
|
|
||||||
out, err := exec.CommandContext(ctx, "xdg-open", url).Output()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "%s", string(out))
|
|
||||||
return fmt.Errorf("unable to xdg-open to %s: %w", url, err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func gitPushUp(ctx context.Context, remote, backportBranch string) error {
|
|
||||||
fmt.Printf("* `git push -u %s %s`\n", remote, backportBranch)
|
|
||||||
out, err := exec.CommandContext(ctx, "git", "push", "-u", remote, backportBranch).Output()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "%s", string(out))
|
|
||||||
return fmt.Errorf("unable to push up to %s: %w", remote, err)
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,18 +179,6 @@ func amendCommit(ctx context.Context, pr string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func cherrypick(ctx context.Context, sha string) error {
|
func cherrypick(ctx context.Context, sha string) error {
|
||||||
// Check if a CHERRY_PICK_HEAD exists
|
|
||||||
if _, err := os.Stat(".git/CHERRY_PICK_HEAD"); err == nil {
|
|
||||||
// Assume that we are in the middle of cherry-pick - continue it
|
|
||||||
fmt.Println("* Attempting git cherry-pick --continue")
|
|
||||||
out, err := exec.CommandContext(ctx, "git", "cherry-pick", "--continue").Output()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "git cherry-pick --continue failed:\n%s\n", string(out))
|
|
||||||
return fmt.Errorf("unable to continue cherry-pick: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("* Attempting git cherry-pick %s\n", sha)
|
fmt.Printf("* Attempting git cherry-pick %s\n", sha)
|
||||||
out, err := exec.CommandContext(ctx, "git", "cherry-pick", sha).Output()
|
out, err := exec.CommandContext(ctx, "git", "cherry-pick", sha).Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -289,22 +189,8 @@ func cherrypick(ctx context.Context, sha string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func checkoutBackportBranch(ctx context.Context, backportBranch, releaseBranch string) error {
|
func checkoutBackportBranch(ctx context.Context, backportBranch, releaseBranch string) error {
|
||||||
out, err := exec.CommandContext(ctx, "git", "branch", "--show-current").Output()
|
fmt.Printf("* `git branch -D %s`\n", backportBranch)
|
||||||
if err != nil {
|
_ = exec.CommandContext(ctx, "git", "branch", "-D", backportBranch).Run()
|
||||||
return fmt.Errorf("unable to check current branch %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
currentBranch := strings.TrimSpace(string(out))
|
|
||||||
fmt.Printf("* Current branch is %s\n", currentBranch)
|
|
||||||
if currentBranch == backportBranch {
|
|
||||||
fmt.Printf("* Current branch is %s - not checking out\n", currentBranch)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := exec.CommandContext(ctx, "git", "rev-list", "-1", backportBranch).Output(); err == nil {
|
|
||||||
fmt.Printf("* Branch %s already exists. Checking it out...\n", backportBranch)
|
|
||||||
return exec.CommandContext(ctx, "git", "checkout", "-f", backportBranch).Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("* `git checkout -b %s %s`\n", backportBranch, releaseBranch)
|
fmt.Printf("* `git checkout -b %s %s`\n", backportBranch, releaseBranch)
|
||||||
return exec.CommandContext(ctx, "git", "checkout", "-b", backportBranch, releaseBranch).Run()
|
return exec.CommandContext(ctx, "git", "checkout", "-b", backportBranch, releaseBranch).Run()
|
||||||
@ -317,7 +203,6 @@ func fetchRemoteAndMain(ctx context.Context, remote, releaseBranch string) error
|
|||||||
fmt.Println(string(out))
|
fmt.Println(string(out))
|
||||||
return fmt.Errorf("unable to fetch %s from %s: %w", "main", remote, err)
|
return fmt.Errorf("unable to fetch %s from %s: %w", "main", remote, err)
|
||||||
}
|
}
|
||||||
fmt.Println(string(out))
|
|
||||||
|
|
||||||
fmt.Printf("* `git fetch %s %s`\n", remote, releaseBranch)
|
fmt.Printf("* `git fetch %s %s`\n", remote, releaseBranch)
|
||||||
out, err = exec.CommandContext(ctx, "git", "fetch", remote, releaseBranch).Output()
|
out, err = exec.CommandContext(ctx, "git", "fetch", remote, releaseBranch).Output()
|
||||||
@ -325,108 +210,10 @@ func fetchRemoteAndMain(ctx context.Context, remote, releaseBranch string) error
|
|||||||
fmt.Println(string(out))
|
fmt.Println(string(out))
|
||||||
return fmt.Errorf("unable to fetch %s from %s: %w", releaseBranch, remote, err)
|
return fmt.Errorf("unable to fetch %s from %s: %w", releaseBranch, remote, err)
|
||||||
}
|
}
|
||||||
fmt.Println(string(out))
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func determineRemote(ctx context.Context, forkUser string) (string, string, error) {
|
|
||||||
out, err := exec.CommandContext(ctx, "git", "remote", "-v").Output()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Unable to list git remotes:\n%s\n", string(out))
|
|
||||||
return "", "", fmt.Errorf("unable to determine forked remote: %w", err)
|
|
||||||
}
|
|
||||||
lines := strings.Split(string(out), "\n")
|
|
||||||
for _, line := range lines {
|
|
||||||
fields := strings.Split(line, "\t")
|
|
||||||
name, remote := fields[0], fields[1]
|
|
||||||
// only look at pushers
|
|
||||||
if !strings.HasSuffix(remote, " (push)") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// only look at github.com pushes
|
|
||||||
if !strings.Contains(remote, "github.com") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// ignore go-gitea/gitea
|
|
||||||
if strings.Contains(remote, "go-gitea/gitea") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !strings.Contains(remote, forkUser) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(remote, "git@github.com:") {
|
|
||||||
forkUser = strings.TrimPrefix(remote, "git@github.com:")
|
|
||||||
} else if strings.HasPrefix(remote, "https://github.com/") {
|
|
||||||
forkUser = strings.TrimPrefix(remote, "https://github.com/")
|
|
||||||
} else if strings.HasPrefix(remote, "https://www.github.com/") {
|
|
||||||
forkUser = strings.TrimPrefix(remote, "https://www.github.com/")
|
|
||||||
} else if forkUser == "" {
|
|
||||||
return "", "", fmt.Errorf("unable to extract forkUser from remote %s: %s", name, remote)
|
|
||||||
}
|
|
||||||
idx := strings.Index(forkUser, "/")
|
|
||||||
if idx >= 0 {
|
|
||||||
forkUser = forkUser[:idx]
|
|
||||||
}
|
|
||||||
return name, forkUser, nil
|
|
||||||
}
|
|
||||||
return "", "", fmt.Errorf("unable to find appropriate remote in:\n%s", string(out))
|
|
||||||
}
|
|
||||||
|
|
||||||
func readCurrentBranch(ctx context.Context) (pr, version string, err error) {
|
|
||||||
out, err := exec.CommandContext(ctx, "git", "branch", "--show-current").Output()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Unable to read current git branch:\n%s\n", string(out))
|
|
||||||
return "", "", fmt.Errorf("unable to read current git branch: %w", err)
|
|
||||||
}
|
|
||||||
parts := strings.Split(strings.TrimSpace(string(out)), "-")
|
|
||||||
|
|
||||||
if len(parts) != 3 || parts[0] != "backport" {
|
|
||||||
fmt.Fprintf(os.Stderr, "Unable to continue from git branch:\n%s\n", string(out))
|
|
||||||
return "", "", fmt.Errorf("unable to continue from git branch:\n%s", string(out))
|
|
||||||
}
|
|
||||||
|
|
||||||
return parts[1], parts[2], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func readVersion() string {
|
|
||||||
bs, err := os.ReadFile("docs/config.yaml")
|
|
||||||
if err != nil {
|
|
||||||
if err == os.ErrNotExist {
|
|
||||||
log.Println("`docs/config.yaml` not present")
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
fmt.Fprintf(os.Stderr, "Unable to read `docs/config.yaml`: %v\n", err)
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
type params struct {
|
|
||||||
Version string
|
|
||||||
}
|
|
||||||
type docConfig struct {
|
|
||||||
Params params
|
|
||||||
}
|
|
||||||
dc := &docConfig{}
|
|
||||||
if err := yaml.Unmarshal(bs, dc); err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Unable to read `docs/config.yaml`: %v\n", err)
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
if dc.Params.Version == "" {
|
|
||||||
fmt.Fprintf(os.Stderr, "No version in `docs/config.yaml`")
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
version := dc.Params.Version
|
|
||||||
if version[0] != 'v' {
|
|
||||||
version = "v" + version
|
|
||||||
}
|
|
||||||
|
|
||||||
split := strings.SplitN(version, ".", 3)
|
|
||||||
|
|
||||||
return strings.Join(split[:2], ".")
|
|
||||||
}
|
|
||||||
|
|
||||||
func determineSHAforPR(ctx context.Context, prStr string) (string, error) {
|
func determineSHAforPR(ctx context.Context, prStr string) (string, error) {
|
||||||
prNum, err := strconv.Atoi(prStr)
|
prNum, err := strconv.Atoi(prStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -381,3 +381,9 @@ If you really need to do so, to make Gitea works with sub-path (eg: `http://exam
|
|||||||
1. Set `[server] ROOT_URL = http://example.com/gitea/` in your `app.ini` file.
|
1. Set `[server] ROOT_URL = http://example.com/gitea/` in your `app.ini` file.
|
||||||
2. Make the reverse-proxy pass `http://example.com/gitea/foo` to `http://gitea-server:3000/foo`.
|
2. Make the reverse-proxy pass `http://example.com/gitea/foo` to `http://gitea-server:3000/foo`.
|
||||||
3. Make sure the reverse-proxy not decode the URI, the request `http://example.com/gitea/a%2Fb` should be passed as `http://gitea-server:3000/a%2Fb`.
|
3. Make sure the reverse-proxy not decode the URI, the request `http://example.com/gitea/a%2Fb` should be passed as `http://gitea-server:3000/a%2Fb`.
|
||||||
|
|
||||||
|
## Docker / Container Registry
|
||||||
|
|
||||||
|
The container registry uses a fixed sub-path `/v2` which can't be changed.
|
||||||
|
Even if you deploy Gitea with a different sub-path, `/v2` will be used by the `docker` client.
|
||||||
|
Therefore you may need to add an additional route to your reverse proxy configuration.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
date: "2017-07-21T12:00:00+02:00"
|
date: "2017-07-21T12:00:00+02:00"
|
||||||
title: "Run as service in Linux"
|
title: "Run as a Linux service"
|
||||||
slug: "linux-service"
|
slug: "linux-service"
|
||||||
sidebar_position: 40
|
sidebar_position: 40
|
||||||
toc: false
|
toc: false
|
||||||
@ -15,11 +15,11 @@ menu:
|
|||||||
identifier: "linux-service"
|
identifier: "linux-service"
|
||||||
---
|
---
|
||||||
|
|
||||||
### Run Gitea as Linux service
|
# Run as a Linux service
|
||||||
|
|
||||||
You can run Gitea as service, using either systemd or supervisor. The steps below tested on Ubuntu 16.04, but those should work on any Linux distributions (with little modification).
|
You can run Gitea as a Linux service, using either systemd or supervisor. The steps below tested on Ubuntu 16.04, but those should work on any Linux distributions (with little modification).
|
||||||
|
|
||||||
#### Using systemd
|
## Using systemd
|
||||||
|
|
||||||
Copy the sample [gitea.service](https://github.com/go-gitea/gitea/blob/main/contrib/systemd/gitea.service) to `/etc/systemd/system/gitea.service`, then edit the file with your favorite editor.
|
Copy the sample [gitea.service](https://github.com/go-gitea/gitea/blob/main/contrib/systemd/gitea.service) to `/etc/systemd/system/gitea.service`, then edit the file with your favorite editor.
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ If you have systemd version 220 or later, you can enable and immediately start G
|
|||||||
sudo systemctl enable gitea --now
|
sudo systemctl enable gitea --now
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Using supervisor
|
## Using supervisor
|
||||||
|
|
||||||
Install supervisor by running below command in terminal:
|
Install supervisor by running below command in terminal:
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
date: "2016-12-21T15:00:00-02:00"
|
date: "2016-12-21T15:00:00-02:00"
|
||||||
title: "Register as a Windows Service"
|
title: "Register as a Windows service"
|
||||||
slug: "windows-service"
|
slug: "windows-service"
|
||||||
sidebar_position: 50
|
sidebar_position: 50
|
||||||
toc: false
|
toc: false
|
||||||
@ -14,8 +14,9 @@ menu:
|
|||||||
sidebar_position: 50
|
sidebar_position: 50
|
||||||
identifier: "windows-service"
|
identifier: "windows-service"
|
||||||
---
|
---
|
||||||
|
# Register as a Windows service
|
||||||
|
|
||||||
# Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
The following changes are made in C:\gitea\custom\conf\app.ini:
|
The following changes are made in C:\gitea\custom\conf\app.ini:
|
||||||
|
|
||||||
@ -27,7 +28,7 @@ Sets Gitea to run as the local system user.
|
|||||||
|
|
||||||
COMPUTERNAME is whatever the response is from `echo %COMPUTERNAME%` on the command line. If the response is `USER-PC` then `RUN_USER = USER-PC$`
|
COMPUTERNAME is whatever the response is from `echo %COMPUTERNAME%` on the command line. If the response is `USER-PC` then `RUN_USER = USER-PC$`
|
||||||
|
|
||||||
## Use absolute paths
|
### Use absolute paths
|
||||||
|
|
||||||
If you use SQLite3, change the `PATH` to include the full path:
|
If you use SQLite3, change the `PATH` to include the full path:
|
||||||
|
|
||||||
@ -36,7 +37,7 @@ If you use SQLite3, change the `PATH` to include the full path:
|
|||||||
PATH = c:/gitea/data/gitea.db
|
PATH = c:/gitea/data/gitea.db
|
||||||
```
|
```
|
||||||
|
|
||||||
# Register as a Windows Service
|
## Register Gitea
|
||||||
|
|
||||||
To register Gitea as a Windows service, open a command prompt (cmd) as an Administrator,
|
To register Gitea as a Windows service, open a command prompt (cmd) as an Administrator,
|
||||||
then run the following command:
|
then run the following command:
|
||||||
@ -51,7 +52,7 @@ Open "Windows Services", search for the service named "gitea", right-click it an
|
|||||||
"Run". If everything is OK, Gitea will be reachable on `http://localhost:3000` (or the port
|
"Run". If everything is OK, Gitea will be reachable on `http://localhost:3000` (or the port
|
||||||
that was configured).
|
that was configured).
|
||||||
|
|
||||||
## Service startup type
|
### Service startup type
|
||||||
|
|
||||||
It was observed that on loaded systems during boot Gitea service may fail to start with timeout records in Windows Event Log.
|
It was observed that on loaded systems during boot Gitea service may fail to start with timeout records in Windows Event Log.
|
||||||
In that case change startup type to `Automatic-Delayed`. This can be done during service creation, or by running config command
|
In that case change startup type to `Automatic-Delayed`. This can be done during service creation, or by running config command
|
||||||
@ -60,7 +61,7 @@ In that case change startup type to `Automatic-Delayed`. This can be done during
|
|||||||
sc.exe config gitea start= delayed-auto
|
sc.exe config gitea start= delayed-auto
|
||||||
```
|
```
|
||||||
|
|
||||||
## Adding startup dependencies
|
### Adding startup dependencies
|
||||||
|
|
||||||
To add a startup dependency to the Gitea Windows service (eg Mysql, Mariadb), as an Administrator, then run the following command:
|
To add a startup dependency to the Gitea Windows service (eg Mysql, Mariadb), as an Administrator, then run the following command:
|
||||||
|
|
||||||
@ -70,9 +71,9 @@ sc.exe config gitea depend= mariadb
|
|||||||
|
|
||||||
This will ensure that when the Windows machine restarts, the automatic starting of Gitea is postponed until the database is ready and thus mitigate failed startups.
|
This will ensure that when the Windows machine restarts, the automatic starting of Gitea is postponed until the database is ready and thus mitigate failed startups.
|
||||||
|
|
||||||
## Unregister as a service
|
## Unregister Gitea
|
||||||
|
|
||||||
To unregister Gitea as a service, open a command prompt (cmd) as an Administrator and run:
|
To unregister Gitea as a Windows service, open a command prompt (cmd) as an Administrator and run:
|
||||||
|
|
||||||
```
|
```
|
||||||
sc.exe delete gitea
|
sc.exe delete gitea
|
||||||
|
@ -81,7 +81,7 @@ func CalcFingerprint(publicKeyContent string) (string, error) {
|
|||||||
fnName, fp string
|
fnName, fp string
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
if setting.SSH.StartBuiltinServer {
|
if len(setting.SSH.KeygenPath) == 0 {
|
||||||
fnName = "calcFingerprintNative"
|
fnName = "calcFingerprintNative"
|
||||||
fp, err = calcFingerprintNative(publicKeyContent)
|
fp, err = calcFingerprintNative(publicKeyContent)
|
||||||
} else {
|
} else {
|
||||||
|
@ -149,8 +149,9 @@ func EnvironmentToConfig(cfg ConfigProvider, envs []string) (changed bool) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
key := section.Key(keyName)
|
key := ConfigSectionKey(section, keyName)
|
||||||
if key == nil {
|
if key == nil {
|
||||||
|
changed = true
|
||||||
key, err = section.NewKey(keyName, keyValue)
|
key, err = section.NewKey(keyName, keyValue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Error creating key: %s in section: %s with value: %s : %v", keyName, sectionName, keyValue, err)
|
log.Error("Error creating key: %s in section: %s with value: %s : %v", keyName, sectionName, keyValue, err)
|
||||||
|
@ -115,3 +115,29 @@ key = old
|
|||||||
EnvironmentToConfig(cfg, []string{"GITEA__sec__key__FILE=" + tmpFile})
|
EnvironmentToConfig(cfg, []string{"GITEA__sec__key__FILE=" + tmpFile})
|
||||||
assert.Equal(t, "value-from-file\n", cfg.Section("sec").Key("key").String())
|
assert.Equal(t, "value-from-file\n", cfg.Section("sec").Key("key").String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEnvironmentToConfigSubSecKey(t *testing.T) {
|
||||||
|
// the INI package has a quirk: by default, the keys are inherited.
|
||||||
|
// when maintaining the keys, the newly added sub key should not be affected by the parent key.
|
||||||
|
cfg, err := NewConfigProviderFromData(`
|
||||||
|
[sec]
|
||||||
|
key = some
|
||||||
|
`)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
changed := EnvironmentToConfig(cfg, []string{"GITEA__sec_0X2E_sub__key=some"})
|
||||||
|
assert.True(t, changed)
|
||||||
|
|
||||||
|
tmpFile := t.TempDir() + "/test-sub-sec-key.ini"
|
||||||
|
defer os.Remove(tmpFile)
|
||||||
|
err = cfg.SaveTo(tmpFile)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
bs, err := os.ReadFile(tmpFile)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, `[sec]
|
||||||
|
key = some
|
||||||
|
|
||||||
|
[sec.sub]
|
||||||
|
key = some
|
||||||
|
`, string(bs))
|
||||||
|
}
|
||||||
|
@ -36,6 +36,14 @@ func GetNote(ctx *context.APIContext) {
|
|||||||
// description: a git ref or commit sha
|
// description: a git ref or commit sha
|
||||||
// type: string
|
// type: string
|
||||||
// required: true
|
// required: true
|
||||||
|
// - name: verification
|
||||||
|
// in: query
|
||||||
|
// description: include verification for every commit (disable for speedup, default 'true')
|
||||||
|
// type: boolean
|
||||||
|
// - name: files
|
||||||
|
// in: query
|
||||||
|
// description: include a list of affected files for every commit (disable for speedup, default 'true')
|
||||||
|
// type: boolean
|
||||||
// responses:
|
// responses:
|
||||||
// "200":
|
// "200":
|
||||||
// "$ref": "#/responses/Note"
|
// "$ref": "#/responses/Note"
|
||||||
@ -78,7 +86,15 @@ func getNote(ctx *context.APIContext, identifier string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cmt, err := convert.ToCommit(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, note.Commit, nil, convert.ToCommitOptions{Stat: true})
|
verification := ctx.FormString("verification") == "" || ctx.FormBool("verification")
|
||||||
|
files := ctx.FormString("files") == "" || ctx.FormBool("files")
|
||||||
|
|
||||||
|
cmt, err := convert.ToCommit(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, note.Commit, nil,
|
||||||
|
convert.ToCommitOptions{
|
||||||
|
Stat: true,
|
||||||
|
Verification: verification,
|
||||||
|
Files: files,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "ToCommit", err)
|
ctx.Error(http.StatusInternalServerError, "ToCommit", err)
|
||||||
return
|
return
|
||||||
|
@ -1275,6 +1275,14 @@ func GetPullRequestCommits(ctx *context.APIContext) {
|
|||||||
// in: query
|
// in: query
|
||||||
// description: page size of results
|
// description: page size of results
|
||||||
// type: integer
|
// type: integer
|
||||||
|
// - name: verification
|
||||||
|
// in: query
|
||||||
|
// description: include verification for every commit (disable for speedup, default 'true')
|
||||||
|
// type: boolean
|
||||||
|
// - name: files
|
||||||
|
// in: query
|
||||||
|
// description: include a list of affected files for every commit (disable for speedup, default 'true')
|
||||||
|
// type: boolean
|
||||||
// responses:
|
// responses:
|
||||||
// "200":
|
// "200":
|
||||||
// "$ref": "#/responses/CommitList"
|
// "$ref": "#/responses/CommitList"
|
||||||
@ -1328,9 +1336,17 @@ func GetPullRequestCommits(ctx *context.APIContext) {
|
|||||||
end = totalNumberOfCommits
|
end = totalNumberOfCommits
|
||||||
}
|
}
|
||||||
|
|
||||||
|
verification := ctx.FormString("verification") == "" || ctx.FormBool("verification")
|
||||||
|
files := ctx.FormString("files") == "" || ctx.FormBool("files")
|
||||||
|
|
||||||
apiCommits := make([]*api.Commit, 0, end-start)
|
apiCommits := make([]*api.Commit, 0, end-start)
|
||||||
for i := start; i < end; i++ {
|
for i := start; i < end; i++ {
|
||||||
apiCommit, err := convert.ToCommit(ctx, ctx.Repo.Repository, baseGitRepo, commits[i], userCache, convert.ToCommitOptions{Stat: true})
|
apiCommit, err := convert.ToCommit(ctx, ctx.Repo.Repository, baseGitRepo, commits[i], userCache,
|
||||||
|
convert.ToCommitOptions{
|
||||||
|
Stat: true,
|
||||||
|
Verification: verification,
|
||||||
|
Files: files,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("toCommit", err)
|
ctx.ServerError("toCommit", err)
|
||||||
return
|
return
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<th class="two wide sha">SHA1</th>
|
<th class="two wide sha">SHA1</th>
|
||||||
<th class="eight wide message">{{ctx.Locale.Tr "repo.commits.message"}}</th>
|
<th class="eight wide message">{{ctx.Locale.Tr "repo.commits.message"}}</th>
|
||||||
<th class="two wide right aligned">{{ctx.Locale.Tr "repo.commits.date"}}</th>
|
<th class="two wide right aligned">{{ctx.Locale.Tr "repo.commits.date"}}</th>
|
||||||
<th class="one wide right aligned"></th>
|
<th class="one wide"></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="commit-list">
|
<tbody class="commit-list">
|
||||||
@ -25,7 +25,7 @@
|
|||||||
{{$userName}}
|
{{$userName}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</td>
|
</td>
|
||||||
<td class="sha gt-df">
|
<td class="sha">
|
||||||
{{$class := "ui sha label"}}
|
{{$class := "ui sha label"}}
|
||||||
{{if .Signature}}
|
{{if .Signature}}
|
||||||
{{$class = (print $class " isSigned")}}
|
{{$class = (print $class " isSigned")}}
|
||||||
@ -76,11 +76,11 @@
|
|||||||
{{else}}
|
{{else}}
|
||||||
<td class="text right aligned">{{TimeSince .Author.When ctx.Locale}}</td>
|
<td class="text right aligned">{{TimeSince .Author.When ctx.Locale}}</td>
|
||||||
{{end}}
|
{{end}}
|
||||||
<td class="gt-pt-0 gt-pb-0">
|
<td class="text right aligned gt-py-0">
|
||||||
<div class="gt-df gt-je">
|
<button class="btn interact-bg gt-p-3" data-tooltip-content="{{ctx.Locale.Tr "copy_hash"}}" data-clipboard-text="{{.ID}}">{{svg "octicon-copy"}}</button>
|
||||||
<button class="btn interact-bg gt-p-3" data-tooltip-content="{{ctx.Locale.Tr "copy_hash"}}" data-clipboard-text="{{.ID}}">{{svg "octicon-copy"}}</button>
|
{{if $.FileName}}
|
||||||
{{if $.FileName}}<a class="btn interact-bg gt-p-3" data-tooltip-content="{{ctx.Locale.Tr "repo.commits.view_path"}}" href="{{printf "%s/src/commit/%s/%s" $commitRepoLink (PathEscape .ID.String) $.FileName}}">{{svg "octicon-file-code"}}</a>{{end}}
|
<a class="btn interact-bg gt-p-3" data-tooltip-content="{{ctx.Locale.Tr "repo.commits.view_path"}}" href="{{printf "%s/src/commit/%s/%s" $commitRepoLink (PathEscape .ID.String) (PathEscapeSegments $.FileName)}}">{{svg "octicon-file-code"}}</a>
|
||||||
</div>
|
{{end}}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -428,15 +428,15 @@
|
|||||||
<div class="ui relaxed divided list">
|
<div class="ui relaxed divided list">
|
||||||
{{range .BlockingDependencies}}
|
{{range .BlockingDependencies}}
|
||||||
<div class="item dependency{{if .Issue.IsClosed}} is-closed{{end}} gt-df gt-ac gt-sb">
|
<div class="item dependency{{if .Issue.IsClosed}} is-closed{{end}} gt-df gt-ac gt-sb">
|
||||||
<div class="item-left gt-df gt-jc gt-fc gt-f1">
|
<div class="item-left gt-df gt-jc gt-fc gt-f1 gt-ellipsis">
|
||||||
<a class="title muted" href="{{.Issue.Link}}" data-tooltip-content="#{{.Issue.Index}} {{.Issue.Title | RenderEmoji $.Context}}">
|
<a class="title muted" href="{{.Issue.Link}}" data-tooltip-content="#{{.Issue.Index}} {{.Issue.Title | RenderEmoji $.Context}}">
|
||||||
#{{.Issue.Index}} {{.Issue.Title | RenderEmoji $.Context}}
|
#{{.Issue.Index}} {{.Issue.Title | RenderEmoji $.Context}}
|
||||||
</a>
|
</a>
|
||||||
<div class="text small">
|
<div class="text small gt-ellipsis" data-tooltip-content="{{.Repository.OwnerName}}/{{.Repository.Name}}">
|
||||||
{{.Repository.OwnerName}}/{{.Repository.Name}}
|
{{.Repository.OwnerName}}/{{.Repository.Name}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-right gt-df gt-ac">
|
<div class="item-right gt-df gt-ac gt-m-2">
|
||||||
{{if and $.CanCreateIssueDependencies (not $.Repository.IsArchived)}}
|
{{if and $.CanCreateIssueDependencies (not $.Repository.IsArchived)}}
|
||||||
<a class="delete-dependency-button ci muted" data-id="{{.Issue.ID}}" data-type="blocking" data-tooltip-content="{{ctx.Locale.Tr "repo.issues.dependency.remove_info"}}">
|
<a class="delete-dependency-button ci muted" data-id="{{.Issue.ID}}" data-type="blocking" data-tooltip-content="{{ctx.Locale.Tr "repo.issues.dependency.remove_info"}}">
|
||||||
{{svg "octicon-trash" 16}}
|
{{svg "octicon-trash" 16}}
|
||||||
@ -446,7 +446,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .BlockingDependenciesNotPermitted}}
|
{{if .BlockingDependenciesNotPermitted}}
|
||||||
<div class="item gt-df gt-ac gt-sb">
|
<div class="item gt-df gt-ac gt-sb gt-ellipsis">
|
||||||
<span>{{ctx.Locale.TrN (len .BlockingDependenciesNotPermitted) "repo.issues.dependency.no_permission_1" "repo.issues.dependency.no_permission_n" (len .BlockingDependenciesNotPermitted)}}</span>
|
<span>{{ctx.Locale.TrN (len .BlockingDependenciesNotPermitted) "repo.issues.dependency.no_permission_1" "repo.issues.dependency.no_permission_n" (len .BlockingDependenciesNotPermitted)}}</span>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
@ -460,15 +460,15 @@
|
|||||||
<div class="ui relaxed divided list">
|
<div class="ui relaxed divided list">
|
||||||
{{range .BlockedByDependencies}}
|
{{range .BlockedByDependencies}}
|
||||||
<div class="item dependency{{if .Issue.IsClosed}} is-closed{{end}} gt-df gt-ac gt-sb">
|
<div class="item dependency{{if .Issue.IsClosed}} is-closed{{end}} gt-df gt-ac gt-sb">
|
||||||
<div class="item-left gt-df gt-jc gt-fc gt-f1">
|
<div class="item-left gt-df gt-jc gt-fc gt-f1 gt-ellipsis">
|
||||||
<a class="title muted" href="{{.Issue.Link}}" data-tooltip-content="#{{.Issue.Index}} {{.Issue.Title | RenderEmoji $.Context}}">
|
<a class="title muted" href="{{.Issue.Link}}" data-tooltip-content="#{{.Issue.Index}} {{.Issue.Title | RenderEmoji $.Context}}">
|
||||||
#{{.Issue.Index}} {{.Issue.Title | RenderEmoji $.Context}}
|
#{{.Issue.Index}} {{.Issue.Title | RenderEmoji $.Context}}
|
||||||
</a>
|
</a>
|
||||||
<div class="text small">
|
<div class="text small gt-ellipsis" data-tooltip-content="{{.Repository.OwnerName}}/{{.Repository.Name}}">
|
||||||
{{.Repository.OwnerName}}/{{.Repository.Name}}
|
{{.Repository.OwnerName}}/{{.Repository.Name}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-right gt-df gt-ac">
|
<div class="item-right gt-df gt-ac gt-m-2">
|
||||||
{{if and $.CanCreateIssueDependencies (not $.Repository.IsArchived)}}
|
{{if and $.CanCreateIssueDependencies (not $.Repository.IsArchived)}}
|
||||||
<a class="delete-dependency-button ci muted" data-id="{{.Issue.ID}}" data-type="blockedBy" data-tooltip-content="{{ctx.Locale.Tr "repo.issues.dependency.remove_info"}}">
|
<a class="delete-dependency-button ci muted" data-id="{{.Issue.ID}}" data-type="blockedBy" data-tooltip-content="{{ctx.Locale.Tr "repo.issues.dependency.remove_info"}}">
|
||||||
{{svg "octicon-trash" 16}}
|
{{svg "octicon-trash" 16}}
|
||||||
@ -480,18 +480,18 @@
|
|||||||
{{if $.CanCreateIssueDependencies}}
|
{{if $.CanCreateIssueDependencies}}
|
||||||
{{range .BlockedByDependenciesNotPermitted}}
|
{{range .BlockedByDependenciesNotPermitted}}
|
||||||
<div class="item dependency{{if .Issue.IsClosed}} is-closed{{end}} gt-df gt-ac gt-sb">
|
<div class="item dependency{{if .Issue.IsClosed}} is-closed{{end}} gt-df gt-ac gt-sb">
|
||||||
<div class="item-left gt-df gt-jc gt-fc gt-f1">
|
<div class="item-left gt-df gt-jc gt-fc gt-f1 gt-ellipsis">
|
||||||
<div>
|
<div class="gt-ellipsis">
|
||||||
<span data-tooltip-content="{{ctx.Locale.Tr "repo.issues.dependency.no_permission.can_remove"}}">{{svg "octicon-lock" 16}}</span>
|
<span data-tooltip-content="{{ctx.Locale.Tr "repo.issues.dependency.no_permission.can_remove"}}">{{svg "octicon-lock" 16}}</span>
|
||||||
<span class="title" data-tooltip-content="#{{.Issue.Index}} {{.Issue.Title | RenderEmoji $.Context}}">
|
<span class="title" data-tooltip-content="#{{.Issue.Index}} {{.Issue.Title | RenderEmoji $.Context}}">
|
||||||
#{{.Issue.Index}} {{.Issue.Title | RenderEmoji $.Context}}
|
#{{.Issue.Index}} {{.Issue.Title | RenderEmoji $.Context}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="text small">
|
<div class="text small gt-ellipsis" data-tooltip-content="{{.Repository.OwnerName}}/{{.Repository.Name}}">
|
||||||
{{.Repository.OwnerName}}/{{.Repository.Name}}
|
{{.Repository.OwnerName}}/{{.Repository.Name}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-right gt-df gt-ac">
|
<div class="item-right gt-df gt-ac gt-m-2">
|
||||||
{{if and $.CanCreateIssueDependencies (not $.Repository.IsArchived)}}
|
{{if and $.CanCreateIssueDependencies (not $.Repository.IsArchived)}}
|
||||||
<a class="delete-dependency-button ci muted" data-id="{{.Issue.ID}}" data-type="blocking" data-tooltip-content="{{ctx.Locale.Tr "repo.issues.dependency.remove_info"}}">
|
<a class="delete-dependency-button ci muted" data-id="{{.Issue.ID}}" data-type="blocking" data-tooltip-content="{{ctx.Locale.Tr "repo.issues.dependency.remove_info"}}">
|
||||||
{{svg "octicon-trash" 16}}
|
{{svg "octicon-trash" 16}}
|
||||||
@ -501,7 +501,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{else if .BlockedByDependenciesNotPermitted}}
|
{{else if .BlockedByDependenciesNotPermitted}}
|
||||||
<div class="item gt-df gt-ac gt-sb">
|
<div class="item gt-df gt-ac gt-sb gt-ellipsis">
|
||||||
<span>{{ctx.Locale.TrN (len .BlockedByDependenciesNotPermitted) "repo.issues.dependency.no_permission_1" "repo.issues.dependency.no_permission_n" (len .BlockedByDependenciesNotPermitted)}}</span>
|
<span>{{ctx.Locale.TrN (len .BlockedByDependenciesNotPermitted) "repo.issues.dependency.no_permission_1" "repo.issues.dependency.no_permission_n" (len .BlockedByDependenciesNotPermitted)}}</span>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
24
templates/swagger/v1_json.tmpl
generated
24
templates/swagger/v1_json.tmpl
generated
@ -5239,6 +5239,18 @@
|
|||||||
"name": "sha",
|
"name": "sha",
|
||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "include verification for every commit (disable for speedup, default 'true')",
|
||||||
|
"name": "verification",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "include a list of affected files for every commit (disable for speedup, default 'true')",
|
||||||
|
"name": "files",
|
||||||
|
"in": "query"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
@ -10521,6 +10533,18 @@
|
|||||||
"description": "page size of results",
|
"description": "page size of results",
|
||||||
"name": "limit",
|
"name": "limit",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "include verification for every commit (disable for speedup, default 'true')",
|
||||||
|
"name": "verification",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "include a list of affected files for every commit (disable for speedup, default 'true')",
|
||||||
|
"name": "files",
|
||||||
|
"in": "query"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
|
@ -35,6 +35,11 @@ func TestAPIPullCommits(t *testing.T) {
|
|||||||
|
|
||||||
assert.Equal(t, "5f22f7d0d95d614d25a5b68592adb345a4b5c7fd", commits[0].SHA)
|
assert.Equal(t, "5f22f7d0d95d614d25a5b68592adb345a4b5c7fd", commits[0].SHA)
|
||||||
assert.Equal(t, "4a357436d925b5c974181ff12a994538ddc5a269", commits[1].SHA)
|
assert.Equal(t, "4a357436d925b5c974181ff12a994538ddc5a269", commits[1].SHA)
|
||||||
|
|
||||||
|
assert.NotEmpty(t, commits[0].Files)
|
||||||
|
assert.NotEmpty(t, commits[1].Files)
|
||||||
|
assert.NotNil(t, commits[0].RepoCommit.Verification)
|
||||||
|
assert.NotNil(t, commits[1].RepoCommit.Verification)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO add tests for already merged PR and closed PR
|
// TODO add tests for already merged PR and closed PR
|
||||||
|
@ -37,5 +37,7 @@ func TestAPIReposGitNotes(t *testing.T) {
|
|||||||
var apiData api.Note
|
var apiData api.Note
|
||||||
DecodeJSON(t, resp, &apiData)
|
DecodeJSON(t, resp, &apiData)
|
||||||
assert.Equal(t, "This is a test note\n", apiData.Message)
|
assert.Equal(t, "This is a test note\n", apiData.Message)
|
||||||
|
assert.NotEmpty(t, apiData.Commit.Files)
|
||||||
|
assert.NotNil(t, apiData.Commit.RepoCommit.Verification)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -95,23 +95,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.repository .issue-content-right .ui.list .title {
|
.repository .issue-content-right .ui.list .title {
|
||||||
max-width: 200px;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 1200px) {
|
|
||||||
.repository .issue-content-right .ui.list .title {
|
|
||||||
max-width: 150px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 1000px) {
|
|
||||||
.repository .issue-content-right .ui.list .title {
|
|
||||||
max-width: 100px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.repository .issue-content-right #deadlineForm input {
|
.repository .issue-content-right #deadlineForm input {
|
||||||
width: 12.8rem;
|
width: 12.8rem;
|
||||||
border-radius: var(--border-radius) 0 0 var(--border-radius);
|
border-radius: var(--border-radius) 0 0 var(--border-radius);
|
||||||
|
@ -57,6 +57,15 @@ function updateSelectionLabel($label) {
|
|||||||
function delegateOne($dropdown) {
|
function delegateOne($dropdown) {
|
||||||
const dropdownCall = fomanticDropdownFn.bind($dropdown);
|
const dropdownCall = fomanticDropdownFn.bind($dropdown);
|
||||||
|
|
||||||
|
// If there is a "search input" in the "menu", Fomantic will only "focus the input" but not "toggle the menu" when the "dropdown icon" is clicked.
|
||||||
|
// Actually, Fomantic UI doesn't support such layout/usage. It needs to patch the "focusSearch" / "blurSearch" functions to make sure it toggles the menu.
|
||||||
|
const oldFocusSearch = dropdownCall('internal', 'focusSearch');
|
||||||
|
const oldBlurSearch = dropdownCall('internal', 'blurSearch');
|
||||||
|
// * If the "dropdown icon" is clicked, Fomantic calls "focusSearch", so show the menu
|
||||||
|
dropdownCall('internal', 'focusSearch', function () { dropdownCall('show'); oldFocusSearch.call(this) });
|
||||||
|
// * If the "dropdown icon" is clicked again when the menu is visible, Fomantic calls "blurSearch", so hide the menu
|
||||||
|
dropdownCall('internal', 'blurSearch', function () { oldBlurSearch.call(this); dropdownCall('hide') });
|
||||||
|
|
||||||
// the "template" functions are used for dynamic creation (eg: AJAX)
|
// the "template" functions are used for dynamic creation (eg: AJAX)
|
||||||
const dropdownTemplates = {...dropdownCall('setting', 'templates'), t: performance.now()};
|
const dropdownTemplates = {...dropdownCall('setting', 'templates'), t: performance.now()};
|
||||||
const dropdownTemplatesMenuOld = dropdownTemplates.menu;
|
const dropdownTemplatesMenuOld = dropdownTemplates.menu;
|
||||||
|
@ -16,9 +16,6 @@ export function initGiteaFomantic() {
|
|||||||
$.fn.dropdown.settings.fullTextSearch = 'exact';
|
$.fn.dropdown.settings.fullTextSearch = 'exact';
|
||||||
// Do not use "cursor: pointer" for dropdown labels
|
// Do not use "cursor: pointer" for dropdown labels
|
||||||
$.fn.dropdown.settings.className.label += ' gt-cursor-default';
|
$.fn.dropdown.settings.className.label += ' gt-cursor-default';
|
||||||
// The default selector has a bug: if there is a "search input" in the "menu", Fomantic will only "focus the input" but not "toggle the menu" when the "dropdown icon" is clicked.
|
|
||||||
// Actually, the "search input in menu" shouldn't be considered as the dropdown's input
|
|
||||||
$.fn.dropdown.settings.selector.search = '> input.search, :not(.menu) > .search > input, :not(.menu) input.search';
|
|
||||||
// Always use Gitea's SVG icons
|
// Always use Gitea's SVG icons
|
||||||
$.fn.dropdown.settings.templates.label = function(_value, text, preserveHTML, className) {
|
$.fn.dropdown.settings.templates.label = function(_value, text, preserveHTML, className) {
|
||||||
const escape = $.fn.dropdown.settings.templates.escape;
|
const escape = $.fn.dropdown.settings.templates.escape;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user