github.com/twelho/conform@v0.0.0-20231016230407-c25e9238598a/cmd/conform/enforce.go (about)

     1  // This Source Code Form is subject to the terms of the Mozilla Public
     2  // License, v. 2.0. If a copy of the MPL was not distributed with this
     3  // file, You can obtain one at http://mozilla.org/MPL/2.0/.
     4  
     5  package main
     6  
     7  import (
     8  	"errors"
     9  	"fmt"
    10  
    11  	git "github.com/go-git/go-git/v5"
    12  	"github.com/spf13/cobra"
    13  
    14  	"github.com/twelho/conform/internal/enforcer"
    15  	"github.com/twelho/conform/internal/policy"
    16  )
    17  
    18  // enforceCmd represents the enforce command.
    19  var enforceCmd = &cobra.Command{
    20  	Use:   "enforce",
    21  	Short: "",
    22  	Long:  ``,
    23  	RunE: func(cmd *cobra.Command, args []string) error {
    24  		if len(args) != 0 {
    25  			return errors.New("the enforce command does not take arguments")
    26  		}
    27  		// Done validating the arguments, do not print usage for errors
    28  		// after this point
    29  		cmd.SilenceUsage = true
    30  
    31  		reporter := cmd.Flags().Lookup("reporter").Value.String()
    32  		e, err := enforcer.New(reporter)
    33  		if err != nil {
    34  			return fmt.Errorf("failed to create enforcer: %w", err)
    35  		}
    36  
    37  		opts := []policy.Option{}
    38  
    39  		if commitMsgFile := cmd.Flags().Lookup("commit-msg-file").Value.String(); commitMsgFile != "" {
    40  			opts = append(opts, policy.WithCommitMsgFile(&commitMsgFile))
    41  		}
    42  
    43  		if commitRef := cmd.Flags().Lookup("commit-ref").Value.String(); commitRef != "" {
    44  			opts = append(opts, policy.WithCommitRef(commitRef))
    45  		} else {
    46  			mainBranch, err := detectMainBranch()
    47  			if err != nil {
    48  				return fmt.Errorf("failed to detect main branch: %w", err)
    49  			}
    50  			if mainBranch != "" {
    51  				opts = append(opts, policy.WithCommitRef(fmt.Sprintf("refs/heads/%s", mainBranch)))
    52  			}
    53  		}
    54  
    55  		if baseBranch := cmd.Flags().Lookup("base-branch").Value.String(); baseBranch != "" {
    56  			opts = append(opts, policy.WithRevisionRange(fmt.Sprintf("%s..HEAD", baseBranch)))
    57  		} else if revisionRange := cmd.Flags().Lookup("revision-range").Value.String(); revisionRange != "" {
    58  			opts = append(opts, policy.WithRevisionRange(revisionRange))
    59  		}
    60  
    61  		return e.Enforce(opts...)
    62  	},
    63  }
    64  
    65  func init() {
    66  	enforceCmd.Flags().String("commit-msg-file", "", "the path to the temporary commit message file")
    67  	enforceCmd.Flags().String("commit-ref", "", "the ref to compare git policies against")
    68  	enforceCmd.Flags().String("reporter", "none", "the reporter method to use")
    69  	enforceCmd.Flags().String("revision-range", "", "<commit1>..<commit2>")
    70  	enforceCmd.Flags().String("base-branch", "", "base branch to compare with")
    71  	rootCmd.AddCommand(enforceCmd)
    72  }
    73  
    74  func detectMainBranch() (string, error) {
    75  	mainBranch := "main"
    76  
    77  	repo, err := git.PlainOpen(".")
    78  	if err != nil {
    79  		// not a git repo, ignore
    80  		return "", nil //nolint:nilerr
    81  	}
    82  
    83  	c, err := repo.Config()
    84  	if err != nil {
    85  		return "", fmt.Errorf("failed to get repository configuration: %w", err)
    86  	}
    87  
    88  	rawConfig := c.Raw
    89  
    90  	const branchSectionName = "branch"
    91  
    92  	branchSection := rawConfig.Section(branchSectionName)
    93  	for _, b := range branchSection.Subsections {
    94  		remote := b.Option("remote")
    95  		if remote == git.DefaultRemoteName {
    96  			mainBranch = b.Name
    97  
    98  			break
    99  		}
   100  	}
   101  
   102  	return mainBranch, nil
   103  }