https://github.com/c2pc/config-migrate
config-migrate is a plugin for golang-migrate that enables versioned migrations for configuration files like YAML and JSON.
https://github.com/c2pc/config-migrate
config go golang json migration yaml
Last synced: 4 months ago
JSON representation
config-migrate is a plugin for golang-migrate that enables versioned migrations for configuration files like YAML and JSON.
- Host: GitHub
- URL: https://github.com/c2pc/config-migrate
- Owner: c2pc
- License: mit
- Created: 2025-03-22T18:47:34.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-04-07T23:01:01.000Z (about 1 year ago)
- Last Synced: 2025-06-03T04:46:23.299Z (about 1 year ago)
- Topics: config, go, golang, json, migration, yaml
- Language: Go
- Homepage:
- Size: 94.7 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Config-Migrate
`config-migrate` is a plugin for [golang-migrate](https://github.com/golang-migrate/migrate) that enables versioned migrations for configuration files like YAML and JSON.
## Configs
Config drivers apply migrations to configuration files instead of traditional databases.
[Want to add a new config driver?](driver/driver.go)
Currently supported config drivers:
* [JSON](driver/json)
* [YAML](driver/yaml)
## Why use `config-migrate`?
This is useful when:
- You want to apply versioned updates to your application configs.
- You need a reproducible and auditable history of config changes.
- You want to manage infrastructure or system configs as part of CI/CD.
## Features
* Seamless integration with [`golang-migrate`](https://github.com/golang-migrate/migrate)
* **Migration scenarios**: rename keys, move paths, `_deprecated` (path→key), `_replace` (force new value), `_deprecated_expand` (array of scalars→array of objects), `_deprecated_collapse` (array of objects→array of scalars). See [docs/MIGRATION_SCENARIOS.md](docs/MIGRATION_SCENARIOS.md) for all scenarios and production tips.
* File-based locking to prevent concurrent writes
* Config merging with support for version tracking
* Supports `version`, `force`, and `drop` commands
* Graceful file handling using `io.Reader` / `io.Writer`
* Thread-safe with `sync.Mutex`
* Built-in support for YAML and JSON config formats
## Getting Started
### Install
Make sure you have Go 1.18+ and Go modules enabled.
```bash
go get github.com/c2pc/config-migrate
```
📚 __[Go Documentation](https://pkg.go.dev/github.com/golang-migrate/migrate/v4)__
### Basic usage with config file:
```go
import (
"github.com/golang-migrate/migrate/v4"
_ "github.com/c2pc/config-migrate/driver/json"
_ "github.com/golang-migrate/migrate/v4/source/github"
)
func main() {
m, err := migrate.New(
"github://username:token@your-repo/json-migrations",
"json://./config.json")
if err != nil {
panic(err)
}
// Apply the next 2 migration steps
m.Steps(2)
}
```
### Advanced usage with an existing config client:
```go
import (
"github.com/golang-migrate/migrate/v4"
"github.com/c2pc/config-migrate/driver/yaml"
"github.com/c2pc/config-migrate/config"
_ "github.com/golang-migrate/migrate/v4/source/file"
)
func main() {
driver := yaml.New(driver.Settings{
Path: "config.yml",
Perm: 0777,
})
m, err := migrate.NewWithDatabaseInstance(
"file://driver/migrations",
"yaml", driver)
if err != nil {
panic(err)
}
m.Up()
}
```
## Dynamic Replacers
You can use dynamic placeholders in your config files and define how they should be replaced at runtime using `replacer`.
### Built-in Example: Random
The following example registers a replacer that replaces `___random___` with random string:
```go
package random
import (
"crypto/rand"
"github.com/c2pc/config-migrate/replacer"
)
const letters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
func init() {
replacer.Register("___random___", randomReplacer(16))
}
func randomReplacer(n int) func() string {
return func() string {
bytes := make([]byte, n)
_, err := rand.Read(bytes)
if err != nil {
return ""
}
for i, b := range bytes {
bytes[i] = letters[b%byte(len(letters))]
}
return string(bytes)
}
}
```
### Writing Your Own Replacers
You can create and register your own replacers by calling `replacer.Register`:
```go
package main
import (
"github.com/c2pc/config-migrate/replacer"
)
func init() {
replacer.Register("___my_placeholder___", func() string {
return "dynamic-value"
})
}
```
These placeholders will be replaced automatically when configs are processed during migrations.
### When to Use Replacers
Use replacers when you want to inject dynamic values (like IPs, ports, timestamps, environment info) into your config files at the time of applying a migration.
## Comments
you can enable comment replacer in settings `UnableToReplaceComments: true`
```go
package main
import (
"embed"
"errors"
"github.com/c2pc/config-migrate/driver"
"github.com/c2pc/config-migrate/driver/yaml"
"github.com/golang-migrate/migrate/v4"
"github.com/golang-migrate/migrate/v4/source/iofs"
)
//go:embed migrations/*.yml
var fs embed.FS
func runMigration(path string) error {
//You can set a comment suffix
driver.CommentSuffix = "___comment___"
//Enable to replace comments
yamlMigr := yaml.New(driver.Settings{
Path: path,
Perm: 0777,
UnableToReplaceComments: true,
})
//Using iofs as a source
d, err := iofs.New(fs, "migrations")
if err != nil {
return err
}
//Create yaml migration
m, err := migrate.NewWithInstance("iofs", d, "yaml", yamlMigr)
if err != nil {
return err
}
//Run migrations
if err := m.Up(); errors.Is(err, migrate.ErrNoChange) {
return nil
} else if err != nil {
return err
}
return nil
}
```
### YAML
You can add comments to your parameters. Add suffix `______` to parameter name
Set empty comment `host______:` to add `\n` to file
```yaml
http______:
http_______: HTTP server configuration1
http________: HTTP server configuration2
http:
host______:
host_______: The IP address the server will bind to
host: ___ip_address___
port______:
port_______: The port the server will listen on
port: 8052
```
As a result we get
```yaml
# HTTP server configuration1
# HTTP server configuration2
http:
# The IP address the server will bind to
host: ___ip_address___
# The port the server will listen on
port: 8052
```
### JSON
You can add comments to your parameters. Add suffix `______` to parameter name.
Set empty comment `"http______": ""` to add `\n` to file
```json
{
"http______": "",
"http_______": "HTTP server configuration",
"http________": "HTTP server configuration1",
"http_________": "HTTP server configuration2",
"http": {
"host______": "",
"host_______": "The IP address the server will bind to",
"host": "___ip_address___",
"port______": "",
"port_______": "The port the server will listen on",
"port": 8052
}
}
```
As a result we get
```json
{
"____http": "HTTP server configuration",
"____http_": "HTTP server configuration1",
"____http__": "HTTP server configuration2",
"http": {
"____host": "The IP address the server will bind to",
"host": "___ip_address___",
"____port": "The port the server will listen on",
"port": 8052
}
}
```
### Examples
* [JSON](driver/json/examples/migrations) - JSON migrations with replacers and comments
* [YAML](driver/yaml/examples/migrations) - YAML migrations with replacers and comments
* [EXAMPLE](example) - Example application with YAML migrations