Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Autochannel feature #75

Merged
merged 29 commits into from
May 9, 2016
Merged

Autochannel feature #75

merged 29 commits into from
May 9, 2016

Conversation

michaelnoonan
Copy link
Contributor

@michaelnoonan michaelnoonan commented Apr 15, 2016

Premise

Follows on from the good work done in #73. See there for more discussion on the "Why?" behind this feature.

Changes

The CreateReleaseCommand has historically been one big long transaction script, and was further built upon for Channels in Octopus 3.2. To make this feature rock-solid, we need to build a ReleasePlan per Channel, and figure out which ones are viable, and then make a good choice based on that information.

  1. I've made ReleasePlan a lot more central to the theme of creating a release.
  2. I've made the building of a ReleasePlan more consistent
  3. I've improved the logging experience and fixed a few small bugs along the way

Exploratory testing

A really good way to test this is using the Channels.Sample project from the Channels Walkthrough - or if you have access, just use the existing Channels.Sample project on the Demo server.

Example: Using --whatif to see what would happen by default (latest package version, no channel specified)

Note: This would actually fail when posted to the server because the default channel would be used, which doesn't accept pre-releases. Is this good enough? Perhaps we can add some better information up-front, by assuming the default channel, and testing against that? Could be a compatibility risk though...

octo.exe create-release --server=https://demo.octopus.com --apiKey=API-XXXXX --project="Channels.Sample" --whatif
What if: no release will be created.
Finding project: Channels.Sample
Finding deployment process...
Finding release template...
The package version for some steps was not specified. Going to try and resolve those automatically...
Finding latest package for step: Deploy Web App
Selected 'Channels.OrderService' version '2.0.0-unstable0006' for 'Deploy Web App'
Using version number from package step.
Release plan for release:    2.0.0-unstable0006
  #   Name             Version              Source             Version rules  
  --- ---------------- -------------------- ------------------ ---------------
  1   Deploy Web App   2.0.0-unstable0006   Latest available                  

What if: not creating this release

Example: Same, but hoping to select the right channel based on the latest available

octo.exe create-release --server=https://demo.octopus.com --apiKey=API-XXXXX --project="Channels.Sample" --whatif --autochannel
Octopus Deploy Command Line Tool, version 3.3.11-autochannel.13+Branch.feature-autochannel.Sha.27aed86b947b5f9da3bddb4b82e369190a5ee262

Handshaking with Octopus server: https://demo.octopus.com
Handshake successful. Octopus version: 3.3.8; API version: 3.0.0
Authenticated as: Administrator <support@octopusdeploy.com> 
What if: no release will be created.
Finding project: Channels.Sample
Automatically selecting the best channel for this release...
Building a release plan for Channel '1.x Hotfix'...
Finding deployment process...
Finding release template...
The package version for some steps was not specified. Going to try and resolve those automatically...
Finding latest package for step: Deploy Web App
Selected 'Channels.OrderService' version '1.1.0' for 'Deploy Web App'
Building a release plan for Channel '1.x Normal'...
Finding deployment process...
Finding release template...
The package version for some steps was not specified. Going to try and resolve those automatically...
Finding latest package for step: Deploy Web App
Selected 'Channels.OrderService' version '1.1.0' for 'Deploy Web App'
Building a release plan for Channel '2.x Beta'...
Finding deployment process...
Finding release template...
The package version for some steps was not specified. Going to try and resolve those automatically...
Finding latest package for step: Deploy Web App
Selected 'Channels.OrderService' version '2.0.0-beta0001' for 'Deploy Web App'
Finding latest package for step: Deploy InventoryJob
Selected 'Channels.InventoryJob' version '2.0.0-beta0001' for 'Deploy InventoryJob'
Building a release plan for Channel '2.x Feature Branch'...
Finding deployment process...
Finding release template...
The package version for some steps was not specified. Going to try and resolve those automatically...
Finding latest package for step: Deploy Web App
Selected 'Channels.OrderService' version '2.0.0-multitenancy0001' for 'Deploy Web App'
Finding latest package for step: Deploy InventoryJob
Selected 'Channels.InventoryJob' version '2.0.0-multitenancy0001' for 'Deploy InventoryJob'
Building a release plan for Channel '2.x Unstable'...
Finding deployment process...
Finding release template...
The package version for some steps was not specified. Going to try and resolve those automatically...
Finding latest package for step: Deploy Web App
Selected 'Channels.OrderService' version '2.0.0-unstable0006' for 'Deploy Web App'
Finding latest package for step: Deploy InventoryJob
Selected 'Channels.InventoryJob' version '2.0.0-unstable0006' for 'Deploy InventoryJob'
There are 5 viable release plans using the provided arguments so we cannot auto-select one. The viable release plans are:
Channel: '1.x Hotfix'
  #   Name             Version   Source             Version rules          
  --- ---------------- --------- ------------------ -----------------------
  1   Deploy Web App   1.1.0     Latest available   Range: PASS Tag: PASS  

Channel: '1.x Normal'
  #   Name             Version   Source             Version rules          
  --- ---------------- --------- ------------------ -----------------------
  1   Deploy Web App   1.1.0     Latest available   Range: PASS Tag: PASS  

Channel: '2.x Beta'
  #   Name                  Version          Source             Version rules          
  --- --------------------- ---------------- ------------------ -----------------------
  1   Deploy Web App        2.0.0-beta0001   Latest available   Range: PASS Tag: PASS  
  2   Deploy InventoryJob   2.0.0-beta0001   Latest available   Range: PASS Tag: PASS  

Channel: '2.x Feature Branch'
  #   Name                  Version                  Source             Version rules          
  --- --------------------- ------------------------ ------------------ -----------------------
  1   Deploy Web App        2.0.0-multitenancy0001   Latest available   Range: PASS Tag: PASS  
  2   Deploy InventoryJob   2.0.0-multitenancy0001   Latest available   Range: PASS Tag: PASS  

Channel: '2.x Unstable'
  #   Name                  Version              Source             Version rules          
  --- --------------------- -------------------- ------------------ -----------------------
  1   Deploy Web App        2.0.0-unstable0006   Latest available   Range: PASS Tag: PASS  
  2   Deploy InventoryJob   2.0.0-unstable0006   Latest available   Range: PASS Tag: PASS  

The unviable release plans are:

Exit code: -1

Example: A release of 2.0.0-beta0001 using --autochannel

octo.exe create-release --server=https://demo.octopus.com --apiKey=API-XXXXX --project="Channels.Sample" --whatif --autochannel --packageVersion=2.0.0-beta0001
What if: no release will be created.
Finding project: Channels.Sample
Automatically selecting the best channel for this release...
Building a release plan for Channel '1.x Hotfix'...
Finding deployment process...
Finding release template...
Building a release plan for Channel '1.x Normal'...
Finding deployment process...
Finding release template...
Building a release plan for Channel '2.x Beta'...
Finding deployment process...
Finding release template...
Building a release plan for Channel '2.x Feature Branch'...
Finding deployment process...
Finding release template...
Building a release plan for Channel '2.x Unstable'...
Finding deployment process...
Finding release template...
Selected the release plan for Channel '2.x Beta' - it is a perfect match
Using version number from package step.
Release plan for release:    2.0.0-beta0001
Channel: '2.x Beta'
  #   Name                  Version          Source           Version rules          
  --- --------------------- ---------------- ---------------- -----------------------
  1   Deploy Web App        2.0.0-beta0001   User specified   Range: PASS Tag: PASS  
  2   Deploy InventoryJob   2.0.0-beta0001   User specified   Range: PASS Tag: PASS  

What if: not creating this release

ryangribble and others added 10 commits April 15, 2016 17:36
Tweak expected step count to just be releasePlan.Steps.Count as the release plan already only includes steps that are package steps
In order to select the right channel based on the provided package versions, we need to simulate what it would happen if we created that release into each of the channels, and pick the right one based on which ReleasePlan was the most viable.

This means we needed a way to reliably and consistently calculate the ReleasePlan, instead of doing it inline in the CreateReleaseCommand. This logic has been moved into the ReleasePlanBuilder.

Now the CreateReleaseCommand can create all of the possible ReleasePlan combinations and select the most viable.

I think overall this has simplified the code quite a lot, and consolidated a lot of the responsibilities into the building of ReleasePlan, instead of scattered around the code base.

I've ended up removing these tests temporarily and will add tests to exercise the new shape.
throw new CommandException("Package versions could not be resolved for one or more of the package steps in this release. See the errors above for details. Either ensure the latest version of the package can be automatically resolved, or set the version to use specifically by using the --package argument.");
}

if (IgnoreIfAlreadyExists)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I raised this in my first PR but to me it seems this logic is out of whack? if IgnoreIfAlreadyExists == true then we check if a release exists and throw an exception if it does. Shouldn't the if condition be if (!IgnoreIfAlreadyExists) ?

@michaelnoonan
Copy link
Contributor Author

After some offline discussion with @MJRichardson and @ryangribble we are leaning towards making the new --autochannel behaviour the default option. It is now smart enough to:

  1. Detect whether Channels are supported by the Octopus Server using hypermedia feature detection
    a. For non-Channels, just attempt to create the release with a null channel
    b. For Channels, attempt to find a perfect match (using the default channel for precedence), and fail with a really helpful message if a channel cannot be auto selected
  2. If you want to opt-out of this behaviour, you can specify --channel=MyChannel to be more explicit

I certainly think this behaviour would be what I'd expect (least-surprise) if I was coming to channels in Octopus for the first time: just take the details I'm giving you and make the release work, otherwise tell me what's wrong and how to fix it.

@ryangribble
Copy link
Contributor

👍

I also think this is the way to go, as it means we dont need to update the "create release" step on all of our teamcity builds to start using channels on those octopus projects

throw new CommandException($"At least one step violates the package version rules for the Channel '{plan.Channel.Name}'. Either correct the package versions for this release, select a different channel using --channel=MyChannel argument, let Octopus select the best channel using the --autoChannel argument, or ignore these version rules altogether by using the --ignoreChannelRules argument.");
}

if (IgnoreIfAlreadyExists)
Copy link
Contributor

@ryangribble ryangribble May 3, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just raising this one again... does this logic make sense?

if IgnoreIfAlreadyExists == true and we do find an existing release, we exit without doing anything. Shouldn't it be continuing on and replacing that release?

The logic here is probably meant to say if (!IgnoreIfAlreadyExists) ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I agree. I'll look into that today as part of this renovation. :) Thanks for the reminder.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, looking at this, I think what the flag actually means is "I'm just going to blindly create releases from my build server, and if I end up doing a duplicate build, and the release already exists, just ignore creating the release and don't get so upset"

I think it's easy to misinterpret, as I did at first glance. I'm going to leave that logic well alone to avoid breaking people who are already using this as a way to make their build servers quiet. :) Hope that's OK.

We had a big discussion in #75 about this.

Made some tweaks to the logging
Renamed Force to IgnoreChannelRules to make the meaning more clear
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants