Welcome to the Inedo Forums! Check out the Forums Guide for help getting started.
If you are experiencing any issues with the forum software, please visit the Contact Form on our website and let us know!
Buildmaster SDK - ReleaseNumber
-
Hey,
Just trying to upgrade the Inedo.Buildmaster.SDK to v6.0.0. Running into an issue where:
public override Task ExecuteAsync(IOperationExecutionContext context) { return Task.Run(async () => { var releaseNumber = $"{context.ReleaseNumber}.{context.BuildNumber}"; }); }
is now invalid because context doesn't contain ReleaseNumber or BuildNumber.
How can I get the current release and build numbers in the new SDK version?
Thanks!
ChrisProduct: BuildMaster
Version: 6.0.6
-
Hi Chris,
That appears to have been an oversight in the Inedo SDK. However, you should be able to just cast
context
toInedo.BuildMaster.Extensibility.IGenericBuildMasterContext
, which does have aReleaseNumber
andBuildNumber
property.This is safe to do; it's how we have the
$ReleaseNumber
function implemented internally.Hope this helps!
-
Thanks Dean, worked like a charm.
-
Hi Dean,
Turns out that built it, but when I cast the IExecutionContext to an IGenericBuildmasterContext it just returns null when run inside Buildmaster.
Any ideas?
Cheers,
Chris
-
Are you able to post the full code, or submit the code as a support ticket if you don't want it public? There must be something else happening because that should definitely work.
-
No worries Todd - here's the code:
Line 62 logs "Package Context is null? True".
Line 133 is where the exception gets thrown: NullReferenceException
Inedo SDK is v1.0.5 (which at the time of writing is the latest stable version)
using Inedo; using Inedo.BuildMaster.Data; using Inedo.BuildMaster.Extensibility; using Inedo.Diagnostics; using Inedo.Documentation; using Inedo.ExecutionEngine.Executer; using Inedo.Extensibility; using Inedo.Extensibility.Operations; using LibGit2Sharp; using Custom.BuildMaster.Interfaces; using System; using System.ComponentModel; using System.IO; using System.Threading.Tasks; namespace Custom.BuildMaster.Actions.Git { [DisplayName("Git-Clone")] [Description("Clone's a repository")] [ScriptAlias("Git-Clone")] [ScriptNamespace("CUSTOM")] [Serializable] public class GitClone : GitOperation { [Required] [ScriptAlias("Branch")] [DisplayName("Branch to Clone")] [PlaceholderText("e.g. master")] public string Branch { get; set; } [ScriptAlias("Commit")] [DisplayName("Commit Hash")] [PlaceholderText("e.g. 3917402e798a42fbdde99a66b8cac5d61a720b8f or leave blank for latest")] public string Commit { get; set; } [Required] [ScriptAlias("CloneTo")] [DisplayName("Clone to")] [PlaceholderText("e.g. $WorkingDirectory")] public string CloneTo { get; set; } [ScriptAlias("SaveToVariable")] [DisplayName("Save Commit Hash to Variable")] [PlaceholderText("VariableName (optional)")] public string VariableName { get; set; } protected override ExtendedRichDescription GetDescription(IOperationConfiguration config) { return new ExtendedRichDescription( new RichDescription( $"Clone {config[nameof(this.RepositoryName)]} to {config[nameof(this.CloneTo)]}" ) ); } public override Task ExecuteAsync(IOperationExecutionContext context) { return Task.Run(async () => { // Turn this into the buildmaster context to get package variables out var packageContext = context as IGenericBuildMasterContext; Log(new SimpleLogMessage(MessageLevel.Debug, $"Package Context is null? {packageContext == null}", "Git", "", context)); // THIS LINE LOGS "Package Context is null? True" // Clone Repo to directory CloneOptions co = new CloneOptions(); co.CredentialsProvider = (_url, _user, _cred) => new LibGit2Sharp.SecureUsernamePasswordCredentials { Username = Username, Password = Password }; var path = context.ResolvePath(CloneTo); path = Repository.Clone(Path.Combine(BaseUrl, RepositoryName), path, co); // Get Commit hash var repo = new Repository(path); var commitHash = repo.Head.Tip.Sha; // Get local + remote branch names var localBranchName = "refs/heads/" + Branch; var remoteBranchName = "refs/remotes/origin/" + Branch; Log(new SimpleLogMessage(Inedo.Diagnostics.MessageLevel.Debug, $"Local Branch set to {localBranchName}", "Git", "", context)); Log(new SimpleLogMessage(Inedo.Diagnostics.MessageLevel.Debug, $"Remote Branch set to {remoteBranchName}", "Git", "", context)); // Check the remote branch exists var trackingBranch = repo.Branches[remoteBranchName]; if (trackingBranch == null) { Log(new SimpleLogMessage(Inedo.Diagnostics.MessageLevel.Error, $"Branch {Branch} does not exist on the remote.", "Git", "", context)); throw new Exception($"Branch {Branch} does not exist on remote"); } // Checkout branch Log(new SimpleLogMessage(Inedo.Diagnostics.MessageLevel.Debug, $"Creating Branch {Branch} Locally", "Git", "", context)); Branch localBranch; try { localBranch = repo.CreateBranch(Branch, trackingBranch.Tip); }catch { // Branch already exists - set it up localBranch = repo.Branches[localBranchName]; } Log(new SimpleLogMessage(Inedo.Diagnostics.MessageLevel.Debug, "Tracking remote branch", "Git", "", context)); repo.Branches.Update(localBranch, b => b.TrackedBranch = trackingBranch.CanonicalName); Log(new SimpleLogMessage(Inedo.Diagnostics.MessageLevel.Debug, "Checking out branch", "Git", "", context)); Commands.Checkout(repo, Branch); Log(new SimpleLogMessage(Inedo.Diagnostics.MessageLevel.Debug, $"Cloned branch {Branch} Successfully", "Git", "", context)); // If hash is specified, checkout that if (!string.IsNullOrWhiteSpace(Commit)) { Log(new SimpleLogMessage(Inedo.Diagnostics.MessageLevel.Debug, $"Commit Hash set. Attempting to checkout commit hash {Commit}", "Git", "", context)); repo.Reset(ResetMode.Hard, Commit); } // Make sure the commit hash is set correctly commitHash = repo.Head.Tip.Sha; Log(new SimpleLogMessage(Inedo.Diagnostics.MessageLevel.Information, $"Cloned Successfully: Hash is {commitHash}", "Git", "", context)); // Set commit hash if (String.IsNullOrWhiteSpace(VariableName)) { Log(new SimpleLogMessage(Inedo.Diagnostics.MessageLevel.Information, "No Commit Hash Variable Specified. Not setting.", "Git", "", context)); } else { using (var db = new DB.Context()) { var build = await db.Builds_GetBuildAsync(packageContext.ApplicationId, packageContext.ReleaseNumber, packageContext.BuildNumber); // THIS LINE FAILS with NullReferenceException if (build == null) throw new ExecutionFailureException($"Package {packageContext.BuildNumber} was not found for release {packageContext.ReleaseNumber}."); db.Variables_CreateOrUpdatePackageVariable( Build_Id: build.Build_Id, Variable_Name: VariableName, ValueType_Code: Domains.VariableValueType.Scalar, Variable_Value: InedoLib.UTF8Encoding.GetBytes(commitHash), Sensitive_Indicator: false, EvaluateVariables_Indicator: false ); Log(new SimpleLogMessage(Inedo.Diagnostics.MessageLevel.Information, $"Assigned commit hash {commitHash} to variable {VariableName}", "Git", "", context)); } } //Delete the .git Directory repo.Dispose(); Helpers.DirectoryHelper.DeleteReadOnlyDirectory(path); Helpers.DirectoryHelper.DeleteReadOnlyFile(context.ResolvePath(".gitignore")); Log(new SimpleLogMessage(Inedo.Diagnostics.MessageLevel.Debug, "Removed .git directory and .gitignore", "Git", "", context)); // Write hash return new object(); }); } } }
-
Try the following code; it removes the need for
IGenericBuildMasterContext
altogether and uses anasync
method to replace theTask.Run
call:
public override async Task ExecuteAsync(IOperationExecutionContext context) { // Clone Repo to directory CloneOptions co = new CloneOptions(); co.CredentialsProvider = (_url, _user, _cred) => new LibGit2Sharp.SecureUsernamePasswordCredentials { Username = Username, Password = Password }; var path = context.ResolvePath(CloneTo); path = Repository.Clone(Path.Combine(BaseUrl, RepositoryName), path, co); // Get Commit hash var repo = new Repository(path); var commitHash = repo.Head.Tip.Sha; // Get local + remote branch names var localBranchName = "refs/heads/" + Branch; var remoteBranchName = "refs/remotes/origin/" + Branch; Log(new SimpleLogMessage(Inedo.Diagnostics.MessageLevel.Debug, $"Local Branch set to {localBranchName}", "Git", "", context)); Log(new SimpleLogMessage(Inedo.Diagnostics.MessageLevel.Debug, $"Remote Branch set to {remoteBranchName}", "Git", "", context)); // Check the remote branch exists var trackingBranch = repo.Branches[remoteBranchName]; if (trackingBranch == null) { Log(new SimpleLogMessage(Inedo.Diagnostics.MessageLevel.Error, $"Branch {Branch} does not exist on the remote.", "Git", "", context)); throw new Exception($"Branch {Branch} does not exist on remote"); } // Checkout branch Log(new SimpleLogMessage(Inedo.Diagnostics.MessageLevel.Debug, $"Creating Branch {Branch} Locally", "Git", "", context)); Branch localBranch; try { localBranch = repo.CreateBranch(Branch, trackingBranch.Tip); } catch { // Branch already exists - set it up localBranch = repo.Branches[localBranchName]; } Log(new SimpleLogMessage(Inedo.Diagnostics.MessageLevel.Debug, "Tracking remote branch", "Git", "", context)); repo.Branches.Update(localBranch, b => b.TrackedBranch = trackingBranch.CanonicalName); Log(new SimpleLogMessage(Inedo.Diagnostics.MessageLevel.Debug, "Checking out branch", "Git", "", context)); Commands.Checkout(repo, Branch); Log(new SimpleLogMessage(Inedo.Diagnostics.MessageLevel.Debug, $"Cloned branch {Branch} Successfully", "Git", "", context)); // If hash is specified, checkout that if (!string.IsNullOrWhiteSpace(Commit)) { Log(new SimpleLogMessage(Inedo.Diagnostics.MessageLevel.Debug, $"Commit Hash set. Attempting to checkout commit hash {Commit}", "Git", "", context)); repo.Reset(ResetMode.Hard, Commit); } // Make sure the commit hash is set correctly commitHash = repo.Head.Tip.Sha; Log(new SimpleLogMessage(Inedo.Diagnostics.MessageLevel.Information, $"Cloned Successfully: Hash is {commitHash}", "Git", "", context)); // Set commit hash if (String.IsNullOrWhiteSpace(VariableName)) { Log(new SimpleLogMessage(Inedo.Diagnostics.MessageLevel.Information, "No Commit Hash Variable Specified. Not setting.", "Git", "", context)); } else { using (var db = new DB.Context()) { var exec = await db.Builds_GetExecutionAsync(context.ExecutionId); await db.Variables_CreateOrUpdatePackageVariableAsync( Build_Id: exec.Build_Id, Variable_Name: VariableName, ValueType_Code: Domains.VariableValueType.Scalar, Variable_Value: InedoLib.UTF8Encoding.GetBytes(commitHash), Sensitive_Indicator: false, EvaluateVariables_Indicator: false ); Log(new SimpleLogMessage(Inedo.Diagnostics.MessageLevel.Information, $"Assigned commit hash {commitHash} to variable {VariableName}", "Git", "", context)); } } //Delete the .git Directory repo.Dispose(); Helpers.DirectoryHelper.DeleteReadOnlyDirectory(path); Helpers.DirectoryHelper.DeleteReadOnlyFile(context.ResolvePath(".gitignore")); Log(new SimpleLogMessage(Inedo.Diagnostics.MessageLevel.Debug, "Removed .git directory and .gitignore", "Git", "", context)); }
However, I'm guessing this was written a while ago before the built-in Git operations handled this? We use the Git operations to perform this same functionality by combining two operations:
# Gets source from the BuildMaster repository and creates a release package variable named GitCommit Git::Git-GetSource ( Credentials: GitLab, RepositoryUrl: https://gitlab.com/inedo/BuildMaster.git, DiskPath: ~\Src, RecurseSubmodules: true, Branch: $Branch, CommitHash => $commit ); Set-ReleaseVariable GitCommit ( Value: $commit, Package: $PackageNumber );
-
Hi Todd,
Thanks for the such quick replies. I've implemented that in the code, but will need to wait for a bit to actually test it.
Is there a way of cloning a particular commit using the built-in extension (as above) or can you only clone branches? I think that's where this extension initially arose.
-
You can actually put a full commit ID in the
Tag
field (which actually supports anyrefname
)... I'll have someone put a note in to change that in the operation.