Skip to content

A CLI tool for developers following Git Flow and Conventional Commits

License

Notifications You must be signed in to change notification settings

KaueSabinoSRV17/Flower

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

52 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Flower 🌻

A CLI tool made to help developers using Git Flow and Conventional Commits.

How to Install

Currently, it can be Installed via:

Brew

brew install KaueSabinoSRV17/homebrew-flower/flower

Linux Binary

wget https://github.com/KaueSabinoSRV17/Flower/releases/download/1.0.6/Flower_1.0.6_linux_amd64.tar.gz
tar -xzf Flower_1.0.6_linux_amd64.tar.gz
mv ./flow /usr/local/bin/flow
rm Flower_1.0.6_linux_amd64.tar.gz

How to Use

Currently, it has only the commit command:

flow commit

It will ask you what files you are going to add to git, what is going to be the Conventional Commit prefix and the Commit Message. After that, you can run git log to validate the commit.

Contribuitions

Project Structure

The Structure can and probaly should be changed, it would be very welcome some advices on how to organize the files and folders properly, since i come from Typescript Development.

.github directory

Where we store yaml files for the ci/cd runs in Github Actions. Currently, i use goreleaser to automate the publishing to brew.

Release Pipeline

The Pipeline is triggered when a new tag (version) is pushed follows these steps:

  • Checkouts the project code:
name: Checkout
uses: actions/checkout@v2
with:
  fetch-depth: 0
  • Installs Go:
name: Set up Go
uses: actions/setup-go@v2
with:
  go-version: 1.20.3
  • Runs go mod vendor, due to some errors without it:
name: Run Mod Vendor
run: go mod vendor
  • Installs and Runs goreleaser --clean (without --clean did not work). It uses the pushed tag as the version and a github token to publish to the homebrew repo:
name: Run GoReleaser
uses: goreleaser/goreleaser-action@v2
with:
  distribution: goreleaser
  version: ${{ env.GITHUB_REF_NAME }}
  args: release --clean
env:
  GITHUB_TOKEN: ${{ secrets.RELEASER_TOKEN }}

cmd directory

Where we store Go files generated by Cobra. They add the functionality of a CLI to the business logic inside use_cases.

Commit Command

The Commit Commandcan be called without any arguments, and that is actually the main Use Case. It is configured in the commit.go file, inside the cmd directory. The function inside the Run Attribute of the Cobra Command is the following:

func(cmd *cobra.Command, args []string) {
    repo := use_cases.GetRepository(".")
    var message string

    unstagedFiles := use_cases.GetUnstaggedFiles(repo)
    if len(unstagedFiles) > 0 {
        filesToStage := use_cases.AskWhatFilesToAddForStaging(unstagedFiles)
        go use_cases.StageFiles(filesToStage, repo)
    }

    prefix := use_cases.AskCommitPrefix()

    if len(args) == 0 {
        message = use_cases.ResolveCommitMessage()
    } else {
        message = args[0]
    }

    use_cases.ConventionalCommit(prefix, message, repo)
}

infra

Where we store terraform files that describe and mainteen any infrastructure that we need to publish the CLI. Currently there is only a S3 Bucket in AWS, that we are trying to use as a repository for apt, making it easier to install on Linux.

use_cases directory

Where we store business logic to implement the Use Cases of the CLI (Currently only Conventional Commits).

Conventional Commit

The logic for the commit message is inside the conventional_commit.go file, in the use_cases directory. The following is the implementation of the Use Case:

  • Open the Git Repo via go-git package:
func GetRepository(pathToRepository string) *git.Worktree {
	repository, err := git.PlainOpen(pathToRepository)
	if err != nil {
		log.Fatal("Could not open Git Repo")
	}

	worktree, err := repository.Worktree()
	if err != nil {
		log.Fatal("Could not get Work Tree")
	}

	return worktree
}
  • Get all Unstagged Files:
func GetUnstaggedFiles(worktree *git.Worktree) []string {
	status, err := worktree.Status()
	if err != nil {
		log.Fatal("Could not get Git Status")
	}

	var modifiedOrUntrackedFiles []string
	for file, s := range status {
		if s.Worktree == git.Modified || s.Worktree == git.Untracked {
			modifiedOrUntrackedFiles = append(modifiedOrUntrackedFiles, file)
		}
	}

	return modifiedOrUntrackedFiles
}
  • If the quantity of Unstagged Files is above 0, it will ask what files to stage, via survey package:
func AskWhatFilesToAddForStaging(files []string) []string {
	var filesToAdd []string
	prompt := &survey.MultiSelect{
		Message: "Chose the files to stage",
		Options: files,
	}
	err := survey.AskOne(prompt, &filesToAdd)
	if err != nil {
		log.Fatal("Could not Ask Files to Stage")
	}
	return filesToAdd
}
  • With the selected files, it will stage them with the go-git package:
func StageFiles(files []string, worktree *git.Worktree) {
	for _, file := range files {
		_, err := worktree.Add(file)
		if err != nil {
			log.Fatal("Could not add " + file + " file")
		}
	}
}
  • After handling none or more staged files, it will ask for a Conventional Commit prefix:
func AskCommitPrefix() string {
	var prefix string
	err := survey.AskOne(
		&survey.Select{
			Message: "Select a Prefix for the commit:",
			Options: []string{"chore", "feat", "fix", "refactor", "tests", "docs"},
		},
		&prefix,
	)

	if err != nil {
		log.Fatal("Could not ask Commit Prefix")
	}

	return prefix
}
  • If there are no arguments given via user input, it will ask for the Commit Message (can be passed via argument)
func ResolveCommitMessage() string {
	var message string
	err := survey.AskOne(
		&survey.Input{
			Message: "What did you do? (Commit Message)",
		},
		&message,
	)

	if err != nil {
		log.Fatal("Could not ask Commit Message")
	}

	return message
}
  • And Lastly, with the prefix and the message in mind, it will commit the changes to the worktree:
func ConventionalCommit(prefix string, message string, worktree *git.Worktree) {
	formatedMessage := fmt.Sprintf("%s: %s", prefix, message)
	worktree.Commit(formatedMessage, &git.CommitOptions{})
	fmt.Println("Sucessfully added a commit!")
}

About

A CLI tool for developers following Git Flow and Conventional Commits

Resources

License

Stars

Watchers

Forks

Packages

No packages published