Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement configuration file #41

Merged
merged 1 commit into from
Aug 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 142 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package rcpr

import (
"os"
)

const (
defaultConfigFile = ".rcpr"
defaultConfigContent = `# config file for rcpr in git config format
[rcpr]
`
envReleaseBranch = "RCPR_RELEASE_BRANCH"
envVersionFile = "RCPR_VERSION_FILE"
configReleaseBranch = "rcpr.releaseBranch"
configVersionFile = "rcpr.versionFile"
)

type config struct {
releaseBranch *configValue
versionFile *configValue

c *commander
conf string
}

func newConfig(c *commander) *config {
cfg := &config{conf: defaultConfigFile, c: c}
if rb := os.Getenv(envReleaseBranch); rb != "" {
cfg.releaseBranch = &configValue{
value: rb,
source: srcEnv,
}
} else {
out, _, err := c.gitE("config", "-f", cfg.conf, configReleaseBranch)
if err != nil {
cfg.releaseBranch = &configValue{
value: out,
source: srcConfigFile,
}
}
}

if rb := os.Getenv(envVersionFile); rb != "" {
cfg.releaseBranch = &configValue{
value: rb,
source: srcEnv,
}
} else {
out, _, err := c.gitE("config", "-f", cfg.conf, configVersionFile)
if err != nil {
cfg.releaseBranch = &configValue{
value: out,
source: srcConfigFile,
}
}
}
return cfg
}

func (cfg *config) set(key, value string) error {
if !exists(cfg.conf) {
if err := cfg.initializeFile(); err != nil {
return err
}
}
if value == "" {
value = "-" // value "-" represents null (really?)
}
_, _, err := cfg.c.gitE("config", "-f", cfg.conf, key, value)
if err != nil {
// in this case, config file might be invalid or broken, so retry once.
if err = cfg.initializeFile(); err != nil {
return err
}
_, _, err = cfg.c.gitE("config", "-f", cfg.conf, key, value)
}
return err
}

func (cfg *config) initializeFile() error {
if err := os.RemoveAll(cfg.conf); err != nil {
return err
}
if err := os.WriteFile(cfg.conf, []byte(defaultConfigContent), 0666); err != nil {
return err
}
return nil
}

func (cfg *config) SetRelaseBranch(br string) error {
if err := cfg.set(configReleaseBranch, br); err != nil {
return err
}
cfg.releaseBranch = &configValue{
value: br,
source: srcDetect,
}
return nil
}

func (cfg *config) SetVersionFile(fpath string) error {
if err := cfg.set(configVersionFile, fpath); err != nil {
return err
}
cfg.versionFile = &configValue{
value: fpath,
source: srcDetect,
}
return nil
}

func (cfg *config) RelaseBranch() *configValue {
return cfg.releaseBranch
}

func (cfg *config) VersionFile() *configValue {
return cfg.versionFile
}

type configValue struct {
value string
source configSource
}

func (cv *configValue) String() string {
if cv.value == "-" {
return ""
}
return cv.value
}

func (cv *configValue) Empty() bool {
return cv.String() == ""
}

type configSource int

const (
srcEnv configSource = iota
srcConfigFile
srcDetect
)
75 changes: 51 additions & 24 deletions rcpr.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ func printVersion(out io.Writer) error {
type rcpr struct {
c *commander
gh *github.Client
cfg *config
remoteName, owner, repo string
}

Expand All @@ -47,23 +48,25 @@ func (rp *rcpr) latestSemverTag() string {
return ""
}

func (rp *rcpr) initialize(ctx context.Context) error {
func newRcpr(ctx context.Context, c *commander) (*rcpr, error) {
rp := &rcpr{c: c}

var err error
rp.remoteName, err = rp.detectRemote()
if err != nil {
return err
return nil, err
}
remoteURL, _, err := rp.c.gitE("config", "remote."+rp.remoteName+".url")
if err != nil {
return err
return nil, err
}
u, err := parseGitURL(remoteURL)
if err != nil {
return fmt.Errorf("failed to parse remote")
return nil, fmt.Errorf("failed to parse remote")
}
m := strings.Split(strings.TrimPrefix(u.Path, "/"), "/")
if len(m) < 2 {
return fmt.Errorf("failed to detect owner and repo from remote URL")
return nil, fmt.Errorf("failed to detect owner and repo from remote URL")
}
rp.owner = m[0]
repo := m[1]
Expand All @@ -74,20 +77,21 @@ func (rp *rcpr) initialize(ctx context.Context) error {

cli, err := ghClient(ctx, "", u.Hostname())
if err != nil {
return err
return nil, err
}
rp.gh = cli

isShallow, _, err := rp.c.gitE("rev-parse", "--is-shallow-repository")
if err != nil {
return err
return nil, err
}
if isShallow == "true" {
if _, _, err := rp.c.gitE("fetch", "--unshallow"); err != nil {
return err
return nil, err
}
}
return nil
rp.cfg = newConfig(rp.c)
return rp, nil
}

func isRcpr(pr *github.PullRequest) bool {
Expand All @@ -114,10 +118,8 @@ func Run(ctx context.Context, argv []string, outStream, errStream io.Writer) err
}

// main logic follows
rp := &rcpr{
c: &commander{outStream: outStream, errStream: errStream, dir: "."},
}
if err := rp.initialize(ctx); err != nil {
rp, err := newRcpr(ctx, &commander{outStream: outStream, errStream: errStream, dir: "."})
if err != nil {
return err
}

Expand All @@ -133,10 +135,20 @@ func Run(ctx context.Context, argv []string, outStream, errStream io.Writer) err
// XXX: Do I need to take care of past tags with and without v-prefixes?
// It might be good to be able to enforce presence or absence in a configuration file item.

releaseBranch, _ := rp.defaultBranch() // TODO: make release branch configable
var releaseBranch string
if rp.cfg.releaseBranch != nil {
releaseBranch = rp.cfg.releaseBranch.String()
}
if releaseBranch == "" {
releaseBranch = defaultReleaseBranch
releaseBranch, _ := rp.defaultBranch()
if releaseBranch == "" {
releaseBranch = defaultReleaseBranch
}
if err := rp.cfg.SetRelaseBranch(releaseBranch); err != nil {
return err
}
}

branch, _, err := rp.c.gitE("symbolic-ref", "--short", "HEAD")
if err != nil {
return fmt.Errorf("failed to git symbolic-ref: %w", err)
Expand Down Expand Up @@ -166,12 +178,17 @@ func Run(ctx context.Context, argv []string, outStream, errStream io.Writer) err
return err
}
if len(pulls) > 0 && isRcpr(pulls[0]) {
rp.c.git("checkout", "HEAD~")
vfile, err := detectVersionFile(".", currVer)
if err != nil {
return err
var vfile string
if rp.cfg.versionFile == nil {
rp.c.git("checkout", "HEAD~")
vfile, err = detectVersionFile(".", currVer)
if err != nil {
return err
}
rp.c.git("checkout", releaseBranch)
} else {
vfile = rp.cfg.versionFile.String()
}
rp.c.git("checkout", releaseBranch)

var nextTag string
if vfile != "" {
Expand Down Expand Up @@ -252,16 +269,26 @@ func Run(ctx context.Context, argv []string, outStream, errStream io.Writer) err

nextVer := guessNextSemver(currVer, currRcpr)

// TODO: make configurable version file
vfile, err := detectVersionFile(".", currVer)
if err != nil {
return err
var vfile string
if rp.cfg.versionFile == nil {
vfile, err = detectVersionFile(".", currVer)
if err != nil {
return err
}
if vfile != "" {
if err := rp.cfg.SetVersionFile(vfile); err != nil {
return err
}
}
} else {
vfile = rp.cfg.versionFile.String()
}
if vfile != "" {
if err := bumpVersionFile(vfile, currVer, nextVer); err != nil {
return err
}
}
rp.c.gitE("add", "-f", rp.cfg.conf) // ignore any errors

// TODO To be able to run some kind of change script set by configuration in advance.

Expand Down