Welcome to goodcommit
- a customizable commit message generator that ensures your commit messages follow best practices and are consistent across your projects.
To build goodcommit
, ensure you have Go installed on your system. Then, follow these steps:
- Clone the repository:
git clone https://github.com/yourusername/goodcommit.git
- Navigate to the project directory:
cd goodcommit
- Build the project:
go build -o goodcommit ./cmd/main.go
- Run
goodcommit
to commit your changes (use--config
to specify the example config file):git add . ./goodcommit --config ./configs/config.example.json
To use a custom configuration file with goodcommit
, you have two options:
-
Using a Command Line Flag: Specify the
--config
flag followed by the path to your configuration file when running the program:./goodcommit --config /path/to/your/config.json
-
Using an Environment Variable: Set the
GOODCOMMIT_CONFIG_PATH
environment variable to the path of your configuration file. If both the environment variable and the--config
flag are provided, the--config
flag takes precedence.export GOODCOMMIT_CONFIG_PATH=/path/to/your/config.json ./goodcommit
Modules in goodcommit
allow for extensibility and customization of the commit form. To develop a new module, follow these steps:
-
Create a New Module File: In the root directory of the project, create a new Go file for your module, e.g.,
mymodule.go
. -
Define Your Module Struct: Implement the
gc.Module
interface.
package mymodule
import (
"github.com/charmbracelet/huh"
gc "github.com/nantli/goodcommit"
)
type myModule struct {
config gc.ModuleConfig
}
// Implement interface methods: LoadConfig, NewField, PostProcess, etc.
-
Implement Required Methods: At minimum, implement
LoadConfig
,NewField
,PostProcess
,Config
,Name
,InitCommitInfo
, andIsActive
methods as per your module's functionality. -
Register Your Module: In your own implementation of
cmd/goodcommit/main.go
, import your goodcommit module and add it to themodules
slice.
import (
"github.com/nantli/goodcommit/mymodule"
)
func main() {
// Other modules...
myModule := mymodule.New()
modules = append(modules, myModule)
// Continue setup...
If using the default commiter is not good enough for you, you can create your own commiter that implements the gc.Commiter
interface. This allows you to define how the commit form operates, handles input, or processes the final commit message. Here's how:
- Define Your Commiter: Create a new Go file in the root directory of the project, e.g.,
yourcommiter.go
. Define a struct that implements thegc.Commiter
interface.
package yourcommiter
import gc "github.com/nantli/goodcommit"
type yourCommiter struct {
// Your fields here
}
func (yc yourCommiter) LoadModules(modules []gc.Module) error {
// Implement how your commiter loads the modules
}
func (yc yourCommiter) RunForm(accessible bool) error {
// Implement how your commiter runs the form
}
func (yc yourCommiter) RunPostProcessing() error {
// Implement any post-processing steps
}
func (yc yourCommiter) PreviewCommit() {
// Implement how your commiter previews the commit
}
func (yc yourCommiter) RenderMessage() string {
// Implement how your commiter renders the final commit message
}
- Use Your Commiter: In your own implementation of
cmd/goodcommit/main.go
, replace the default commiter with your custom commiter.
import (
gc "github.com/nantli/goodcommit"
"github.com/username/module/yourcommiter"
)
func main() {
// ...
// Initialize your commiter
yourCommiter := yourcommiter.New()
err = yourCommiter.LoadModules(modules)
if err != nil {
fmt.Println("Error occurred while loading modules:", err) os.Exit(1)
}
goodcommit := gc.New(yourCommiter)
// Execute
if err := goodcommit.Execute(accessible); err != nil {
fmt.Println("Error occurred:", err)
os.Exit(1)
}
}
- Test Your Commiter: After implementing your commiter, test it thoroughly to ensure it works as expected with the
goodcommit
form.
By following these steps, you can create and integrate your own commiter into goodcommit
, allowing for a highly customized commit process.
Modules in goodcommit
can be customized through a JSON file. This section outlines how to configure modules, detailing the available fields, their types, and functionalities.
Each module configuration can include the following fields:
name
:string
- The unique identifier for the module.page
:int
- Determines on which page the module appears in the form.position
:int
(optional, default:0
) - The order of the module on the page.pinned
:bool
(optional, default:false
) - Iftrue
, the module is pinned to the top of every page after its initial appearance.active
:bool
(optional, default:true
) - Controls the module's activation state. Inactive modules are not displayed.path
:string
(optional) - Specifies a path to additional configuration or data files required by the module.priority
:int
(optional, default:0
) - Used to determine the module's priority. Lower values indicate higher priority.checkpoint
:bool
(optional, default:false
) - Iftrue
, the form will prompt for confirmation before proceeding past this module.dependencies
:[]string
(optional) - A list of module names that must be active for this module to be activated. This ensures that the current module's functionality is only available if its dependencies are met.
Below are examples of different module configurations and their effects:
-
Basic Module Configuration
{ "name": "description", "page": 1, "position": 1, "pinned": false, "active": true }
This configuration activates the
description
module, placing it first on page 1 without pinning it. -
Pinned Module Configuration
{ "name": "logo", "page": 1, "position": 1, "pinned": true, "active": true }
The
logo
module is activated, pinned, and placed at the top of every page. -
Module with External Configuration
{ "name": "types", "page": 1, "position": 2, "active": true, "path": "./configs/commit_types.json" }
Activates the
types
module, using an external file for additional configuration. -
Module with Dependencies
{ "name": "breakingmsg", "page": 4, "position": 1, "active": true, "dependencies": ["breaking"] }
This configuration activates the
breakingmsg
module, which depends on thebreaking
module being active. If thebreaking
module is not active,breakingmsg
will not be activated.
By adjusting these fields in the config.json
file, you can tailor the goodcommit
form to meet your project's specific needs.
This is an example configuration file that activates the modules: types
, scopes
, description
, body
, breaking
and breakingmsg
. You can use this as a starting point for your own configuration.
{
"activeModules": [
{
"name": "types",
"page": 1,
"position": 1,
"active": true,
"path": "./configs/commit_types.example.json",
"checkpoint": true
},
{
"name": "scopes",
"page": 2,
"position": 1,
"active": true,
"path": "./configs/commit_scopes.example.json",
"dependencies": ["types"],
"priority": 3
},
{
"name": "description",
"page": 3,
"position": 1,
"active": true
},
{
"name": "body",
"page": 3,
"position": 2,
"active": true,
"priority": 2
},
{
"name": "breaking",
"page": 3,
"position": 3,
"active": true,
"priority": 4,
"checkpoint": true
},
{
"name": "breakingmsg",
"page": 4,
"position": 1,
"active": true,
"priority": 5,
"dependencies": ["breaking"]
}
]
}