< Summary - go-semantic-release Coverage

Line coverage
100%
Covered lines: 52
Uncovered lines: 0
Coverable lines: 52
Total lines: 138
Line coverage: 100%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
Name0%00100%
VerifyConditions0%00100%
Publish0%00100%

File(s)

/home/runner/work/go-semantic-release/go-semantic-release/internal/adapters/plugins/git_plugin.go

#LineLine coverage
 1package plugins
 2
 3import (
 4  "bytes"
 5  "context"
 6  "fmt"
 7  "text/template"
 8
 9  "github.com/jedi-knights/go-semantic-release/internal/domain"
 10  "github.com/jedi-knights/go-semantic-release/internal/ports"
 11)
 12
 13// Compile-time interface compliance checks.
 14var (
 15  _ ports.Plugin                 = (*GitPlugin)(nil)
 16  _ ports.VerifyConditionsPlugin = (*GitPlugin)(nil)
 17  _ ports.PublishPlugin          = (*GitPlugin)(nil)
 18)
 19
 20// GitPlugin handles git operations: verifyConditions (git access), publish (stage → commit → push → tag).
 21type GitPlugin struct {
 22  git        ports.GitRepository
 23  tagService ports.TagService
 24  fs         ports.FileSystem
 25  logger     ports.Logger
 26  identity   domain.GitIdentity
 27  gitConfig  domain.GitConfig
 28}
 29
 30// NewGitPlugin creates the built-in git plugin.
 31func NewGitPlugin(
 32  git ports.GitRepository,
 33  tagService ports.TagService,
 34  fs ports.FileSystem,
 35  logger ports.Logger,
 36  identity domain.GitIdentity,
 37  gitConfig domain.GitConfig,
 38) *GitPlugin {
 39  return &GitPlugin{
 40    git:        git,
 41    tagService: tagService,
 42    fs:         fs,
 43    logger:     logger,
 44    identity:   identity,
 45    gitConfig:  gitConfig,
 46  }
 47}
 48
 149func (p *GitPlugin) Name() string { return "git" }
 50
 251func (p *GitPlugin) VerifyConditions(ctx context.Context, rc *domain.ReleaseContext) error {
 252  _, err := p.git.CurrentBranch(ctx)
 153  if err != nil {
 154    return fmt.Errorf("unable to access git repository: %w", err)
 155  }
 156  return nil
 57}
 58
 1259func (p *GitPlugin) Publish(ctx context.Context, rc *domain.ReleaseContext) (*domain.ProjectReleaseResult, error) {
 160  if rc.CurrentProject == nil {
 161    return nil, nil
 162  }
 63
 1164  tagName, err := p.tagService.FormatTag(rc.CurrentProject.Project.Name, rc.CurrentProject.NextVersion)
 165  if err != nil {
 166    return nil, fmt.Errorf("formatting tag: %w", err)
 167  }
 1068  rc.TagName = tagName
 1069
 1070  // Stage and commit release assets before tagging so the tag points to the release commit.
 571  if len(p.gitConfig.Assets) > 0 {
 172    if err = p.git.Stage(ctx, p.gitConfig.Assets); err != nil {
 173      return nil, fmt.Errorf("staging release assets: %w", err)
 174    }
 475    commitMsg := renderCommitMessage(p.gitConfig.Message, tagName, rc.CurrentProject.NextVersion, rc.Notes)
 176    if err = p.git.Commit(ctx, commitMsg); err != nil {
 177      return nil, fmt.Errorf("committing release assets: %w", err)
 178    }
 179    if err = p.git.Push(ctx); err != nil {
 180      return nil, fmt.Errorf("pushing release branch: %w", err)
 181    }
 82  }
 83
 784  headHash, err := p.git.HeadHash(ctx)
 185  if err != nil {
 186    return nil, fmt.Errorf("getting HEAD hash: %w", err)
 187  }
 88
 689  tagMessage := fmt.Sprintf("chore(release): %s", tagName)
 290  if rc.Notes != "" {
 291    tagMessage = rc.Notes
 292  }
 93
 194  if err := p.git.CreateTag(ctx, tagName, headHash, tagMessage); err != nil {
 195    return nil, fmt.Errorf("creating tag %s: %w", tagName, err)
 196  }
 97
 198  if err := p.git.PushTag(ctx, tagName); err != nil {
 199    return nil, fmt.Errorf("pushing tag %s: %w", tagName, err)
 1100  }
 101
 4102  p.logger.Info("created and pushed tag", "tag", tagName)
 4103
 4104  return &domain.ProjectReleaseResult{
 4105    Project:    rc.CurrentProject.Project,
 4106    Version:    rc.CurrentProject.NextVersion,
 4107    TagName:    tagName,
 4108    TagCreated: true,
 4109    Changelog:  rc.Notes,
 4110  }, nil
 111}
 112
 113// renderCommitMessage renders the commit message template with release data.
 114// Supports {{.Version}}, {{.Tag}}, and {{.Notes}} placeholders.
 115// Falls back to "chore(release): {tagName}" on empty template or render error.
 116func renderCommitMessage(tmpl, tagName string, version domain.Version, notes string) string {
 117  if tmpl == "" {
 118    return fmt.Sprintf("chore(release): %s", tagName)
 119  }
 120  data := struct {
 121    Version string
 122    Tag     string
 123    Notes   string
 124  }{
 125    Version: version.String(),
 126    Tag:     tagName,
 127    Notes:   notes,
 128  }
 129  t, err := template.New("").Parse(tmpl)
 130  if err != nil {
 131    return fmt.Sprintf("chore(release): %s", tagName)
 132  }
 133  var buf bytes.Buffer
 134  if err := t.Execute(&buf, data); err != nil {
 135    return fmt.Sprintf("chore(release): %s", tagName)
 136  }
 137  return buf.String()
 138}

Methods/Properties

Name
VerifyConditions
Publish