/// <summary> /// Initializes a new instance of the <see cref="VersionOracle"/> class. /// </summary> public VersionOracle(string projectDirectory, LibGit2Sharp.Repository repo, ICloudBuild cloudBuild) { this.cloudBuild = cloudBuild; this.VersionOptions = VersionFile.GetVersion(repo, projectDirectory) ?? VersionFile.GetVersion(projectDirectory); var repoRoot = repo?.Info?.WorkingDirectory?.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); var relativeRepoProjectDirectory = !string.IsNullOrWhiteSpace(repoRoot) ? projectDirectory.Substring(repoRoot.Length).TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) : null; var commit = repo?.Head.Commits.FirstOrDefault(); this.GitCommitId = commit?.Id.Sha ?? cloudBuild?.GitCommitId ?? null; this.VersionHeight = repo?.GetVersionHeight(relativeRepoProjectDirectory) ?? 0; this.BuildingRef = cloudBuild?.BuildingTag ?? cloudBuild?.BuildingBranch ?? repo?.Head.CanonicalName; // Override the typedVersion with the special build number and revision components, when available. this.Version = repo?.GetIdAsVersion(relativeRepoProjectDirectory, this.VersionHeight) ?? this.VersionOptions?.Version.Version; this.Version = this.Version ?? new Version(0, 0); this.CloudBuildNumberOptions = this.VersionOptions?.CloudBuild?.BuildNumber ?? new VersionOptions.CloudBuildNumberOptions(); if (!string.IsNullOrEmpty(this.BuildingRef) && this.VersionOptions?.PublicReleaseRefSpec?.Length > 0) { this.PublicRelease = this.VersionOptions.PublicReleaseRefSpec.Any( expr => Regex.IsMatch(this.BuildingRef, expr)); } }
/// <summary> /// Initializes a new instance of the <see cref="VersionOracle"/> class. /// </summary> public VersionOracle(string projectDirectory, LibGit2Sharp.Repository repo, ICloudBuild cloudBuild, int?overrideBuildNumberOffset = null, string projectPathRelativeToGitRepoRoot = null) { var repoRoot = repo?.Info?.WorkingDirectory?.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); var relativeRepoProjectDirectory = !string.IsNullOrWhiteSpace(repoRoot) ? (!string.IsNullOrEmpty(projectPathRelativeToGitRepoRoot) ? projectPathRelativeToGitRepoRoot : projectDirectory.Substring(repoRoot.Length).TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)) : null; var commit = repo?.Head.Commits.FirstOrDefault(); var committedVersion = VersionFile.GetVersion(commit, relativeRepoProjectDirectory); var workingVersion = VersionFile.GetVersion(projectDirectory); if (overrideBuildNumberOffset.HasValue) { if (committedVersion != null) { committedVersion.BuildNumberOffset = overrideBuildNumberOffset.Value; } if (workingVersion != null) { workingVersion.BuildNumberOffset = overrideBuildNumberOffset.Value; } } this.VersionOptions = committedVersion ?? workingVersion; this.GitCommitId = commit?.Id.Sha ?? cloudBuild?.GitCommitId ?? null; this.VersionHeight = CalculateVersionHeight(relativeRepoProjectDirectory, commit, committedVersion, workingVersion); this.BuildingRef = cloudBuild?.BuildingTag ?? cloudBuild?.BuildingBranch ?? repo?.Head.CanonicalName; // Override the typedVersion with the special build number and revision components, when available. if (repo != null) { this.Version = GetIdAsVersion(commit, committedVersion, workingVersion, this.VersionHeight); } else { this.Version = this.VersionOptions?.Version.Version ?? Version0; } this.VersionHeightOffset = this.VersionOptions?.BuildNumberOffsetOrDefault ?? 0; this.PrereleaseVersion = ReplaceMacros(this.VersionOptions?.Version.Prerelease ?? string.Empty); this.CloudBuildNumberOptions = this.VersionOptions?.CloudBuild?.BuildNumberOrDefault ?? VersionOptions.CloudBuildNumberOptions.DefaultInstance; if (!string.IsNullOrEmpty(this.BuildingRef) && this.VersionOptions?.PublicReleaseRefSpec?.Length > 0) { this.PublicRelease = this.VersionOptions.PublicReleaseRefSpec.Any( expr => Regex.IsMatch(this.BuildingRef, expr)); } }
/// <summary> /// Initializes a new instance of the <see cref="VersionOracle"/> class. /// </summary> public VersionOracle(string projectDirectory, LibGit2Sharp.Repository repo, ICloudBuild cloudBuild, int?overrideBuildNumberOffset = null, string projectPathRelativeToGitRepoRoot = null) : this(projectDirectory, repo, null, cloudBuild, overrideBuildNumberOffset, projectPathRelativeToGitRepoRoot) { }
/// <summary> /// Initializes a new instance of the <see cref="VersionOracle"/> class. /// </summary> public static VersionOracle Create(string projectDirectory, string gitRepoDirectory = null, ICloudBuild cloudBuild = null, int?overrideBuildNumberOffset = null, string projectPathRelativeToGitRepoRoot = null) { Requires.NotNull(projectDirectory, nameof(projectDirectory)); if (string.IsNullOrEmpty(gitRepoDirectory)) { gitRepoDirectory = projectDirectory; } using (var git = GitExtensions.OpenGitRepo(gitRepoDirectory)) { return(new VersionOracle(projectDirectory, git, null, cloudBuild, overrideBuildNumberOffset, projectPathRelativeToGitRepoRoot)); } }
/// <summary> /// Adds version variables to the the current cloud build environment. /// </summary> /// <exception cref="CloudCommandException">Thrown when the build environment could not be updated.</exception> /// <param name="projectDirectory"> /// The path to the directory which may (or its ancestors may) define the version file. /// </param> /// <param name="metadata"> /// Optionally adds an identifier to the build metadata part of a semantic version. /// </param> /// <param name="version"> /// The string to use for the cloud build number. If not specified, the computed version will be used. /// </param> /// <param name="ciSystem"> /// The CI system to activate. If not specified, auto-detection will be used. /// </param> /// <param name="allVars"> /// Controls whether to define all version variables as cloud build variables. /// </param> /// <param name="commonVars"> /// Controls whether to define common version variables as cloud build variables. /// </param> /// <param name="additionalVariables"> /// Additional cloud build variables to define. /// </param> /// <param name="alwaysUseLibGit2"> /// Force usage of LibGit2 for accessing the git repository. /// </param> public void SetBuildVariables(string projectDirectory, IEnumerable <string> metadata, string version, string ciSystem, bool allVars, bool commonVars, IEnumerable <KeyValuePair <string, string> > additionalVariables, bool alwaysUseLibGit2) { Requires.NotNull(projectDirectory, nameof(projectDirectory)); Requires.NotNull(additionalVariables, nameof(additionalVariables)); ICloudBuild activeCloudBuild = CloudBuild.Active; if (!string.IsNullOrEmpty(ciSystem)) { int matchingIndex = Array.FindIndex(CloudProviderNames, m => string.Equals(m, ciSystem, StringComparison.OrdinalIgnoreCase)); if (matchingIndex == -1) { throw new CloudCommandException( $"No cloud provider found by the name: \"{ciSystem}\"", CloudCommandError.NoCloudBuildProviderMatch); } activeCloudBuild = CloudBuild.SupportedCloudBuilds[matchingIndex]; } using var context = GitContext.Create(projectDirectory, writable: alwaysUseLibGit2); var oracle = new VersionOracle(context, cloudBuild: activeCloudBuild); if (metadata is not null) { oracle.BuildMetadata.AddRange(metadata); } var variables = new Dictionary <string, string>(); if (allVars) { foreach (var pair in oracle.CloudBuildAllVars) { variables.Add(pair.Key, pair.Value); } } if (commonVars) { foreach (var pair in oracle.CloudBuildVersionVars) { variables.Add(pair.Key, pair.Value); } } foreach (var kvp in additionalVariables) { if (variables.ContainsKey(kvp.Key)) { throw new CloudCommandException( $"Cloud build variable \"{kvp.Key}\" specified more than once.", CloudCommandError.DuplicateCloudVariable); } variables[kvp.Key] = kvp.Value; } if (activeCloudBuild is not null) { if (string.IsNullOrEmpty(version)) { version = oracle.CloudBuildNumber; } activeCloudBuild.SetCloudBuildNumber(version, this.stdout, this.stderr); foreach (var pair in variables) { activeCloudBuild.SetCloudBuildVariable(pair.Key, pair.Value, this.stdout, this.stderr); } } else { throw new CloudCommandException( "No cloud build detected.", CloudCommandError.NoCloudBuildEnvDetected); } }
private static ExitCodes OnCloudCommand(string projectPath, string version, string cisystem, bool cloudBuildAllVars, bool cloudBuildCommonVars, IReadOnlyList <string> cloudVariables) { string searchPath = GetSpecifiedOrCurrentDirectoryPath(projectPath); if (!Directory.Exists(searchPath)) { Console.Error.WriteLine("\"{0}\" is not an existing directory.", searchPath); return(ExitCodes.NoGitRepo); } ICloudBuild activeCloudBuild = CloudBuild.Active; if (!string.IsNullOrEmpty(cisystem)) { int matchingIndex = Array.FindIndex(CloudProviderNames, m => string.Equals(m, cisystem, StringComparison.OrdinalIgnoreCase)); if (matchingIndex == -1) { Console.Error.WriteLine("No cloud provider found by the name: \"{0}\"", cisystem); return(ExitCodes.NoCloudBuildProviderMatch); } activeCloudBuild = CloudBuild.SupportedCloudBuilds[matchingIndex]; } var oracle = VersionOracle.Create(searchPath, cloudBuild: activeCloudBuild); var variables = new Dictionary <string, string>(); if (cloudBuildAllVars) { foreach (var pair in oracle.CloudBuildAllVars) { variables.Add(pair.Key, pair.Value); } } if (cloudBuildCommonVars) { foreach (var pair in oracle.CloudBuildVersionVars) { variables.Add(pair.Key, pair.Value); } } foreach (string def in cloudVariables) { string[] split = def.Split(new char[] { '=' }, 2); if (split.Length < 2) { Console.Error.WriteLine($"\"{def}\" is not in the NAME=VALUE syntax required for cloud variables."); return(ExitCodes.BadCloudVariable); } if (variables.ContainsKey(split[0])) { Console.Error.WriteLine($"Cloud build variable \"{split[0]}\" specified more than once."); return(ExitCodes.DuplicateCloudVariable); } variables[split[0]] = split[1]; } if (activeCloudBuild != null) { if (string.IsNullOrEmpty(version)) { version = oracle.CloudBuildNumber; } activeCloudBuild.SetCloudBuildNumber(version, Console.Out, Console.Error); foreach (var pair in variables) { activeCloudBuild.SetCloudBuildVariable(pair.Key, pair.Value, Console.Out, Console.Error); } return(ExitCodes.OK); } else { Console.Error.WriteLine("No cloud build detected."); return(ExitCodes.NoCloudBuildEnvDetected); } }
/// <summary> /// Initializes a new instance of the <see cref="VersionOracle"/> class. /// </summary> public VersionOracle(string projectDirectory, LibGit2Sharp.Repository repo, LibGit2Sharp.Commit head, ICloudBuild cloudBuild, int?overrideVersionHeightOffset = null, string projectPathRelativeToGitRepoRoot = null) { var relativeRepoProjectDirectory = projectPathRelativeToGitRepoRoot ?? repo?.GetRepoRelativePath(projectDirectory); if (repo is object) { // If we're particularly git focused, normalize/reset projectDirectory to be the path we *actually* want to look at in case we're being redirected. projectDirectory = Path.Combine(repo.Info.WorkingDirectory, relativeRepoProjectDirectory); } var commit = head ?? repo?.Head.Tip; var committedVersion = VersionFile.GetVersion(commit, relativeRepoProjectDirectory); var workingVersion = head is object?VersionFile.GetVersion(head, relativeRepoProjectDirectory) : VersionFile.GetVersion(projectDirectory); if (overrideVersionHeightOffset.HasValue) { if (committedVersion != null) { committedVersion.VersionHeightOffset = overrideVersionHeightOffset.Value; } if (workingVersion != null) { workingVersion.VersionHeightOffset = overrideVersionHeightOffset.Value; } } this.VersionOptions = committedVersion ?? workingVersion; this.GitCommitId = commit?.Id.Sha ?? cloudBuild?.GitCommitId ?? null; this.GitCommitDate = commit?.Author.When; this.VersionHeight = CalculateVersionHeight(relativeRepoProjectDirectory, commit, committedVersion, workingVersion); this.BuildingRef = cloudBuild?.BuildingTag ?? cloudBuild?.BuildingBranch ?? repo?.Head.CanonicalName; // Override the typedVersion with the special build number and revision components, when available. if (repo != null) { this.Version = GetIdAsVersion(commit, committedVersion, workingVersion, this.VersionHeight); } else { this.Version = this.VersionOptions?.Version.Version ?? Version0; } // get the commit id abbreviation only if the commit id is set if (!string.IsNullOrEmpty(this.GitCommitId)) { var gitCommitIdShortFixedLength = this.VersionOptions?.GitCommitIdShortFixedLength ?? VersionOptions.DefaultGitCommitIdShortFixedLength; var gitCommitIdShortAutoMinimum = this.VersionOptions?.GitCommitIdShortAutoMinimum ?? 0; // get it from the git repository if there is a repository present and it is enabled if (repo != null && gitCommitIdShortAutoMinimum > 0) { this.GitCommitIdShort = repo.ObjectDatabase.ShortenObjectId(commit, gitCommitIdShortAutoMinimum); } else { this.GitCommitIdShort = this.GitCommitId.Substring(0, gitCommitIdShortFixedLength); } } this.VersionHeightOffset = this.VersionOptions?.VersionHeightOffsetOrDefault ?? 0; this.PrereleaseVersion = this.ReplaceMacros(this.VersionOptions?.Version?.Prerelease ?? string.Empty); this.CloudBuildNumberOptions = this.VersionOptions?.CloudBuild?.BuildNumberOrDefault ?? VersionOptions.CloudBuildNumberOptions.DefaultInstance; if (!string.IsNullOrEmpty(this.BuildingRef) && this.VersionOptions?.PublicReleaseRefSpec?.Count > 0) { this.PublicRelease = this.VersionOptions.PublicReleaseRefSpec.Any( expr => Regex.IsMatch(this.BuildingRef, expr)); } }
/// <summary> /// Initializes a new instance of the <see cref="VersionOracle"/> class. /// </summary> /// <param name="projectDirectory"></param> /// <param name="gitRepoDirectory"></param> /// <param name="cloudBuild"></param> /// <returns></returns> public static VersionOracle Create(string projectDirectory, string gitRepoDirectory = null, ICloudBuild cloudBuild = null) { Requires.NotNull(projectDirectory, nameof(projectDirectory)); if (string.IsNullOrEmpty(gitRepoDirectory)) { gitRepoDirectory = projectDirectory; } using (var git = OpenGitRepo(gitRepoDirectory)) { return(new VersionOracle(projectDirectory, git, cloudBuild)); } }
/// <summary> /// Initializes a new instance of the <see cref="VersionOracle"/> class. /// </summary> public VersionOracle(string projectDirectory, LibGit2Sharp.Repository repo, LibGit2Sharp.Commit head, ICloudBuild cloudBuild, int?overrideVersionHeightOffset = null, string projectPathRelativeToGitRepoRoot = null) { var repoRoot = repo?.Info?.WorkingDirectory?.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); var relativeRepoProjectDirectory = !string.IsNullOrWhiteSpace(repoRoot) ? (!string.IsNullOrEmpty(projectPathRelativeToGitRepoRoot) ? projectPathRelativeToGitRepoRoot : projectDirectory.Substring(repoRoot.Length).TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)) : null; var commit = head ?? repo?.Head.Commits.FirstOrDefault(); var committedVersion = VersionFile.GetVersion(commit, relativeRepoProjectDirectory); var workingVersion = head != null?VersionFile.GetVersion(head, relativeRepoProjectDirectory) : VersionFile.GetVersion(projectDirectory); if (overrideVersionHeightOffset.HasValue) { if (committedVersion != null) { committedVersion.VersionHeightOffset = overrideVersionHeightOffset.Value; } if (workingVersion != null) { workingVersion.VersionHeightOffset = overrideVersionHeightOffset.Value; } } this.VersionOptions = committedVersion ?? workingVersion; this.GitCommitId = commit?.Id.Sha ?? cloudBuild?.GitCommitId ?? null; this.GitCommitDate = commit?.Author.When; this.VersionHeight = CalculateVersionHeight(relativeRepoProjectDirectory, commit, committedVersion, workingVersion); this.BuildingRef = cloudBuild?.BuildingTag ?? cloudBuild?.BuildingBranch ?? repo?.Head.CanonicalName; // Override the typedVersion with the special build number and revision components, when available. if (repo != null) { this.Version = GetIdAsVersion(commit, committedVersion, workingVersion, this.VersionHeight); } else { this.Version = this.VersionOptions?.Version.Version ?? Version0; } // get the commit id abbreviation only if the commit id is set if (!string.IsNullOrEmpty(this.GitCommitId)) { var gitCommitIdShortFixedLength = this.VersionOptions?.GitCommitIdShortFixedLength ?? VersionOptions.DefaultGitCommitIdShortFixedLength; var gitCommitIdShortAutoMinimum = this.VersionOptions?.GitCommitIdShortAutoMinimum ?? 0; // get it from the git repository if there is a repository present and it is enabled if (repo != null && gitCommitIdShortAutoMinimum > 0) { this.GitCommitIdShort = repo.ObjectDatabase.ShortenObjectId(commit, gitCommitIdShortAutoMinimum); } else { this.GitCommitIdShort = this.GitCommitId.Substring(0, gitCommitIdShortFixedLength); } } this.VersionHeightOffset = this.VersionOptions?.VersionHeightOffsetOrDefault ?? 0; this.PrereleaseVersion = this.ReplaceMacros(this.VersionOptions?.Version?.Prerelease ?? string.Empty); this.CloudBuildNumberOptions = this.VersionOptions?.CloudBuild?.BuildNumberOrDefault ?? VersionOptions.CloudBuildNumberOptions.DefaultInstance; if (!string.IsNullOrEmpty(this.BuildingRef) && this.VersionOptions?.PublicReleaseRefSpec?.Length > 0) { this.PublicRelease = this.VersionOptions.PublicReleaseRefSpec.Any( expr => Regex.IsMatch(this.BuildingRef, expr)); } }