.Net, Azure and occasionally gamedev

Shortening VSTS urls

2017/08/03

Last week I hailed VSTS as a great service.

One point that always bothers me is the long url to access repositories.

It's no problem if you use team explorer in Visual Studio as it will list all your repositories and allows you to clone them without ever seeing the url. However even that takes ~10 seconds to load the list the first time (I have ~100 git repositories across 4 tfs instances that I have access to) and not everyone likes to use the integrated team explorer.

I personally use a combination of git commandline and Git Extensions and thus need the url for cloning.

I can get it by either logging in to the website and to copy the url or type a very long url that I have to remember.

I'd really like to have a shorter url.

Thankfully git supports http redirects, so you can use any existing webserver and just have it forward requests and git will follow them.

One of my projects "StaticSiteGenerator" (a weekend project of mine that I use to generate the static content for this domain) is hosted on VSTS. Since it's mostly fleshed out I rarely have to touch it and thus don't keep a local copy.

If I want to access it I have to clone it again.

The full url is:

https://marcstan.visualstudio.com/Internals/_git/StaticSiteGenerator

which is already better than the old path from Visual Studio Online:

https://marcstan.visualstudio.com/DefaultCollection/Internals/_git/StaticSiteGenerator

(they used to allow you to create your own collections of projects but have since removed that feature).

The path could technically be shortend if the project and repository name where identical:

https://marcstan.visualstudio.com/_git/StaticSiteGenerator

However this is not the case because I put the StaticSiteGenerator tool (along with many others) into a project I called "Internals" (tools I use myself but don't want to opensource/maintain openly).

Either way it's a long path to type and I would much prefer https://tfs.marcstan.net/StaticSiteGenerator or even better: https://tfs.marcstan.net/ssgen (ssgen is the name I use for the resulting executable).

So I created all the necessary bits and pieces:

This is the web.config I use:

<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="HTTP to HTTPS redirect" stopProcessing="false">
                    <match url="(.*)" />
                    <conditions>
                        <add input="{HTTPS}" pattern="off" ignoreCase="true" />
                    </conditions>
                    <action type="Redirect" redirectType="Found" url="https://{HTTP_HOST}/{R:1}" />
                </rule>
                <rule name="ssgen" stopProcessing="true">
                    <match url="^ssgen(.*)$" />
                    <action type="Redirect" url="https://marcstan.visualstudio.com/Internals/_git/StaticSiteGenerator{R:1}" />
                </rule>
                <!-- run generic rule last as it would otherwise match everything due to commands being tfs/project/repo/?git.. -->
                <rule name="complete url" stopProcessing="true">
                    <!-- Match any word followed by / followed by everything else. Words can be digit, char or _, should be good enough for names used as VST project names -->
                    <match url="^(\w+)\/(.+)" />
                    <action type="Redirect" url="https://marcstan.visualstudio.com/{R:1}/_git/{R:2}" />
                </rule>
            </rules>
            <outboundRules>
                <rule name="Add Strict-Transport-Security when HTTPS" enabled="true">
                    <match serverVariable="RESPONSE_Strict_Transport_Security" pattern=".*" />
                    <conditions>
                        <add input="{HTTPS}" pattern="on" ignoreCase="true" />
                    </conditions>
                    <action type="Rewrite" value="max-age=31536000" />
                </rule>
            </outboundRules>
        </rewrite>
    </system.webServer>
</configuration>

It has 4 rules:

  1. "HTTP to HTTPS redirect"

Does what it says, just forces https redirect on every request made via http://

  1. "ssgen"

The actual rule to redirect https://tfs.marcstan.net/ssgen to https://marcstan.visualstudio.com/Internals/_git/StaticSiteGenerator

Two things to note:

First the regex "^ssgen(.*)" it matches any url that starts with "ssgen" (after the hostname itself) but may contain any further trailing stuff.

This might technically collide with rule 3 if I have a project of the same name (which I don't).

Note that the trailing (.*) is important because git will make requests such as "https://tfs.marcstan.net/ssgen/info/refs?service=git-upload-pack" and we want to match all urls starting with "ssgen".

Second the redirect "https://marcstan.visualstudio.com/Internals/_git/StaticSiteGenerator" contains "" to reinsert the matched regex group (.*) from above.

Pretty basic url rewrite rule stuff so far.

You can use IIS to configure all these via the UI (including a regex tester) too, if you don't like messing with the config file directly.

  1. "complete url"

This is my generic catch all redirect that allows me to write "https://tfs.marcstan.net/projectName/repoName" and have it redirect to https://marcstan.visualstudio.com/projectName/_git/repoName

I use it to instantly support all my projects (saves me from having to write "/_git/", too) that I didn't add specialized rules for.

Note that the regex starts with a \w+ (word group) instead of a anything group (.+).

This is important because "^(.+)/(.+)" in the context of e.g. "projectName/repoName"

would match like this:

due to (.+) greedily matching everything already, leaving nothing for the next group.

Whereas "^(\w+)/(.+)" specifically says "from the start, match only alphanumeric chars as well as underscore (but not a "/"), then require a "/" followed by anything else.

Thus turning the above example into:

Allowing the full redirect url to be built correctly.

  1. "HSTS rule"

This simply sets the HSTS header and forces the user to remain on the SSL version of the site when he is already on the https version (my site thus doesn't even support http:// anymore).


After I got this up and running I added more rules (like rule 2) for all my most used projects (as well as those with long names like "MonoGame.Framework.WpfInterop").

Note that the order of the rules is important:

Overall this is a pretty simple solution (doesn't sanitize any input, everything is just forwarded to my VSTS account blindely resulting in possible 404's if something is misspelt) but as they say: If it's stupid and works it ain't stupid.

You will note that this causes an actual redirect and git issues a warning:

git clone https://tfs.marcstan.net/ssgen

Cloning into 'ssgen'...

warning: redirecting to https://marcstan.visualstudio.com/Internals/_git/StaticSiteGenerator/

Likewise visiting the url in a browser causes a redirect to the visualstudio domain.

For me this is enough as it satisfies my usecase.

Technically there is a way to make the target url disappear completely by using a reverse proxy.

That way the url would literally remain https://tfs.marcstan.net for all requests as the IIS engine will replace the target url with the custom url in each request.

However I won't cover that in this post.

tagged as Azure, Visual Studio Team Services, VSTS and Azure DevOps