I’ve been using Azure DevOps to build a library I have sourced in GitHub. I really should learn about GitHub Actions, but my main focus has been 1) learning Python and 2) how to build a pipeline to publish to PyPi, and so the quickest way for me to learn the second point was to stick to the tool I know the best. Anyway, in Azure DevOps you need to create a service conection to an external source in able to communicate with it in a pipeline. There’s a lot of documention on how to set one up, go and have a read to learn more about these.

So, when creating a connection to PyPi, I followed the documenation, added the publish yaml into my pipeline and hey presto, it broke!

  - script: |
      python3 -m twine upload --skip-existing --verbose --repository runeatest  --config-file $(PYPIRC_PATH) dist/*.whl
     condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
    displayName: "Upload to Pypi"

Now in order for this to authenticate, you need to authenticate using the TwineAuthenticate task. What this does is create the config file referenced in the task which is used to authenticate.

  - task: TwineAuthenticate@1
    displayName: 'Twine Authenticate'
    condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
      pythonUploadServiceConnection: 'pypi_runeatest'

OK, so why did it fail? My service connection was set up correctly as I was using an authentication token. Well it come as no surprise to some of you, but even with all my years of expereience I am always surprised and disappointed to discover when the documentation is incorrect. When setting up a service connection the documentation says to use the “authentication token” option. However I have since found that this is incorrect, and that you should use username and password option, specify __token__ as the uname and the authentication token needs to be the password.


So now I can publish my library to pypi no issues.