diff --git a/cmd/containerd-release/build.go b/cmd/containerd-release/build.go new file mode 100644 index 000000000..1c7297458 --- /dev/null +++ b/cmd/containerd-release/build.go @@ -0,0 +1,43 @@ +package main + +import ( + "crypto/sha256" + "encoding/hex" + "fmt" + "io" + "os" + "os/exec" + "runtime" +) + +func build() error { + out, err := exec.Command("make").CombinedOutput() + if err != nil { + return fmt.Errorf("%s: %s", err, out) + } + return nil +} + +const tarFormat = "containerd-%s.%s-%s.tar.gz" + +func tarRelease(tag string) (string, error) { + path := fmt.Sprintf(tarFormat, tag, runtime.GOOS, runtime.GOARCH) + out, err := exec.Command("tar", "-zcf", path, "bin/").CombinedOutput() + if err != nil { + return "", fmt.Errorf("%s: %s", err, out) + } + return path, nil +} + +func hash(path string) (string, error) { + f, err := os.Open(path) + if err != nil { + return "", err + } + defer f.Close() + s := sha256.New() + if _, err := io.Copy(s, f); err != nil { + return "", err + } + return hex.EncodeToString(s.Sum(nil)), nil +} diff --git a/cmd/containerd-release/main.go b/cmd/containerd-release/main.go index a6d3389e3..459c22633 100644 --- a/cmd/containerd-release/main.go +++ b/cmd/containerd-release/main.go @@ -1,57 +1,14 @@ package main import ( - "bufio" - "bytes" - "errors" "fmt" - "io" "os" - "os/exec" - "path/filepath" - "sort" - "strings" "text/template" - "github.com/BurntSushi/toml" "github.com/sirupsen/logrus" "github.com/urfave/cli" ) -const releaseNotes = `Welcome to the release of containerd {{.Version}}! -{{if .PreRelease}} -*This is a pre-release of containerd* -{{- end}} - -{{.Preface}} - -Please try out the release binaries and report any issues at -https://github.com/containerd/containerd/issues. - -{{range $note := .Notes}} -### {{$note.Title}} - -{{$note.Description}} -{{- end}} - -### Contributors -{{range $contributor := .Contributors}} -* {{$contributor}} -{{- end}} - -### Changes -{{range $change := .Changes}} -* {{$change.Commit}} {{$change.Description}} -{{- end}} - -### Dependency Changes - -Previous release can be found at [{{.Previous}}](https://github.com/containerd/containerd/releases/tag/{{.Previous}}) -{{range $dep := .Dependencies}} -* {{$dep.Previous}} -> {{$dep.Commit}} **{{$dep.Name}}** -{{- end}} -` - const vendorConf = "vendor.conf" type note struct { @@ -70,6 +27,11 @@ type dependency struct { Previous string } +type download struct { + Filename string + Hash string +} + type release struct { Commit string `toml:"commit"` Previous string `toml:"previous"` @@ -82,6 +44,7 @@ type release struct { Contributors []string Dependencies []dependency Version string + Downloads []download } func main() { @@ -142,6 +105,7 @@ This tool should be ran from the root of the containerd repository for a new rel } return t.Execute(os.Stdout, r) } + logrus.Info("release complete!") return nil } if err := app.Run(os.Args); err != nil { @@ -149,152 +113,3 @@ This tool should be ran from the root of the containerd repository for a new rel os.Exit(1) } } - -func loadRelease(path string) (*release, error) { - var r release - if _, err := toml.DecodeFile(path, &r); err != nil { - if os.IsNotExist(err) { - return nil, errors.New("please specify the release file as the first argument") - } - return nil, err - } - return &r, nil -} - -func parseTag(path string) string { - return strings.TrimSuffix(filepath.Base(path), ".toml") -} - -func parseDependencies(r io.Reader) ([]dependency, error) { - var deps []dependency - s := bufio.NewScanner(r) - for s.Scan() { - ln := strings.TrimSpace(s.Text()) - if strings.HasPrefix(ln, "#") || ln == "" { - continue - } - cidx := strings.Index(ln, "#") - if cidx > 0 { - ln = ln[:cidx] - } - ln = strings.TrimSpace(ln) - parts := strings.Fields(ln) - if len(parts) != 2 && len(parts) != 3 { - return nil, fmt.Errorf("invalid config format: %s", ln) - } - deps = append(deps, dependency{ - Name: parts[0], - Commit: parts[1], - }) - } - if err := s.Err(); err != nil { - return nil, err - } - return deps, nil -} - -func getPreviousDeps(previous string) ([]dependency, error) { - r, err := fileFromRev(previous, vendorConf) - if err != nil { - return nil, err - } - return parseDependencies(r) -} - -func changelog(previous, commit string) ([]change, error) { - raw, err := getChangelog(previous, commit) - if err != nil { - return nil, err - } - return parseChangelog(raw) -} - -func getChangelog(previous, commit string) ([]byte, error) { - return git("log", "--oneline", fmt.Sprintf("%s..%s", previous, commit)) -} - -func parseChangelog(changelog []byte) ([]change, error) { - var ( - changes []change - s = bufio.NewScanner(bytes.NewReader(changelog)) - ) - for s.Scan() { - fields := strings.Fields(s.Text()) - changes = append(changes, change{ - Commit: fields[0], - Description: strings.Join(fields[1:], " "), - }) - } - if err := s.Err(); err != nil { - return nil, err - } - return changes, nil -} - -func fileFromRev(rev, file string) (io.Reader, error) { - p, err := git("show", fmt.Sprintf("%s:%s", rev, file)) - if err != nil { - return nil, err - } - - return bytes.NewReader(p), nil -} - -func git(args ...string) ([]byte, error) { - o, err := exec.Command("git", args...).CombinedOutput() - if err != nil { - return nil, fmt.Errorf("%s: %s", err, o) - } - return o, nil -} - -func updatedDeps(previous, deps []dependency) []dependency { - var updated []dependency - pm, cm := toDepMap(previous), toDepMap(deps) - for name, c := range cm { - d, ok := pm[name] - if !ok { - // it is a new dep and should be noted - updated = append(updated, c) - continue - } - // it exists, see if its updated - if d.Commit != c.Commit { - // set the previous commit - c.Previous = d.Commit - updated = append(updated, c) - } - } - return updated -} - -func toDepMap(deps []dependency) map[string]dependency { - out := make(map[string]dependency) - for _, d := range deps { - out[d.Name] = d - } - return out -} - -func getContributors(previous, commit string) ([]string, error) { - raw, err := git("log", "--format=%aN", fmt.Sprintf("%s..%s", previous, commit)) - if err != nil { - return nil, err - } - var ( - set = make(map[string]struct{}) - s = bufio.NewScanner(bytes.NewReader(raw)) - out []string - ) - for s.Scan() { - set[s.Text()] = struct{}{} - } - if err := s.Err(); err != nil { - return nil, err - } - for name := range set { - out = append(out, name) - } - sort.Strings(out) - return out, nil -} diff --git a/cmd/containerd-release/template.go b/cmd/containerd-release/template.go new file mode 100644 index 000000000..bb2f0a7d3 --- /dev/null +++ b/cmd/containerd-release/template.go @@ -0,0 +1,35 @@ +package main + +const releaseNotes = `Welcome to the release of containerd {{.Version}}! +{{if .PreRelease}} +*This is a pre-release of containerd* +{{- end}} + +{{.Preface}} + +Please try out the release binaries and report any issues at +https://github.com/containerd/containerd/issues. + +{{range $note := .Notes}} +### {{$note.Title}} + +{{$note.Description}} +{{- end}} + +### Contributors +{{range $contributor := .Contributors}} +* {{$contributor}} +{{- end}} + +### Changes +{{range $change := .Changes}} +* {{$change.Commit}} {{$change.Description}} +{{- end}} + +### Dependency Changes + +Previous release can be found at [{{.Previous}}](https://github.com/containerd/containerd/releases/tag/{{.Previous}}) +{{range $dep := .Dependencies}} +* {{$dep.Previous}} -> {{$dep.Commit}} **{{$dep.Name}}** +{{- end}} +` diff --git a/cmd/containerd-release/util.go b/cmd/containerd-release/util.go new file mode 100644 index 000000000..e041822bb --- /dev/null +++ b/cmd/containerd-release/util.go @@ -0,0 +1,165 @@ +package main + +import ( + "bufio" + "bytes" + "errors" + "fmt" + "io" + "os" + "os/exec" + "path/filepath" + "sort" + "strings" + + "github.com/BurntSushi/toml" +) + +func loadRelease(path string) (*release, error) { + var r release + if _, err := toml.DecodeFile(path, &r); err != nil { + if os.IsNotExist(err) { + return nil, errors.New("please specify the release file as the first argument") + } + return nil, err + } + return &r, nil +} + +func parseTag(path string) string { + return strings.TrimSuffix(filepath.Base(path), ".toml") +} + +func parseDependencies(r io.Reader) ([]dependency, error) { + var deps []dependency + s := bufio.NewScanner(r) + for s.Scan() { + ln := strings.TrimSpace(s.Text()) + if strings.HasPrefix(ln, "#") || ln == "" { + continue + } + cidx := strings.Index(ln, "#") + if cidx > 0 { + ln = ln[:cidx] + } + ln = strings.TrimSpace(ln) + parts := strings.Fields(ln) + if len(parts) != 2 && len(parts) != 3 { + return nil, fmt.Errorf("invalid config format: %s", ln) + } + deps = append(deps, dependency{ + Name: parts[0], + Commit: parts[1], + }) + } + if err := s.Err(); err != nil { + return nil, err + } + return deps, nil +} + +func getPreviousDeps(previous string) ([]dependency, error) { + r, err := fileFromRev(previous, vendorConf) + if err != nil { + return nil, err + } + return parseDependencies(r) +} + +func changelog(previous, commit string) ([]change, error) { + raw, err := getChangelog(previous, commit) + if err != nil { + return nil, err + } + return parseChangelog(raw) +} + +func getChangelog(previous, commit string) ([]byte, error) { + return git("log", "--oneline", fmt.Sprintf("%s..%s", previous, commit)) +} + +func parseChangelog(changelog []byte) ([]change, error) { + var ( + changes []change + s = bufio.NewScanner(bytes.NewReader(changelog)) + ) + for s.Scan() { + fields := strings.Fields(s.Text()) + changes = append(changes, change{ + Commit: fields[0], + Description: strings.Join(fields[1:], " "), + }) + } + if err := s.Err(); err != nil { + return nil, err + } + return changes, nil +} + +func fileFromRev(rev, file string) (io.Reader, error) { + p, err := git("show", fmt.Sprintf("%s:%s", rev, file)) + if err != nil { + return nil, err + } + + return bytes.NewReader(p), nil +} + +func git(args ...string) ([]byte, error) { + o, err := exec.Command("git", args...).CombinedOutput() + if err != nil { + return nil, fmt.Errorf("%s: %s", err, o) + } + return o, nil +} + +func updatedDeps(previous, deps []dependency) []dependency { + var updated []dependency + pm, cm := toDepMap(previous), toDepMap(deps) + for name, c := range cm { + d, ok := pm[name] + if !ok { + // it is a new dep and should be noted + updated = append(updated, c) + continue + } + // it exists, see if its updated + if d.Commit != c.Commit { + // set the previous commit + c.Previous = d.Commit + updated = append(updated, c) + } + } + return updated +} + +func toDepMap(deps []dependency) map[string]dependency { + out := make(map[string]dependency) + for _, d := range deps { + out[d.Name] = d + } + return out +} + +func getContributors(previous, commit string) ([]string, error) { + raw, err := git("log", "--format=%aN", fmt.Sprintf("%s..%s", previous, commit)) + if err != nil { + return nil, err + } + var ( + set = make(map[string]struct{}) + s = bufio.NewScanner(bytes.NewReader(raw)) + out []string + ) + for s.Scan() { + set[s.Text()] = struct{}{} + } + if err := s.Err(); err != nil { + return nil, err + } + for name := range set { + out = append(out, name) + } + sort.Strings(out) + return out, nil +}