2021-06-14 19:20:43 +02:00
// Copyright 2021 The Gitea Authors. All rights reserved.
2022-11-27 13:20:29 -05:00
// SPDX-License-Identifier: MIT
2021-06-14 19:20:43 +02:00
package mirror
import (
"context"
"fmt"
"strings"
"time"
2021-12-10 09:27:50 +08:00
repo_model "code.gitea.io/gitea/models/repo"
2022-10-17 07:29:26 +08:00
system_model "code.gitea.io/gitea/models/system"
2021-06-14 19:20:43 +02:00
"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/git"
2025-09-15 23:33:12 -07:00
"code.gitea.io/gitea/modules/git/gitcmd"
2024-04-13 23:41:57 +08:00
giturl "code.gitea.io/gitea/modules/git/url"
2024-01-28 04:09:51 +08:00
"code.gitea.io/gitea/modules/gitrepo"
2025-03-15 10:23:18 -07:00
"code.gitea.io/gitea/modules/globallock"
2021-06-14 19:20:43 +02:00
"code.gitea.io/gitea/modules/lfs"
"code.gitea.io/gitea/modules/log"
2021-11-30 20:06:32 +00:00
"code.gitea.io/gitea/modules/process"
2023-02-11 01:39:50 +01:00
"code.gitea.io/gitea/modules/proxy"
2021-06-14 19:20:43 +02:00
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
2026-02-20 14:19:12 -08:00
"code.gitea.io/gitea/services/migrations"
2023-09-06 02:37:47 +08:00
notify_service "code.gitea.io/gitea/services/notify"
2024-10-02 04:25:08 +09:00
repo_service "code.gitea.io/gitea/services/repository"
2021-06-14 19:20:43 +02:00
)
// UpdateAddress writes new address to Git repository and database
2022-01-19 23:26:57 +00:00
func UpdateAddress ( ctx context . Context , m * repo_model . Mirror , addr string ) error {
2025-01-07 13:17:44 +08:00
u , err := giturl . ParseGitURL ( addr )
2024-04-13 23:41:57 +08:00
if err != nil {
return fmt . Errorf ( "invalid addr: %v" , err )
}
2021-06-14 19:20:43 +02:00
remoteName := m . GetRemoteName ( )
2025-09-01 11:47:04 -07:00
repo := m . GetRepository ( ctx )
2021-06-14 19:20:43 +02:00
// Remove old remote
2025-09-01 11:47:04 -07:00
err = gitrepo . GitRemoteRemove ( ctx , repo , remoteName )
2025-01-07 21:42:45 +09:00
if err != nil && ! git . IsRemoteNotExistError ( err ) {
2021-06-14 19:20:43 +02:00
return err
}
2025-09-01 11:47:04 -07:00
err = gitrepo . GitRemoteAdd ( ctx , repo , remoteName , addr , gitrepo . RemoteOptionMirrorFetch )
2025-01-07 21:42:45 +09:00
if err != nil && ! git . IsRemoteNotExistError ( err ) {
2021-06-14 19:20:43 +02:00
return err
}
2025-09-01 11:12:58 -07:00
if repo_service . HasWiki ( ctx , m . Repo ) {
2022-01-19 23:26:57 +00:00
wikiRemotePath := repo_module . WikiRemoteURL ( ctx , addr )
2021-06-14 19:20:43 +02:00
// Remove old remote of wiki
2025-09-01 11:47:04 -07:00
err = gitrepo . GitRemoteRemove ( ctx , repo . WikiStorageRepo ( ) , remoteName )
2025-01-07 21:42:45 +09:00
if err != nil && ! git . IsRemoteNotExistError ( err ) {
2021-06-14 19:20:43 +02:00
return err
}
2025-09-01 11:47:04 -07:00
err = gitrepo . GitRemoteAdd ( ctx , repo . WikiStorageRepo ( ) , remoteName , wikiRemotePath , gitrepo . RemoteOptionMirrorFetch )
2025-01-07 21:42:45 +09:00
if err != nil && ! git . IsRemoteNotExistError ( err ) {
2021-06-14 19:20:43 +02:00
return err
}
}
2024-04-13 23:41:57 +08:00
// erase authentication before storing in database
u . User = nil
m . Repo . OriginalURL = u . String ( )
2025-05-11 12:18:46 -07:00
return repo_model . UpdateRepositoryColsNoAutoTime ( ctx , m . Repo , "original_url" )
2021-06-14 19:20:43 +02:00
}
2026-01-19 07:10:33 +08:00
func pruneBrokenReferences ( ctx context . Context , m * repo_model . Mirror , gitRepo gitrepo . Repository , timeout time . Duration ) error {
cmd := gitcmd . NewCommand ( "remote" , "prune" ) . AddDynamicArguments ( m . GetRemoteName ( ) ) . WithTimeout ( timeout )
stdout , _ , pruneErr := gitrepo . RunCmdString ( ctx , gitRepo , cmd )
2021-10-21 09:45:25 +01:00
if pruneErr != nil {
2026-01-19 07:10:33 +08:00
// sanitize the output, since it may contain the remote address, which may contain a password
stderrMessage := util . SanitizeCredentialURLs ( pruneErr . Stderr ( ) )
2022-03-31 10:25:40 +08:00
stdoutMessage := util . SanitizeCredentialURLs ( stdout )
2021-10-21 09:45:25 +01:00
2026-01-19 07:10:33 +08:00
log . Error ( "Failed to prune mirror repository %s references:\nStdout: %s\nStderr: %s\nErr: %v" , gitRepo . RelativePath ( ) , stdoutMessage , stderrMessage , pruneErr )
2026-02-01 17:06:57 +08:00
desc := fmt . Sprintf ( "Failed to prune mirror repository (%s) references: %s" , m . Repo . FullName ( ) , stderrMessage )
2022-10-17 07:29:26 +08:00
if err := system_model . CreateRepositoryNotice ( desc ) ; err != nil {
2021-10-21 09:45:25 +01:00
log . Error ( "CreateRepositoryNotice: %v" , err )
}
}
return pruneErr
}
2025-03-26 11:04:46 -07:00
// checkRecoverableSyncError takes an error message from a git fetch command and returns false if it should be a fatal/blocking error
func checkRecoverableSyncError ( stderrMessage string ) bool {
switch {
case strings . Contains ( stderrMessage , "unable to resolve reference" ) && strings . Contains ( stderrMessage , "reference broken" ) :
return true
case strings . Contains ( stderrMessage , "remote error" ) && strings . Contains ( stderrMessage , "not our ref" ) :
return true
case strings . Contains ( stderrMessage , "cannot lock ref" ) && strings . Contains ( stderrMessage , "but expected" ) :
return true
case strings . Contains ( stderrMessage , "cannot lock ref" ) && strings . Contains ( stderrMessage , "unable to resolve reference" ) :
return true
case strings . Contains ( stderrMessage , "Unable to create" ) && strings . Contains ( stderrMessage , ".lock" ) :
return true
default :
return false
}
}
2021-06-14 19:20:43 +02:00
// runSync returns true if sync finished without error.
2026-02-10 16:16:05 -08:00
func runSync ( ctx context . Context , m * repo_model . Mirror ) ( [ ] * repo_module . SyncResult , bool ) {
2021-06-14 19:20:43 +02:00
log . Trace ( "SyncMirrors [repo: %-v]: running git remote update..." , m . Repo )
2022-03-29 18:12:33 +01:00
2025-09-01 11:47:04 -07:00
remoteURL , remoteErr := gitrepo . GitRemoteGetURL ( ctx , m . Repo , m . GetRemoteName ( ) )
2021-06-14 19:20:43 +02:00
if remoteErr != nil {
2025-09-01 11:47:04 -07:00
log . Error ( "SyncMirrors [repo: %-v]: GetRemoteURL Error %v" , m . Repo , remoteErr )
2022-06-11 21:50:14 +08:00
return nil , false
2021-06-14 19:20:43 +02:00
}
2023-02-11 01:39:50 +01:00
envs := proxy . EnvWithProxy ( remoteURL . URL )
2026-01-19 07:10:33 +08:00
timeout := time . Duration ( setting . Git . Timeout . Mirror ) * time . Second
2023-02-11 01:39:50 +01:00
2026-01-19 07:10:33 +08:00
// use fetch but not remote update because git fetch support --tags but remote update doesn't
cmdFetch := func ( ) * gitcmd . Command {
cmd := gitcmd . NewCommand ( "fetch" , "--tags" )
if m . EnablePrune {
cmd . AddArguments ( "--prune" )
}
return cmd . AddDynamicArguments ( m . GetRemoteName ( ) ) . WithTimeout ( timeout ) . WithEnv ( envs )
}
2021-06-14 19:20:43 +02:00
2026-01-19 07:10:33 +08:00
var err error
fetchStdout , fetchStderr , err := gitrepo . RunCmdString ( ctx , m . Repo , cmdFetch ( ) )
if err != nil {
2022-03-31 10:25:40 +08:00
// sanitize the output, since it may contain the remote address, which may contain a password
2026-01-19 07:10:33 +08:00
stderrMessage := util . SanitizeCredentialURLs ( fetchStderr )
stdoutMessage := util . SanitizeCredentialURLs ( fetchStdout )
2021-06-14 19:20:43 +02:00
2021-10-21 09:45:25 +01:00
// Now check if the error is a resolve reference due to broken reference
2026-01-19 07:10:33 +08:00
if checkRecoverableSyncError ( fetchStderr ) {
2022-03-10 10:09:48 +00:00
log . Warn ( "SyncMirrors [repo: %-v]: failed to update mirror repository due to broken references:\nStdout: %s\nStderr: %s\nErr: %v\nAttempting Prune" , m . Repo , stdoutMessage , stderrMessage , err )
2021-10-21 09:45:25 +01:00
err = nil
// Attempt prune
2026-01-19 07:10:33 +08:00
pruneErr := pruneBrokenReferences ( ctx , m , m . Repo , timeout )
2021-10-21 09:45:25 +01:00
if pruneErr == nil {
// Successful prune - reattempt mirror
2026-01-19 07:10:33 +08:00
fetchStdout , fetchStderr , err = gitrepo . RunCmdString ( ctx , m . Repo , cmdFetch ( ) )
if err != nil {
// sanitize the output, since it may contain the remote address, which may contain a password
stderrMessage = util . SanitizeCredentialURLs ( fetchStderr )
stdoutMessage = util . SanitizeCredentialURLs ( fetchStdout )
2021-10-21 09:45:25 +01:00
}
}
}
// If there is still an error (or there always was an error)
if err != nil {
2022-03-10 10:09:48 +00:00
log . Error ( "SyncMirrors [repo: %-v]: failed to update mirror repository:\nStdout: %s\nStderr: %s\nErr: %v" , m . Repo , stdoutMessage , stderrMessage , err )
2026-02-01 17:06:57 +08:00
desc := fmt . Sprintf ( "Failed to update mirror repository (%s): %s" , m . Repo . FullName ( ) , stderrMessage )
2026-01-19 07:10:33 +08:00
if err := system_model . CreateRepositoryNotice ( desc ) ; err != nil {
2021-10-21 09:45:25 +01:00
log . Error ( "CreateRepositoryNotice: %v" , err )
}
return nil , false
2021-06-14 19:20:43 +02:00
}
}
2025-10-17 20:00:44 -07:00
if err := gitrepo . WriteCommitGraph ( ctx , m . Repo ) ; err != nil {
2022-03-29 18:12:33 +01:00
log . Error ( "SyncMirrors [repo: %-v]: %v" , m . Repo , err )
}
2024-01-28 04:09:51 +08:00
gitRepo , err := gitrepo . OpenRepository ( ctx , m . Repo )
2021-06-14 19:20:43 +02:00
if err != nil {
2022-03-10 10:09:48 +00:00
log . Error ( "SyncMirrors [repo: %-v]: failed to OpenRepository: %v" , m . Repo , err )
2021-06-14 19:20:43 +02:00
return nil , false
}
2025-03-26 11:04:46 -07:00
if m . LFS && setting . LFS . StartServer {
log . Trace ( "SyncMirrors [repo: %-v]: syncing LFS objects..." , m . Repo )
endpoint := lfs . DetermineEndpoint ( remoteURL . String ( ) , m . LFSEndpoint )
2026-02-20 14:19:12 -08:00
lfsClient := lfs . NewClient ( endpoint , migrations . NewMigrationHTTPTransport ( ) )
2025-03-26 11:04:46 -07:00
if err = repo_module . StoreMissingLfsObjectsInRepository ( ctx , m . Repo , gitRepo , lfsClient ) ; err != nil {
2025-09-01 11:12:58 -07:00
log . Error ( "SyncMirrors [repo: %-v]: failed to synchronize LFS objects for repository: %v" , m . Repo . FullName ( ) , err )
2025-03-26 11:04:46 -07:00
}
}
2023-07-06 19:18:37 +08:00
log . Trace ( "SyncMirrors [repo: %-v]: syncing branches..." , m . Repo )
2026-02-10 16:16:05 -08:00
_ , results , err := repo_module . SyncRepoBranchesWithRepo ( ctx , m . Repo , gitRepo , 0 )
if err != nil {
2023-07-06 19:18:37 +08:00
log . Error ( "SyncMirrors [repo: %-v]: failed to synchronize branches: %v" , m . Repo , err )
}
2021-06-14 19:20:43 +02:00
log . Trace ( "SyncMirrors [repo: %-v]: syncing releases with tags..." , m . Repo )
2026-02-10 16:16:05 -08:00
tagResults , err := repo_module . SyncReleasesWithTags ( ctx , m . Repo , gitRepo )
if err != nil {
2022-03-10 10:09:48 +00:00
log . Error ( "SyncMirrors [repo: %-v]: failed to synchronize tags to releases: %v" , m . Repo , err )
2021-06-14 19:20:43 +02:00
}
2026-02-10 16:16:05 -08:00
results = append ( results , tagResults ... )
2021-06-14 19:20:43 +02:00
gitRepo . Close ( )
log . Trace ( "SyncMirrors [repo: %-v]: updating size of repository" , m . Repo )
2022-06-06 16:01:49 +08:00
if err := repo_module . UpdateRepoSize ( ctx , m . Repo ) ; err != nil {
2025-09-01 11:12:58 -07:00
log . Error ( "SyncMirrors [repo: %-v]: failed to update size for mirror repository: %v" , m . Repo . FullName ( ) , err )
2021-06-14 19:20:43 +02:00
}
2026-01-19 07:10:33 +08:00
cmdRemoteUpdatePrune := func ( ) * gitcmd . Command {
return gitcmd . NewCommand ( "remote" , "update" , "--prune" ) .
AddDynamicArguments ( m . GetRemoteName ( ) ) . WithTimeout ( timeout ) . WithEnv ( envs )
}
2025-09-01 11:12:58 -07:00
if repo_service . HasWiki ( ctx , m . Repo ) {
2021-06-14 19:20:43 +02:00
log . Trace ( "SyncMirrors [repo: %-v Wiki]: running git remote update..." , m . Repo )
2026-01-19 07:10:33 +08:00
// the result of "git remote update" is in stderr
stdout , stderr , err := gitrepo . RunCmdString ( ctx , m . Repo . WikiStorageRepo ( ) , cmdRemoteUpdatePrune ( ) )
if err != nil {
2022-03-31 10:25:40 +08:00
// sanitize the output, since it may contain the remote address, which may contain a password
stderrMessage := util . SanitizeCredentialURLs ( stderr )
stdoutMessage := util . SanitizeCredentialURLs ( stdout )
2021-06-14 19:20:43 +02:00
2021-10-21 09:45:25 +01:00
// Now check if the error is a resolve reference due to broken reference
2025-03-26 11:04:46 -07:00
if checkRecoverableSyncError ( stderrMessage ) {
2022-03-10 10:09:48 +00:00
log . Warn ( "SyncMirrors [repo: %-v Wiki]: failed to update mirror wiki repository due to broken references:\nStdout: %s\nStderr: %s\nErr: %v\nAttempting Prune" , m . Repo , stdoutMessage , stderrMessage , err )
2021-10-21 09:45:25 +01:00
err = nil
// Attempt prune
2026-01-19 07:10:33 +08:00
pruneErr := pruneBrokenReferences ( ctx , m , m . Repo . WikiStorageRepo ( ) , timeout )
2021-10-21 09:45:25 +01:00
if pruneErr == nil {
// Successful prune - reattempt mirror
2026-01-19 07:10:33 +08:00
stdout , stderr , err = gitrepo . RunCmdString ( ctx , m . Repo . WikiStorageRepo ( ) , cmdRemoteUpdatePrune ( ) )
if err != nil {
2022-03-31 10:25:40 +08:00
stderrMessage = util . SanitizeCredentialURLs ( stderr )
stdoutMessage = util . SanitizeCredentialURLs ( stdout )
2021-10-21 09:45:25 +01:00
}
}
}
// If there is still an error (or there always was an error)
if err != nil {
2022-03-10 10:09:48 +00:00
log . Error ( "SyncMirrors [repo: %-v Wiki]: failed to update mirror repository wiki:\nStdout: %s\nStderr: %s\nErr: %v" , m . Repo , stdoutMessage , stderrMessage , err )
2026-02-01 17:06:57 +08:00
desc := fmt . Sprintf ( "Failed to update mirror repository wiki (%s): %s" , m . Repo . FullName ( ) , stderrMessage )
2026-01-19 07:10:33 +08:00
if err := system_model . CreateRepositoryNotice ( desc ) ; err != nil {
2021-10-21 09:45:25 +01:00
log . Error ( "CreateRepositoryNotice: %v" , err )
}
return nil , false
2021-06-14 19:20:43 +02:00
}
2022-03-29 18:12:33 +01:00
2025-10-17 20:00:44 -07:00
if err := gitrepo . WriteCommitGraph ( ctx , m . Repo . WikiStorageRepo ( ) ) ; err != nil {
2022-03-29 18:12:33 +01:00
log . Error ( "SyncMirrors [repo: %-v]: %v" , m . Repo , err )
}
2021-06-14 19:20:43 +02:00
}
log . Trace ( "SyncMirrors [repo: %-v Wiki]: git remote update complete" , m . Repo )
}
log . Trace ( "SyncMirrors [repo: %-v]: invalidating mirror branch caches..." , m . Repo )
2024-01-28 04:09:51 +08:00
branches , _ , err := gitrepo . GetBranchesByPath ( ctx , m . Repo , 0 , 0 )
2021-06-14 19:20:43 +02:00
if err != nil {
2022-03-10 10:09:48 +00:00
log . Error ( "SyncMirrors [repo: %-v]: failed to GetBranches: %v" , m . Repo , err )
2021-06-14 19:20:43 +02:00
return nil , false
}
for _ , branch := range branches {
2025-04-02 10:31:32 -07:00
cache . Remove ( m . Repo . GetCommitsCountCacheKey ( branch , true ) )
2021-06-14 19:20:43 +02:00
}
m . UpdatedUnix = timeutil . TimeStampNow ( )
2026-02-10 16:16:05 -08:00
return results , true
2021-06-14 19:20:43 +02:00
}
2025-03-15 10:23:18 -07:00
func getRepoPullMirrorLockKey ( repoID int64 ) string {
return fmt . Sprintf ( "repo_pull_mirror_%d" , repoID )
}
2021-06-14 19:20:43 +02:00
// SyncPullMirror starts the sync of the pull mirror and schedules the next run.
func SyncPullMirror ( ctx context . Context , repoID int64 ) bool {
log . Trace ( "SyncMirrors [repo_id: %v]" , repoID )
defer func ( ) {
err := recover ( )
if err == nil {
return
}
// There was a panic whilst syncMirrors...
2022-03-10 10:09:48 +00:00
log . Error ( "PANIC whilst SyncMirrors[repo_id: %d] Panic: %v\nStacktrace: %s" , repoID , err , log . Stack ( 2 ) )
2021-06-14 19:20:43 +02:00
} ( )
2025-03-15 10:23:18 -07:00
releaser , err := globallock . Lock ( ctx , getRepoPullMirrorLockKey ( repoID ) )
if err != nil {
log . Error ( "globallock.Lock(): %v" , err )
return false
}
defer releaser ( )
2022-05-20 22:08:52 +08:00
m , err := repo_model . GetMirrorByRepoID ( ctx , repoID )
2021-06-14 19:20:43 +02:00
if err != nil {
2022-03-10 10:09:48 +00:00
log . Error ( "SyncMirrors [repo_id: %v]: unable to GetMirrorByRepoID: %v" , repoID , err )
2021-06-14 19:20:43 +02:00
return false
}
2025-12-11 16:15:40 -08:00
repo := m . GetRepository ( ctx ) // force load repository of mirror
2021-06-14 19:20:43 +02:00
2021-11-30 20:06:32 +00:00
ctx , _ , finished := process . GetManager ( ) . AddContext ( ctx , fmt . Sprintf ( "Syncing Mirror %s/%s" , m . Repo . OwnerName , m . Repo . Name ) )
defer finished ( )
2021-06-14 19:20:43 +02:00
log . Trace ( "SyncMirrors [repo: %-v]: Running Sync" , m . Repo )
results , ok := runSync ( ctx , m )
if ! ok {
2022-03-27 15:40:17 +01:00
if err = repo_model . TouchMirror ( ctx , m ) ; err != nil {
log . Error ( "SyncMirrors [repo: %-v]: failed to TouchMirror: %v" , m . Repo , err )
}
2021-06-14 19:20:43 +02:00
return false
}
log . Trace ( "SyncMirrors [repo: %-v]: Scheduling next update" , m . Repo )
m . ScheduleNextUpdate ( )
2022-05-20 22:08:52 +08:00
if err = repo_model . UpdateMirror ( ctx , m ) ; err != nil {
2022-03-10 10:09:48 +00:00
log . Error ( "SyncMirrors [repo: %-v]: failed to UpdateMirror with next update date: %v" , m . Repo , err )
2021-06-14 19:20:43 +02:00
return false
}
2024-04-13 12:01:02 +09:00
gitRepo , err := gitrepo . OpenRepository ( ctx , m . Repo )
if err != nil {
log . Error ( "SyncMirrors [repo: %-v]: unable to OpenRepository: %v" , m . Repo , err )
return false
}
defer gitRepo . Close ( )
2021-06-14 19:20:43 +02:00
2024-04-13 12:01:02 +09:00
log . Trace ( "SyncMirrors [repo: %-v]: %d branches updated" , m . Repo , len ( results ) )
if len ( results ) > 0 {
2024-04-27 06:44:49 -04:00
if ok := checkAndUpdateEmptyRepository ( ctx , m , results ) ; ! ok {
2024-04-13 12:01:02 +09:00
log . Error ( "SyncMirrors [repo: %-v]: checkAndUpdateEmptyRepository: %v" , m . Repo , err )
2021-06-14 19:20:43 +02:00
return false
}
}
for _ , result := range results {
// Discard GitHub pull requests, i.e. refs/pull/*
2026-02-10 16:16:05 -08:00
if result . RefName . IsPull ( ) {
2021-06-14 19:20:43 +02:00
continue
}
// Create reference
2026-02-10 16:16:05 -08:00
if result . OldCommitID == "" {
commitID , err := gitRepo . GetRefCommitID ( result . RefName . String ( ) )
2021-06-14 19:20:43 +02:00
if err != nil {
2026-02-10 16:16:05 -08:00
log . Error ( "SyncMirrors [repo: %-v]: unable to GetRefCommitID [ref_name: %s]: %v" , m . Repo , result . RefName , err )
2021-06-14 19:20:43 +02:00
continue
}
2024-03-11 05:30:36 +08:00
objectFormat := git . ObjectFormatFromName ( m . Repo . ObjectFormatName )
2023-09-06 02:37:47 +08:00
notify_service . SyncPushCommits ( ctx , m . Repo . MustOwner ( ctx ) , m . Repo , & repo_module . PushUpdateOptions {
2026-02-10 16:16:05 -08:00
RefFullName : result . RefName ,
2023-12-17 19:56:08 +08:00
OldCommitID : objectFormat . EmptyObjectID ( ) . String ( ) ,
2021-06-14 19:20:43 +02:00
NewCommitID : commitID ,
} , repo_module . NewPushCommits ( ) )
2026-02-10 16:16:05 -08:00
notify_service . SyncCreateRef ( ctx , m . Repo . MustOwner ( ctx ) , m . Repo , result . RefName , commitID )
2021-06-14 19:20:43 +02:00
continue
}
// Delete reference
2026-02-10 16:16:05 -08:00
if result . NewCommitID == "" {
notify_service . SyncDeleteRef ( ctx , m . Repo . MustOwner ( ctx ) , m . Repo , result . RefName )
2021-06-14 19:20:43 +02:00
continue
}
// Push commits
2026-02-10 16:16:05 -08:00
oldCommitID , err := gitrepo . GetFullCommitID ( ctx , repo , result . OldCommitID )
2021-06-14 19:20:43 +02:00
if err != nil {
2026-02-10 16:16:05 -08:00
log . Error ( "SyncMirrors [repo: %-v]: unable to get GetFullCommitID[%s]: %v" , m . Repo , result . OldCommitID , err )
2021-06-14 19:20:43 +02:00
continue
}
2026-02-10 16:16:05 -08:00
newCommitID , err := gitrepo . GetFullCommitID ( ctx , repo , result . NewCommitID )
2021-06-14 19:20:43 +02:00
if err != nil {
2026-02-10 16:16:05 -08:00
log . Error ( "SyncMirrors [repo: %-v]: unable to get GetFullCommitID [%s]: %v" , m . Repo , result . NewCommitID , err )
2021-06-14 19:20:43 +02:00
continue
}
commits , err := gitRepo . CommitsBetweenIDs ( newCommitID , oldCommitID )
if err != nil {
2022-03-10 10:09:48 +00:00
log . Error ( "SyncMirrors [repo: %-v]: unable to get CommitsBetweenIDs [new_commit_id: %s, old_commit_id: %s]: %v" , m . Repo , newCommitID , oldCommitID , err )
2021-06-14 19:20:43 +02:00
continue
}
2021-08-09 20:08:51 +02:00
theCommits := repo_module . GitToPushCommits ( commits )
2021-06-14 19:20:43 +02:00
if len ( theCommits . Commits ) > setting . UI . FeedMaxCommitNum {
theCommits . Commits = theCommits . Commits [ : setting . UI . FeedMaxCommitNum ]
}
2024-04-22 13:48:42 +02:00
newCommit , err := gitRepo . GetCommit ( newCommitID )
if err != nil {
2023-03-04 12:45:53 +08:00
log . Error ( "SyncMirrors [repo: %-v]: unable to get commit %s: %v" , m . Repo , newCommitID , err )
continue
}
2024-04-22 13:48:42 +02:00
theCommits . HeadCommit = repo_module . CommitToPushCommit ( newCommit )
2021-06-14 19:20:43 +02:00
theCommits . CompareURL = m . Repo . ComposeCompareURL ( oldCommitID , newCommitID )
2023-09-06 02:37:47 +08:00
notify_service . SyncPushCommits ( ctx , m . Repo . MustOwner ( ctx ) , m . Repo , & repo_module . PushUpdateOptions {
2026-02-10 16:16:05 -08:00
RefFullName : result . RefName ,
2021-06-14 19:20:43 +02:00
OldCommitID : oldCommitID ,
NewCommitID : newCommitID ,
} , theCommits )
}
log . Trace ( "SyncMirrors [repo: %-v]: done notifying updated branches/tags - now updating last commit time" , m . Repo )
2024-04-13 12:01:02 +09:00
isEmpty , err := gitRepo . IsEmpty ( )
2021-06-14 19:20:43 +02:00
if err != nil {
2024-04-13 12:01:02 +09:00
log . Error ( "SyncMirrors [repo: %-v]: unable to check empty git repo: %v" , m . Repo , err )
2021-06-14 19:20:43 +02:00
return false
}
2024-04-13 12:01:02 +09:00
if ! isEmpty {
// Get latest commit date and update to current repository updated time
2025-12-11 16:15:40 -08:00
commitDate , err := gitrepo . GetLatestCommitTime ( ctx , m . Repo )
2024-04-13 12:01:02 +09:00
if err != nil {
log . Error ( "SyncMirrors [repo: %-v]: unable to GetLatestCommitDate: %v" , m . Repo , err )
return false
}
if err = repo_model . UpdateRepositoryUpdatedTime ( ctx , m . RepoID , commitDate ) ; err != nil {
log . Error ( "SyncMirrors [repo: %-v]: unable to update repository 'updated_unix': %v" , m . Repo , err )
return false
}
2021-06-14 19:20:43 +02:00
}
2024-10-02 04:25:08 +09:00
// Update License
if err = repo_service . AddRepoToLicenseUpdaterQueue ( & repo_service . LicenseUpdaterOptions {
RepoID : m . Repo . ID ,
} ) ; err != nil {
log . Error ( "SyncMirrors [repo: %-v]: unable to add repo to license updater queue: %v" , m . Repo , err )
return false
}
2021-06-14 19:20:43 +02:00
log . Trace ( "SyncMirrors [repo: %-v]: Successfully updated" , m . Repo )
return true
}
2026-02-10 16:16:05 -08:00
func checkAndUpdateEmptyRepository ( ctx context . Context , m * repo_model . Mirror , results [ ] * repo_module . SyncResult ) bool {
2021-06-14 19:20:43 +02:00
if ! m . Repo . IsEmpty {
return true
}
hasDefault := false
hasMaster := false
hasMain := false
defaultBranchName := m . Repo . DefaultBranch
if len ( defaultBranchName ) == 0 {
defaultBranchName = setting . Repository . DefaultBranch
}
firstName := ""
for _ , result := range results {
2026-02-10 16:16:05 -08:00
if ! result . RefName . IsBranch ( ) {
2021-06-14 19:20:43 +02:00
continue
}
2023-05-26 09:04:48 +08:00
2026-02-10 16:16:05 -08:00
name := result . RefName . BranchName ( )
2021-06-14 19:20:43 +02:00
if len ( firstName ) == 0 {
firstName = name
}
hasDefault = hasDefault || name == defaultBranchName
hasMaster = hasMaster || name == "master"
hasMain = hasMain || name == "main"
}
if len ( firstName ) > 0 {
if hasDefault {
m . Repo . DefaultBranch = defaultBranchName
} else if hasMaster {
m . Repo . DefaultBranch = "master"
} else if hasMain {
m . Repo . DefaultBranch = "main"
} else {
m . Repo . DefaultBranch = firstName
}
// Update the git repository default branch
2024-03-08 15:30:10 +08:00
if err := gitrepo . SetDefaultBranch ( ctx , m . Repo , m . Repo . DefaultBranch ) ; err != nil {
2024-11-02 19:20:22 +08:00
log . Error ( "Failed to update default branch of underlying git repository %-v. Error: %v" , m . Repo , err )
return false
2021-06-14 19:20:43 +02:00
}
m . Repo . IsEmpty = false
// Update the is empty and default_branch columns
2025-05-11 12:18:46 -07:00
if err := repo_model . UpdateRepositoryColsWithAutoTime ( ctx , m . Repo , "default_branch" , "is_empty" ) ; err != nil {
2021-06-14 19:20:43 +02:00
log . Error ( "Failed to update default branch of repository %-v. Error: %v" , m . Repo , err )
2026-02-01 17:06:57 +08:00
desc := fmt . Sprintf ( "Failed to update default branch of repository (%s): %v" , m . Repo . FullName ( ) , err )
2022-10-17 07:29:26 +08:00
if err = system_model . CreateRepositoryNotice ( desc ) ; err != nil {
2021-06-14 19:20:43 +02:00
log . Error ( "CreateRepositoryNotice: %v" , err )
}
return false
}
}
return true
}