MCPcopy Index your code
hub / github.com/bytebase/bytebase / CreateIssue

Method CreateIssue

backend/api/v1/issue_service.go:382–432  ·  view source on GitHub ↗

CreateIssue creates a issue.

(ctx context.Context, req *connect.Request[v1pb.CreateIssueRequest])

Source from the content-addressed store, hash-verified

380
381// CreateIssue creates a issue.
382func (s *IssueService) CreateIssue(ctx context.Context, req *connect.Request[v1pb.CreateIssueRequest]) (*connect.Response[v1pb.Issue], error) {
383 projectID, err := common.GetProjectID(req.Msg.Parent)
384 if err != nil {
385 return nil, connect.NewError(connect.CodeInvalidArgument, errors.Errorf("%v", err.Error()))
386 }
387 project, err := s.store.GetProject(ctx, &store.FindProjectMessage{
388 Workspace: common.GetWorkspaceIDFromContext(ctx),
389 ResourceID: &projectID,
390 })
391 if err != nil {
392 return nil, connect.NewError(connect.CodeInternal, errors.Wrapf(err, "failed to get project"))
393 }
394 if project == nil {
395 return nil, connect.NewError(connect.CodeNotFound, errors.Errorf("project not found for id: %v", projectID))
396 }
397
398 issueLabels := store.CanonicalizeIssueLabels(req.Msg.Issue.Labels)
399 if project.Setting.ForceIssueLabels && len(issueLabels) == 0 {
400 return nil, connect.NewError(connect.CodeInvalidArgument, errors.Errorf("require issue labels"))
401 }
402
403 // enforceIssueTitle is enforced on CreatePlan (plan.Name is gated there). Issues
404 // with empty Title inherit plan.Name via buildIssueMessage; ROLE_GRANT issues
405 // have their own title-required check below. No gate needed here.
406
407 user, ok := GetUserFromContext(ctx)
408 if !ok {
409 return nil, connect.NewError(connect.CodeInternal, errors.Errorf("user not found"))
410 }
411
412 issue, err := s.buildIssueMessage(ctx, project, user.Email, req.Msg, issueLabels)
413 if err != nil {
414 return nil, err
415 }
416 issue, err = s.store.CreateIssue(ctx, issue)
417 if err != nil {
418 return nil, connect.NewError(connect.CodeInternal, errors.Wrapf(err, "failed to create issue"))
419 }
420
421 issue, err = postCreateIssue(ctx, s.store, s.webhookManager, s.licenseService, s.bus, project, user.Name, user.Email, issue)
422 if err != nil {
423 return nil, connect.NewError(connect.CodeInternal, err)
424 }
425
426 converted, err := s.convertToIssue(issue)
427 if err != nil {
428 return nil, connect.NewError(connect.CodeInternal, errors.Wrapf(err, "failed to convert to issue"))
429 }
430
431 return connect.NewResponse(converted), nil
432}
433
434func (s *IssueService) buildIssueMessage(ctx context.Context, project *store.ProjectMessage, userEmail string, request *v1pb.CreateIssueRequest, labels []string) (*store.IssueMessage, error) {
435 var planUID *int64

Callers 1

UpdateIssueMethod · 0.95

Calls 11

buildIssueMessageMethod · 0.95
convertToIssueMethod · 0.95
GetProjectIDFunction · 0.92
CanonicalizeIssueLabelsFunction · 0.92
GetUserFromContextFunction · 0.85
postCreateIssueFunction · 0.85
ErrorfMethod · 0.80
GetProjectMethod · 0.65
CreateIssueMethod · 0.65
ErrorMethod · 0.45

Tested by

no test coverage detected