I recently returned to Delphi for the first time in years, to work on a project that I’ve had at the back of my mind for a long time and whose time I thought had come. Before I get into that though, I decided to bring the old and new together for this project, using Azure DevOps to host the code and provide build and test automation.
In Azure DevOps you can run your build processes on Microsoft hosted servers. This is very convenient but comes with some drawbacks not least of which is that those hosted build servers only support the build tools that Microsoft feel worth making available.
Delphi isn’t one of them (at least not at time of writing).
Fortunately you can connect your own build machine to the Azure DevOps infrastructure very simply by installing an incredibly simple piece of software on it called an “Agent”.
Note: Azure DevOps also supports using containers for builds which could conceivably have been used but was not the object of this exercise. If you’re interested in that approach, this article may be of interest.
On a self-hosted build machine, the agent serves two purposes:
- First, it identifies your build machine capabilities to Azure DevOps. This enables Azure DevOps to send your machine only those build tasks that your build machine is capable of. If you don’t have an Android SDK installed then you won’t be sent Android builds, for example.
- Second it polls for build tasks that it can run for you, executes those tasks and communicates the results (and potentially resulting artefacts) back to the Azure DevOps service.
For the first part, there are capabilities that are defined by Azure DevOps to identify things such as MSBuild or Visual Studio, Java and Android SDK’s, Xcode (your build machine may be a Mac) etc etc.
These capabilities are identified automatically when you configure the agent software on your build machine by scanning for known software on the machine. In addition you can define your own capabilities, things that the agent does not know to look for itself. Delphi falls into that camp.
But we’ll get into that later. Let’s get started.
First, I’m assuming you already have an Azure DevOps account (its free!) but if you don’t go ahead and sign up now. I’ll wait here…
Back? Cool. 🙂
Enrolling a New Agent
On your Azure DevOps organization landing page, go to Organization Settings:
Then navigate to the Agent Pools settings in the Pipelines section. Here you will see a pool already exists for builds to run on the hosted infrastructure (the Azure Pipelines pool).
Add a new pool using the Add Pool button (top right) and name it however you wish. I have two build machines that I’m using in my den at home, so I added a pool called The Den:
With the pool created, you can now select that pool to see all the agents in that pool. The default view actually shows the history of jobs run on those agents, but since there are no agents there are no jobs either.
Either way, we use the New Agent button to add a new agent.
Actually, we don’t.
When you select New Agent what you actually get is a dialog with a link to download the agent software for the detected browser OS – you can change this if (e.g. like me) you’re using a Mac but intending to setup a Windows build machine:
Everything you need to get your agent up and running is in this one dialog and the links it provides. It really is straightforward. The most important step is creating the PAT (Personal Access Token) which is used to configure the agent and needs the scope Agent Pools (Read & Manage).
This is only used when setting up the agent so you don’t need to worry about keeping it around afterward. You also need a PAT when removing an agent, but it doesn’t need to be the same PAT used to configure the agent; you can create these PAT’s and revoke them when you’re done with them instead of worrying about how to manage them.
When the agent is configured you will be asked for the pool the agent should be part of, a name for the agent (which will default to the system/host name) and whether you want to run it as a service (Yes is a good answer if you want your build machine to auto-connect to the pool after a restart, for example). You will also need to identify an account for the agent to run under, though a default is provided if you don’t want to have to think too much).
Finally, you will need to specify a folder where work files are downloaded and acted upon by the tasks sent to your agent.
Oh, and all of this has to be done in an elevated command prompt.
Once all of this has been done and assuming everything has gone smoothly, your agent will now be registered with your pool:
As you can see, my build machine is an Intel NUC, unimaginatively named NUC. And we can see that everything so far is working as Azure DevOps is both aware of the machine (so the machine can talk to the service – it has to, to have been able to register) and Azure DevOps has determined that the machine is online (so the agent service on the machine is contactable).
Great, but so far this machine isn’t capable of very much. Well, actually it is.
I already had Visual Studio 2017 installed on this machine along with JDK and the Android SDK. All of this, along with a bunch of other things were detected by the auto-scan performed by the agent config which we can see by selecting the agent and then browsing the detected capabilities.
There are way too many capabilities to show here, but I’ve highlighted some of the more interesting ones.
You can click to view the larger image if you’re interested. A key thing to note with these capabilities is that they are not just a yes/no indicator but have a value associated with them which could be useful to any task which relies on these capabilities.
For example, the JAVA capability not only identifies that the Java Runtime is present on the machine, but also identifies the path to the installed runtime. Similarly all of the different .NET framework version paths are identified along with each version as a distinct capability.
But no Delphi.
I can assure you that Delphi is on this machine however. In fact, every version from Delphi 7 thru XE4 (except 2005 and 2006). All of these versions are present in a folder c:\dcc on the machine:
These are not full installs but just enough needed to run command line compiles. That is, the bin and lib folders, donated from my Delphi development VM where I do have these versions fully installed.
So I’m going to add some user defined capabilities to my agent, to identify these locations and the presence of Delphi on this machine:
It doesn’t matter what I call these capabilities (as long as they aren’t confused with any system defined capabilities). Nor does it matter what value I give them. At least not yet.
It will matter when we come to make use of these capabilities later, but for now these are having no effect what-so-ever. Azure DevOps could care less about these capabilities – it still has no idea what to do with them. That’s up to us.
Testing The Agent
To test the agent we will need some code to build and something to tell the agent how to build it.
We’ll do that in the next post.