이 문서는 GitLab 저장소가 Bitbucket 저장소를 미러링하도록 Mirror Hook을 설정하는 방법의 가이드를 공유하기 위해 작성되었다.
도구명 | Bitbucket, GitLab |
---|---|
버전 | Bitbucket : 8.19.8 GitLab : 15.2 |
비고 | - |
Bitbucket 저장소와 GitLab 저장소 연동 설정하기
1. GitLab에 저장소 생성하기
TroubleShooting
다음 에러는 GitLab 저장소에 ReadMe 파일이 있을 때 발생한 에러입니다.
2024-10-16 08:33:24,303 ERROR [MirrorRepositoryHook:thread-2] c.a.s.i.c.HazelcastBucketedExecutor Attempt 5 of 5 at processing bucket 'MirrorRepositoryHook@32:https://gitlab-playground.curvc.com/root/demo-project.git' for executor 'MirrorRepositoryHook' failed: com.atlassian.bitbucket.ServerException: An error occurred while executing an external process: Wrapping ProcessFailedException: 'git push --prune https://root:**********@gitlab-playground.curvc.com/root/demo-project.git --force --atomic +refs/heads/*:refs/heads/* +refs/tags/*:refs/tags/* +refs/notes/*:refs/notes/*' exited with code 1 at com.atlassian.bitbucket.scm.git.command.GitCommandExitHandler.evaluateThrowable(GitCommandExitHandler.java:163) at com.atlassian.bitbucket.scm.git.command.GitCommandExitHandler.onError(GitCommandExitHandler.java:297) at com.atlassian.bitbucket.scm.DefaultCommandExitHandler.onExit(DefaultCommandExitHandler.java:32) at com.englishtown.bitbucket.hook.PasswordHandler.onExit(PasswordHandler.java:50) at com.atlassian.stash.internal.scm.git.mesh.AbstractFragmentResponseObserver.callExitHandler(AbstractFragmentResponseObserver.java:180) at com.atlassian.stash.internal.scm.git.mesh.AbstractFragmentResponseObserver.asResult(AbstractFragmentResponseObserver.java:150) at com.atlassian.stash.internal.scm.git.mesh.BidirectionalFragmentResponseObserver.asResult(BidirectionalFragmentResponseObserver.java:66) at com.atlassian.stash.internal.scm.git.mesh.GrpcPlumbingClient.call(GrpcPlumbingClient.java:71) at jdk.internal.reflect.GeneratedMethodAccessor794.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at jdk.internal.reflect.GeneratedMethodAccessor187.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at jdk.proxy3/jdk.proxy3.$Proxy477.call(Unknown Source) at com.atlassian.stash.internal.scm.git.mesh.MeshGitFreeFormCommandBuilder$1.call(MeshGitFreeFormCommandBuilder.java:105) at com.englishtown.bitbucket.hook.MirrorBucketProcessor.runMirrorCommand(MirrorBucketProcessor.java:130) at com.englishtown.bitbucket.hook.MirrorBucketProcessor.lambda$process$0(MirrorBucketProcessor.java:80) at com.atlassian.stash.internal.user.DefaultEscalatedSecurityContext.call(DefaultEscalatedSecurityContext.java:59) at com.englishtown.bitbucket.hook.MirrorBucketProcessor.process(MirrorBucketProcessor.java:70) at com.atlassian.stash.internal.concurrent.HazelcastBucketedExecutor$BucketProcessingBootstrapper.run(HazelcastBucketedExecutor.java:146) at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) at java.base/java.lang.Thread.run(Thread.java:840) ... 15 frames trimmed Caused by: com.englishtown.bitbucket.hook.PasswordHandler$PasswordSafeException: Wrapping ProcessFailedException: 'git push --prune https://root:**********@gitlab-playground.curvc.com/root/demo-project.git --force --atomic +refs/heads/*:refs/heads/* +refs/tags/*:refs/tags/* +refs/notes/*:refs/notes/*' exited with code 1 at com.atlassian.stash.internal.scm.git.command.BioStdioHandler.onComplete(BioStdioHandler.java:92) at com.atlassian.stash.internal.scm.git.mesh.LatchedNioStdioHandler.onComplete(LatchedNioStdioHandler.java:61) at com.atlassian.stash.internal.scm.git.mesh.AbstractFragmentResponseObserver.maybeSummarize(AbstractFragmentResponseObserver.java:278) at com.atlassian.stash.internal.scm.git.mesh.AbstractFragmentResponseObserver.finish(AbstractFragmentResponseObserver.java:228) at com.atlassian.stash.internal.scm.git.mesh.AbstractFragmentResponseObserver.callOnExit(AbstractFragmentResponseObserver.java:200) at com.atlassian.stash.internal.scm.git.mesh.AbstractFragmentResponseObserver.onNext(AbstractFragmentResponseObserver.java:120) at com.atlassian.stash.internal.scm.git.mesh.AbstractFragmentResponseObserver.onNext(AbstractFragmentResponseObserver.java:41) at io.grpc.stub.ClientCalls$StreamObserverToCallListenerAdapter.onMessage(ClientCalls.java:468) at io.grpc.ForwardingClientCallListener.onMessage(ForwardingClientCallListener.java:33) at io.grpc.ForwardingClientCallListener.onMessage(ForwardingClientCallListener.java:33) at com.atlassian.stash.internal.scm.git.mesh.StatefulClientCallListener.onMessage(StatefulClientCallListener.java:45) at io.grpc.ForwardingClientCallListener.onMessage(ForwardingClientCallListener.java:33) at com.atlassian.stash.internal.scm.git.mesh.DeadlinePropagatingClientInterceptor$DeadlinePropagatingListener.onMessage(DeadlinePropagatingClientInterceptor.java:169) at io.grpc.ForwardingClientCallListener.onMessage(ForwardingClientCallListener.java:33) at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1MessagesAvailable.runInternal(ClientCallImpl.java:667) at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1MessagesAvailable.runInContext(ClientCallImpl.java:654) at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37) at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:133) ... 3 common frames omitted
GitLab에 아무 파일도 없는 상태 (ReadMe 파일도
) 인 경우에는 에러 발생하지 않습니다.
따라서, Initialize Repository with a README 선택 해제해야 합니다.
2. Bitbucket 저장소의 Mirror Hook 설정
- 저장소의 Repository settings → Hooks
Pipeline 에러
Bitbucket에서 Mirror Hook 활성화 후 거의 바로 저장소 clone 되지만, Pipeline 에서 에러 발생
GitLab 웹 페이지에 나타나는 에러
$ /build/build.sh bash: line 179: /build/build.sh: No such file or directory Uploading artifacts for failed job Uploading artifacts... Runtime platform arch=amd64 os=linux pid=19961 revision=66269445 version=17.3.1 WARNING: gl-auto-build-variables.env: no matching files. Ensure that the artifact path is relative to the working directory (/home/gitlab-runner/builds/2a7FHkMoh/0/test/mirroring-test) // build.sh 파일 X ERROR: No files to upload Cleaning up project directory and file based variables ERROR: Job failed: exit status 1
GitLab 로그
{ "severity": "WARN", "time": "2024-10-16T01:28:01.706Z", "class": "Git::BranchHooksService", "correlation_id": "01JA9F0S8ZXF5785N7KSG01K2N", "project_id": 6, "project_path": "test/mirroring-test", "message": "Error creating pipeline", "errors": "Missing CI config file", // CI Config file 이 없어서 발생 "pipeline_params": { "before": "23289086630c099e53bc5a8c614693fac7893568", "after": "7a4af81869ff3a1bf222ad120e0fb69e93f70ce8", "ref": "refs/heads/master", "variables_attributes": [], "checkout_sha": "7a4af81869ff3a1bf222ad120e0fb69e93f70ce8" }, "retry": 0 }
CI Config file이 없어서 발생했기 때문에 추가합니다.
미러링 테스트
Bitbucket 저장소에서 Commit
GitLab 저장소에서 Commit 내역 업데이트
Bitbucket 저장소에서 Pull Request & Merge
GitLab 저장소에 업데이트
Bitbucket의 Git LFS 포함 저장소를 GitLab으로 미러링
에러 발생, LFS 파일이 포함된 Commit이 업데이트 되지 않습니다.
GitLab 로그
{ "correlation_id": "01JABWQS7EC26MEHMCZJ8J6EMG", "duration_ms": 114, "error": "LFS objects are missing. Ensure LFS is properly set up or try a manual \"git lfs push --all\".", "level": "error", // 로그 레벨: 오류 발생 "method": "POST", "msg": "Internal API error", "pid": 286, "status": 401, // 상태 코드: 권한 없음 (401 Unauthorized) "time": "2024-10-17T00:06:15.354Z", "url": "http://unix/api/v4/internal/allowed" } { "component": "gitaly.StreamServerInterceptor", "correlation_id": "01JABWQS7EC26MEHMCZJ8J6EMG", "error": "GitLab: LFS objects are missing. Ensure LFS is properly set up or try a manual \"git lfs push --all\".", // 오류 메시지: Git LFS 오브젝트 누락 "grpc.meta.client_name": "gitaly-hooks", "grpc.meta.deadline_type": "none", "grpc.meta.method_operation": "accessor", "grpc.meta.method_scope": "repository", "grpc.meta.method_type": "bidi_stream", "grpc.method": "PreReceiveHook", // gRPC 메서드: PreReceiveHook "grpc.request.fullMethod": "/gitaly.HookService/PreReceiveHook", "grpc.request.glProjectPath": "test/bitbucket-java-ex", "grpc.request.glRepository": "project-12", "grpc.request.repoPath": "@hashed/6b/51/6b51d431df5d7f141cbececcf79edf3dd861c3b4069f0b11661a3eefacbba918.git", "grpc.request.repoStorage": "default", "grpc.service": "gitaly.HookService", "grpc.start_time": "2024-10-17T00:06:15.239", "level": "warning", "msg": "stopping transaction because pre-receive hook failed", // 메시지: pre-receive hook 실패로 트랜잭션 중단 "pid": 286, "span.kind": "server", "system": "grpc", "time": "2024-10-17T00:06:15.354Z", "user_id": "user-1", "username": "root" }
Bitbucket 로그
2024-10-17 09:07:56,053 ERROR [MirrorRepositoryHook:thread-3] c.a.s.i.c.HazelcastBucketedExecutor Attempt 5 of 5 at processing bucket 'MirrorRepositoryHook@73:https://gitlab-playground.curvc.com/test/bitbucket-java-ex.git' for executor 'MirrorRepositoryHook' failed: com.atlassian.bitbucket.ServerException: An error occurred while executing an external process: Wrapping ProcessFailedException: 'git push --prune https://root:**********@gitlab-playground.curvc.com/test/bitbucket-java-ex.git --force --atomic +refs/heads/*:refs/heads/* +refs/tags/*:refs/tags/* +refs/notes/*:refs/notes/*' exited with code 1 at com.atlassian.bitbucket.scm.git.command.GitCommandExitHandler.evaluateThrowable(GitCommandExitHandler.java:163) at com.atlassian.bitbucket.scm.git.command.GitCommandExitHandler.onError(GitCommandExitHandler.java:297) at com.atlassian.bitbucket.scm.DefaultCommandExitHandler.onExit(DefaultCommandExitHandler.java:32) at com.englishtown.bitbucket.hook.PasswordHandler.onExit(PasswordHandler.java:50) at com.atlassian.stash.internal.scm.git.mesh.AbstractFragmentResponseObserver.callExitHandler(AbstractFragmentResponseObserver.java:180) at com.atlassian.stash.internal.scm.git.mesh.AbstractFragmentResponseObserver.asResult(AbstractFragmentResponseObserver.java:150) at com.atlassian.stash.internal.scm.git.mesh.BidirectionalFragmentResponseObserver.asResult(BidirectionalFragmentResponseObserver.java:66) at com.atlassian.stash.internal.scm.git.mesh.GrpcPlumbingClient.call(GrpcPlumbingClient.java:71) at jdk.internal.reflect.GeneratedMethodAccessor794.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at jdk.internal.reflect.GeneratedMethodAccessor187.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at jdk.proxy3/jdk.proxy3.$Proxy477.call(Unknown Source) at com.atlassian.stash.internal.scm.git.mesh.MeshGitFreeFormCommandBuilder$1.call(MeshGitFreeFormCommandBuilder.java:105) at com.englishtown.bitbucket.hook.MirrorBucketProcessor.runMirrorCommand(MirrorBucketProcessor.java:130) at com.englishtown.bitbucket.hook.MirrorBucketProcessor.lambda$process$0(MirrorBucketProcessor.java:80) at com.atlassian.stash.internal.user.DefaultEscalatedSecurityContext.call(DefaultEscalatedSecurityContext.java:59) at com.englishtown.bitbucket.hook.MirrorBucketProcessor.process(MirrorBucketProcessor.java:70) at com.atlassian.stash.internal.concurrent.HazelcastBucketedExecutor$BucketProcessingBootstrapper.run(HazelcastBucketedExecutor.java:146) at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) at java.base/java.lang.Thread.run(Thread.java:840) ... 15 frames trimmed Caused by: com.englishtown.bitbucket.hook.PasswordHandler$PasswordSafeException: Wrapping ProcessFailedException: 'git push --prune https://root:**********@gitlab-playground.curvc.com/test/bitbucket-java-ex.git --force --atomic +refs/heads/*:refs/heads/* +refs/tags/*:refs/tags/* +refs/notes/*:refs/notes/*' exited with code 1 at com.atlassian.stash.internal.scm.git.command.BioStdioHandler.onComplete(BioStdioHandler.java:92) at com.atlassian.stash.internal.scm.git.mesh.LatchedNioStdioHandler.onComplete(LatchedNioStdioHandler.java:61) at com.atlassian.stash.internal.scm.git.mesh.AbstractFragmentResponseObserver.maybeSummarize(AbstractFragmentResponseObserver.java:278) at com.atlassian.stash.internal.scm.git.mesh.AbstractFragmentResponseObserver.finish(AbstractFragmentResponseObserver.java:228) at com.atlassian.stash.internal.scm.git.mesh.AbstractFragmentResponseObserver.callOnExit(AbstractFragmentResponseObserver.java:200) at com.atlassian.stash.internal.scm.git.mesh.AbstractFragmentResponseObserver.onNext(AbstractFragmentResponseObserver.java:120) at com.atlassian.stash.internal.scm.git.mesh.AbstractFragmentResponseObserver.onNext(AbstractFragmentResponseObserver.java:41) at io.grpc.stub.ClientCalls$StreamObserverToCallListenerAdapter.onMessage(ClientCalls.java:468) at io.grpc.ForwardingClientCallListener.onMessage(ForwardingClientCallListener.java:33) at io.grpc.ForwardingClientCallListener.onMessage(ForwardingClientCallListener.java:33) at com.atlassian.stash.internal.scm.git.mesh.StatefulClientCallListener.onMessage(StatefulClientCallListener.java:45) at io.grpc.ForwardingClientCallListener.onMessage(ForwardingClientCallListener.java:33) at com.atlassian.stash.internal.scm.git.mesh.DeadlinePropagatingClientInterceptor$DeadlinePropagatingListener.onMessage(DeadlinePropagatingClientInterceptor.java:169) at io.grpc.ForwardingClientCallListener.onMessage(ForwardingClientCallListener.java:33) at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1MessagesAvailable.runInternal(ClientCallImpl.java:667) at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1MessagesAvailable.runInContext(ClientCallImpl.java:654) at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37) at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:133) ... 3 common frames omitted