gabor-boros/minutes

View on GitHub
cmd/root/flags.go

Summary

Maintainability
A
0 mins
Test Coverage
package root

import (
    "fmt"
    "regexp"
    "strings"

    "github.com/gabor-boros/minutes/internal/cmd/utils"
    "github.com/spf13/cobra"
    "github.com/spf13/viper"
)

var (
    sources = []string{"clockify", "harvest", "tempo", "timewarrior", "toggl"}
    targets = []string{"tempo"}
)

func initCommonFlags() {
    rootCmd.PersistentFlags().StringVar(&configFile, "config", "", fmt.Sprintf("config file (default is $HOME/.%s.yaml)", program))

    rootCmd.Flags().StringP("start", "", "", "set the start date (defaults to 00:00:00)")
    rootCmd.Flags().StringP("end", "", "", "set the end date (defaults to now)")
    rootCmd.Flags().StringP("date-format", "", defaultDateFormat, "set start and end date format (in Go style)")

    rootCmd.Flags().StringP("source-user", "", "", "set the source user ID")
    rootCmd.Flags().StringP("source", "s", "", fmt.Sprintf("set the source of the sync %v", sources))

    rootCmd.Flags().StringP("target-user", "", "", "set the source user ID")
    rootCmd.Flags().StringP("target", "t", "", fmt.Sprintf("set the target of the sync %v", targets))

    rootCmd.Flags().StringSliceP("table-sort-by", "", []string{utils.ColumnStart, utils.ColumnProject, utils.ColumnTask, utils.ColumnSummary}, fmt.Sprintf("sort table by column %v", utils.Columns))
    rootCmd.Flags().StringSliceP("table-hide-column", "", []string{}, fmt.Sprintf("hide table column %v", utils.HideableColumns))

    rootCmd.Flags().StringP("tags-as-tasks-regex", "", "", "regex of the task pattern")

    rootCmd.Flags().BoolP("round-to-closest-minute", "", false, "round time to closest minute")
    rootCmd.Flags().BoolP("force-billed-duration", "", false, "treat every second spent as billed")

    rootCmd.Flags().StringP("filter-client", "", "", "filter for client name after fetching")
    rootCmd.Flags().StringP("filter-project", "", "", "filter for project name after fetching")

    rootCmd.Flags().BoolP("dry-run", "", false, "fetch entries, but do not sync them")
    rootCmd.Flags().BoolP("version", "", false, "show command version")
}

func initClockifyFlags() {
    rootCmd.Flags().StringP("clockify-url", "", "https://api.clockify.me", "set the base URL")
    rootCmd.Flags().StringP("clockify-api-key", "", "", "set the API key")
    rootCmd.Flags().StringP("clockify-workspace", "", "", "set the workspace ID")
}

func initHarvestFlags() {
    rootCmd.Flags().StringP("harvest-api-key", "", "", "set the API key")
    rootCmd.Flags().IntP("harvest-account", "", 0, "set the Account ID")
}

func initTempoFlags() {
    rootCmd.Flags().StringP("tempo-url", "", "", "set the base URL")
    rootCmd.Flags().StringP("tempo-username", "", "", "set the login user ID")
    rootCmd.Flags().StringP("tempo-password", "", "", "set the login password")
}

func initTimewarriorFlags() {
    rootCmd.Flags().StringP("timewarrior-command", "", "timew", "set the executable name")
    rootCmd.Flags().StringSliceP("timewarrior-arguments", "", []string{}, "set additional arguments")

    rootCmd.Flags().StringP("timewarrior-unbillable-tag", "", "unbillable", "set the unbillable tag")
    rootCmd.Flags().StringP("timewarrior-client-tag-regex", "", "", "regex of client tag pattern")
    rootCmd.Flags().StringP("timewarrior-project-tag-regex", "", "", "regex of project tag pattern")
}

func initTogglFlags() {
    rootCmd.Flags().StringP("toggl-api-key", "", "", "set the API key")
    rootCmd.Flags().IntP("toggl-workspace", "", 0, "set the workspace ID")
}

func validateFlags() {
    var err error
    source := viper.GetString("source")
    target := viper.GetString("target")

    if source == "" {
        cobra.CheckErr("sync source must be set")
    }

    if target == "" {
        cobra.CheckErr("sync target must be set")
    }

    if source == target {
        cobra.CheckErr("sync source cannot match the target")
    }

    if !utils.IsSliceContains(source, sources) {
        cobra.CheckErr(fmt.Sprintf("\"%s\" is not part of the supported sources %v\n", source, sources))
    }

    if !utils.IsSliceContains(target, targets) {
        cobra.CheckErr(fmt.Sprintf("\"%s\" is not part of the supported targets %v\n", target, targets))
    }

    tagsAsTasksRegex := viper.GetString("tags-as-tasks-regex")
    _, err = regexp.Compile(tagsAsTasksRegex)
    cobra.CheckErr(err)

    for _, sortBy := range viper.GetStringSlice("table-sort-by") {
        column := sortBy

        if strings.HasPrefix(column, "-") {
            column = sortBy[1:]
        }

        if !utils.IsSliceContains(column, utils.Columns) {
            cobra.CheckErr(fmt.Sprintf("\"%s\" is not part of the sortable columns %v\n", column, utils.Columns))
        }
    }

    for _, column := range viper.GetStringSlice("table-hide-column") {
        if !utils.IsSliceContains(column, utils.HideableColumns) {
            cobra.CheckErr(fmt.Sprintf("\"%s\" is not part of the hideable columns %v\n", column, utils.HideableColumns))
        }
    }

    _, err = regexp.Compile(viper.GetString("filter-client"))
    cobra.CheckErr(err)

    _, err = regexp.Compile(viper.GetString("filter-project"))
    cobra.CheckErr(err)

    switch source {
    case "timewarrior":
        if viper.GetString("timewarrior-command") == "" {
            cobra.CheckErr("timewarrior command must be set")
        }

        if viper.GetString("timewarrior-unbillable-tag") == "" {
            cobra.CheckErr("timewarrior unbillable tag must be set")
        }

        if viper.GetString("timewarrior-client-tag-regex") == "" {
            cobra.CheckErr("timewarrior client tag regex must be set")
        }

        if viper.GetString("timewarrior-project-tag-regex") == "" {
            cobra.CheckErr("timewarrior project tag regex must be set")
        }
    }
}