首页 > 解决方案 > 以编程方式克隆 Octopus Deploy Process 步骤并修改克隆的步骤

问题描述

我们正在开发一个管道,我们必须为其添加 100 多个步骤并为每个步骤修改两件事:步骤名称和 PackageID。与其经历通过 UI 执行此操作的痛苦,我们更愿意以编程方式执行此操作。

下面是我为此草拟的一些 C#(我是一名 C# 开发人员,PowerShell 技能极其有限,这就是我在 C# 中这样做的原因)。注释“从这里开始是我模糊的地方”上方的行是工作代码,但注释下方的行只是伪代码。

有人可以向我解释如何在评论(或 PowerShell 等效项)下方写下几行吗?我无法为此找到 API 调用。

谢谢

    namespace ODClientExample
{
    class Program
    {
        static void Main(string[] args)
        {
            List<string> ListOfWindowsServices = new List<string>();
            ListOfWindowsServices.Add("svc1");
            ListOfWindowsServices.Add("svc2");
            ListOfFWindowsServices.Add("svc3");
            var server = "https://mysite.whatever/";
            var apiKey = "API-xxxxxxxxxxxxxxxxxx";   // I generated this via the Octopus UI         

            var endpoint = new OctopusServerEndpoint(server, apiKey);
            var repository = new OctopusRepository(endpoint);
            var project = repository.Projects.FindByName("Windows Services");

            // From here on is where I'm fuzzy:
            //
            var procesSteps = GetProcessSteps(project);
            var processStepToClone = GetProcesStepByName(processSteps, "SomeProcessStep");
            foreach (string svcName in ListofSvcNames)
            {
                processStepToClone.StepName = svcName;
                processStepToClone.PackageID = svcName;
            }
        }
    }
}

我又进步了一点。我现在可以访问流程中的步骤,并添加一个步骤。但是,当我的代码调用 repository.DeploymentProcesses.Modify 时,我得到了这个异常:

这是我的最新代码:

    static void Main(string[] args)
    {
        List<string> ListOfFexWindowsServices = new List<string>();
        ListOfFexWindowsServices.Add("svc2");
        ListOfFexWindowsServices.Add("svc3");
        ListOfFexWindowsServices.Add("svc4");
        string server = "https://mysite.stuff/";
        string apiKey = "API-xxxxxxxxxxxxxxxxxxxxxxxx";   // I generated this via the Octopus UI         

        OctopusServerEndpoint endpoint = new OctopusServerEndpoint(server, apiKey);
        OctopusRepository repository = new OctopusRepository(endpoint);
        ProjectResource projectResource = repository.Projects.FindByName("MyProject");
        DeploymentProcessResource deploymentProcess = repository.DeploymentProcesses.Get(projectResource.DeploymentProcessId);

        var projectSteps = deploymentProcess.Steps;
        DeploymentStepResource stepToClone = new DeploymentStepResource();
        foreach (DeploymentStepResource step in projectSteps)
        {
            if (step.Name == "svc1")
            {
                stepToClone = step;
                break;
            }
        }

        foreach (string serviceName in ListOfFexWindowsServices)
        {
            DeploymentStepResource newStep = new DeploymentStepResource();
            PopulateNewStep(newStep, stepToClone, serviceName);
            deploymentProcess.Steps.Add(newStep);
            repository.DeploymentProcesses.Modify(deploymentProcess);
        }
    }

    static void PopulateNewStep(DeploymentStepResource newStep, DeploymentStepResource stepToClone, string serviceName)
    {
        newStep.Name = serviceName;
        newStep.Id = Guid.NewGuid().ToString();
        newStep.StartTrigger = stepToClone.StartTrigger;
        newStep.Condition = stepToClone.Condition;
        DeploymentActionResource action = new DeploymentActionResource
        {
            Name = newStep.Name,
            ActionType = "Octopus.TentaclePackage",
            Id = Guid.NewGuid().ToString(),
        };

        PopulateActionProperties(action);
        newStep.Actions.Add(action);
        // ISSUE:  Anything else to do (eg, any other things from stepToClone to copy, or other stuff to create)?
        newStep.PackageRequirement = stepToClone.PackageRequirement;

    }

    static void PopulateActionProperties(DeploymentActionResource action)
    {
        action.Properties.Add(new KeyValuePair<string, PropertyValueResource>("Octopus.Action.WindowsService.CustomAccountPassword", "#{WindowsService.Password}"));

        // TODO:  Repeat this sort of thing for each Action Property you see in stepToClone.
    }

标签: octopus-deploy

解决方案


void Main()
{
    var sourceProjectName = "<source project name>";
    var targetProjectName = "<target project name>";
    var stepToCopyName = "<step name to copy>";

    var repo = GetOctopusRepository();
    var sourceProject = repo.Projects.FindByName(sourceProjectName);
    var targetProject = repo.Projects.FindByName(targetProjectName);

    if (sourceProject != null && targetProject != null)
    {
        var sourceDeploymentProcess = repo.DeploymentProcesses.Get(sourceProject.DeploymentProcessId);
        var targetDeploymentProcess = repo.DeploymentProcesses.Get(targetProject.DeploymentProcessId);

        if (sourceDeploymentProcess != null && targetDeploymentProcess != null)
        {
            Console.WriteLine($"Start copy from project '{sourceProjectName}' to project '{targetProjectName}'");

            CopyStepToTarget(sourceDeploymentProcess, targetDeploymentProcess, stepToCopyName);

            // Update or add the target deployment process
            repo.DeploymentProcesses.Modify(targetDeploymentProcess);

            Console.WriteLine($"End copy from project '{sourceProjectName}' to project '{targetProjectName}'");
        }
    }
}

private OctopusRepository GetOctopusRepository()
{
    var octopusServer = Environment.GetEnvironmentVariable("OCTOPUS_CLI_SERVER");
    var octopusApiKey = Environment.GetEnvironmentVariable("OCTOPUS_CLI_API_KEY");
    var endPoint = new OctopusServerEndpoint(octopusServer, octopusApiKey);

    return new OctopusRepository(endPoint);
}

private void CopyStepToTarget(DeploymentProcessResource sourceProcess, DeploymentProcessResource targetProcess, string sourceStepName, bool includeChannels = false, bool includeEnvironments = false)
{
    var sourceStep = sourceProcess.FindStep(sourceStepName);

    if (sourceStep == null)
    {
        Console.WriteLine($"{sourceStepName} not found in {sourceProcess.ProjectId}");
        return;
    }

    Console.WriteLine($"-> copy step '{sourceStep.Name}'");

    var stepToAdd = targetProcess.AddOrUpdateStep(sourceStep.Name);
    stepToAdd.RequirePackagesToBeAcquired(sourceStep.RequiresPackagesToBeAcquired);
    stepToAdd.WithCondition(sourceStep.Condition);
    stepToAdd.WithStartTrigger(sourceStep.StartTrigger);

    foreach (var property in sourceStep.Properties)
    {
        if (stepToAdd.Properties.ContainsKey(property.Key))
        {
            stepToAdd.Properties[property.Key] = property.Value;
        }
        else
        {
            stepToAdd.Properties.Add(property.Key, property.Value);
        }
    }

    foreach (var sourceAction in sourceStep.Actions)
    {
        Console.WriteLine($"-> copy action '{sourceAction.Name}'");

        var targetAction = stepToAdd.AddOrUpdateAction(sourceAction.Name);
        targetAction.ActionType = sourceAction.ActionType;
        targetAction.IsDisabled = sourceAction.IsDisabled;

        if (includeChannels)
        {
            foreach (var sourceChannel in sourceAction.Channels)
            {
                targetAction.Channels.Add(sourceChannel);
            }
        }

        if (includeEnvironments)
        {
            foreach (var sourceEnvironment in sourceAction.Environments)
            {
                targetAction.Environments.Add(sourceEnvironment);
            }
        }

        foreach (var actionProperty in sourceAction.Properties)
        {
            if (targetAction.Properties.ContainsKey(actionProperty.Key))
            {
                targetAction.Properties[actionProperty.Key] = actionProperty.Value;
            }
            else
            {
                targetAction.Properties.Add(actionProperty.Key, actionProperty.Value);
            }
        }
    }
}

上述代码示例可在Octopus Client Api Samples中找到


推荐阅读