Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add JSON output option to 'prepare-release' command #486

Merged
merged 8 commits into from May 29, 2020
43 changes: 43 additions & 0 deletions doc/nbgv-cli.md
Expand Up @@ -121,6 +121,49 @@ The behaviour of the `prepare-release` command can be customized in
| versionIncrement | `minor` | Specifies which part of the version on the current branch is incremented when preparing a release. Allowed values are `major`, `minor` and `build`. |
| firstUnstableTag | `alpha` | Specified the unstable tag to use for the main branch. |

### Customizing the `prepare-release` output format

By default, the `prepare-release` command writes information about created and updated branches to the console as text.
Alternatively the information can be written to the output as `json`.
The output format to use can be set using the `--format` command line parameter.

For example, running the follwoing command on `master`

```
nbgv prepare-release --format json
```

will generate output similar to this:

```json
{
"CurrentBranch": {
"Name": "master",
"Commit": "5a7487098ac1be1ceb4dbf72d862539cf0b0c27a",
"Version": "1.7-alpha"
},
"NewBranch": {
"Name": "v1.7",
"Commit": "b2f164675ffe891b66b601c00efc4343581fc8a5",
"Version": "1.7"
}
}
```

The JSON object has to properties:

- `CurrentBranch` provides information about the branch `prepare-release` was started on (typically `master`)
- `NewBranch` provides information about the new branch created by the command.

For each branch, the following proprties are provided:

- `Name`: The name of the branch
- `Commit`: The id of the latest commit on that branch
- `Version`: The version configured in that branch's `version.json`

**Note:** When the current branch is already the release branch for the current version, no new branch will be created.
In that case, the `NewBranch` property will be `null`.

## Learn more

There are several more sub-commands and switches to each to help you build and maintain your projects, find a commit that built a particular version later on, create tags, etc.
Expand Down
152 changes: 152 additions & 0 deletions src/NerdBank.GitVersioning.Tests/ReleaseManagerTests.cs
Expand Up @@ -3,6 +3,8 @@
using System.Linq;
using LibGit2Sharp;
using Nerdbank.GitVersioning;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Xunit;
using Xunit.Abstractions;

Expand Down Expand Up @@ -401,6 +403,156 @@ public void PrepareRelease_InvalidVersionIncrement()
this.AssertError(() => new ReleaseManager().PrepareRelease(this.RepoPath), ReleasePreparationError.InvalidVersionIncrementSetting);
}

[Fact]
public void PrepareRelease_TextOutput()
{
// create and configure repository
this.InitializeSourceControl();

// create version.json
var versionOptions = new VersionOptions() { Version = SemanticVersion.Parse("1.0") };
this.WriteVersionFile(versionOptions);

var stdout = new StringWriter();
var releaseManager = new ReleaseManager(stdout);
releaseManager.PrepareRelease(this.RepoPath);

// by default, text output mode should be used => trying to parse it as JSON should fail
Assert.ThrowsAny<JsonException>(() => JsonConvert.DeserializeObject(stdout.ToString()));
}

[Fact]
public void PrepareRelease_JsonOutput()
{
// create and configure repository
this.InitializeSourceControl();

// create version.json
var versionOptions = new VersionOptions()
{
Version = SemanticVersion.Parse("1.0"),
Release = new ReleaseOptions()
{
BranchName = "v{version}",
VersionIncrement = ReleaseVersionIncrement.Minor
}
};
this.WriteVersionFile(versionOptions);

var currentBranchName = this.Repo.Head.FriendlyName;
var releaseBranchName = "v1.0";

// run release preparation
var stdout = new StringWriter();
var releaseManager = new ReleaseManager(stdout);
releaseManager.PrepareRelease(this.RepoPath, outputMode: ReleaseManager.ReleaseManagerOutputMode.Json);


// Expected output:
// {
// "CurrentBranch" : {
// "Name" : "<NAME-OF-CURRENT-BRANCH>",
// "Commit" : "<HEAD-COMMIT-OF-CURRENT-BRANCH>",
// "Version" : "<UPDATED-VERSION-ON-CURRENT-BRANCH>",
// },
// "NewBranch" : {
// "Name" : "<NAME-OF-CREATED-BRANCH>",
// "Commit" : "<HEAD-COMMIT-OF-CREATED-BRANCH>",
// "Version" : "<VERSION-ON-CREATED-BRANCH>",
// }
// }

var jsonOutput = JObject.Parse(stdout.ToString());

// check "CurrentBranch" output
{
var expectedCommitId = this.Repo.Branches[currentBranchName].Tip.Sha;
var expectedVersion = VersionFile.GetVersion(this.Repo.Branches[currentBranchName].Tip).Version.ToString();

var currentBranchOutput = jsonOutput.Property("CurrentBranch")?.Value as JObject;
Assert.NotNull(currentBranchOutput);

Assert.Equal(currentBranchName, currentBranchOutput.GetValue("Name")?.ToString());
Assert.Equal(expectedCommitId, currentBranchOutput.GetValue("Commit")?.ToString());
Assert.Equal(expectedVersion, currentBranchOutput.GetValue("Version")?.ToString());

}

// Check "NewBranch" output
{
var expectedCommitId = this.Repo.Branches[releaseBranchName].Tip.Sha;
var expectedVersion = VersionFile.GetVersion(this.Repo.Branches[releaseBranchName].Tip).Version.ToString();

var newBranchOutput = jsonOutput.Property("NewBranch")?.Value as JObject;
Assert.NotNull(newBranchOutput);

Assert.Equal(releaseBranchName, newBranchOutput.GetValue("Name")?.ToString());
Assert.Equal(expectedCommitId, newBranchOutput.GetValue("Commit")?.ToString());
Assert.Equal(expectedVersion, newBranchOutput.GetValue("Version")?.ToString());
}
}

[Fact]
public void PrepareRelease_JsonOutputWhenUpdatingReleaseBranch()
{
// create and configure repository
this.InitializeSourceControl();

// create version.json
var versionOptions = new VersionOptions()
{
Version = SemanticVersion.Parse("1.0"),
Release = new ReleaseOptions()
{
BranchName = "v{version}",
VersionIncrement = ReleaseVersionIncrement.Minor
}
};
this.WriteVersionFile(versionOptions);
var branchName = "v1.0";

// switch to release branch
Commands.Checkout(this.Repo, this.Repo.CreateBranch(branchName));

// run release preparation
var stdout = new StringWriter();
var releaseManager = new ReleaseManager(stdout);
releaseManager.PrepareRelease(this.RepoPath, outputMode: ReleaseManager.ReleaseManagerOutputMode.Json);


// Expected output:
// {
// "CurrentBranch" : {
// "Name" : "<NAME>",
// "Commit" : "<COMMIT>",
// "Version" : "<VERSION>",
// },
// "NewBranch" : null
// }

var jsonOutput = JObject.Parse(stdout.ToString());

// check "CurrentBranch" output
{
var expectedCommitId = this.Repo.Branches[branchName].Tip.Sha;
var expectedVersion = VersionFile.GetVersion(this.Repo.Branches[branchName].Tip).Version.ToString();

var currentBranchOutput = jsonOutput.Property("CurrentBranch")?.Value as JObject;
Assert.NotNull(currentBranchOutput);

Assert.Equal(branchName, currentBranchOutput.GetValue("Name")?.ToString());
Assert.Equal(expectedCommitId, currentBranchOutput.GetValue("Commit")?.ToString());
Assert.Equal(expectedVersion, currentBranchOutput.GetValue("Version")?.ToString());

}
// Check "NewBranch" output
{
// no new branch was created, so "NewBranch" should be null
var newBranchOutput = jsonOutput.Property("NewBranch")?.Value as JObject;
Assert.Null(newBranchOutput);
}
}

private void AssertError(Action testCode, ReleasePreparationError expectedError)
{
var ex = Assert.Throws<ReleasePreparationException>(testCode);
Expand Down