Modified - [migrate] [cancel] [windows] [git] [retry] Made canceled repository migrations wait for the real clone shutdown before exposing retry/delete actions, and added Windows process-tree termination for migration clones.
- 1 - Fix: canceling a repository migration no longer marks the page as failed while the Git clone is still running. - 2 - Mod: `Retry` and `Delete This Repository` stay hidden until the migration task is fully stopped. - 3 - Fix: canceled migrations now persist as `stopped` and no longer show the raw `clone error: context canceled ...` message. - 4 - Fix: added an opt-in Windows process-tree kill for migration clone commands via `taskkill /T /F`, because Git helper processes could remain alive after `Cancel`, keep writing `tmp_pack_*`, and block cleanup or retry.
This commit is contained in:
@@ -879,3 +879,12 @@ History search guidance:
|
||||
|
||||
182 - [2026-05-24 01:27:20] - v1.27.0-dev-194-gf293572182 - Type: Modified - [locale] [ro] Refined several Romanian UI strings for clearer wording and corrected grammar in settings, migration, repository, and admin badge messages.
|
||||
- 1 - I updated `options/locale/locale_ro-RO.json` so several existing Romanian translations now use clearer and more natural phrasing, including the account deletion warning, Git migration progress text, archive action wording, workflow notification label order, and a few admin badge status messages with corrected agreement and grammar.
|
||||
|
||||
183 - [2026-05-24 01:44:32] - v1.27.0-dev-195-g70659dc6c3 - Type: Modified - [migrate] [cancel] [ui] Distinguished user-stopped repository migrations from genuine migration failures in the status UI.
|
||||
- 1 - I updated `routers/web/repo/migrate.go`, `templates/repo/migrate/migrating.tmpl`, `web_src/js/features/repo-migrate.ts`, and the EN/RO locale files so a migration canceled by the user still uses the existing failed task state internally, but the repository migration page now renders it as `stopped` instead of `failed`, with dedicated stopped wording in both the main status title and the follow-up status message.
|
||||
|
||||
184 - [2026-05-24 03:12:34] - v1.27.0-dev-195-g70659dc6c3 - Type: Modified - [migrate] [cancel] [windows] [git] [retry] Made canceled repository migrations wait for the real clone shutdown before exposing retry/delete actions, and added Windows process-tree termination for migration clones.
|
||||
- 1 - Fix: canceling a repository migration no longer marks the page as failed while the Git clone is still running.
|
||||
- 2 - Mod: `Retry` and `Delete This Repository` stay hidden until the migration task is fully stopped.
|
||||
- 3 - Fix: canceled migrations now persist as `stopped` and no longer show the raw `clone error: context canceled ...` message.
|
||||
- 4 - Fix: added an opt-in Windows process-tree kill for migration clone commands via `taskkill /T /F`, because Git helper processes could remain alive after `Cancel`, keep writing `tmp_pack_*`, and block cleanup or retry.
|
||||
|
||||
@@ -43,6 +43,7 @@ type Command struct {
|
||||
cmdCancel process.CancelCauseFunc
|
||||
cmdFinished process.FinishedFunc
|
||||
cmdStartTime time.Time
|
||||
cmdWaitDone chan struct{} // edit/add - by petru @ codex
|
||||
|
||||
parentPipeFiles []*os.File
|
||||
parentPipeReaders []*os.File
|
||||
@@ -207,8 +208,9 @@ func ToTrustedCmdArgs(args []string) TrustedCmdArgs {
|
||||
}
|
||||
|
||||
type runOpts struct {
|
||||
Env []string
|
||||
Timeout time.Duration
|
||||
Env []string
|
||||
Timeout time.Duration
|
||||
KillProcessTreeOnCancel bool // edit/add - by petru @ codex
|
||||
|
||||
// Dir is the working dir for the git command, however:
|
||||
// FIXME: this could be incorrect in many cases, for example:
|
||||
@@ -276,6 +278,11 @@ func (c *Command) WithTimeout(timeout time.Duration) *Command {
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Command) WithKillProcessTreeOnCancel(v bool) *Command { // edit/add - by petru @ codex
|
||||
c.opts.KillProcessTreeOnCancel = v
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Command) makeStdoutStderr(w *io.Writer) (PipeReader, func()) {
|
||||
pr, pw, err := os.Pipe()
|
||||
if err != nil {
|
||||
@@ -434,7 +441,13 @@ func (c *Command) Start(ctx context.Context) (retErr error) {
|
||||
|
||||
c.cmdStartTime = time.Now()
|
||||
|
||||
c.cmd = exec.CommandContext(c.cmdCtx, c.prog, append(c.configArgs, c.args...)...)
|
||||
// start edit/add - by petru @ codex
|
||||
if c.opts.KillProcessTreeOnCancel && useManualProcessTreeKillMode() {
|
||||
c.cmd = exec.Command(c.prog, append(c.configArgs, c.args...)...)
|
||||
} else {
|
||||
c.cmd = exec.CommandContext(c.cmdCtx, c.prog, append(c.configArgs, c.args...)...)
|
||||
}
|
||||
// end edit/add - by petru @ codex
|
||||
if c.opts.Env == nil {
|
||||
c.cmd.Env = os.Environ()
|
||||
} else {
|
||||
@@ -447,7 +460,18 @@ func (c *Command) Start(ctx context.Context) (retErr error) {
|
||||
c.cmd.Stdout = c.cmdStdout
|
||||
c.cmd.Stdin = c.cmdStdin
|
||||
c.cmd.Stderr = c.cmdStderr
|
||||
return c.cmd.Start()
|
||||
if err := c.cmd.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// start edit/add - by petru @ codex
|
||||
c.cmdWaitDone = make(chan struct{})
|
||||
if c.opts.KillProcessTreeOnCancel && c.cmd.Process != nil {
|
||||
go c.killProcessTreeOnCancel()
|
||||
}
|
||||
// end edit/add - by petru @ codex
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Command) closePipeFiles(files []*os.File) {
|
||||
@@ -464,6 +488,13 @@ func (c *Command) discardPipeReaders(files []*os.File) {
|
||||
|
||||
func (c *Command) Wait() error {
|
||||
defer func() {
|
||||
// start edit/add - by petru @ codex
|
||||
if c.cmdWaitDone != nil {
|
||||
close(c.cmdWaitDone)
|
||||
c.cmdWaitDone = nil
|
||||
}
|
||||
// end edit/add - by petru @ codex
|
||||
|
||||
// The reader in another goroutine might be still reading the stdout, so we shouldn't close the pipes here
|
||||
// MakeStdoutPipe returns a closer function to force callers to close the pipe correctly
|
||||
// Here we only need to mark the command as finished
|
||||
@@ -515,6 +546,31 @@ func (c *Command) Wait() error {
|
||||
return errors.Join(errCause, errWait)
|
||||
}
|
||||
|
||||
// start edit/add - by petru @ codex
|
||||
func (c *Command) killProcessTreeOnCancel() {
|
||||
select {
|
||||
case <-c.cmdWaitDone:
|
||||
return
|
||||
case <-c.cmdCtx.Done():
|
||||
}
|
||||
|
||||
select {
|
||||
case <-c.cmdWaitDone:
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
if c.cmd == nil || c.cmd.Process == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := killProcessTree(c.cmd.Process.Pid); err != nil {
|
||||
log.Debug("failed to kill git process tree for pid %d: %v", c.cmd.Process.Pid, err)
|
||||
}
|
||||
}
|
||||
|
||||
// end edit/add - by petru @ codex
|
||||
|
||||
func (c *Command) StartWithStderr(ctx context.Context) RunStdError {
|
||||
if c.cmdStderr != nil {
|
||||
panic("caller-provided stderr receiver doesn't work with managed stderr buffer")
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
//go:build !windows
|
||||
|
||||
package gitcmd
|
||||
|
||||
// start edit/add - by petru @ codex
|
||||
func useManualProcessTreeKillMode() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func killProcessTree(pid int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// end edit/add - by petru @ codex
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
//go:build windows
|
||||
|
||||
package gitcmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// start edit/add - by petru @ codex
|
||||
func useManualProcessTreeKillMode() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func killProcessTree(pid int) error {
|
||||
if pid <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
output, err := exec.Command("taskkill", "/T", "/F", "/PID", strconv.Itoa(pid)).CombinedOutput()
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
msg := strings.ToLower(string(output))
|
||||
if strings.Contains(msg, "there is no running instance") || strings.Contains(msg, "not found") {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("taskkill /T /F /PID %d failed: %w: %s", pid, err, strings.TrimSpace(string(output)))
|
||||
}
|
||||
|
||||
// end edit/add - by petru @ codex
|
||||
+14
-12
@@ -99,18 +99,19 @@ func (repo *Repository) IsEmpty() (bool, error) {
|
||||
|
||||
// CloneRepoOptions options when clone a repository
|
||||
type CloneRepoOptions struct {
|
||||
Timeout time.Duration
|
||||
Mirror bool
|
||||
Bare bool
|
||||
Quiet bool
|
||||
Branch string
|
||||
Shared bool
|
||||
NoCheckout bool
|
||||
Depth int
|
||||
Filter string
|
||||
SkipTLSVerify bool
|
||||
SingleBranch bool
|
||||
Env []string
|
||||
Timeout time.Duration
|
||||
Mirror bool
|
||||
Bare bool
|
||||
Quiet bool
|
||||
Branch string
|
||||
Shared bool
|
||||
NoCheckout bool
|
||||
Depth int
|
||||
Filter string
|
||||
SkipTLSVerify bool
|
||||
SingleBranch bool
|
||||
KillProcessTreeOnCancel bool // edit/add - by petru @ codex
|
||||
Env []string
|
||||
}
|
||||
|
||||
// Clone clones original repository to target path.
|
||||
@@ -170,6 +171,7 @@ func Clone(ctx context.Context, from, to string, opts CloneRepoOptions) error {
|
||||
return cmd.
|
||||
WithTimeout(opts.Timeout).
|
||||
WithEnv(envs).
|
||||
WithKillProcessTreeOnCancel(opts.KillProcessTreeOnCancel). // edit/add - by petru @ codex
|
||||
RunWithStderr(ctx)
|
||||
}
|
||||
|
||||
|
||||
@@ -1287,6 +1287,10 @@
|
||||
"repo.migrate.migrating_failed": "Migrating from <b>%s</b> failed.",
|
||||
"repo.migrate.migrating_failed.error": "Failed to migrate: %s",
|
||||
"repo.migrate.migrating_failed_no_addr": "Migration failed.",
|
||||
"repo.migrate.migrating_canceling": "Stopping migration and terminating Git clone processes...",
|
||||
"repo.migrate.migrating_stopped": "Migrating from <b>%s</b> stopped.",
|
||||
"repo.migrate.migrating_stopped.error": "Migration stopped.",
|
||||
"repo.migrate.migrating_stopped_no_addr": "Migration stopped.",
|
||||
"repo.migrate.github.description": "Migrate data from github.com or other GitHub instances.",
|
||||
"repo.migrate.git.description": "Migrate a repository only from any Git service.",
|
||||
"repo.migrate.gitlab.description": "Migrate data from gitlab.com or other GitLab instances.",
|
||||
|
||||
@@ -1287,6 +1287,10 @@
|
||||
"repo.migrate.migrating_failed": "Migrarea de la <b>%s</b> a eșuat.",
|
||||
"repo.migrate.migrating_failed.error": "Migrare eșuată: %s",
|
||||
"repo.migrate.migrating_failed_no_addr": "Migrarea a eșuat.",
|
||||
"repo.migrate.migrating_canceling": "Se oprește migrarea și se închid procesele Git de clonare...",
|
||||
"repo.migrate.migrating_stopped": "Migrarea de la <b>%s</b> a fost oprită.",
|
||||
"repo.migrate.migrating_stopped.error": "Migrarea a fost oprită.",
|
||||
"repo.migrate.migrating_stopped_no_addr": "Migrarea a fost oprită.",
|
||||
"repo.migrate.github.description": "Migrează datele de pe github.com sau alte instanțe GitHub.",
|
||||
"repo.migrate.git.description": "Migrează un repozitoriu de pe orice serviciu de tip Git.",
|
||||
"repo.migrate.gitlab.description": "Migrează datele de pe gitlab.com sau alte instanțe GitLab.",
|
||||
|
||||
@@ -281,13 +281,15 @@ func MigrateCancelPost(ctx *context.Context) {
|
||||
ctx.Redirect(ctx.Repo.Repository.Link())
|
||||
return
|
||||
}
|
||||
if migratingTask.Status == structs.TaskStatusRunning {
|
||||
taskUpdate := &admin_model.Task{ID: migratingTask.ID, Status: structs.TaskStatusFailed, Message: "canceled"}
|
||||
// start edit/add - by petru @ codex
|
||||
if migratingTask.Status == structs.TaskStatusQueued || migratingTask.Status == structs.TaskStatusRunning {
|
||||
taskUpdate := &admin_model.Task{ID: migratingTask.ID, Status: structs.TaskStatusStopped, Message: "canceling"}
|
||||
if err = taskUpdate.UpdateCols(ctx, "status", "message"); err != nil {
|
||||
ctx.ServerError("task.UpdateCols", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
// end edit/add - by petru @ codex
|
||||
ctx.Redirect(ctx.Repo.Repository.Link())
|
||||
}
|
||||
|
||||
@@ -310,7 +312,15 @@ func MigrateStatus(ctx *context.Context) {
|
||||
|
||||
message := task.Message
|
||||
|
||||
if task.Message != "" && task.Message[0] == '{' {
|
||||
// start edit/add - by petru @ codex
|
||||
stopping := task.Status == structs.TaskStatusStopped && task.EndTime == 0
|
||||
stopped := task.Status == structs.TaskStatusStopped && task.EndTime != 0
|
||||
|
||||
if stopping {
|
||||
message = ctx.Locale.TrString("repo.migrate.migrating_canceling")
|
||||
} else if stopped {
|
||||
message = ctx.Locale.TrString("repo.migrate.migrating_stopped.error")
|
||||
} else if task.Message != "" && task.Message[0] == '{' {
|
||||
// assume message is actually a translatable string
|
||||
var translatableMessage admin_model.TranslatableMessage
|
||||
if err := json.Unmarshal([]byte(message), &translatableMessage); err != nil {
|
||||
@@ -321,9 +331,12 @@ func MigrateStatus(ctx *context.Context) {
|
||||
}
|
||||
message = ctx.Locale.TrString(translatableMessage.Format, translatableMessage.Args...)
|
||||
}
|
||||
// end edit/add - by petru @ codex
|
||||
|
||||
ctx.JSON(http.StatusOK, map[string]any{
|
||||
"status": task.Status,
|
||||
"message": message,
|
||||
"status": task.Status,
|
||||
"message": message,
|
||||
"stopping": stopping, // edit/add - by petru @ codex
|
||||
"stopped": stopped, // edit/add - by petru @ codex
|
||||
})
|
||||
}
|
||||
|
||||
@@ -198,7 +198,8 @@ func checkHomeCodeViewable(ctx *context.Context) {
|
||||
ctx.Data["Repo"] = ctx.Repo
|
||||
ctx.Data["MigrateTask"] = task
|
||||
ctx.Data["CloneAddr"], _ = util.SanitizeURL(cfg.CloneAddr)
|
||||
ctx.Data["Failed"] = task.Status == structs.TaskStatusFailed
|
||||
ctx.Data["Stopping"] = task.Status == structs.TaskStatusStopped && task.EndTime == 0 // edit/add - by petru @ codex
|
||||
ctx.Data["Failed"] = task.Status == structs.TaskStatusFailed || (task.Status == structs.TaskStatusStopped && task.EndTime != 0) // edit/add - by petru @ codex
|
||||
ctx.HTML(http.StatusOK, tplMigrating)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -45,10 +45,11 @@ func cloneWiki(ctx context.Context, repo *repo_model.Repository, opts migration.
|
||||
}
|
||||
}
|
||||
if err := gitrepo.CloneExternalRepo(ctx, wikiRemoteURL, storageRepo, git.CloneRepoOptions{
|
||||
Mirror: true,
|
||||
Quiet: true,
|
||||
Timeout: migrateTimeout,
|
||||
SkipTLSVerify: setting.Migrations.SkipTLSVerify,
|
||||
Mirror: true,
|
||||
Quiet: true,
|
||||
Timeout: migrateTimeout,
|
||||
KillProcessTreeOnCancel: true, // edit/add - by petru @ codex
|
||||
SkipTLSVerify: setting.Migrations.SkipTLSVerify,
|
||||
}); err != nil {
|
||||
log.Error("Clone wiki failed, err: %v", err)
|
||||
cleanIncompleteWikiPath()
|
||||
@@ -91,10 +92,11 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User,
|
||||
}
|
||||
|
||||
if err := gitrepo.CloneExternalRepo(ctx, opts.CloneAddr, repo, git.CloneRepoOptions{
|
||||
Mirror: true,
|
||||
Quiet: true,
|
||||
Timeout: migrateTimeout,
|
||||
SkipTLSVerify: setting.Migrations.SkipTLSVerify,
|
||||
Mirror: true,
|
||||
Quiet: true,
|
||||
Timeout: migrateTimeout,
|
||||
KillProcessTreeOnCancel: true, // edit/add - by petru @ codex
|
||||
SkipTLSVerify: setting.Migrations.SkipTLSVerify,
|
||||
}); err != nil {
|
||||
if errors.Is(err, context.DeadlineExceeded) {
|
||||
return repo, fmt.Errorf("clone timed out, consider increasing [git.timeout] MIGRATE in app.ini, underlying err: %w", err)
|
||||
|
||||
@@ -41,6 +41,18 @@ func handleCreateError(owner *user_model.User, err error) error {
|
||||
}
|
||||
}
|
||||
|
||||
// start edit/add - by petru @ codex
|
||||
func isMigrationCancelRequested(ctx context.Context, t *admin_model.Task) bool {
|
||||
if t.Status == structs.TaskStatusStopped && t.Message == "canceling" {
|
||||
return true
|
||||
}
|
||||
|
||||
currentTask, loadErr := admin_model.GetMigratingTask(ctx, t.RepoID)
|
||||
return loadErr == nil && currentTask.ID == t.ID && currentTask.Status == structs.TaskStatusStopped && currentTask.Message == "canceling"
|
||||
}
|
||||
|
||||
// end edit/add - by petru @ codex
|
||||
|
||||
func runMigrateTask(ctx context.Context, t *admin_model.Task) (err error) {
|
||||
defer func(ctx context.Context) {
|
||||
if e := recover(); e != nil {
|
||||
@@ -59,9 +71,16 @@ func runMigrateTask(ctx context.Context, t *admin_model.Task) (err error) {
|
||||
|
||||
log.Error("runMigrateTask[%d] by DoerID[%d] to RepoID[%d] for OwnerID[%d] failed: %v", t.ID, t.DoerID, t.RepoID, t.OwnerID, err)
|
||||
|
||||
// start edit/add - by petru @ codex
|
||||
t.EndTime = timeutil.TimeStampNow()
|
||||
t.Status = structs.TaskStatusFailed
|
||||
t.Message = err.Error()
|
||||
if isMigrationCancelRequested(ctx, t) {
|
||||
t.Status = structs.TaskStatusStopped
|
||||
t.Message = "canceled"
|
||||
} else {
|
||||
t.Status = structs.TaskStatusFailed
|
||||
t.Message = err.Error()
|
||||
}
|
||||
// end edit/add - by petru @ codex
|
||||
if err := t.UpdateCols(ctx, "status", "message", "end_time"); err != nil {
|
||||
log.Error("Task UpdateCols failed: %v", err)
|
||||
}
|
||||
|
||||
@@ -136,9 +136,12 @@ func RetryMigrateTask(ctx context.Context, repoID int64) error {
|
||||
log.Error("GetMigratingTask: %v", err)
|
||||
return err
|
||||
}
|
||||
if migratingTask.Status == structs.TaskStatusQueued || migratingTask.Status == structs.TaskStatusRunning {
|
||||
// start edit/add - by petru @ codex
|
||||
if migratingTask.Status == structs.TaskStatusQueued || migratingTask.Status == structs.TaskStatusRunning ||
|
||||
(migratingTask.Status == structs.TaskStatusStopped && migratingTask.EndTime == 0) {
|
||||
return nil
|
||||
}
|
||||
// end edit/add - by petru @ codex
|
||||
|
||||
// TODO Need to removing the storage/database garbage brought by the failed task
|
||||
|
||||
|
||||
@@ -26,21 +26,18 @@
|
||||
</div>
|
||||
<div id="repo_migrating_failed" class="tw-hidden">
|
||||
{{if .CloneAddr}}
|
||||
<p>{{ctx.Locale.Tr "repo.migrate.migrating_failed" .CloneAddr}}</p>
|
||||
<p id="repo_migrating_failed_title" data-failed-html="{{ctx.Locale.Tr "repo.migrate.migrating_failed" .CloneAddr}}" data-stopped-html="{{ctx.Locale.Tr "repo.migrate.migrating_stopped" .CloneAddr}}">{{ctx.Locale.Tr "repo.migrate.migrating_failed" .CloneAddr}}</p> <!-- edit/add - by petru @ codex -->
|
||||
{{else}}
|
||||
<p>{{ctx.Locale.Tr "repo.migrate.migrating_failed_no_addr"}}</p>
|
||||
<p id="repo_migrating_failed_title" data-failed-html="{{ctx.Locale.Tr "repo.migrate.migrating_failed_no_addr"}}" data-stopped-html="{{ctx.Locale.Tr "repo.migrate.migrating_stopped_no_addr"}}">{{ctx.Locale.Tr "repo.migrate.migrating_failed_no_addr"}}</p> <!-- edit/add - by petru @ codex -->
|
||||
{{end}}
|
||||
<p id="repo_migrating_failed_error"></p>
|
||||
</div>
|
||||
{{if .Permission.IsAdmin}}
|
||||
<div class="divider"></div>
|
||||
<div class="item">
|
||||
{{if .Failed}}
|
||||
<button class="ui basic red show-modal button" data-modal="#delete-repo-modal">{{ctx.Locale.Tr "repo.settings.delete"}}</button>
|
||||
{{else}}
|
||||
<button class="ui basic show-modal button" data-modal="#cancel-repo-modal">{{ctx.Locale.Tr "cancel"}}</button>
|
||||
{{end}}
|
||||
<button id="repo_migrating_retry" data-migrating-task-retry-url="{{.Link}}/settings/migrate/retry" class="ui basic button tw-hidden">{{ctx.Locale.Tr "retry"}}</button>
|
||||
<button id="repo_migrating_delete" class="ui basic red show-modal button{{if not .Failed}} tw-hidden{{end}}" data-modal="#delete-repo-modal">{{ctx.Locale.Tr "repo.settings.delete"}}</button> <!-- edit/add - by petru @ codex -->
|
||||
<button id="repo_migrating_cancel" class="ui basic show-modal button{{if or .Failed .Stopping}} tw-hidden{{end}}" data-modal="#cancel-repo-modal">{{ctx.Locale.Tr "cancel"}}</button> <!-- edit/add - by petru @ codex -->
|
||||
<button id="repo_migrating_retry" data-migrating-task-retry-url="{{.Link}}/settings/migrate/retry" class="ui basic button{{if not .Failed}} tw-hidden{{end}}">{{ctx.Locale.Tr "retry"}}</button> <!-- edit/add - by petru @ codex -->
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,8 @@ export function initRepoMigrationStatusChecker() {
|
||||
const repoMigrating = document.querySelector('#repo_migrating');
|
||||
if (!repoMigrating) return;
|
||||
|
||||
document.querySelector<HTMLButtonElement>('#repo_migrating_retry')?.addEventListener('click', doMigrationRetry);
|
||||
const repoMigratingRetry = document.querySelector<HTMLButtonElement>('#repo_migrating_retry');
|
||||
if (repoMigratingRetry) repoMigratingRetry.addEventListener('click', doMigrationRetry); // edit/add - by petru @ codex
|
||||
|
||||
const repoLink = repoMigrating.getAttribute('data-migrating-repo-link');
|
||||
|
||||
@@ -21,19 +22,31 @@ export function initRepoMigrationStatusChecker() {
|
||||
document.querySelector('#repo_migrating_progress_message')!.textContent = data.message;
|
||||
}
|
||||
|
||||
// migration cancel requested, keep polling until the clone process tree is actually gone
|
||||
if (data.stopping) {
|
||||
hideElem('#repo_migrating_cancel'); // edit/add - by petru @ codex
|
||||
hideElem('#repo_migrating_retry'); // edit/add - by petru @ codex
|
||||
hideElem('#repo_migrating_delete'); // edit/add - by petru @ codex
|
||||
return true;
|
||||
}
|
||||
|
||||
// TaskStatusFinished
|
||||
if (data.status === 4) {
|
||||
window.location.reload();
|
||||
return false;
|
||||
}
|
||||
|
||||
// TaskStatusFailed
|
||||
if (data.status === 3) {
|
||||
// TaskStatusFailed / TaskStatusStopped
|
||||
if (data.status === 3 || data.stopped) {
|
||||
hideElem('#repo_migrating_progress');
|
||||
hideElem('#repo_migrating');
|
||||
hideElem('#repo_migrating_cancel'); // edit/add - by petru @ codex
|
||||
showElem('#repo_migrating_retry');
|
||||
showElem('#repo_migrating_delete'); // edit/add - by petru @ codex
|
||||
showElem('#repo_migrating_failed');
|
||||
showElem('#repo_migrating_failed_image');
|
||||
const failedTitle = document.querySelector<HTMLElement>('#repo_migrating_failed_title'); // edit/add - by petru @ codex
|
||||
if (failedTitle) failedTitle.innerHTML = failedTitle.getAttribute(data.stopped ? 'data-stopped-html' : 'data-failed-html') || failedTitle.innerHTML; // edit/add - by petru @ codex
|
||||
document.querySelector('#repo_migrating_failed_error')!.textContent = data.message;
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user