Skip to content

Commit

Permalink
Added changelog to newly support Rust release
Browse files Browse the repository at this point in the history
  • Loading branch information
maoueh committed May 2, 2023
1 parent a501c33 commit 0b3041b
Show file tree
Hide file tree
Showing 8 changed files with 159 additions and 104 deletions.
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

* Added support for releasing Rust library project.

This newly added support will publish Rust crates of a library. The crates to publish must be
specified in the configuration file via the path `releaser.rust-crates` where the value is a list
of crates name:

```yaml
global:
...
release:
rust-crates:
- crate1
- crate2
```
Order is important as it will be respected when doing the commands. A GitHub release will be produced just
like for Golang.
The crates publishing happen only if release is published right now. Otherwise, if the command complete
and release is not published yet, commands to publish the crates manually is printed.
2 changes: 1 addition & 1 deletion cmd/sfreleaser/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func ensureGitHubReleaseValid(version string) {

case ghReleaseDraft:
fmt.Printf("A draft release for %q already exists at %s\n", version, url)
if yes, _ := cli.PromptConfirm("Would you like to delete this draft release?"); yes {
if yes, _ := cli.PromptConfirm("Would you like to delete this existing draft release?"); yes {
deleteExistingRelease(version)
fmt.Println()
} else {
Expand Down
79 changes: 37 additions & 42 deletions cmd/sfreleaser/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,61 +40,39 @@ var InstallCmd = Command(install,
)

func install(cmd *cobra.Command, _ []string) error {
language := mustGetLanguage(cmd)
variant := mustGetVariant(cmd)
root := sflags.MustGetString(cmd, "root")
global := mustGetGlobal(cmd)
overwrite := sflags.MustGetBool(cmd, "overwrite")
project := sflags.MustGetString(cmd, "project")

if project == "" {
target := root
if target == "" {
target = cli.WorkingDirectory()
}

project = filepath.Base(target)
}

zlog.Debug("starting 'sfreleaser install'",
zap.Stringer("language", language),
zap.Stringer("variant", variant),
zap.String("root", root),
zap.Inline(global),
zap.Bool("overwrite", overwrite),
zap.String("project", project),
)

if language == LanguageUnset {
language = promptLanguage()
if global.Language == LanguageUnset {
global.Language = promptLanguage()
}

if variant == VariantUnset {
variant = promptVariant()
if global.Variant == VariantUnset {
global.Variant = promptVariant()
}

if language == LanguageRust && variant == VariantApplication {
if global.Language == LanguageRust && global.Variant == VariantApplication {
cli.Quit("Application variant for language Rust is currently not supported")
}

if root != "" {
cli.NoError(os.Chdir(root), "Unable to change directory to %q", root)
}
cli.NoError(os.Chdir(global.WorkingDirectory), "Unable to change directory to %q", global.WorkingDirectory)

model := map[string]any{
"binary": project,
"project": project,
"language": language.Lower(),
"variant": variant.Lower(),
}
model := getInstallTemplateModel(global)

goreleaserTemplate := goreleaserAppTmpl
if variant == VariantLibrary {
if global.Variant == VariantLibrary {
goreleaserTemplate = goreleaserLibTmpl
}

renderTemplate(".goreleaser.yaml", overwrite, goreleaserTemplate, model)
renderTemplateAndReport(".goreleaser.yaml", overwrite, goreleaserTemplate, model)

var sfreleaserYamlTmpl []byte
switch language {
switch global.Language {
case LanguageGolang:
sfreleaserYamlTmpl = sfreleaserGolangYamlTmpl

Expand All @@ -103,14 +81,14 @@ func install(cmd *cobra.Command, _ []string) error {
sfreleaserYamlTmpl = sfreleaserRustYamlTmpl

default:
cli.Quit("unhandled language %q", language)
cli.Quit("unhandled language %q", global.Language)
}

renderTemplate(".sfreleaser", overwrite, sfreleaserYamlTmpl, model)
renderTemplateAndReport(".sfreleaser", overwrite, sfreleaserYamlTmpl, model)

if !cli.FileExists("CHANGELOG.md") {
if yes, _ := cli.PromptConfirm("Do you want to generate an empty CHANGELOG.md file?"); yes {
renderTemplate("CHANGELOG.md", false, changelogTmpl, model)
renderTemplateAndReport("CHANGELOG.md", false, changelogTmpl, model)
}
}

Expand All @@ -119,12 +97,26 @@ func install(cmd *cobra.Command, _ []string) error {
return nil
}

func renderTemplate(file string, overwrite bool, tmplContent []byte, model map[string]any) {
fileExists := cli.FileExists(file)
func getInstallTemplateModel(global *GlobalModel) map[string]any {
return map[string]any{
"binary": global.Project,
"project": global.Project,
"language": global.Language.Lower(),
"variant": global.Variant.Lower(),
}
}

if fileExists && !overwrite {
func renderTemplateAndReport(file string, overwrite bool, tmplContent []byte, model map[string]any) {
wrote := renderTemplate(file, overwrite, tmplContent, model)
if wrote == "" {
fmt.Printf("Ignoring %q, it already exists\n", file)
} else if !fileExists || overwrite {
} else {
fmt.Printf("Wrote %s\n", wrote)
}
}

func renderTemplate(file string, overwrite bool, tmplContent []byte, model map[string]any) (wrote string) {
if !cli.FileExists(file) || overwrite {
tmpl, err := template.New(file).Parse(string(tmplContent))
cli.NoError(err, "Unable to instantiate template")

Expand All @@ -137,8 +129,11 @@ func renderTemplate(file string, overwrite bool, tmplContent []byte, model map[s
}

cli.WriteFile(file, buffer.String())
fmt.Printf("Wrote %s\n", file)

return file
}

return ""
}

type RustInstallModel struct {
Expand Down
19 changes: 18 additions & 1 deletion cmd/sfreleaser/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ func release(cmd *cobra.Command, args []string) error {
Don't forget to activate link with GitHub by doing 'gh auth login'.
`))

printRustCratesNotPublishedMessage(release.Rust)
os.Exit(1)

if release.Version == "" {
release.Version = promptVersion()
}
Expand Down Expand Up @@ -167,7 +170,17 @@ func release(cmd *cobra.Command, args []string) error {

envFilePath := "build/.env.release"
releaseNotesPath := "build/.release_notes.md"
releaseGithub(allowDirty, envFilePath, releaseNotesPath)

switch global.Language {
case LanguageGolang:
releaseGolangGitHub(".goreleaser.yaml", allowDirty, envFilePath, releaseNotesPath)

case LanguageRust:
releaseRustGitHub(global, allowDirty, envFilePath, releaseNotesPath)

default:
cli.Quit("unhandled language %q", global.Language)
}

if uploadSpkgPath != "" {
fmt.Printf("Uploading Substreams package file %q to release\n", filepath.Base(uploadSpkgPath))
Expand Down Expand Up @@ -206,6 +219,10 @@ func release(cmd *cobra.Command, args []string) error {
fmt.Println()
if yes, _ := cli.PromptConfirm("Publish release right now?"); yes {
publishReleaseNow(global, release)
} else {
if global.Language == LanguageRust && global.Variant == VariantLibrary {
printRustCratesNotPublishedMessage(release.Rust)
}
}

fmt.Println("Completed")
Expand Down
3 changes: 2 additions & 1 deletion cmd/sfreleaser/release_github.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"github.com/streamingfast/cli"
)

func releaseGithub(allowDirty bool, envFilePath string, releaseNotesPath string) {
func releaseGithub(goreleaseConfigPath string, allowDirty bool, envFilePath string, releaseNotesPath string) {
if devSkipGoreleaser {
return
}
Expand All @@ -26,6 +26,7 @@ func releaseGithub(allowDirty bool, envFilePath string, releaseNotesPath string)
"goreleaser/goreleaser-cross:" + golangCrossVersion,

// goreleaser arguments
"-f", goreleaseConfigPath,
"--timeout=60m",
"--rm-dist",
"--release-notes=" + releaseNotesPath,
Expand Down
39 changes: 1 addition & 38 deletions cmd/sfreleaser/release_golang.go
Original file line number Diff line number Diff line change
@@ -1,40 +1,3 @@
package main

import (
"fmt"

"github.com/streamingfast/cli"
)

func releaseGolang(allowDirty bool, envFilePath string, releaseNotesPath string) {
if devSkipGoreleaser {
return
}

golangCrossVersion := "v1.20.2"
arguments := []string{
"docker",

// docker arguments
"run",
"--rm",
"-e CGO_ENABLED=1",
"--env-file", envFilePath,
"-v /var/run/docker.sock:/var/run/docker.sock",
"-v", cli.WorkingDirectory() + ":/go/src/work",
"-w /go/src/work",
"goreleaser/goreleaser-cross:" + golangCrossVersion,

// goreleaser arguments
"--timeout=60m",
"--rm-dist",
"--release-notes=" + releaseNotesPath,
}

if allowDirty {
arguments = append(arguments, "--skip-validate")
}

fmt.Println()
run(arguments...)
}
var releaseGolangGitHub = releaseGithub
75 changes: 67 additions & 8 deletions cmd/sfreleaser/release_rust.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,78 @@
package main

import "github.com/streamingfast/cli"
import (
"fmt"
"os"
"path/filepath"
"strings"

func releaseRustPublishCrates(rust *RustReleaseModel) {
if devSkipRustCargoPublish {
return
"github.com/streamingfast/cli"
)

func releaseRustGitHub(global *GlobalModel, allowDirty bool, envFilePath string, releaseNotesPath string) {
buildDirectory := "build"
goreleaserPath := filepath.Join(buildDirectory, "goreleaser.yaml")

cli.NoError(os.MkdirAll(buildDirectory, os.ModePerm), `Unable to create %q directory`, buildDirectory)

goreleaserTemplate := goreleaserAppTmpl
if global.Variant == VariantLibrary {
goreleaserTemplate = goreleaserLibTmpl
}

renderTemplate(goreleaserPath, true, goreleaserTemplate, getInstallTemplateModel(global))

releaseGithub(goreleaserPath, allowDirty, envFilePath, releaseNotesPath)
}

func printRustCratesNotPublishedMessage(rust *RustReleaseModel) {
cli.Ensure(rust != nil, "Rust model should have been populated by now but it's currently nil")

fmt.Println(dedent(`
Since release is not published yet, we have not perform crates publishing to crates.io
repository. Once the release is published, you will need afterward to publish the crates
manually.
Here the command you need to perform to publish your crate(s):
`))

fmt.Println()
for _, crate := range rust.Crates {
args := []string{"cargo publish"}
args = append(args, rust.CargoPublishArgs...)
args = append(args, "-p", crate)
fmt.Println(" ", publishRustCrateCommand(crate, rust.CargoPublishArgs))
}

fmt.Println()
fmt.Println(dedent(`
It's important to run them strictly in the order printed above, otherwise publishing will fail.
Also, ensure that you are on the published tag before doing the 'cargo publish' commands, to
be 100%% your are releasing the crates from the correct commit.
`))
}

run(args...)
func releaseRustPublishCrates(rust *RustReleaseModel) {
cli.Ensure(rust != nil, "Rust model should have been populated by now but it's currently nil")

if devSkipRustCargoPublish {
return
}

for _, crate := range rust.Crates {
run(publishRustCrateArgs(crate, rust.CargoPublishArgs)...)
}
}

func publishRustCrateArgs(crate string, publishArgs []string) []string {
args := []string{"cargo publish"}
args = append(args, publishArgs...)
args = append(args, "-p", crate)

return args
}

func publishRustCrateCommand(crate string, publishArgs []string) string {
args := publishRustCrateArgs(crate, publishArgs)

return strings.Join(unquotedFlatten(args...), " ")

}
26 changes: 13 additions & 13 deletions cmd/sfreleaser/templates/sfreleaser-rust.yaml.gotmpl
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
global:
language: {{ .language }}
variant: {{ .variant }}
{{- if .rust.Crates }}
release:
# This is the list of Rust crates that are going to be 'cargo publish'.
# **Important** Ordering must be strictly specified so that crates
# are ordered by dependency order, a crate that depends on another
# one should be listed below it's dependency.
#
# The generated values below are **unordered**, you must re-order them!
rust-crates:
{{- range $crate := .rust.Crates }}
- {{ $crate }}
{{- end }}
{{- end }}
{{- if .rust.Crates }}
release:
# This is the list of Rust crates that are going to be 'cargo publish'.
# **Important** Ordering must be strictly specified so that crates
# are ordered by dependency order, a crate that depends on another
# one should be listed below it's dependency.
#
# The generated values below are **unordered**, you must re-order them!
rust-crates:
{{- range $crate := .rust.Crates }}
- {{ $crate }}
{{- end }}
{{- end }}

0 comments on commit 0b3041b

Please sign in to comment.