Merging multiple accounts on UserEcho

UserEcho is a service employed by the likes of OzCode and SublimeText for collecting and managing customer issues and suggestions; often regarding software features and bugs. It enables users and developers to discuss bugs and ideas, and respond to frequently asked questions.

OzCode UserEcho landing page
OzCode UserEcho landing page

Recently, I signed into the OzCode UserEcho site using my Google credentials. UserEcho supports the OpenID identity system, providing a wide range of ways to authenticate. Upon logging in, I was immediately confused; where was the issue I had raised a week or two earlier? I was certain it should be there but it was not. After a little thought, I realised I may have logged in with the wrong credentials, inadvertently creating a new account. I logged out and then, using my GitHub account to authenticate instead of Google, tried logging back in. Voila! My issue appeared.

For some, this would probably be the end of it, but it bugged me that I now had two accounts. You may think this is no big deal and you are right, but it was bothering me1.

Settings dropdown on UserEcho
Settings dropdown on UserEcho

Using the dropdown captioned with my name at the top-right of the UserEcho site, I chose User Profile. At the bottom of the subsequent page, I found a table of OpenID logins that the account used but no way to edit it. How could I merge my accounts or add new OpenID identities?

OpenID table on UserEcho user profile screen
OpenID table on UserEcho user profile screen

After searching around the UserEcho site a bit and trying a few Google searches2, I was almost ready to contact UserEcho for some help (or just give up), but then I had an idea. If UserEcho was like most sites these days, it probably keyed accounts using a primary email address for the user. So, I checked the two UserEcho accounts I knew I had and confirmed they had different email addresses.

User details section of a UserEcho profile
User details section of a UserEcho profile

I edited the email address for one of the two accounts to match the other, triggering UserEcho to send a verification email3, so I followed the instructions and verified the email address change.

UserEcho table of accounts with the same email
UserEcho table of accounts with the same email

Then I returned to the User Profile screen in OzCode's UserEcho. At the bottom, below the OpenID table, I was now presented with a message saying that there were other accounts with the same email address, including a Merge button. I clicked that button and immediately, the table showed both the Google and GitHub logins.

OpenID table in UserEcho showing GitHub and Google IDs
OpenID table in UserEcho showing GitHub and Google IDs

So, there you go. If you have multiple accounts for a UserEcho product site, make sure the email addresses match and that you have verified the email address on each account, then view one and click Merge. Job done.


  1. In writing this blog and generating the screenshots, I discovered I actually had three accounts! 

  2. and maybe one Bing 

  3. just making sure you're still you 

Prerelease packages with branches, Appveyor, and MyGet

We use a workflow where Appveyor is setup for CI and then it automatically pushes newly built nuget packages to a MyGet feed for consumption. Perhaps in a future post, I will go over how to set all this up, but for now, let's assume you already have this working; you push changes to a branch in your GitHub repo, which then gets built and tested on Appveyor, before being pushed to MyGet. Everything is nice and smooth.

Unfortunately, the magic ended there. Since there is no differentiation between pushing prerelease changes and release changes, I found that I would either have to limit what branches built in on Appveyor or spend a lot of time curating MyGet to remove intermediate builds I did not want used. I knew that MyGet supported prerelease packages but no matter what I tried, I could not get Appveyor to build them. Unsurprisingly, I found this frustrating. Then I stumbled on this particular answer on StackOverflow:

However, there were some issues I had with this.

  1. It seemed wrong that I had to use an after_build or on_success step to explicitly build my nuget package
  2. I didn't want every build to be prerelease
  3. It didn't work

The first point smelled enough that I wanted to see if I could not have to do that, and that second point seemed really important.

So, I delved a little deeper and discovered that the nuspec file, which has a handy $version$ substitution for the version takes that information from the value of the AssemblyInformationalVersion attribute, which I did not have declared in my AssemblyInfo.cs. Since it was not in there, the Appveyor step declared to patch it did not do anything. This was easy to fix, so I edited my AssemblyInfo.cs to include the attribute and tried again. This time the version updated as I wanted, even without the after_build or on_success shenanigans.

However, it still was not quite right since now, every build being performed was marked as prerelease. While this is a potential workflow, where the appveyor.yml is updated when finally reaching release, what I wanted was for releases to occur when I tagged a branch. For that, I looked at tweaking how the Appveyor build version updated and what environment variables Appveyor defined that I could leverage.

It turns out that Appveyor defines APPVEYOR_REPO_TAG, which is set to true if the build was started by a tag being pushed. It also defines APPVEYOR_REPO_BRANCH containing the name of the branch being built. Armed with these two variables, I updated my appveyor.yml to have two init scripts.

The first script creates a new environment variable. If the APPVEYOR_REPO_TAG is set to true, the new variable gets set to the value of APPVEYOR_BUILD_VERSION; if not, it is set to APPVEYOR_BUILD_VERSION-APPVEYOR_REPO_BRANCH. So, for example, if the build was going to be version 2.4.0, it was not a tag, and the branch was master, then the new variable would be set to 2.4.0-master; however, if it was a tag, it would just be 2.4.0.

The second script calls the Update-AppveyorBuild cmdlet provided by Appveyor, passing the value of the new environment variable as the -Version parameter value.

These two init scripts, plus the AssemblyInformationalVersion attribute in the AssemblyInfo.cs (and corresponding assembly_information_version field under the assembly_info section of the appveyor.yml) were all I needed. Now, whenever I push to a branch, I get a new prerelease nuget package that I can use in my development coding, and whenever I create a new tag, I get a release package instead. Not only does this reduce my need to manually manage my nuget packages on MyGet, but it also means I can take advantage of the different retention policy settings between prerelease and release packages.

All in all, I find this workflow much nicer than what I had before. Hopefully some of you do too. Examples of the appveyor.yml file and associated AssemblyInfo.cs change can be seen in the following Gist.

Signing GitHub Commits With A Passphrase-protected Key and GPG2

GitHub recently added support for signed commits. The instructions for setting it up can be found on their website and I do not intend to rehash them here. I followed those instructions and they work splendidly. However, when I set mine up, I had used the version of GPG that came with my Git installation. A side effect I noticed was that if I were rebasing some code and wanted to make sure the rebased commits were still signed (by running git rebase with the -S option), I would have to enter my passphrase for the GPG key for every commit (which gets a little tedious after the first five or so).

Shows some commits on GitHub with the Verified indicator showing those that have been signed
How GitHub shows signed commits

Now, there are a couple of ways to fix this. One is easy; just don't use a passphrase protected key. Of course, that would make it a lot easier for someone to sign commits as me if they got my key file, so I decided that probably was not the best option. Instead, I did a little searching and found that GPG2 supports passphrase protected keys a little better than the version of GPG I had installed as part of my original git installation.

Using the GPG4Win website, I installed the Vanilla version1. I then had to export the key I had already setup with GitHub from my old GPG and import it into the new. Using gpg --list-keys, I obtained the 8 character ID for my key (the bit that reads BAADF00D in this example output):

Which I then used to export my keys from a Git prompt:

This gave me two files ( privatekey.txt and publickey.txt) containing text representations of the private and public keys.

Using a shell in the GPG2 pub folder ( "C:\Program Files (x86)\GNU\GnuPG\pub"), I then verified them (always a good practice, especially if you got the key from someone else) before importing them2:

And rather than give me details of the key, it showed me this error:

What was going on? I tried verifying it with the old GPG and it gave me a different but similar error:

I tried the public key export and it too gave these errors. It did not make a whole heap of sense. Trying to get to the bottom of it, I opened the key files in Visual Studio Code. Everything looked fine until I saw this at the bottom of the screen.

Encoding information from Visual Studio Code showing UTF16
Encoding information from Visual Studio Code

It turns out that Powershell writes redirected output as UTF-16 and I had not bothered to check. Thinking this might be the problem, I resaved each file as UTF-8 and tried verifying privatekey.txt again:

Success! Repeating this for the publickey.txt file gave the exact same information. With the keys verified, I was ready to import them into GPG2:

With the keys imported, I ran gpg --list-keys to verify they were there and then made sure to delete the text files.

Finally, to make sure that Git used the new GPG2 instead of the version of GPG that it came with, I edited my Git configuration:

Now, when I sign commits and rebases, instead of needing to enter my passphrase for each commit, I am prompted for the passphrase once. Lovely.


  1. You could also look at installing the command line tools from https://www.gnupg.org/download/ though I do not know if the results will be the same 

  2. Note that I am not showing the path to the file here for the sake of brevity, though I am sure you get the idea that you'll need to provide it 

Octokit, Merge Commits, and the Story So Far

In the last post we had reduced our commits by matching them against pull requests; next, we can look for noise in the commit message content itself. Although I have been using the Octokit.NET repository as the target for testing with its low noise, high quality commit messages, we can envisage a less consistent repository that has some noisy commits. For example, how often have you seen or written commit messages like "Fixed spelling", "Fixed bug", or "Stuff"1?

How we detect these noisy commits is important; if our filtering is too simple, we remove too many things and if it is too strict, we remove too few. Rather than go deep into one specific implementation, I just want to introduce the idea of filtering based on message content. In the long term, I think it would be interesting to apply learning algorithms,  but I'm sure some simple, configurable pattern matching should suffice2.

If I run the filtering I have described so far3 on the Octokit.NET latest release, this is what we get:

The value of this is clearer if we see the commit list before processing:

The work so far has reduced a list of 135 commits down to 58, and so far, it looks like we have not lost any really useful "release note"-worthy information. However, the eagle-eyed among you may noticed that our 58 messages contain duplicate information. This is because each pull request is listed twice; once for the pull request title I inserted in place of its individual commits, and again for the merge commit that merged that pull request. These merge commits are not filtered out because they do not belong to the commits inside the pull request. Instead, they are an artifact of merging the pull request4.

At first, I thought the handy MergeCommitSha property of the pull request would help, but it turns out this refers to a test merge and is to be deprecated5. Instead, I realised that the messages I wanted to remove all had "Merge pull request #" in them, followed by the pull request number. This seems like a perfect use case for our pattern matching filtering. Since we have the pull requests, we could use their numbers to match each merge message exactly, but I decided to do the simpler thing of excluding any message starting with "Merge pull request #".

Filtering for messages that begin with "Merge pull request #" gives us a shortlist of just 31 messages:

I think this is a pretty good improvement over the raw commit list. Combining this list with links back to the relevant commits and pull requests should enable someone to discern the content of a release note much faster than using the raw commit list alone. I will leave that as an exercise or perhaps a future post. As always, thanks for reading. If you find yourself using Octokit to trawl your own repositories for release note information, I would love to hear about it in the comments.


  1. We're all friends here, you can admit it 

  2. The filtering should be configurable so that we can tailor it to the repository we are processing 

  3. excluding the last step of filtering by message content 

  4. Perhaps stating the obvious 

  5. https://developer.github.com/v3/pulls/ 

Octokit and Noise Reduction with Pull Requests

Last time in this series on Octokit we looked at how to get the commits that have been made between one release and another. Usually, these commits will contain noise such as lazy commit messages and merge flog ("Fixed it", "Corrected spelling", etc.), merge commits, or commits that formed part of a larger feature change submitted via pull request. Rather than include all this noise in our release note generation, I want to filter those commits and either remove them entirely, or replace them with their associated pull request (which hopefully will be a little less noisy).

Before we filter out the noise, it seems prudent to reduce the commits to be filtered by matching them to pull requests. As with commits, we can query pull requests using a specific set of criteria; however, though we can request the results be sorted a certain way, we cannot specify a date range. To get all the pull requests that were merged before our release, we need to query for all the pull requests and then filter by date locally.

This query can be slow, since we are getting all closed pull requests in the repository. We could speed it up by providing a base branch name in the query criteria. However, to remove as much commit noise as possible, I would like to include pull requests that were merged to a different branch besides just the release branch1. We could make things more performant by managing a list of active release branches and then querying pull requests for each of those branches only rather than the entire repository, but for now, we will stick with the less optimal approach as it keeps the code examples a little cleaner.

Before we can start filtering our commits against the pull requests, we need to get the commits that comprise each pull request. When requesting a collection of items (like we did for pull requests), the GitHub API returns just enough information about each item so that we can filter and identify the ones we really care about. Before we can do things with other properties on the items, we have to request additional information. More information on each pull request can be obtained about a specific pull request by using the Get, Commits, Files, and Merged calls. The Get call returns the same type of objects as the GetAllForRepository method, except that all the data is now populated instead of just a few select properties; the Merged call returns a Boolean value indicating if the PR has been merged (equivalent to the Merged property populated by Get); the Files method returns the files changed by that pull request; and the Commits method returns the commits.

At this point, things are looking pretty good: we can get a list of commits in the release and a list of pull requests that might be in the release. Now, we want to filter that list of commits to remove items that are covered by a pull request. This is easy; we just compare the hashes and remove the matches.

Using the collection of commits for the latest release, we join the commits from the pull requests using the SHA hash and then select all release commits that have no matching commit in the pull requests2. However, we don't want to lose information just because we're losing noise, so we have to maintain a list of the pull requests that were matched so that we can build our release note history. To keep track, we will hold off on discarding any information by pairing up commits in the release with their prospective pull requests instead of just dropping them.

Going back to where we had a list of pull requests merged prior to our release, let us revisit getting the commits for those pull requests and this time, pairing them with the commits in the release to retain information.

Now we have a list of commits paired with their parent pull request, if there is one. Using this we can build a more meaningful set of changes for a release. If I run this on the latest release of the Octokit.NET repository and then group the commits by their paired pull request, I can see that the original list of 135 commits would be reduced to just 58 if each commit that belonged to a pull request were bundled into just one entry.

Next, we need to process the commits to remove those representing merges and other noise. These are things to discuss in the next post of this series where perhaps we will take stock and see whether this effort has been valuable in producing more meaningful release note generation. Until then, thanks for reading and don't forget to leave a comment.


  1. often changes are merged forward from one branch to another, especially if there are multiple release branches to support patch development and such 

  2. The join in this example is an outer join; we are taking the join results and using DefaultIfEmpty() to supply an empty collection when there was nothing to join