Bitbucket Server 8.0 Early Access Program (EAP) release

Thanks @rlander - after upgrading local git version to 2.35 atlas-debug works out of the box!

@khughes @bturner

[UPDATE: Once the escalated permission is REPO_READ the code retrieves correct build results, :see_no_evil: ]

I see the access denied when accessing build results as LICENSED USER

[INFO] 2022-04-11 15:38:34,190 DEBUG [threadpool:thread-15]  c.a.s.i.c.StateTransferringCallable Error while processing asynchronous task
[INFO] com.atlassian.bitbucket.AuthorisationException: You are not permitted to access this resource
[INFO] 	at com.atlassian.stash.internal.aop.ExceptionRewriteAdvice.afterThrowing(ExceptionRewriteAdvice.java:37)
[INFO] 	at com.atlassian.bitbucket.internal.build.status.DefaultBuildStatusService.validateSearchRequest(DefaultBuildStatusService.java:614)
[INFO] 	at com.atlassian.bitbucket.internal.build.status.DefaultBuildStatusService.searchInternal(DefaultBuildStatusService.java:353)
[INFO] 	at com.atlassian.bitbucket.internal.build.status.DefaultBuildStatusService.search(DefaultBuildStatusService.java:322)
[INFO] 	at com.atlassian.plugin.util.ContextClassLoaderSettingInvocationHandler.invoke(ContextClassLoaderSettingInvocationHandler.java:26)
[INFO] 	at org.eclipse.gemini.blueprint.service.importer.support.internal.aop.ServiceInvoker.doInvoke(ServiceInvoker.java:56)
[INFO] 	at org.eclipse.gemini.blueprint.service.importer.support.internal.aop.ServiceInvoker.invoke(ServiceInvoker.java:60)
[INFO] 	at org.eclipse.gemini.blueprint.service.util.internal.aop.ServiceTCCLInterceptor.invokeUnprivileged(ServiceTCCLInterceptor.java:70)
[INFO] 	at org.eclipse.gemini.blueprint.service.util.internal.aop.ServiceTCCLInterceptor.invoke(ServiceTCCLInterceptor.java:53)
[INFO] 	at org.eclipse.gemini.blueprint.service.importer.support.LocalBundleContextAdvice.invoke(LocalBundleContextAdvice.java:57)
[INFO] 	at com.izymes.workzone.listener.BuildEventListener$1.perform(BuildEventListener.java:179)
[INFO] 	at com.izymes.workzone.listener.BuildEventListener$1.perform(BuildEventListener.java:170)
[INFO] 	at com.atlassian.stash.internal.user.DefaultEscalatedSecurityContext.call(DefaultEscalatedSecurityContext.java:59)

Workzone code looks like

UncheckedOperation<Page<RepositoryBuildStatus>> op = () -> {
  final Page<RepositoryBuildStatus> buildStatusPage = 
    repositoryBuildStatusService.search(searchRequest,
          new PageRequestImpl(0, 256));
}
securityService.withPermission(
Permission.LICENSED_USER, 
"Escalated permission for anonymous 2LO"
).call(op)

This used to work in 7.x

See also [BSERV-12101] PullRequestService.searchByCommit should require same permission as PullRequestService.search - Create and track feature requests for Atlassian products. for a similar issue in the past.

Workzone scans build results in a scheduled job context, without an authenticated user. It needs to be able to search for build status in this context.

@bturner, thank you for your answer!

Submodule Changes for Bitbucket uses requests from the Bitbucket frontend to trigger submodule diff calculation.

There is a difference between URL composing to get changes in the sources of Bitbucket 8.0.0-eap05.
For commit changes diff plugins/frontend/src/feature/commit/commit-changes/commit-changes.jsx:47:

const changesUrlBuilder = useMemo(
    () =>
        nav
            .rest()
            .repository(repository)
            .commits()
            .addPathComponents(commit.id, 'changes')
            .withDefinedParams({ since: activeParent && activeParent.id }),
    [repository, commit.id, activeParent]
);

For pull request changes diff plugins/frontend/src/feature/pull-request/pull-request-changes/pull-request-changes.jsx:15:

const urlBuilder = useMemo(() => {
    let builder = nav.rest().pullRequest(pullRequest).changes().withParams({
        avatarSize: AvatarSize.DEFAULT,
        markup: true,
    });

    if (commit) {
        const sinceId = sinceCommitId ? sinceCommitId : get(commit, 'parents.0.id');

        builder = builder.withParams({
            changeScope: 'RANGE',
            untilId: commit.id,
            sinceId,
        });
    }

    return builder;
}, [commit, sinceCommitId, pullRequest]);

For branch compare changes diff plugins/frontend/src/feature/compare/compare-changes/compare-changes.jsx:17

const changesUrlBuilder = useMemo(
    () =>
        nav.repository(targetRepo).compare().changes().withDefinedParams({
            to: targetRef.latestCommit,
            fromRepo: sourceRepo.id,
            from: sourceRef.latestCommit,
        }),
    [targetRepo, targetRef, sourceRepo, sourceRef]
);

There is no .rest() part in the branch compare changes diff.

Is it possible to standardize all the places where Bitbucket composes changes diff URL and add the .rest() part to the branch compare changes diff URL forming code?

1 Like

@YuriKarnilaev,

It’s not a part of the product I work with. The URLs likely aren’t standardized because for how the app works they don’t need to be. The request without rest() will still end up hitting the /rest/api/1.0 URL because the Accept: application/json rewrite on the server-side will send it there, so the UI logic all ends up working as expected.

I’ll forward this comment to a few people internally who actually worked on the changes to the commit and compare diffs (updating them to use the pull request React code) and they’ll say what they say.

Best regards,
Bryan Turner
Atlassian Bitbucket

@UlrichKuhnhardtIzym1,

I’m not across any changes to the build status logic. Kristy is out on leave, but I’ll forward your question internally to some folks who have worked in that area. Hopefully one of them can reply.

One thing your question doesn’t show is what searchRequest's type is; search has two overloads, one for BuildStatusRepositorySearchRequest and one for BuildStatusPullRequestSearchRequest.

With that said, I wouldn’t expect LICENSED_USER to have ever been enough here. The RepositoryBuildStatusResource that exposes this over REST escalates to REPO_READ for anonymous 2LO, for example. I suspect the answer is going to end up being that REPO_READ is what your app should be using (and likely should always have been using), but we’ll see what they say.

Best regards,
Bryan Turner
Atlassian Bitbucket

1 Like

@khughes , @bturner - here is the snippet how we build the search request.

      final String latestCommit = pullRequest.getFromRef().getLatestCommit();
      BuildStatusPullRequestSearchRequest searchRequest = new BuildStatusPullRequestSearchRequest
          .Builder(pullRequest)
          .commitId(latestCommit)
          .buildOrder(BuildOrder.NEWEST)
          .build();

For this particular case it will work with or without .rest() , there is no reason why not to explicitly use the .rest() , I agree it will be better to standardize it since it is only doing a request to the API to get the changes and we could explicitly show that from the code, improving the code readability, by not using .rest() it leaves some room for interpretation, like thinking the URL could be use for some other reasons like linking to another FE page.

Some weeks ago I worked on the navbuilder library that generates that URL and we removed a lot of its deprecated functionality, I will create ticket to apply this fix, and do some work on finding other places it is used in different ways.

This issue will be fixed with 8.0

2 Likes

Is the source code available for the Bitbucket 8 EAP for vendors?
It would help as a lot in the transition to CSE for the PR create page changes.
For instances what are the required arguments for setReviewers for the Extension point: bitbucket.ui.create.pullrequest.form
?

Thanks.

1 Like

Hi @UlrichKuhnhardtIzym1,

This used to work in 7.x

Can you confirm for which version of 7.x this code worked? As far as I can see all requests through RepositoryBuildStatusService#search, regardless of which method overload is used, pass through this validation requiring REPO_READ permissions:

    private void validateSearchRequest(AbstractBuildStatusSearchRequest request) {
        requireNonNull(request);
        permissionValidationService.validateForRepository(request.getRepository(), Permission.REPO_READ);
    }

    private void validateSummaryRequest(AbstractBuildStatusSummaryRequest request) {
        requireNonNull(request);
        permissionValidationService.validateForRepository(request.getRepository(), Permission.REPO_READ);
    }

Could it be possible that you were previously using LegacyBuildStatusService#findAll, as this method for searching for builds only required Permission.LICENSED_USER, as these older builds were not scoped to a repository.

Kind regards,
Eli Salter
Atlassian Bitbucket

Hey @khughes

When can we expect Bitbucket 8 to be released? How far away is it roughly?

Cheers!

Reece

2 Likes

:star_struck: 2 weeks :star_struck:

1 Like

Do you have access to a crystal ball that I do not have access to @UlrichKuhnhardtIzym1 ? :wink:

1 Like

I’m trying to follow this instruction to setup Bitbucket Mesh. But the link for Bitbucket Mesh leads to Bitbucket 8.0.0 eap05 and when I download and unpack it, it doesn’t have

<installation-directory>/bin/set-mesh-home.sh

file as the instruction suggests.

Neither does it contain MESH_HOME variable (I’m running recursive ‘grep’ through the <installation-directory>). How can I setup Mesh to make sure our app works with it correctly?

I’d also like to report an issue: we’re using GitCommandBuilderFactory to run a lot of Git commands pretty often, we implement our own CommandExitHandler but often (though not predictably) CommandExitHandler#onExit is executed with exitCode=-1001 and the following throwable:

UNKNOWN io.grpc.StatusRuntimeException: UNKNOWN
	at io.grpc.Status.asRuntimeException(Status.java:535)
	at io.grpc.stub.ClientCalls$StreamObserverToCallListenerAdapter.onClose(ClientCalls.java:479)
	at io.grpc.PartialForwardingClientCallListener.onClose(PartialForwardingClientCallListener.java:39)
	at io.grpc.ForwardingClientCallListener.onClose(ForwardingClientCallListener.java:23)
	at io.grpc.ForwardingClientCallListener$SimpleForwardingClientCallListener.onClose(ForwardingClientCallListener.java:40)
	at com.atlassian.stash.internal.scm.git.mesh.LastSeenClientInterceptor$LastSeenClientListener.onClose(LastSeenClientInterceptor.java:40)
	at io.grpc.PartialForwardingClientCallListener.onClose(PartialForwardingClientCallListener.java:39)
	at io.grpc.ForwardingClientCallListener.onClose(ForwardingClientCallListener.java:23)
	at io.grpc.ForwardingClientCallListener$SimpleForwardingClientCallListener.onClose(ForwardingClientCallListener.java:40)
	at com.atlassian.stash.internal.scm.git.mesh.StatefulClientCallListener.onClose(StatefulClientCallListener.java:34)
	at io.grpc.PartialForwardingClientCallListener.onClose(PartialForwardingClientCallListener.java:39)
	at io.grpc.ForwardingClientCallListener.onClose(ForwardingClientCallListener.java:23)
	at io.grpc.ForwardingClientCallListener$SimpleForwardingClientCallListener.onClose(ForwardingClientCallListener.java:40)
	at com.atlassian.stash.internal.scm.git.mesh.DeadlinePropagatingClientInterceptor$DeadlinePropagatingListener.onClose(DeadlinePropagatingClientInterceptor.java:156)
	at com.atlassian.stash.internal.scm.git.mesh.ErrorHandlingClientInterceptor$ErrorHandlingCall$1.onClose(ErrorHandlingClientInterceptor.java:136)
	at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:562)
	at io.grpc.internal.ClientCallImpl.access$300(ClientCallImpl.java:70)
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInternal(ClientCallImpl.java:743)
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:722)
	at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
	at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:133)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:829)

I would note that this happens more often when we run more Git commands. The main log has a corresponding exception:

2022-05-10 21:15:01,754 WARN  [mesh-grpc-request:thread-79]  c.a.s.i.s.g.m.DefaultMeshSidebandRegistry sidecar (http://localhost:7777): Reopening sideband channel failed
io.grpc.StatusRuntimeException: UNKNOWN: Uncaught exception in the SynchronizationContext. Re-thrown.
	at io.grpc.Status.asRuntimeException(Status.java:526)
	at io.grpc.internal.RetriableStream$1.uncaughtException(RetriableStream.java:75)
	at io.grpc.SynchronizationContext.drain(SynchronizationContext.java:97)
	at io.grpc.SynchronizationContext.execute(SynchronizationContext.java:127)
	at io.grpc.internal.RetriableStream.drain(RetriableStream.java:328)
	at io.grpc.internal.RetriableStream.start(RetriableStream.java:387)
	at io.grpc.internal.ClientCallImpl.startInternal(ClientCallImpl.java:289)
	at io.grpc.internal.ClientCallImpl.start(ClientCallImpl.java:191)
	at com.atlassian.stash.internal.scm.git.mesh.ErrorHandlingClientInterceptor$ErrorHandlingCall.start(ErrorHandlingClientInterceptor.java:122)
	at io.grpc.ForwardingClientCall.start(ForwardingClientCall.java:32)
	at com.atlassian.stash.internal.scm.git.mesh.MetadataClientInterceptor$1.start(MetadataClientInterceptor.java:43)
	at com.atlassian.stash.internal.scm.git.mesh.StateTransferringClientInterceptor$1.start(StateTransferringClientInterceptor.java:36)
	at com.atlassian.stash.internal.scm.git.mesh.LastSeenClientInterceptor$1.start(LastSeenClientInterceptor.java:23)
	at io.grpc.stub.ClientCalls.startCall(ClientCalls.java:332)
	at io.grpc.stub.ClientCalls.asyncStreamingRequestCall(ClientCalls.java:323)
	at io.grpc.stub.ClientCalls.asyncBidiStreamingCall(ClientCalls.java:111)
	at com.atlassian.bitbucket.mesh.rpc.v1.ManagementServiceGrpc$ManagementServiceStub.sideband(ManagementServiceGrpc.java:808)
	at com.atlassian.stash.internal.scm.git.mesh.DefaultMeshSidebandRegistry$SidebandChannel.reopen(DefaultMeshSidebandRegistry.java:255)
	at com.atlassian.stash.internal.scm.git.mesh.DefaultMeshSidebandRegistry$SidebandChannel.onCompleted(DefaultMeshSidebandRegistry.java:149)
	at io.grpc.stub.ClientCalls$StreamObserverToCallListenerAdapter.onClose(ClientCalls.java:477)
	at io.grpc.PartialForwardingClientCallListener.onClose(PartialForwardingClientCallListener.java:39)
	at io.grpc.ForwardingClientCallListener.onClose(ForwardingClientCallListener.java:23)
	at io.grpc.ForwardingClientCallListener$SimpleForwardingClientCallListener.onClose(ForwardingClientCallListener.java:40)
	at com.atlassian.stash.internal.scm.git.mesh.LastSeenClientInterceptor$LastSeenClientListener.onClose(LastSeenClientInterceptor.java:40)
	at io.grpc.PartialForwardingClientCallListener.onClose(PartialForwardingClientCallListener.java:39)
	at io.grpc.ForwardingClientCallListener.onClose(ForwardingClientCallListener.java:23)
	at io.grpc.ForwardingClientCallListener$SimpleForwardingClientCallListener.onClose(ForwardingClientCallListener.java:40)
	at com.atlassian.stash.internal.scm.git.mesh.StatefulClientCallListener.onClose(StatefulClientCallListener.java:34)
	at com.atlassian.stash.internal.scm.git.mesh.ErrorHandlingClientInterceptor$ErrorHandlingCall$1.onClose(ErrorHandlingClientInterceptor.java:136)
	at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:562)
	at io.grpc.internal.ClientCallImpl.access$300(ClientCallImpl.java:70)
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInternal(ClientCallImpl.java:743)
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:722)
	at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
	at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:133)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.lang.Thread.run(Thread.java:829)
	... 1 frame trimmed
Caused by: java.util.concurrent.RejectedExecutionException: Task io.grpc.internal.SerializingExecutor@67c47830 rejected from java.util.concurrent.ThreadPoolExecutor@54917e81[Shutting down, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 2833]
	at java.base/java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2055)
	at java.base/java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:825)
	at java.base/java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1355)
	at io.grpc.internal.SerializingExecutor.schedule(SerializingExecutor.java:102)
	at io.grpc.internal.SerializingExecutor.execute(SerializingExecutor.java:95)
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.onReady(ClientCallImpl.java:793)
	at io.grpc.internal.RetriableStream$3.run(RetriableStream.java:288)
	at io.grpc.SynchronizationContext.drain(SynchronizationContext.java:95)
	... 35 common frames omitted

This never happened with the previous Bitbucket versions. It seems like the thread pool is too small and the policy is to reject execution if there’re no free thread. Could this be fixed on Bitbucket side? Or is there an option for that?

Our app runs a lot of Git commands and sometimes we encounter into the following error:


2022-05-10 21:15:01,754 WARN  [mesh-grpc-request:thread-79]  c.a.s.i.s.g.m.DefaultMeshSidebandRegistry sidecar (http://localhost:7777): Reopening sideband channel failed
io.grpc.StatusRuntimeException: UNKNOWN: Uncaught exception in the SynchronizationContext. Re-thrown.
	at io.grpc.Status.asRuntimeException(Status.java:526)
	at io.grpc.internal.RetriableStream$1.uncaughtException(RetriableStream.java:75)
	at io.grpc.SynchronizationContext.drain(SynchronizationContext.java:97)
	at io.grpc.SynchronizationContext.execute(SynchronizationContext.java:127)
	at io.grpc.internal.RetriableStream.drain(RetriableStream.java:328)
	at io.grpc.internal.RetriableStream.start(RetriableStream.java:387)
	at io.grpc.internal.ClientCallImpl.startInternal(ClientCallImpl.java:289)
	at io.grpc.internal.ClientCallImpl.start(ClientCallImpl.java:191)
	at com.atlassian.stash.internal.scm.git.mesh.ErrorHandlingClientInterceptor$ErrorHandlingCall.start(ErrorHandlingClientInterceptor.java:122)
	at io.grpc.ForwardingClientCall.start(ForwardingClientCall.java:32)
	at com.atlassian.stash.internal.scm.git.mesh.MetadataClientInterceptor$1.start(MetadataClientInterceptor.java:43)
	at com.atlassian.stash.internal.scm.git.mesh.StateTransferringClientInterceptor$1.start(StateTransferringClientInterceptor.java:36)
	at com.atlassian.stash.internal.scm.git.mesh.LastSeenClientInterceptor$1.start(LastSeenClientInterceptor.java:23)
	at io.grpc.stub.ClientCalls.startCall(ClientCalls.java:332)
	at io.grpc.stub.ClientCalls.asyncStreamingRequestCall(ClientCalls.java:323)
	at io.grpc.stub.ClientCalls.asyncBidiStreamingCall(ClientCalls.java:111)
	at com.atlassian.bitbucket.mesh.rpc.v1.ManagementServiceGrpc$ManagementServiceStub.sideband(ManagementServiceGrpc.java:808)
	at com.atlassian.stash.internal.scm.git.mesh.DefaultMeshSidebandRegistry$SidebandChannel.reopen(DefaultMeshSidebandRegistry.java:255)
	at com.atlassian.stash.internal.scm.git.mesh.DefaultMeshSidebandRegistry$SidebandChannel.onCompleted(DefaultMeshSidebandRegistry.java:149)
	at io.grpc.stub.ClientCalls$StreamObserverToCallListenerAdapter.onClose(ClientCalls.java:477)
	at io.grpc.PartialForwardingClientCallListener.onClose(PartialForwardingClientCallListener.java:39)
	at io.grpc.ForwardingClientCallListener.onClose(ForwardingClientCallListener.java:23)
	at io.grpc.ForwardingClientCallListener$SimpleForwardingClientCallListener.onClose(ForwardingClientCallListener.java:40)
	at com.atlassian.stash.internal.scm.git.mesh.LastSeenClientInterceptor$LastSeenClientListener.onClose(LastSeenClientInterceptor.java:40)
	at io.grpc.PartialForwardingClientCallListener.onClose(PartialForwardingClientCallListener.java:39)
	at io.grpc.ForwardingClientCallListener.onClose(ForwardingClientCallListener.java:23)
	at io.grpc.ForwardingClientCallListener$SimpleForwardingClientCallListener.onClose(ForwardingClientCallListener.java:40)
	at com.atlassian.stash.internal.scm.git.mesh.StatefulClientCallListener.onClose(StatefulClientCallListener.java:34)
	at com.atlassian.stash.internal.scm.git.mesh.ErrorHandlingClientInterceptor$ErrorHandlingCall$1.onClose(ErrorHandlingClientInterceptor.java:136)
	at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:562)
	at io.grpc.internal.ClientCallImpl.access$300(ClientCallImpl.java:70)
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInternal(ClientCallImpl.java:743)
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:722)
	at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
	at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:133)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.lang.Thread.run(Thread.java:829)
	... 1 frame trimmed
Caused by: java.util.concurrent.RejectedExecutionException: Task io.grpc.internal.SerializingExecutor@67c47830 rejected from java.util.concurrent.ThreadPoolExecutor@54917e81[Shutting down, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 2833]
	at java.base/java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2055)
	at java.base/java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:825)
	at java.base/java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1355)
	at io.grpc.internal.SerializingExecutor.schedule(SerializingExecutor.java:102)
	at io.grpc.internal.SerializingExecutor.execute(SerializingExecutor.java:95)
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.onReady(ClientCallImpl.java:793)
	at io.grpc.internal.RetriableStream$3.run(RetriableStream.java:288)
	at io.grpc.SynchronizationContext.drain(SynchronizationContext.java:95)
	... 35 common frames omitted

It looks like the relevant thread pool becomes depleted and the policy is to reject execution of Git commands upon depletion. This never happened with older Bitbucket versions. Is there any way to solve that problem at Bitbucket level (maybe change the policy or make the thread pool grow)?

1 Like

In case it’s helpful to anyone, we were able to use AbstractCommandInputOutputHandler, from the dependency @RomanStoffel mentioned (com.atlassian.bitbucket.server/bitbucket-scm-common) to replace CommandOutputHandler with very minimal effort. We simply override its latching functionality with our own process() method(s), and throw an UnsupportedOperationException for any that we don’t use.

1 Like

There seem to be a number of regressions related to command handlers. Noting the following two issues we found, in case anyone else is running into them:

A follow-up on my previous post – we found & filed another Bitbucket 8 command handling bug. I started a new thread for awareness: Bitbucket 8 serious regressions with command handling (the mesh sidecar)

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.