github.com/thetechnoweenie/graven@v1.0.2/commands/bump.go (about) 1 package commands 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "strings" 8 "text/template" 9 10 "github.com/cbegin/graven/domain" 11 "github.com/urfave/cli" 12 ) 13 14 const ( 15 versionPackage = "version" 16 versionFileName = "version.go" 17 versionTemplate = `// graven - This file was generated. It will be overwritten. Do not modify. 18 package {{.Package}} 19 20 var Version = "{{.Version}}" 21 ` 22 ) 23 24 var BumpCommand = cli.Command{ 25 Name: "bump", 26 Usage: "Manage the version (major, minor, patch) and clear or set qualifier (e.g. DEV)", 27 Description: ` 28 Bump manages incremental version updates using simple semantic versioning practices. 29 30 The valid arguments are: 31 32 major - bumps the major version X._._ 33 minor - bumps the minor version _.X._ 34 patch - bumps the patch version _._.X 35 clear - clears the qualifier if any 36 _____ - Anything else, sets the qualifier (e.g. SNAPSHOT, DEV, ALPHA)`, 37 Action: bump, 38 } 39 40 func bump(c *cli.Context) error { 41 project, err := domain.FindProject() 42 if err != nil { 43 return err 44 } 45 46 oldVersion := project.Version 47 arg := c.Args().First() 48 if arg == "" { 49 fmt.Printf("%v\n", oldVersion) 50 return nil 51 } 52 if err := bumpVersion(project, arg); err != nil { 53 return err 54 } 55 if err := writeVersionFile(project); err != nil { 56 return err 57 } 58 newVersion := project.Version 59 fmt.Printf("Version changed from %v to %v\n", oldVersion, newVersion) 60 return nil 61 } 62 63 func writeVersionFile(project *domain.Project) error { 64 versionPath := project.ProjectPath(versionPackage) 65 versionFile := project.ProjectPath(versionPackage, versionFileName) 66 67 if err := validateHeader(versionFile); err != nil { 68 return err 69 } 70 71 _ = os.Mkdir(versionPath, 0755) // ignore error. we'll catch file errors later 72 73 file, err := os.Create(versionFile) 74 defer file.Close() 75 if err != nil { 76 return err 77 } 78 tmpl, err := template.New("version").Parse(versionTemplate) 79 if err != nil { 80 return err 81 } 82 83 tmpl.Execute(file, struct { 84 Version string 85 Package string 86 }{ 87 Version: project.Version, 88 Package: versionPackage, 89 }) 90 return nil 91 } 92 93 func validateHeader(versionFile string) error { 94 const headerLength = 10 95 file, err := os.Open(versionFile) 96 defer file.Close() 97 if os.IsNotExist(err) { 98 // it's okay if the file doesn't exist 99 return nil 100 } else if err != nil { 101 // but fail for any other reason 102 return err 103 } 104 105 var buffer = make([]byte, headerLength) 106 _, err = file.Read(buffer) 107 if err != nil { 108 return err 109 } 110 if string(buffer) != versionTemplate[:headerLength] { 111 return fmt.Errorf("Header in %v doesn't match, so graven won't overwrite it.", versionFile) 112 } 113 return nil 114 } 115 116 func bumpVersion(project *domain.Project, arg string) error { 117 version := domain.Version{} 118 119 if err := version.Parse(project.Version); err != nil { 120 return fmt.Errorf("Error parsing version: %v", err) 121 } 122 123 switch arg { 124 case "major": 125 version.Major++ 126 version.Minor = 0 127 version.Patch = 0 128 version.Qualifier = "" 129 case "minor": 130 version.Minor++ 131 version.Patch = 0 132 version.Qualifier = "" 133 case "patch": 134 version.Patch++ 135 version.Qualifier = "" 136 case "clear": 137 version.Qualifier = "" 138 case "": 139 default: 140 version.Qualifier = arg 141 } 142 143 project.Version = version.ToString() 144 145 if err := updateProjectFileVersion(project); err != nil { 146 return err 147 } 148 149 return nil 150 } 151 152 func updateProjectFileVersion(project *domain.Project) error { 153 fileInfo, err := os.Stat(project.FilePath) 154 if err != nil { 155 return err 156 } 157 158 input, err := ioutil.ReadFile(project.FilePath) 159 if err != nil { 160 return err 161 } 162 163 eol := "" 164 lines := strings.Split(string(input), "\n") 165 for i, line := range lines { 166 if strings.HasPrefix(line, "version:") { 167 if strings.HasSuffix(line, "\r") { 168 eol = "\r" 169 } 170 lines[i] = fmt.Sprintf("version: %v%v", project.Version, eol) 171 } 172 } 173 174 output := strings.Join(lines, "\n") 175 if err := ioutil.WriteFile(project.FilePath, []byte(output), fileInfo.Mode()); err != nil { 176 return err 177 } 178 179 return nil 180 }