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 demo test screnario #3191

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
using GitTools.Testing;
using GitVersion.Model.Configuration;
using LibGit2Sharp;
using NUnit.Framework;
using Shouldly;

namespace GitVersion.Core.Tests.IntegrationTests;

/// <summary>
/// This demonstrates a full cycle to the release of 1.0.0 with the git flow workflow.
/// Since merging stuff to release/* from develop has a bug then decrements versions on develop
/// (as shown in the failing test <see cref="ReducedReleaseWorkflowDemo"/>),
/// we use cherry picking instead of merging to get stuff from develop to release/*.
/// For simplicity, we ignore the fact that the develop branch is usually updated via feature/* branches.
/// </summary>
public class FullReleaseGitFlowWithCherryPickWorkaround : IDisposable
{
private readonly EmptyRepositoryFixture _fixture = new();

private readonly Config _config = new()
{
// ❓ In my GitVersion.yml I actually have set the version to "1.0"
// but that will cause an exception when I do it here in the tests
NextVersion = "1.0.0"
};

public void Dispose() => _fixture.Dispose();

[Test]
public void Demonstrate()
{
// create main and develop branches
// develop is one commits ahead of main
MakeACommit("Commit 1 (made on main)");
CreateAndCheckoutBranch("develop");
MakeACommit("Commit 2 (made on develop)");

// ✅ succeeds as expected
GetCurrentSemVer().ShouldBe("1.0.0-alpha.1");

// now we are ready to start with the preparation of the 1.0.0 release
CreateAndCheckoutBranch("release/1.0.0");

// ✅ succeeds as expected
GetCurrentSemVer().ShouldBe("1.0.0-beta.1");
GetCurrentSemVer("develop").ShouldBe("1.0.0-alpha.1");

// make another commit on release/1.0.0 to prepare the actual beta1 release
MakeACommit("Commit 3 (made on release/1.0.0)");

// ✅ succeeds as expected
GetCurrentSemVer().ShouldBe("1.0.0-beta.1");
GetCurrentSemVer("develop").ShouldBe("1.0.0-alpha.1");

// now we makes changes on develop that may or may not end up in the 1.0.0 release
CheckoutBranch("develop");
MakeACommit("Commit 4 (made on develop)");

// ✅ succeeds as expected
GetCurrentSemVer().ShouldBe("1.1.0-alpha.1");
GetCurrentSemVer("release/1.0.0").ShouldBe("1.0.0-beta.1");

// now we do the actual release of beta 1
CheckoutBranch("release/1.0.0");
ApplyTag("1.0.0-beta1");

// ✅ succeeds as expected
GetCurrentSemVer().ShouldBe("1.0.0-beta.1");
GetCurrentSemVer("develop").ShouldBe("1.1.0-alpha.1");

// continue with more work on develop that may or may not end up in the 1.0.0 release
CheckoutBranch("develop");
MakeACommit("Commit 5 (made on develop)");

// ✅ succeeds as expected
GetCurrentSemVer().ShouldBe("1.1.0-alpha.2");
GetCurrentSemVer("release/1.0.0").ShouldBe("1.0.0-beta.1");

// now we decide that Commit 5 made on develop should be part of the beta 2 release
// se we cherry pick it
CheckoutBranch("release/1.0.0");
CherryPickLatestCommitFromBranch("develop");

// ✅ succeeds as expected
GetCurrentSemVer().ShouldBe("1.0.0-beta.2");
GetCurrentSemVer("develop").ShouldBe("1.1.0-alpha.2");

// now we do an important bugfix that we found while preparing beta 2
MakeACommit("Commit 6 (made on release/1.0.0)");

// ✅ succeeds as expected
GetCurrentSemVer().ShouldBe("1.0.0-beta.2");
GetCurrentSemVer("develop").ShouldBe("1.1.0-alpha.2");

// we want everything (Commit 3 and 6) that we made only on release/1.0.0 be in develop
CheckoutBranch("develop");
MergeWithNoFF("release/1.0.0");

// ✅ succeeds as expected
GetCurrentSemVer().ShouldBe("1.1.0-alpha.6");
GetCurrentSemVer("release/1.0.0").ShouldBe("1.0.0-beta.2");

// now we do the actual 1.0.0 release
CheckoutBranch("release/1.0.0");
MakeACommit("Commit 7 (made on release/1.0.0)");
CheckoutBranch("main");
MergeWithNoFF("release/1.0.0");
ApplyTag("1.0.0");
CheckoutBranch("develop");
MergeWithNoFF("release/1.0.0");
DeleteBranch("relesase/1.0.0");

// ✅ succeeds as expected
GetCurrentSemVer().ShouldBe("1.1.0-alpha.8");
GetCurrentSemVer("main").ShouldBe("1.0.0");


}

private void DeleteBranch(string branch) => _fixture.Repository.Branches.Remove(branch);

private void MakeACommit(string? message = null) => _fixture.Repository.MakeACommit(message);

private void CheckoutBranch(string branchName) => Commands.Checkout(_fixture.Repository, _fixture.Repository.Branches[branchName]);

private void CreateAndCheckoutBranch(string branchName) => Commands.Checkout(_fixture.Repository, _fixture.Repository.CreateBranch(branchName));

private string GetCurrentSemVer(string? branch = null)
{
if (branch == null)
{
return _fixture.GetVersion(_config).SemVer;
}

if (_fixture.Repository.Branches.All(b => b.FriendlyName != branch))
{
throw new InvalidOperationException($"Branch {branch} does not exist");
}

return _fixture.GetVersion(_config, branch: branch).SemVer;
}

private void ApplyTag(string tag) => _fixture.Repository.ApplyTag(tag);

private void MergeWithNoFF(string sourceBranch) => _fixture.Repository.MergeNoFF(sourceBranch);

private void CherryPickLatestCommitFromBranch(string sourceBranch) => this._fixture.Repository.CherryPick(this._fixture.Repository.Branches[sourceBranch].Commits.First(), Generate.SignatureNow());
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
using GitTools.Testing;
using GitVersion.Model.Configuration;
using GitVersion.OutputVariables;
using LibGit2Sharp;
using NUnit.Framework;
using Shouldly;

namespace GitVersion.Core.Tests.IntegrationTests;

/// <summary>
/// This demonstrates exactly the git flow described in https://github.com/GitTools/GitVersion/discussions/3177
/// The assertions expect that the version on develop always increments on develop.
/// The eventually fail (at the end of this test) after we merged develop -> release/1.0.0.
/// For simplicity, we ignore the fact that the develop branch is usually updated via feature/* branches.
/// </summary>
public class GitFlowScenarioFromDiscussion
{
[Test]
public void Demonstrate()
{
var configuration = new Config
{
// Settings the below NextVersion results in an exception
// I wanted to set it to globally start with version 1
// Setting the version to 1.0 (which is not a valid semantic version)
// works in GitVersion.yml but not here.

// NextVersion = "1.0"
};

// create main and develop branch, develop is two commits ahead of main
using var fixture = new EmptyRepositoryFixture();
fixture.Repository.MakeACommit();
Commands.Checkout(fixture.Repository, fixture.Repository.CreateBranch("develop"));
fixture.Repository.MakeACommit();
fixture.Repository.MakeACommit();

var previousVersion = GetSemVer(fixture.GetVersion(configuration));

// make a 3rd commit on develop
fixture.Repository.MakeACommit();

var currentVersion = GetSemVer(fixture.GetVersion(configuration));

currentVersion.ShouldBeGreaterThan(previousVersion,
"the semver should be incremented after a commit on develop");

// we are ready to prepare the 1.0.0 release, create and checkout release/1.0.0
Commands.Checkout(fixture.Repository, fixture.Repository.CreateBranch("release/1.0.0"));

fixture.GetVersion(configuration).SemVer.ShouldBe("1.0.0-beta.1",
"the first semver on release/1.0.0 should be beta1");

// make another commit on release/1.0.0 to prepare the actual beta1 release
fixture.Repository.MakeACommit();

fixture.GetVersion(configuration).SemVer.ShouldBe("1.0.0-beta.1",
"the semver on release/1.0.0 should still be be beta1");

Commands.Checkout(fixture.Repository, fixture.Repository.Branches["develop"]);

previousVersion = currentVersion;
currentVersion = GetSemVer(fixture.GetVersion(configuration));

currentVersion.ShouldBe(previousVersion,
"the semver on develop should not have changed " +
"even when release/1.0.0 has new commits due to beta 1 preparations");

// now some other team member makes changes on develop that may or may not end up in 1.0.0
fixture.Repository.MakeACommit();
fixture.Repository.MakeACommit();

previousVersion = currentVersion;
currentVersion = GetSemVer(fixture.GetVersion(configuration));

currentVersion.ShouldBeGreaterThan(previousVersion,
"the semver should be incremented after a even more commit on develop");

Commands.Checkout(fixture.Repository, fixture.Repository.Branches["release/1.0.0"]);

// now we release the beta 1
fixture.Repository.ApplyTag("1.0.0-beta1");

fixture.GetVersion(configuration).SemVer.ShouldBe("1.0.0-beta.1",
"the on release/1.0.0 should still be beta1 after the beta 1 tag");

// continue with more work on develop that may or may not end up in 1.0.0
Commands.Checkout(fixture.Repository, fixture.Repository.Branches["develop"]);
fixture.Repository.MakeACommit();
fixture.Repository.MakeACommit();

previousVersion = currentVersion;
currentVersion = GetSemVer(fixture.GetVersion(configuration));

currentVersion.ShouldBeGreaterThan(previousVersion,
"the semver should be incremented after a even more commit on develop");

// now we decide that the three commits on develop should be part of the beta 2 release
// se we merge it into release/1.0.0 with --no-ff because it is a protected branch
Commands.Checkout(fixture.Repository, fixture.Repository.Branches["release/1.0.0"]);
fixture.Repository.Merge(
fixture.Repository.Branches["develop"],
Generate.SignatureNow(),
new MergeOptions {FastForwardStrategy = FastForwardStrategy.NoFastForward});

fixture.GetVersion(configuration).SemVer.ShouldBe("1.0.0-beta.2",
"the next semver on release/1.0.0 should be beta2");

Commands.Checkout(fixture.Repository, fixture.Repository.Branches["develop"]);
previousVersion = currentVersion;
currentVersion = GetSemVer(fixture.GetVersion(configuration));

currentVersion.ShouldBeGreaterThanOrEqualTo(previousVersion,
"the semver should be incremented (or unchanged) " +
"after we merged develop into release/1.0.0");

static SemanticVersion GetSemVer(VersionVariables ver)
=> SemanticVersion.Parse(ver.FullSemVer, null);
}
}
108 changes: 108 additions & 0 deletions src/GitVersion.Core.Tests/IntegrationTests/ReducedGitFlowWithMerge.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
using GitTools.Testing;
using GitVersion.Model.Configuration;
using LibGit2Sharp;
using NUnit.Framework;
using Shouldly;

namespace GitVersion.Core.Tests.IntegrationTests;

/// <summary>
/// This demonstrates a bug that decrements the version on develop when we merge stuff from develop to release/*
/// in the default git flow workflow.
/// For simplicity, we ignore the fact that the develop branch is usually updated via feature/* branches.
/// </summary>
public class ReducedGitFlowWithMerge : IDisposable
{
private static readonly EmptyRepositoryFixture _fixture = new();

private static readonly Config _config = new()
{
// ❓ In my GitVersion.yml I actually have set the version to "1.0"
// but that will cause an exception when I do it here in the tests
NextVersion = "1.0.0"
};

public void Dispose() => _fixture.Dispose();

[Test]
public void Demonstrate()
{
// create main and develop branches
// develop is one commits ahead of main
MakeACommit();
CreateAndCheckoutBranch("develop");
MakeACommit();

// ✅ succeeds as expected
GetCurrentSemVer().ShouldBe("1.0.0-alpha.1");

// now we are ready to start with the preparation of the 1.0.0 release
CreateAndCheckoutBranch("release/1.0.0");

// ✅ succeeds as expected
GetCurrentSemVer().ShouldBe("1.0.0-beta.1");

// make another commit on release/1.0.0 to prepare the actual beta1 release
MakeACommit();

// ✅ succeeds as expected
GetCurrentSemVer().ShouldBe("1.0.0-beta.1");

// now we makes changes on develop that may or may not end up in the 1.0.0 release
CheckoutBranch("develop");
MakeACommit();

// ❌ fails! actual: "1.1.0-alpha.1"
// We have not released 1.0.0, not even a beta, so why increment to 1.1.0?
// Even though this surprising, it might actually be OK,
// at least the version is incremented, which is needed for the CI nuget feed
GetCurrentSemVer().ShouldBe("1.0.0-alpha.2");

// now we do the actual release of beta 1
CheckoutBranch("release/1.0.0");
ApplyTag("1.0.0-beta1");

// ✅ succeeds as expected
GetCurrentSemVer().ShouldBe("1.0.0-beta.1");

// continue with more work on develop that may or may not end up in the 1.0.0 release
CheckoutBranch("develop");
MakeACommit();

// ❌ fails! actual: "1.1.0-alpha.2"
// We still have not finally released 1.0.0 yet, only a beta, so why increment to 1.1.0?
// Even though this surprising, it might actually be OK,
// at least the version is incremented, which is needed for the CI nuget feed
GetCurrentSemVer().ShouldBe("1.0.0-alpha.3");

// now we decide that the new changes on develop should be part of the beta 2 release
// se we merge it into release/1.0.0 with --no-ff because it is a protected branch
// but we don't do the release of beta 2 jus yet
CheckoutBranch("release/1.0.0");
MergeWithNoFF("develop");

// ✅ succeeds as expected
GetCurrentSemVer().ShouldBe("1.0.0-beta.2");

CheckoutBranch("develop");

// ❌ fails! actual "1.0.0-alpha.3"
// This is now really a problem. Why did it decrement the minor version?
// All subsequent changes on develop will now a lower version that previously
// and the nuget packages end up on the CI feed with a lower version
// so users of that feed would need to _downgrade_ to get a _newer_ version.
GetCurrentSemVer().ShouldBe("1.1.0-alpha.2");
}

private static void MakeACommit() => _fixture.Repository.MakeACommit();

private void CheckoutBranch(string branchName) => Commands.Checkout(_fixture.Repository, _fixture.Repository.Branches[branchName]);

private void CreateAndCheckoutBranch(string branchName) => Commands.Checkout(_fixture.Repository, _fixture.Repository.CreateBranch(branchName));

private string GetCurrentSemVer() => _fixture.GetVersion(_config).SemVer;

private void ApplyTag(string tag) => _fixture.Repository.ApplyTag(tag);

private void MergeWithNoFF(string sourceBranch) => _fixture.Repository.MergeNoFF(sourceBranch);
}