Update AzureDevOps PR Status’ with Powershell

on Monday, May 25, 2020

AzureDevOps integrates third party CI pipeline components through a Pull Request Status API (example usage with node.js). The end goal of the status API is to allow you to integrate any number of 3rd party tooling into your pull request validation processes. Hopefully creating something that looks like this:

The Build succeeded link comes from the built-in Build Policy of Azure DevOps Branch Protection. But, for any other service, you’ll need to integrate it’s results using an external service. That’s how the Deploy succeeded link was created in the screenshot above.

There are examples on how to use the API for external services (like the node.js example), but I didn’t run across any examples for powershell. So, here’s a quick example.

The example code:

  • Load’s up some dlls from AzureDevOps .NET Client Libraries.
  • Loads up the VSTeam powershell module.
  • Signs into Azure DevOps using your Personal Access Token (both VSTeam and the .NET Client libraries need to be signed into separately).
  • Uses VSTeam to retrieve your Project’s internal Guid.
    • You can do this with the .NET libraries too. I just want to support the usage of the VSTeam module.
  • Uses the .NET Libraries to retrieve your Repositories internal Guid.
  • Creates a GitPullRequestStatus object and populates it with some information.
  • Uses CreatePullRequestStatusAsync to update the status.
    • The great part of CreatePullRequestStatusAsync is that the display will always show the most recently supplied status for an integration component. So, you don’t have to worry about “updating” the status. Just call CreatePullRequestStatusAsync repeatedly throughout your process to update the status.

Book Review? A Seat at the Table

on Monday, May 18, 2020

Mark Schwartz’ A Seat at the Table (amazon, audible) is as close of description of DevOps to the one I have in my head as I’ve ever read. It definitely doesn’t have all the answers, and it asks some questions where the offered answers don’t feel like they satisfy all aspects of the question. But, it’s always an earnest answer which tries to address as many aspects as it can while still being very coherent and relatable.

Some pieces that I haven’t heard from other books (which seemed to match my own thoughts):

  • Projects which are bound by start and ends dates aren’t enough for long term success. By placing an artificial end date on a project it only ensures that the product will become stale and unmaintained after that end date. Even if you were to have product teams (Project to Product) it still isn’t enough, because that only secures knowledgeable resources to be available as future needs are determined. You also need to flatten the management structure to give the product team full agency over the product direction. So that the team can pull feedback directly from their customers and determine the future needs themselves. This is very hard to achieve because of the need for the team to be knowledgeable about the long term needs of the company and it’s strategies.
  • In a lot of Lean Management books (like James P. Womack’s works) there are incredibly vivid and tangible descriptions of how to implement Lean Principles within a Product line. But, they feel somewhat vague about the role of management within Lean production. Even Gemba Walks (2nd Edition) description felt like it was saying “the leadership should set a direction and strategize on how to execute in that direction without creating confusion”. It’s very vague and kind of hand wavy.

    But, in this book, Mark Schwartz very clearly states that management is a form of Waste. “If your not coding, your a waste” (<—take that with a grain of salt, it’s taken out of context). The goal of management is to set a direction and remove as many impediments as possible from the path to achieve that goal. Management adds value by removing the impediments and reducing the number of interruptions. And you don’t need multiple levels of management to do that. For me, that helps explain why Lean Management books are soo thin on the topic of what Managements role is: Management just isn’t a massively important part of product creation in Lean.

Of course no two people ever see eye-to-eye on everything. There was one statement that really threw me for a loop and I’m puzzling to better understand his view point:

In a chapter describing Quality in Software development he stated that all bugs should fall into two categories: either they should be fixed immediately, or they should be accepted as acceptable and never recorded/addressed as backlog items.

Now, I’m definitely on board with the idea that not all bugs are equal and there are some that should be fixed right away: Build is broken (test failure, deployment failure), production bug, practically anything that prevents work from being completed. But, when a bug isn’t an immediate fix, I feel like it should still be added to the backlog to be fixed during the next sprint. Maybe I need to read/listen to the chapter again and see if he made some caveats around when you should change it from a bug report to a feature request, or if the bug report comes from an end user it’s always an immediate fix. I don’t know.

I really hope that one day he might write another book that tackles real world problem scenarios that he’s run into and how he overcame them. I feel like the majority of DevOps books bring up that there are almost always conflicts between colleagues surrounding producing functionality vs meeting security and compliance goals; but then the authors wave a magic wand by saying “and this leads to discussions that ultimately result in value being created.” But, I haven’t read a book that digs in and describes an actual situation that occurred, getting into the details of the difficulties (from conflicts in opinion, conflicts over policy interpretation, conflicts in ideology, etc) and then describes all the tools and strategies that we used to overcome each of the difficulties. Maybe I have read that book and I’m just too dense to have noticed it.

camelCase Enums in Swashbuckle

on Monday, May 11, 2020

In an earlier version of Swashbuckle.AspNetCore, SwaggerGenOptions came with two extensions method that helped facilitate returning camelCase values from your enum data types.

However, in newer versions of Swashbuckle, those methods have been deprecated and they ask you to use the built-in features of your preferred JsonSerializer (this example is for Newtonsoft’s Json.NET):

These options will produce the expected camelCased data to flow across the wire. But, it won’t update the documentation generated by Swashbuckle to show the camelCased values. Instead Swashbuckle will continue to show the enum values:

The Unchase.Swashbuckle.AspNetCore.Extensions collection has an Enum’s extension which will provide the documentation that you’re looking for, but it still expects you to return numerical values (instead of the camelCased names).

I was looking for both:

  • Return camelCased values across the wire, and
  • Update the swagger/OpenApi documentation to display the camelCased values

Of course, I couldn’t be the only one looking for something like this and there was a nice piece of starting code on stackoverflow (Swagger UI Web Api documentation Present enums as strings), which grew into an EnumDocumentFilter.cs class (its specific to Newtonsoft’s Json.NET). The document filter produces output that looks like this:

Swashbuckle Duplicate SchemaId Detected

on Monday, May 4, 2020

I’m sure this is rarely run into, but every once in a while, you might reuse the name of  class between two namespaces. For example:

  • YourCompany.CommonComponentLibary.SystemOperation
  • YourCompany.ProjectXXXXX.SystemOperation

If both of those classes are then exposed as return types from an API endpoint, there is a chance that Swagger might throw an error that looks something like this:

The Swashbuckle team has run into this / thought about this and there is a function called CustomSchemaIds to handle it. The function’s usage looks a little like this (default implementation):

As best as I can tell the intention behind this function is to generate out the expected name for a given Type, completely agnostic of any external information.

Not using external information creates helps ensure the result should always be the same, because their is no “state of the system” information used to create unique names. This makes the names consistent despite processing order or updates to the underlying code base. So, it’s a good thing.

But … it can make for rather large names. Using the above code snippet as a example, the FullName is a unique name, but it contains a lot of information about how you internally generated the name. I’m not looking to have that information concealed for any security or risk purpose, it can just be hard to read in a json/yaml format or even in a Swagger UI display.

So, it might be easier to create a new Custom Schema Id which would try to stick with the default implementation, but alter it to return a longer name if conflicts occur. For example, what if the rules were:

  • Use the default implementation of the Class Name (without Namespace) when possible.
  • If the Class Name has already been used, then start prefixing Namespace names (from closest to the Class Name, back down to the root Namespace last).

An example of this might be:

  • YourCompany.CommonComponentLibary.SystemOperation –> SystemOperation
  • YourCompany.ProjectXXXXX.SystemOperation –> ProjectXXXXX.SystemOperation

But, to do that you would need to know about the current registered types (ie. external information).

Interestingly enough, the code which calls the CustomSchemaId/SchemaIdSelector function has access to a SchemaRepository class which contains exactly that information. But, it doesn’t pass the SchemaRepository into the function. The SchemaRespository was available within the code at the time of the SchemaIdSelector’s introduction (Swashbuckle.AspNetCore.SwaggerGen-5.0.0-rc2), so it could have been passed in. But, sometimes it’s just hard for see weird use cases like the one I’m describing.

There is a way to implement the use case I’m describing, by replicating the SchemaRepository within your own code. It doesn’t take a lot of effort, but it can feel like you’re doing something wrong. Here’s what that can look like:

As a sidenote, I think I’ll touch on is the large change that came with version 5.0.0-rc3. That version introduced/switch over to OpenApi 3.0 and the Microsoft.OpenApi libraries. It was a great change, but it also changed the way that the SchemaIdSelector worked. In the 5.0.0-rc2 version (the first version that introduced the selector), the selector would only be called once per type. In 5.0.0-rc3+, it started to be called on every type lookup. This means when you’re writing a custom selector, the selector needs to detect if a type has been selected before, and return the same value as it did previously.


Creative Commons License
This site uses Alex Gorbatchev's SyntaxHighlighter, and hosted by herdingcode.com's Jon Galloway.