Skip to content

Commit

Permalink
generate migration docs inside a doc template
Browse files Browse the repository at this point in the history
  • Loading branch information
Pantani authored and Pantani committed Mar 1, 2024
1 parent 57ea7b3 commit 6f7c06e
Show file tree
Hide file tree
Showing 7 changed files with 247 additions and 81 deletions.
6 changes: 3 additions & 3 deletions docs/docs/06-migration/v28.0.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,15 @@ This guide provides a step-by-step process for developers to upgrade their appli
- **Old Code**:

```go
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.PostKey))
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.PostKey))

```

- **New Code**:

```go
storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx))
store := prefix.NewStore(storeAdapter, types.KeyPrefix(types.PostKey))
storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx))
store := prefix.NewStore(storeAdapter, types.KeyPrefix(types.PostKey))
```

Expand Down
38 changes: 34 additions & 4 deletions ignite/internal/tools/gen-mig-diffs/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@ package cmd

import (
"fmt"
"path/filepath"

"github.com/Masterminds/semver/v3"
"github.com/spf13/cobra"

"github.com/ignite/cli/v28/ignite/internal/tools/gen-mig-diffs/pkg/diff"
"github.com/ignite/cli/v28/ignite/internal/tools/gen-mig-diffs/pkg/repo"
"github.com/ignite/cli/v28/ignite/internal/tools/gen-mig-diffs/pkg/scaffold"
"github.com/ignite/cli/v28/ignite/internal/tools/gen-mig-diffs/templates/doc"
"github.com/ignite/cli/v28/ignite/pkg/cliui"
"github.com/ignite/cli/v28/ignite/pkg/errors"
"github.com/ignite/cli/v28/ignite/pkg/placeholder"
"github.com/ignite/cli/v28/ignite/pkg/xgenny"
)

const (
Expand All @@ -23,6 +27,8 @@ const (
flagRepoCleanup = "repo-cleanup"
flagScaffoldOutput = "scaffold-output"
flagScaffoldCache = "scaffold-cache"

defaultDocPath = "docs/docs/06-migration"
)

// NewRootCmd creates a new root command.
Expand Down Expand Up @@ -76,6 +82,11 @@ func NewRootCmd() *cobra.Command {
}
defer igniteRepo.Cleanup()

releaseDescription, err := igniteRepo.ReleaseDescription()
if err != nil {
return errors.Wrapf(err, "failed to fetch the release tag %s description", igniteRepo.To.Original())
}

fromBin, toBin, err := igniteRepo.GenerateBinaries(cmd.Context())
if err != nil {
return err
Expand Down Expand Up @@ -122,21 +133,40 @@ func NewRootCmd() *cobra.Command {
if err != nil {
return errors.Wrap(err, "failed to calculate diff")
}

formatedDiffs, err := diff.FormatDiffs(diffs)
if err != nil {
return errors.Wrap(err, "failed to save diff map")
}
session.StopSpinner()
session.EventBus().SendInfo("Diff calculated successfully")

if err = diff.SaveDiffs(diffs, output); err != nil {
return errors.Wrap(err, "failed to save diff map")
output, err = filepath.Abs(output)
if err != nil {
return errors.Wrap(err, "failed to find the abs path")
}

// Generate the docs file.
g, err := doc.NewGenerator(doc.Options{
Path: output,
FromVersion: igniteRepo.From,
ToVersion: igniteRepo.To,
Diffs: string(formatedDiffs),
Description: releaseDescription,
})
if _, err := xgenny.RunWithValidation(placeholder.New(), g); err != nil {
return err
}
session.Printf("Migration diffs generated successfully at %s\n", output)

session.Printf("Migration doc generated successfully at %s\n", output)

return nil
},
}

cmd.Flags().StringP(flagFrom, "f", "", "Version of ignite or path to ignite source code to generate the diff from")
cmd.Flags().StringP(flagTo, "t", "", "Version of ignite or path to ignite source code to generate the diff to")
cmd.Flags().StringP(flagOutput, "o", "./diffs", "Output directory to save the migration diff files")
cmd.Flags().StringP(flagOutput, "o", defaultDocPath, "Output directory to save the migration document")
cmd.Flags().StringP(flagSource, "s", "", "Path to ignite source code repository. Set the source automatically set the cleanup to false")
cmd.Flags().String(flagRepoURL, "", "Git URL for the Ignite repository")
cmd.Flags().String(flagRepoOutput, "", "Output path to clone the ignite repository")
Expand Down
15 changes: 15 additions & 0 deletions ignite/internal/tools/gen-mig-diffs/pkg/diff/diff.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package diff

import (
"bytes"
"fmt"
"os"
"path/filepath"

"github.com/hexops/gotextdiff"

"github.com/ignite/cli/v28/ignite/pkg/diff"
"github.com/ignite/cli/v28/ignite/pkg/xstrings"
)

type Diffs map[string][]gotextdiff.Unified
Expand Down Expand Up @@ -93,6 +95,19 @@ func SaveDiffs(diffs Diffs, outputPath string) error {
return nil
}

// FormatDiffs format all diffs in a single markdown byte array.
func FormatDiffs(diffs Diffs) ([]byte, error) {
buffer := &bytes.Buffer{}
for name, diffs := range diffs {
buffer.WriteString(fmt.Sprintf("#### **%s diff**\n\n", xstrings.ToUpperFirst(name)))
for _, d := range diffs {
buffer.WriteString(fmt.Sprint(d))
buffer.WriteString("\n\n")
}
}
return buffer.Bytes(), nil
}

// readRootFolders return a map of all root folders from a directory.
func readRootFolders(dir string) (map[string]struct{}, error) {
paths := make(map[string]struct{})
Expand Down
169 changes: 95 additions & 74 deletions ignite/internal/tools/gen-mig-diffs/pkg/repo/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ func New(from, to *semver.Version, session *cliui.Session, options ...Options) (
session.EventBus().SendInfo(fmt.Sprintf("Cloned ignite repository to: %s", source))
}

versions, err := getRepoVersionTags(source)
versions, err := getRepoVersionTags(repo)
if err != nil {
return nil, err
}
Expand All @@ -172,13 +172,103 @@ func New(from, to *semver.Version, session *cliui.Session, options ...Options) (
}, nil
}

// getRepoVersionTags returns a sorted collection of semver tags from the ignite cli repository.
func getRepoVersionTags(repoDir string) (semver.Collection, error) {
repo, err := git.PlainOpen(repoDir)
func (g *Generator) ReleaseDescription() (string, error) {
tag, err := g.repo.Tag(g.To.Original())
if err != nil {
return nil, err
return "", errors.Wrapf(err, "failed to get tag %s", g.To.Original())
}
tagObj, err := g.repo.TagObject(tag.Hash())
if err != nil {
return "", errors.Wrapf(err, "failed to get tag object %s", tag.Hash().String())
}
description := fmt.Sprintf(`Tag: %[1]v
Commit: %[2]v
Author: %[3]v
Date: %[4]v
%[5]v
`,
g.To.Original(),
tagObj.Hash.String(),
tagObj.Tagger.String(),
tagObj.Tagger.When.Format("Jan 2 15:04:05 2006"),
tagObj.Message,
)

return description, nil
}

// Cleanup cleanup all temporary directories.
func (g *Generator) Cleanup() {
if !g.cleanup {
return
}
if err := os.RemoveAll(g.source); err != nil {
g.session.EventBus().SendError(err)
return
}
g.session.EventBus().SendInfo(fmt.Sprintf("Removed temporary directory: %s", g.source))
}

func (g *Generator) GenerateBinaries(ctx context.Context) (string, string, error) {
fromBinPath, err := g.buildIgniteCli(ctx, g.From)
if err != nil {
return "", "", errors.Wrapf(err, "failed to run scaffolds for 'FROM' version %s", g.From)
}
toBinPath, err := g.buildIgniteCli(ctx, g.To)
if err != nil {
return "", "", errors.Wrapf(err, "failed to run scaffolds for 'TO' version %s", g.To)
}
return fromBinPath, toBinPath, nil
}

// buildIgniteCli build the ignite CLI from version.
func (g *Generator) buildIgniteCli(ctx context.Context, ver *semver.Version) (string, error) {
g.session.StartSpinner(fmt.Sprintf("Building binary for version v%s...", ver))

if err := g.checkoutToTag(ver.Original()); err != nil {
return "", err
}

err := exec.Exec(ctx, []string{"make", "build"}, exec.StepOption(step.Workdir(g.source)))
if err != nil {
return "", errors.Wrap(err, "failed to build ignite cli using make build")
}

// Copy the built binary to the binary path.
genBinaryPath := filepath.Join(g.source, defaultBinaryPath)
binPath := filepath.Join(g.binPath, ver.Original(), "ignite")
if err := copyFile(genBinaryPath, binPath); err != nil {
return "", err
}

g.session.StopSpinner()
g.session.EventBus().SendInfo(fmt.Sprintf("Built ignite cli for %s at %s", ver.Original(), binPath))

return binPath, nil
}

// checkoutToTag checkout the repository from a specific git tag.
func (g *Generator) checkoutToTag(tag string) error {
wt, err := g.repo.Worktree()
if err != nil {
return err
}
// Reset and clean the git directory before the checkout to avoid conflicts.
if err := wt.Reset(&git.ResetOptions{Mode: git.HardReset}); err != nil {
return errors.Wrapf(err, "failed to reset %s", g.source)
}
if err := wt.Clean(&git.CleanOptions{Dir: true}); err != nil {
return errors.Wrapf(err, "failed to reset %s", g.source)
}
if err = wt.Checkout(&git.CheckoutOptions{Branch: plumbing.NewTagReferenceName(tag)}); err != nil {
return errors.Wrapf(err, "failed to checkout tag %s", tag)
}
return nil
}

// getRepoVersionTags returns a sorted collection of semver tags from the ignite cli repository.
func getRepoVersionTags(repo *git.Repository) (semver.Collection, error) {
tags, err := repo.Tags()
if err != nil {
return nil, errors.Wrap(err, "failed to get tags")
Expand Down Expand Up @@ -207,18 +297,6 @@ func getRepoVersionTags(repoDir string) (semver.Collection, error) {
return versions, nil
}

// Cleanup cleanup all temporary directories.
func (g *Generator) Cleanup() {
if !g.cleanup {
return
}
if err := os.RemoveAll(g.source); err != nil {
g.session.EventBus().SendError(err)
return
}
g.session.EventBus().SendInfo(fmt.Sprintf("Removed temporary directory: %s", g.source))
}

// validateVersionRange checks if the provided fromVer and toVer exist in the versions and if any of them is nil, then it picks default values.
func validateVersionRange(fromVer, toVer *semver.Version, versions semver.Collection) (*semver.Version, *semver.Version, error) {
// Unable to generate migration document if there are less than two releases!
Expand Down Expand Up @@ -266,63 +344,6 @@ func validateVersionRange(fromVer, toVer *semver.Version, versions semver.Collec
return fromVer, toVer, nil
}

func (g *Generator) GenerateBinaries(ctx context.Context) (string, string, error) {
fromBinPath, err := g.buildIgniteCli(ctx, g.From)
if err != nil {
return "", "", errors.Wrapf(err, "failed to run scaffolds for 'FROM' version %s", g.From)
}
toBinPath, err := g.buildIgniteCli(ctx, g.To)
if err != nil {
return "", "", errors.Wrapf(err, "failed to run scaffolds for 'TO' version %s", g.To)
}
return fromBinPath, toBinPath, nil
}

// buildIgniteCli build the ignite CLI from version.
func (g *Generator) buildIgniteCli(ctx context.Context, ver *semver.Version) (string, error) {
g.session.StartSpinner(fmt.Sprintf("Building binary for version v%s...", ver))

if err := g.checkoutToTag(ver.Original()); err != nil {
return "", err
}

err := exec.Exec(ctx, []string{"make", "build"}, exec.StepOption(step.Workdir(g.source)))
if err != nil {
return "", errors.Wrap(err, "failed to build ignite cli using make build")
}

// Copy the built binary to the binary path.
genBinaryPath := filepath.Join(g.source, defaultBinaryPath)
binPath := filepath.Join(g.binPath, ver.Original(), "ignite")
if err := copyFile(genBinaryPath, binPath); err != nil {
return "", err
}

g.session.StopSpinner()
g.session.EventBus().SendInfo(fmt.Sprintf("Built ignite cli for %s at %s", ver.Original(), binPath))

return binPath, nil
}

// checkoutToTag checkout the repository from a specific git tag.
func (g *Generator) checkoutToTag(tag string) error {
wt, err := g.repo.Worktree()
if err != nil {
return err
}
// Reset and clean the git directory before the checkout to avoid conflicts.
if err := wt.Reset(&git.ResetOptions{Mode: git.HardReset}); err != nil {
return errors.Wrapf(err, "failed to reset %s", g.source)
}
if err := wt.Clean(&git.CleanOptions{Dir: true}); err != nil {
return errors.Wrapf(err, "failed to reset %s", g.source)
}
if err = wt.Checkout(&git.CheckoutOptions{Branch: plumbing.NewTagReferenceName(tag)}); err != nil {
return errors.Wrapf(err, "failed to checkout tag %s", tag)
}
return nil
}

// copyFile copy a file to a destination directory. Creates the directory if not exist.
func copyFile(srcPath, dstPath string) error {
dstDir := filepath.Dir(dstPath)
Expand Down
Loading

0 comments on commit 6f7c06e

Please sign in to comment.