Can not add a prompt variable in Code

(Oisin) #1

Hi, we have a project set up in Octopus which I would like to release/deploy programmatically via #C code using Octopus.Client (the project clears a key from a Redis cache on a server). All works great, apart from the fact that I can not add/edit/update (not sure which) the main variable which is KeyName. I am struggling to understand if I am even on the right approach, I think I am close but could you guide me please as atm when I run this code the release fails in Octopus due to no value set in the KeyName variable, so clearly I am not doing it right:

public static bool ClearCacheKey(Logger auditLog, IConfiguration config, string cacheKey)
            var octopusURL = config.GetValue<string>("Octopus:ApiURL");
            var octopusAPIKey = config.GetValue<string>("Octopus:ApiKey");

            var endpoint = new OctopusServerEndpoint(octopusURL, octopusAPIKey);
            var repository = new OctopusRepository(endpoint);

            //var spaceName = "Spaces-1";
            var spaceName = "Default";
            var projectName = "Redis.FlushSpecificKeys";
            var channelName = "Default"; // Channels are not used in the Redis.FlushSpecificKeys project
            var environmentName = "Stage-DATACENTRE";

                // Get the space to work in
                var space = repository.Spaces.FindByName(spaceName);
                auditLog.Info($"Using Space named {space.Name} with id {space.Id}");

                // Create space specific repository
                var repositoryForSpace = repository.ForSpace(space);

                // Get project by name
                var project = repositoryForSpace.Projects.FindByName(projectName);
                auditLog.Info($"Using Project named {project.Name} with id {project.Id}");

                // Get variables
                var variables = repository.VariableSets.Get(project.VariableSetId);

                // Get channel by name
                var channel = repositoryForSpace.Channels.FindByName(project, channelName);
                auditLog.Info($"Using Channel named {channel.Name} with id {channel.Id}");

                // Get environment by name
                var environment = repositoryForSpace.Environments.FindByName(environmentName);
                auditLog.Info($"Using Environment named {environment.Name} with id {environment.Id}");

                // Get the deployment process template
                auditLog.Info("Fetching deployment process template");
                var process = repositoryForSpace.DeploymentProcesses.Get(project.DeploymentProcessId);
                var template = repositoryForSpace.DeploymentProcesses.GetTemplate(process, channel);

                var release = new Octopus.Client.Model.ReleaseResource
                    ChannelId = channel.Id,
                    ProjectId = project.Id,
                    Version = template.NextVersionIncrement,
                    ReleaseNotes = $"Created automatically by Sentinel for cache key {cacheKey}"

                // Set the package version to the latest for each package
                // If you have channel rules that dictate what versions can be used
                //  you'll need to account for that by overriding the selected package version
                auditLog.Info("Getting action package versions");
                foreach (var package in template.Packages)
                    var feed = repositoryForSpace.Feeds.Get(package.FeedId);
                    var latestPackage = repositoryForSpace.Feeds.GetVersions(feed, new[] { package.PackageId }).FirstOrDefault();

                    var selectedPackage = new SelectedPackage
                        ActionName = package.ActionName,
                        Version = latestPackage.Version

                    auditLog.Info($"Using version {latestPackage.Version} for step {package.ActionName} package {package.PackageId}");


                // # Create release
                release = repositoryForSpace.Releases.Create(release, true); // pass in $true if you want to ignore channel rules

                // Re-snapshot the variables so we can modify them
                release = repository.Releases.SnapshotVariables(release);

                var projVarSetId = release.ProjectVariableSetSnapshotId;

                //Get the project variable set using the new snapshot id
                var projSet = repository.VariableSets.Get(projVarSetId);

                //Amend the KeyName var
                projSet.Variables.Where(item => item.Name == "KeyName").FirstOrDefault().Value = cacheKey;
                projSet.Variables.Where(item => item.Name == "KeyName").FirstOrDefault().Scope.Add(ScopeField.Environment, environmentName);
                // # Create deployment
                var deployment = new DeploymentResource
                    ReleaseId = release.Id,
                    EnvironmentId = environment.Id


                auditLog.Info($"Creating deployment for release {release.Version} of project {projectName} to environment {environmentName}");
                deployment = repositoryForSpace.Deployments.Create(deployment);

                return true;
            catch (Exception ex)
                return false;
(Oisin) #3

Anybody at all?

(Oisin) #4

For anyone else stuck, the answers is here, kudos to these guys for sharing cos it is not intuitive, but it works:

(Daniel Fischer) #5

Hi @oisin,

Thanks for the update here! And thank you for posting your solution for anyone else who may run into this problem in the future. :slight_smile:

I’m sorry we didn’t manage to get back to you in time with a solution. It’s great to see that you managed to find a relevant conversation for your problem though.

If you have any questions at all on this or run into any further issues, please don’t hesitate to let me know.

Best regards,

(Oisin) #6

@Daniel_Fischer Thanks for coming back to me on this, I would point out that although I found a “solution” which allowed me to achieve the POC I was working on, the solution was based on running a previously ran release of an Octopus project, rather than creating a new one, which would be preferable.

If you do happen to have a suggestion on how to do the following but by creatingt a new release instead I think the community would find that helpful:

var apiKey = "API-12345678910";
var server = "http://localhost:8065";
var environmentName = "MyEnvironment";
var projectName = "MyProject";
var releaseVersion = "0.0.1";

//Add your prompted variables here
var PromptedVariablesForm = new Dictionary<string,string>{
	{ "PromptedVariable1", "foo" },
	{ "PromptedVariable2","bar"}

var endpoint = new OctopusServerEndpoint(server, apiKey);
var repository = new OctopusRepository(endpoint);

var environment = repository.Environments.FindByName(environmentName);
var project = repository.Projects.FindByName(projectName);

var release = repository.Releases.FindOne(x => x.ProjectId == project.Id && x.Version == releaseVersion);
var releaseTemplate = repository.Releases.GetTemplate(release);

var promotion = releaseTemplate.PromoteTo.FirstOrDefault(x => string.Equals(x.Name, environment.Name, StringComparison.InvariantCultureIgnoreCase));

var preview = repository.Releases.GetPreview(promotion);

var formValues = new Dictionary<string, string>();
foreach (var element in preview.Form.Elements)
	var variableInput = element.Control as VariableValue;
	if(variableInput == null){
	string val;
	if(PromptedVariablesForm.TryGetValue(variableInput.Name, out val)){
		formValues.Add(element.Name, val);

//creating the deployment object
var deployment = new DeploymentResource
	ReleaseId = release.Id,
	ProjectId = project.Id,
	EnvironmentId = environment.Id,
	FormValues = formValues

//Deploying the release in Octopus
var result = repository.Deployments.Create(deployment);