Skip to content
Merged
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
16 changes: 10 additions & 6 deletions src/CsProj/ProjectFileParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ namespace Skarp.Version.Cli.CsProj
public class ProjectFileParser
{
public virtual string Version { get; private set; }

public virtual string PackageVersion { get; private set; }

public virtual void Load(string xmlDocument)
{
Expand All @@ -31,12 +33,14 @@ from prop in propertyGroup.Elements()
where prop.Name == "Version"
select prop
).FirstOrDefault();

if(xVersion == null)
{
throw new ArgumentException("Provided csproj file does not contain a <Version>", paramName: "version");
}
Version = xVersion.Value;
Version = xVersion?.Value ?? "0.0.0";

var xPackageVersion = (
from prop in propertyGroup.Elements()
where prop.Name == "PackageVersion"
select prop
).FirstOrDefault();
PackageVersion = xPackageVersion?.Value ?? Version;
}
}
}
94 changes: 86 additions & 8 deletions src/CsProj/ProjectFileVersionPatcher.cs
Original file line number Diff line number Diff line change
@@ -1,32 +1,110 @@
using System;
using System.IO;
using System.Linq;
using System.Xml.Linq;

namespace Skarp.Version.Cli.CsProj
{
public class ProjectFileVersionPatcher
{
private XDocument _doc;

public virtual void Load(string xmlDocument)
{
_doc = XDocument.Parse(xmlDocument);
}

/// <summary>
/// Replace the existing version number in the csproj xml with the new version
/// </summary>
/// <param name="xml">The csproj xml loaded from disk</param>
/// <param name="oldVersion">The old version number present in the xml</param>
/// <param name="newVersion">The new version number to persist in the csproj file</param>
/// <returns></returns>
public virtual string Patch(string xml, string oldVersion, string newVersion)
public virtual void PatchVersionField(string oldVersion, string newVersion)
{
var elementName = "Version";
PatchGenericField(elementName, oldVersion, newVersion);
}

/// <summary>
/// Replace the existing PackageVersion number in the csproj xml file
/// </summary>
/// <param name="oldVersion">Old version to replace</param>
/// <param name="newVersion">New version to insert</param>
/// <returns></returns>
/// <exception cref="NotSupportedException"></exception>
public virtual void PatchPackageVersionField(string oldVersion, string newVersion)
{
var elementName = "PackageVersion";
PatchGenericField(elementName, oldVersion, newVersion);
}

/// <summary>
/// Helper method for patching up a generic XML field in the loaded XML
/// </summary>
/// <param name="elementName">The name to find and update or add it to the tree</param>
/// <param name="oldVal">Old value</param>
/// <param name="newVal">New value</param>
/// <exception cref="InvalidOperationException"></exception>
private void PatchGenericField(string elementName, string oldVal, string newVal)
{
return xml.Replace(
$"<Version>{oldVersion}</Version>",
$"<Version>{newVersion}</Version>"
);
if (_doc == null)
{
throw new InvalidOperationException("Please call Load(string xml) before invoking patch operations");
}

// If the element is not present, add it to the XML document (csproj file
if (!ContainsElement(elementName))
{
AddMissingElementToCsProj(elementName, oldVal);
}

var elm = _doc.Descendants(elementName).First();
elm.Value = newVal;
}

private bool ContainsElement(string elementName)
{
var nodes = _doc.Descendants(elementName);
return nodes.Any();
}

private void AddMissingElementToCsProj(string elementName, string value)
{
// try to locate the PropertyGroup where the element belongs
var node = _doc.Descendants("TargetFramework").FirstOrDefault();
if (node == null)
{
node = _doc.Descendants("TargetFrameworks").FirstOrDefault();

if (node == null)
{
throw new ArgumentException(
"Given XML does not contain PackageVersion and cannot locate PropertyGroup to add it to - is this a valid csproj?");
}
}

var propertyGroup = node.Parent;
propertyGroup.Add(new XElement(elementName, value));
}

/// <summary>
/// Save the csproj changes to disk
/// </summary>
/// <param name="xml">The csproj xml content</param>
/// <param name="filePath">The path of the csproj to write to</param>
public virtual void Flush(string xml, string filePath)
public virtual void Flush(string filePath)
{
File.WriteAllText(filePath, _doc.ToString());
}

/// <summary>
/// Get the underlying csproj XML back from the patcher
/// </summary>
/// <returns></returns>
public virtual string ToXml()
{
File.WriteAllText(filePath, xml);
return _doc.ToString();
}
}
}
27 changes: 20 additions & 7 deletions src/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ static void Main(string[] args)
"-f | --project-file <path/to/csproj>",
"The project file to work on. Defaults to auto-locating in current directory",
CommandOptionType.SingleValue);

var buildMetaOption = commandLineApplication.Option(
"-b | --build-meta <the-build-meta>",
"Additional build metadata to add to a `premajor`, `preminor` or `prepatch` version bump",
CommandOptionType.SingleValue);

commandLineApplication.OnExecute(() =>
{
Expand Down Expand Up @@ -79,7 +84,8 @@ static void Main(string[] args)
outputFormat,
doVcs,
dryRunEnabled,
csProjectFileOption.Value()
csProjectFileOption.Value(),
buildMetaOption.Value()
);
_cli.Execute(cliArgs);

Expand Down Expand Up @@ -110,30 +116,37 @@ static void Main(string[] args)
commandLineApplication.Execute(args);
}

internal static VersionCliArgs GetVersionBumpFromRemainingArgs(
List<string> remainingArguments,
internal static VersionCliArgs GetVersionBumpFromRemainingArgs(List<string> remainingArguments,
OutputFormat outputFormat,
bool doVcs,
bool dryRunEnabled,
string userSpecifiedCsProjFilePath)
string userSpecifiedCsProjFilePath,
string userSpecifiedBuildMeta
)
{
if (remainingArguments == null || !remainingArguments.Any())
{
var msgEx =
"No version bump specified, please specify one of:\n\tmajor | minor | patch | <specific version>";
"No version bump specified, please specify one of:\n\tmajor | minor | patch | premajor | preminor | prepatch | <specific version>";
// ReSharper disable once NotResolvedInText
throw new ArgumentException(msgEx, "versionBump");
}

var args = new VersionCliArgs {OutputFormat = outputFormat, DoVcs = doVcs, DryRun = dryRunEnabled};
var args = new VersionCliArgs
{
OutputFormat = outputFormat,
DoVcs = doVcs,
DryRun = dryRunEnabled,
BuildMeta = userSpecifiedBuildMeta,
};
var bump = VersionBump.Patch;

foreach (var arg in remainingArguments)
{
if (Enum.TryParse(arg, true, out bump)) break;

var ver = SemVer.FromString(arg);
args.SpecificVersionToApply = ver.ToVersionString();
args.SpecificVersionToApply = ver.ToSemVerVersionString();
bump = VersionBump.Specific;
}

Expand Down
Loading