/// <summary> /// Writes the version.json file to a directory within a repo with the specified version information. /// </summary> /// <param name="projectDirectory"> /// The path to the directory in which to write the version.json file. /// The file's impact will be all descendent projects and directories from this specified directory, /// except where any of those directories have their own version.json file. /// </param> /// <param name="version">The version information to write to the file.</param> /// <returns>The path to the file written.</returns> public static string SetVersion(string projectDirectory, VersionOptions version) { Requires.NotNullOrEmpty(projectDirectory, nameof(projectDirectory)); Requires.NotNull(version, nameof(version)); Requires.Argument(version.Version != null || version.Inherit, nameof(version), $"{nameof(VersionOptions.Version)} must be set for a root-level version.json file."); Directory.CreateDirectory(projectDirectory); string versionTxtPath = Path.Combine(projectDirectory, TxtFileName); if (File.Exists(versionTxtPath)) { if (version.IsDefaultVersionTheOnlyPropertySet) { File.WriteAllLines( versionTxtPath, new[] { version.Version.Version.ToString(), version.Version.Prerelease }); return(versionTxtPath); } else { // The file must be upgraded to use the more descriptive JSON format. File.Delete(versionTxtPath); } } string versionJsonPath = Path.Combine(projectDirectory, JsonFileName); var jsonContent = JsonConvert.SerializeObject(version, VersionOptions.GetJsonSettings(version.Inherit)); File.WriteAllText(versionJsonPath, jsonContent); return(versionJsonPath); }
/// <summary> /// Tries to read a version.json file from the specified string, but favors returning null instead of throwing a <see cref="JsonSerializationException"/>. /// </summary> /// <param name="jsonContent">The content of the version.json file.</param> /// <returns>The deserialized <see cref="VersionOptions"/> object, if deserialization was successful.</returns> private static VersionOptions TryReadVersionJsonContent(string jsonContent) { try { return(JsonConvert.DeserializeObject <VersionOptions>(jsonContent, VersionOptions.GetJsonSettings())); } catch (JsonSerializationException) { return(null); } }
/// <summary> /// Tries to read a version.json file from the specified string, but favors returning null instead of throwing a <see cref="JsonSerializationException"/>. /// </summary> /// <param name="jsonContent">The content of the version.json file.</param> /// <param name="repoRelativeBaseDirectory">Directory that this version.json file is relative to the root of the repository.</param> /// <returns>The deserialized <see cref="VersionOptions"/> object, if deserialization was successful.</returns> private static VersionOptions TryReadVersionJsonContent(string jsonContent, string repoRelativeBaseDirectory) { try { return(JsonConvert.DeserializeObject <VersionOptions>(jsonContent, VersionOptions.GetJsonSettings(repoRelativeBaseDirectory: repoRelativeBaseDirectory))); } catch (JsonSerializationException) { return(null); } }
/// <summary> /// Reads the version.txt file and returns the <see cref="Version"/> and prerelease tag from it. /// </summary> /// <param name="commit">The commit to read the version file from.</param> /// <param name="repoRelativeProjectDirectory">The directory to consider when searching for the version.txt file.</param> /// <returns>The version information read from the file.</returns> public static VersionOptions GetVersion(LibGit2Sharp.Commit commit, string repoRelativeProjectDirectory = null) { if (commit == null) { return(null); } string searchDirectory = repoRelativeProjectDirectory ?? string.Empty; while (searchDirectory != null) { string parentDirectory = searchDirectory.Length > 0 ? Path.GetDirectoryName(searchDirectory) : null; string candidatePath = Path.Combine(searchDirectory, TxtFileName).Replace('\\', '/'); var versionTxtBlob = commit.Tree[candidatePath]?.Target as LibGit2Sharp.Blob; if (versionTxtBlob != null) { var result = TryReadVersionFile(new StreamReader(versionTxtBlob.GetContentStream()), isJsonFile: false); if (result != null) { return(result); } } candidatePath = Path.Combine(searchDirectory, JsonFileName).Replace('\\', '/'); var versionJsonBlob = commit.Tree[candidatePath]?.Target as LibGit2Sharp.Blob; if (versionJsonBlob != null) { string versionJsonContent; using (var sr = new StreamReader(versionJsonBlob.GetContentStream())) { versionJsonContent = sr.ReadToEnd(); } VersionOptions result; try { result = TryReadVersionJsonContent(versionJsonContent); } catch (FormatException ex) { throw new FormatException( $"Failure while reading {JsonFileName} from commit {commit.Sha}. " + "Fix this commit with rebase if this is an error, or review this doc on how to migrate to Nerdbank.GitVersioning: " + "https://github.com/AArnott/Nerdbank.GitVersioning/blob/master/doc/migrating.md", ex); } if (result?.Inherit ?? false) { if (parentDirectory != null) { result = GetVersion(commit, parentDirectory); if (result != null) { JsonConvert.PopulateObject(versionJsonContent, result, VersionOptions.GetJsonSettings()); return(result); } } throw new InvalidOperationException($"\"{candidatePath}\" inherits from a parent directory version.json file but none exists."); } else if (result != null) { return(result); } } searchDirectory = parentDirectory; } return(null); }
/// <summary> /// Reads the version.txt file and returns the <see cref="Version"/> and prerelease tag from it. /// </summary> /// <param name="projectDirectory">The path to the directory which may (or its ancestors may) define the version.txt file.</param> /// <param name="actualDirectory">Set to the actual directory that the version file was found in, which may be <paramref name="projectDirectory"/> or one of its ancestors.</param> /// <returns>The version information read from the file, or <c>null</c> if the file wasn't found.</returns> public static VersionOptions GetVersion(string projectDirectory, out string actualDirectory) { Requires.NotNullOrEmpty(projectDirectory, nameof(projectDirectory)); string searchDirectory = projectDirectory; while (searchDirectory != null) { string parentDirectory = Path.GetDirectoryName(searchDirectory); string versionTxtPath = Path.Combine(searchDirectory, TxtFileName); if (File.Exists(versionTxtPath)) { using (var sr = new StreamReader(File.OpenRead(versionTxtPath))) { var result = TryReadVersionFile(sr, isJsonFile: false); if (result != null) { actualDirectory = searchDirectory; return(result); } } } string versionJsonPath = Path.Combine(searchDirectory, JsonFileName); if (File.Exists(versionJsonPath)) { string versionJsonContent = File.ReadAllText(versionJsonPath); VersionOptions result = TryReadVersionJsonContent(versionJsonContent); if (result?.Inherit ?? false) { if (parentDirectory != null) { result = GetVersion(parentDirectory); if (result != null) { JsonConvert.PopulateObject(versionJsonContent, result, VersionOptions.GetJsonSettings()); actualDirectory = searchDirectory; return(result); } } throw new InvalidOperationException($"\"{versionJsonPath}\" inherits from a parent directory version.json file but none exists."); } else if (result != null) { actualDirectory = searchDirectory; return(result); } } searchDirectory = parentDirectory; } actualDirectory = null; return(null); }
/// <summary> /// Reads the version.txt file and returns the <see cref="Version"/> and prerelease tag from it. /// </summary> /// <param name="commit">The commit to read the version file from.</param> /// <param name="repoRelativeProjectDirectory">The directory to consider when searching for the version.txt file.</param> /// <returns>The version information read from the file.</returns> public static VersionOptions GetVersion(LibGit2Sharp.Commit commit, string repoRelativeProjectDirectory = null) { if (commit == null) { return(null); } string searchDirectory = repoRelativeProjectDirectory ?? string.Empty; while (searchDirectory != null) { string parentDirectory = searchDirectory.Length > 0 ? Path.GetDirectoryName(searchDirectory) : null; string candidatePath = Path.Combine(searchDirectory, TxtFileName).Replace('\\', '/'); var versionTxtBlob = commit.Tree[candidatePath]?.Target as LibGit2Sharp.Blob; if (versionTxtBlob != null) { var result = TryReadVersionFile(new StreamReader(versionTxtBlob.GetContentStream()), isJsonFile: false); if (result != null) { return(result); } } candidatePath = Path.Combine(searchDirectory, JsonFileName).Replace('\\', '/'); var versionJsonBlob = commit.Tree[candidatePath]?.Target as LibGit2Sharp.Blob; if (versionJsonBlob != null) { string versionJsonContent; using (var sr = new StreamReader(versionJsonBlob.GetContentStream())) { versionJsonContent = sr.ReadToEnd(); } VersionOptions result = TryReadVersionJsonContent(versionJsonContent); if (result?.Inherit ?? false) { if (parentDirectory != null) { result = GetVersion(commit, parentDirectory); if (result != null) { JsonConvert.PopulateObject(versionJsonContent, result, VersionOptions.GetJsonSettings()); return(result); } } throw new InvalidOperationException($"\"{candidatePath}\" inherits from a parent directory version.json file but none exists."); } else if (result != null) { return(result); } } searchDirectory = parentDirectory; } return(null); }
/// <summary> /// Reads the version.json file and returns the <see cref="Version"/> and prerelease tag from it. /// </summary> /// <param name="commit">The commit to read the version file from.</param> /// <param name="repoRelativeProjectDirectory">The directory to consider when searching for the version.txt file.</param> /// <param name="blobVersionCache">An optional blob cache for storing the raw parse results of a version.txt or version.json file (before any inherit merge operations are applied).</param> /// <returns>The version information read from the file.</returns> public static VersionOptions GetVersion(LibGit2Sharp.Commit commit, string repoRelativeProjectDirectory = null, Dictionary <LibGit2Sharp.ObjectId, VersionOptions> blobVersionCache = null) { if (commit == null) { return(null); } string searchDirectory = repoRelativeProjectDirectory ?? string.Empty; while (searchDirectory != null) { string parentDirectory = searchDirectory.Length > 0 ? Path.GetDirectoryName(searchDirectory) : null; string candidatePath = Path.Combine(searchDirectory, TxtFileName).Replace('\\', '/'); var versionTxtBlob = commit.Tree[candidatePath]?.Target as LibGit2Sharp.Blob; if (versionTxtBlob != null) { if (blobVersionCache is null || !blobVersionCache.TryGetValue(versionTxtBlob.Id, out VersionOptions result)) { result = TryReadVersionFile(new StreamReader(versionTxtBlob.GetContentStream())); if (blobVersionCache is object) { result?.Freeze(); blobVersionCache.Add(versionTxtBlob.Id, result); } } if (result != null) { return(result); } } candidatePath = Path.Combine(searchDirectory, JsonFileName).Replace('\\', '/'); var versionJsonBlob = commit.Tree[candidatePath]?.Target as LibGit2Sharp.Blob; if (versionJsonBlob != null) { string versionJsonContent = null; if (blobVersionCache is null || !blobVersionCache.TryGetValue(versionJsonBlob.Id, out VersionOptions result)) { using (var sr = new StreamReader(versionJsonBlob.GetContentStream())) { versionJsonContent = sr.ReadToEnd(); } try { result = TryReadVersionJsonContent(versionJsonContent, searchDirectory); } catch (FormatException ex) { throw new FormatException( $"Failure while reading {JsonFileName} from commit {commit.Sha}. " + "Fix this commit with rebase if this is an error, or review this doc on how to migrate to Nerdbank.GitVersioning: " + "https://github.com/dotnet/Nerdbank.GitVersioning/blob/master/doc/migrating.md", ex); } if (blobVersionCache is object) { result?.Freeze(); blobVersionCache.Add(versionJsonBlob.Id, result); } } if (result?.Inherit ?? false) { if (parentDirectory != null) { result = GetVersion(commit, parentDirectory, blobVersionCache); if (result != null) { if (versionJsonContent is null) { // We reused a cache VersionOptions, but now we need the actual JSON string. using (var sr = new StreamReader(versionJsonBlob.GetContentStream())) { versionJsonContent = sr.ReadToEnd(); } } if (result.IsFrozen) { result = new VersionOptions(result); } JsonConvert.PopulateObject(versionJsonContent, result, VersionOptions.GetJsonSettings(repoRelativeBaseDirectory: searchDirectory)); return(result); } } throw new InvalidOperationException($"\"{candidatePath}\" inherits from a parent directory version.json file but none exists."); } else if (result != null) { return(result); } } searchDirectory = parentDirectory; } return(null); }