If you are working on several closed-source projects and have many internal libraries that you wish to share as NuGet packages, you’d be looking for a way to privately host those packages. We had been using Azure DevOps Artifact Feed for this purpose. However, with the release of GitHub Packages we’ve started moving our packages there as all our devs were already on GitHub and we didn’t have to reprovision AzDO Package Management feature for those who weren’t really creating or maintaining build pipelines.
Following is what we did to keep our build pipelines in Azure DevOps and post the NuGet packages that they built in to GitHub Packages.
Prerequisites
- An Azure DevOps account
- Access to Azure KeyValut
- A GitHub account with GitHub Packages feature enabled
Prepare your project for GitHub Packages
When publishing the NuGet package you’ll be pushing from the pipeline, you’ll need the RepositoryUrl
element in the project’s .csproj
file to be set properly. Do this either by using the Project Properties screen in Visual Studio, or directly add it in the .csproj
file.
Create a GitHub PAT for managing GitHub Packages
In GitHub, click on your profile icon on the top right corner and click Settings
in the drop down menu. Then go to Developer Settings
and then Personal access tokens
. Click on the Generate new token
button and select the following scopes.
Click Generate token
at the bottom of the page and note down the Access Token generated for you.
Create an Azure Key Valut to hold the PAT
On the Azure Portal, create a new Key Vault and add the Access Token as a secret with the name GitHubPackagesPAT
.
Create a Build Pipeline in Azure DevOps
Login to your Azure DevOps Organization and create a new Pipeline. Select the Classic Editor to build your pipeline using the wizard UI.
Select to GiHub as the source repository type. You would need to create a new Service Connection at this point, if you had not already setup a GitHub connection before. You can do this using OAuth or by setting up a new GitHub PAT granting the following permissions.
-
repo
admin:repo_hook
user
Technically, you can set up one PAT with these permissions as well as the ones from the previous one. However, since you’ll be using these two tokens in different ways, I’d recommend setting up two separate tokens.
Use the ASP.NET Core
template.
Pull existing NuGet Packags from GitHub at Build-time
Next, you need the build pipeline to be able to pull in NuGet packages that may already be in GitHub Packages. You can do this by creating a NuGet.config
file that holds the GitHub PAT we created earlier. However, as we wouldn’t want to check this file back in to source control, we’d generate this file at build-time by pulling in the PAT from Azure KeyVault.
Click on the +
button to add a task to the pipeline. From the available list of tasks, select Bash Script
and move to the top of the pipeline. In the Task Configuration, select Inline
and enter the following script to the Script
box:
echo ‘ ‘ > NuGet.config
Be sure to replace your_github_org with the name of your GitHub Organization.
When this script runs at build-time, Azure DevOps will replace $(GitHubPackagesPAT)
with a value we’ll expose through Azure KeyVault. You will see how this is done later on.
Next, click on the Restore
task in the pipeline (which should be the 2nd task), and select Feeds from my NuGet.config
option under Feeds to use
. In Path to NuGet.config
just type in NuGet.config
as the above script will create the file at the root.
Push the built NuGet package to GitHub Packages
Remove the last two tasks (Publish
and Publish Artifact
) tasks from the pipeline. Then add a NuGet
task at the end. Configure the task as below, setting the Command
to push
. Be sure to change Path to NuGet package(s) to publish
to,
$(Build.SourcesDirectory)/**/*.nupkg;!$(Build.SourcesDirectory)/**/*.symbols.nupkg
Select the External NuGet server (including other accounts/collections)
under Target feed location
. Then create a new service connection for the NuGet server
.
Note that your Feed URL
will take the form of https://nuget.pkg.github.com/your_github_org/index.json
.
The username will also be your_github_org.
The pipeline tasks are now setup. Hit Save
(rather than Save & Queue
) to save up to now.
Setup Pipeline Variables
Under Pipeline
on the left navigation pane, click on Library
. Click + Variable group
button.
Give the Variable group a name and turn on the option to Link secrets from Azure key vault as variables
.
Switch to the Variables
tab and click on Variable Groups
. Now click the Link variable group
button. Pick your Azure Subscription
and Authorize it. Then pick the key vault and authorize it.
Now, click + Add
button under Variables
and pick GitHubPackagesPAT
from the popup window. Click Save
.
Now go back to your pipeline and switch to the Variables
tab. Then click on Variable groups
and then Link variable group
button. From the Link variable group
flyout, select the variable group you created earlier and click Link
.
You have just setup the mapping for the $(GitHubPackagesPAT)
variable you used in the Bash script.
Queue the Pipeline
Can go ahead and do a bit more configuration on Triggers and Options tab in the pipeline. However, as far as the core build pipeline is concerned, you are ready to execute. You can go ahead and queue it now.