Skip to content

Commit

Permalink
Merge pull request #458 from JakeGinnivan/Docs
Browse files Browse the repository at this point in the history
Docs
  • Loading branch information
JakeGinnivan committed Jun 8, 2015
2 parents 3cffd4a + ca422f7 commit 24fa6b5
Show file tree
Hide file tree
Showing 28 changed files with 848 additions and 47 deletions.
1 change: 1 addition & 0 deletions Docs/configurationOptions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Confiuration options
44 changes: 44 additions & 0 deletions Docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# GitVersion Docs
GitVersion is a tool to help you achieve Semantic Versioning on your project.

This influences many of the decisions GitVersion has made, please read and understand this page as it will help you start using GitVersion effectively!

## Assumptions/Rules
### You tag releases when you release, not before
GitVersion assumes that tags are used to *tag a release* and not used to build a release.

This means that the version is calculated pre-emptively, if you currently tag, build then release that tag then GitVersion will probably not work for you.

### Tags override other rules
If a commit is tagged, then GitVersion will *always* use that version over any calculated versions. This is so if you rebuild a tag then the same version will be produced.

### The Semantic Version does not increment every commit
This trips a lot of people up, by default GitVersion *does not* increment the SemVer every commit. This means that you will get multiple builds producing the *same version* of your application.

Read more at [version increments](./versionIncrements.md)

### Version sources
There are a number of sources GitVersion can get it's versions from, they include:

- Tags
- Version numbers in branches (i.e `release/2.0.0`)
- Merge messages (for branches with versions in them, i.e `Merged branch 'release/2.0.0' into master`)
- Track version of another branch (i.e develop tracks master, so when master increments so does develop)
- GitVersionConfig.yaml file (i.e `next-version: 2.0.0`)

Read more at [version sources](./versionSources.md)

## Configuration
GitVersion v3 was rewritten to be very configuration driven rather than hardcoding git workflows into it. This has made it a lot more flexible. Configuration options can be set globally or per branch.

Read more about the different [configuration options](./configurationOptions.md)

## Output Variables
We recognise that a single formatted version number does not work for all cases. A simple example is NuGet, it doesn't support SemVer 2.0 meaning that the SemVer of `1.3.5-beta.10+500` needs to be formatted as `1.3.5-beta0010` so it will sort properly.

You can just run `GitVersion.exe` in your repository to see what variables are available (by default a json object is returned).

## Exe or MSBuild Task
There are two ways to consume GitVersion, the first is by running GitVersion.exe. The second is an MSBUild task. The MSBuild task is really easy to get up and running, simply install GitVersionTask from NuGet and it will integrate into your project and write out variables to your build server if it's running on one. The exe offers more options and works for not just .net projects.

Read more about [using GitVersion](./usage.md)
7 changes: 7 additions & 0 deletions Docs/usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Usage
Info about exe and msbuild task.

### Output options
By default GitVersion returns a json object to stdout. This works great if you want to get your build scripts to parse the json object then use the variables, but there is a simpler way.

`GitVersion.exe /output buildserver` will change the mode of GitVersion to write out the variables to whatever build server it is running in. You can then use those variables in your build scripts or run different tools to create versioned NuGet packages or whatever you would like to do.
22 changes: 22 additions & 0 deletions Docs/versionIncrements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Version Incrementing
SemVer is all about *releases*, not builds. When you release the next version of your library/app/website/whatever you should only increment major/minor or patch then reset all lower parts to 0, for instance given 1.0.0, the next release should be either `2.0.0`, `1.1.0` or `1.0.1`. Bumping one of the version components by more than 1 in a single release means you will be missing versions.

Because of this, GitVersion works out what the next SemVer of your app is on each commit. When you are ready to release you simply deploy the latest built version and tag the release it was from. This practice is called *continuous delivery*. GitVersion will increment the metadata for each build so you can tell builds apart. For example `1.0.0+5` followed by `1.0.0+6`.

This causes problems for people as NuGet and other package managers do not support multiple packages with the same version with only different metadata.
There are a few ways to handle this problem depending on what your requirements are:

## 1. GitFlow
If you are using GitFlow then builds off the `develop` branch will actually increment on every commit. By default `develop` builds are tagged with the `unstable` pre-release tag. This is so they are sorted higher than release branches.

If you need to consume packages built from develop, we recommend publishing these packages to a separate NuGet feed as an alpha channel. That way you can publish beta/release candidate builds and only people who opt into the alpha feed will see the unstable pacakges.

## 2. Octopus deploy
Because Octopus uses NuGet under the covers you cannot publish every build into Octopus deploy. For this we have two possible options:

### 2a. 'Release' packages to Octopus deploy
Rather than all builds going into Octopus's NuGet feed, you release builds into it's feed. When you push a package into the NuGet feed you need to tag that release. The next commit will then increment the version.
This has the advantage that if you have a multi-stage deployment pipeline you pick packages which you would like to start through the pipeline, then you can see all the versions which did not make it through the pipeline (for instance, they got to UAT but not production due to a bug being found). In the release notes this can be mentioned or those versions can be skipped.

### 2b. Configure GitVersion to increment per commit
As mentioned above, this means you will burn multiple versions per release. This might not be an issue for you, but can confuse consumers of your library as the version has semantic meaning.
35 changes: 35 additions & 0 deletions Docs/versionSources.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Version Sources
GitVersion has a two step process for calculating the version number, the first is to calculate the base version which is used to then calculate what the next version should be.

The logic of GitVersion is something like this:

- Is the current commit tagged
- Yes: Use the tag as the version
- No: continue
- Calculate the base version (highest version from all the sources)
- Increment version if needed based on branch config
- Calculate the build metadata (everything after the +) and append to the calcuated version

## Version Sources
### Highest Accessible Tag
GitVersion will find all tags on the current branch and return the highest one.

Will increment: true

### Version in branch name
If the branch has a version in it, then that version will be returned

Will increment: false

### Merge message
If a branch with a version number in it is merged into the current branch, that version number will be used.

Will increment: false

### GitVersionConfig.yaml
If the next-version property is specified in the config file, it will be used as a version source.

Will increment: false

### Others?
Want more ways to increment the version? Open an issue with your idea and submit a pull request!
18 changes: 0 additions & 18 deletions GitVersionCore.Tests/ConfigProviderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,24 +124,6 @@ public void CanReadDefaultDocument()
config.NextVersion.ShouldBe(null);
}

[Test]
public void VerifyInit()
{
var config = typeof(Config);
var aliases = config.GetProperties()
.Where(p => p.GetCustomAttribute<ObsoleteAttribute>() == null)
.Select(p => ((YamlMemberAttribute) p.GetCustomAttribute(typeof(YamlMemberAttribute))).Alias);
var writer = new StringWriter();

ConfigSerialiser.WriteSample(writer);
var initFile = writer.GetStringBuilder().ToString();

foreach (var alias in aliases)
{
initFile.ShouldContain(alias);
}
}

[Test]
public void VerifyAliases()
{
Expand Down
12 changes: 0 additions & 12 deletions GitVersionCore/Configuration/ConfigSerialiser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,5 @@ public static void Write(Config config, TextWriter writer)
var serializer = new Serializer(SerializationOptions.None, new HyphenatedNamingConvention());
serializer.Serialize(writer, config);
}

public static void WriteSample(TextWriter writer)
{
writer.WriteLine("# assembly-versioning-scheme: MajorMinorPatchTag | MajorMinorPatch | MajorMinor | Major");
writer.WriteLine("# tag-prefix: '[vV|version-] # regex to match git tag prefix");
writer.WriteLine("# next-version: 1.0.0");
writer.WriteLine("# mode: ContinuousDelivery | ContinuousDeployment");
writer.WriteLine("# continuous-delivery-fallback-tag: ci");
writer.WriteLine("#branches:");
writer.WriteLine("# release[/-]:\n mode: ContinuousDelivery | ContinuousDeployment\n tag: rc");
writer.WriteLine("# develop:\n# mode: ContinuousDelivery | ContinuousDeployment\n# tag: alpha");
}
}
}
29 changes: 13 additions & 16 deletions GitVersionCore/Configuration/ConfigurationProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,27 +33,24 @@ public static string GetEffectiveConfigAsString(string gitDirectory, IFileSystem
return stringBuilder.ToString();
}

public static void WriteSample(string workingDirectory, IFileSystem fileSystem)
static string GetConfigFilePath(string workingDirectory)
{
return Path.Combine(workingDirectory, "GitVersionConfig.yaml");
}

public static void Init(string workingDirectory, IFileSystem fileSystem)
{
var configFilePath = GetConfigFilePath(workingDirectory);
var config = new ConfigInitWizard().Run(Provide(workingDirectory, fileSystem));
if (config == null) return;

if (!fileSystem.Exists(configFilePath))
{
using (var stream = fileSystem.OpenWrite(configFilePath))
using (var writer = new StreamWriter(stream))
{
ConfigSerialiser.WriteSample(writer);
}
}
else
using (var stream = fileSystem.OpenWrite(configFilePath))
using (var writer = new StreamWriter(stream))
{
Logger.WriteError("Cannot write sample, GitVersionConfig.yaml already exists");
Logger.WriteInfo("Saving config file");
ConfigSerialiser.Write(config, writer);
stream.Flush();
}
}

static string GetConfigFilePath(string workingDirectory)
{
return Path.Combine(workingDirectory, "GitVersionConfig.yaml");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
namespace GitVersion
{
using System.Collections.Generic;

public class AssemblyVersioningSchemeSetting : ConfigInitWizardStep
{
protected override StepResult HandleResult(string result, Queue<ConfigInitWizardStep> steps, Config config)
{
switch (result)
{
case "0":
steps.Enqueue(new EditConfigStep());
return StepResult.Ok();
case "1":
config.AssemblyVersioningScheme = AssemblyVersioningScheme.Major;
steps.Enqueue(new EditConfigStep());
return StepResult.Ok();
case "2":
config.AssemblyVersioningScheme = AssemblyVersioningScheme.MajorMinor;
steps.Enqueue(new EditConfigStep());
return StepResult.Ok();
case "3":
config.AssemblyVersioningScheme = AssemblyVersioningScheme.MajorMinorPatch;
steps.Enqueue(new EditConfigStep());
return StepResult.Ok();
case "4":
config.AssemblyVersioningScheme = AssemblyVersioningScheme.MajorMinorPatchTag;
steps.Enqueue(new EditConfigStep());
return StepResult.Ok();
}

return StepResult.InvalidResponseSelected();
}

protected override string GetPrompt(Config config)
{
return @"What assembly versioning scheme do you want to use:
0) Back
1) Major.0.0.0
2) Major.Minor.0.0
3) Major.Minor.Patch.0 (default)
4) Major.Minor.Patch.TagCount (Allows different pre-release tags to cause assembly version to change)";
}

protected override string DefaultResult
{
get { return "0"; }
}
}
}
26 changes: 26 additions & 0 deletions GitVersionCore/Configuration/Wizard/ConfigInitWizard.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
namespace GitVersion
{
using System;
using System.Collections.Generic;

public class ConfigInitWizard
{
public Config Run(Config config)
{
Console.WriteLine("GitVersion init will guide you through setting GitVersion up to work for you");
var steps = new Queue<ConfigInitWizardStep>();
steps.Enqueue(new SimpleOrTutorialStep());

while (steps.Count > 0)
{
var currentStep = steps.Dequeue();
if (!currentStep.Apply(steps, config))
{
return null;
}
}

return config;
}
}
}
54 changes: 54 additions & 0 deletions GitVersionCore/Configuration/Wizard/ConfigInitWizardStep.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
namespace GitVersion
{
using System;
using System.Collections.Generic;

public abstract class ConfigInitWizardStep
{
public bool Apply(Queue<ConfigInitWizardStep> steps, Config config)
{
Console.WriteLine();
Console.WriteLine(GetPrompt(config));
var input = Console.ReadLine();
if (input == null)
{
Console.WriteLine("Would you like to save changes? (y/n)");
input = Console.ReadLine();
if (input == null || input.ToLower() == "n") return false;
if (input.ToLower() == "y")
{
steps.Clear();
return true;
}

InvalidResponse(steps);
return true;
}
var resultWithDefaultApplied = string.IsNullOrEmpty(input) ? DefaultResult : input;
var stepResult = HandleResult(resultWithDefaultApplied, steps, config);
if (stepResult.InvalidResponse)
{
InvalidResponse(steps);
}
else if (stepResult.Exit)
{
steps.Clear();
return stepResult.Save;
}
return true;
}

void InvalidResponse(Queue<ConfigInitWizardStep> steps)
{
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Invalid response!");
Console.ResetColor();
steps.Enqueue(this);
}

protected abstract StepResult HandleResult(string result, Queue<ConfigInitWizardStep> steps, Config config);
protected abstract string GetPrompt(Config config);
protected abstract string DefaultResult { get; }
}
}
48 changes: 48 additions & 0 deletions GitVersionCore/Configuration/Wizard/ConfigureBranch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
namespace GitVersion
{
using System.Collections.Generic;

public class ConfigureBranch : ConfigInitWizardStep
{
string name;
readonly BranchConfig branchConfig;

public ConfigureBranch(string name, BranchConfig branchConfig)
{
this.branchConfig = branchConfig;
this.name = name;
}

protected override StepResult HandleResult(string result, Queue<ConfigInitWizardStep> steps, Config config)
{
switch (result)
{
case "0":
steps.Enqueue(new ConfigureBranches());
return StepResult.Ok();
case "1":
steps.Enqueue(new SetBranchTag(name, branchConfig));
return StepResult.Ok();
case "2":
steps.Enqueue(new SetBranchIncrementMode(name, branchConfig));
return StepResult.Ok();
}

return StepResult.InvalidResponseSelected();
}

protected override string GetPrompt(Config config)
{
return string.Format(@"What would you like to change for '{0}':
0) Back
1) Branch Pre-release tag (Current: {1})
2) Branch Increment mode (per commit/after tag) (Current: {2})", name, branchConfig.Tag, branchConfig.VersioningMode);
}

protected override string DefaultResult
{
get { return "0"; }
}
}
}
Loading

0 comments on commit 24fa6b5

Please sign in to comment.