diff --git a/src/extension/task/index.ts b/src/extension/task/index.ts index a9078f8f..d30e6fc6 100644 --- a/src/extension/task/index.ts +++ b/src/extension/task/index.ts @@ -34,6 +34,16 @@ function getGithubEndPointToken(githubEndpoint: string): string { return githubEndpointToken; } +function extractVirtualDirectory(organizationUrl: URL): string { + let path = organizationUrl.pathname.split("/"); + // Virtual Directories are sometimes used in on-premises + // URLs tipically are like this: https://server.domain.com/tfs/x/ + if (path.length == 4) { + return path[1]; + } + return ""; +} + function extractOrganization(organizationUrl: string): string { let parts = organizationUrl.split("/"); @@ -62,13 +72,6 @@ function extractOrganization(organizationUrl: string): string { ); } -function extractHostname(organizationUrl: string): string { - let parts = organizationUrl.split("/"); - - // For both new (https://dev.azure.com/x/) and old style (https://x.visualstudio.com/), the hostname is in position 2 - return parts[2]; -} - async function run() { try { // Checking if docker is installed @@ -81,11 +84,28 @@ async function run() { dockerRunner.arg(["--rm"]); // remove after execution dockerRunner.arg(["-i"]); // attach pseudo tty - // Set the hostname + + // Set the protocol var organizationUrl = tl.getVariable("System.TeamFoundationCollectionUri"); - let hostname: string = extractHostname(organizationUrl); + var parsedUrl = new URL(organizationUrl); + let protocol: string = parsedUrl.protocol.slice(0, -1); + dockerRunner.arg(["-e", `AZURE_PROTOCOL=${protocol}`]); + + // Set the hostname + let hostname: string = parsedUrl.hostname; dockerRunner.arg(["-e", `AZURE_HOSTNAME=${hostname}`]); + // Set the port + let port: string = parsedUrl.port; + if (port !== "") { + dockerRunner.arg(["-e", `AZURE_PORT=${port}`]); + } + + // Set the virtual directory + let virtualDirectory: string = extractVirtualDirectory(parsedUrl); + if (virtualDirectory !== "") { + dockerRunner.arg(["-e", `AZURE_VIRTUAL_DIRECTORY=${virtualDirectory}`]); + } // Set the github token, if one is provided const githubEndpointId = tl.getInput("gitHubConnection"); if (githubEndpointId) { diff --git a/src/script/README.md b/src/script/README.md index 08dfbf87..ac4290a1 100644 --- a/src/script/README.md +++ b/src/script/README.md @@ -11,7 +11,10 @@ Next create and run a container from the image: ```bash docker run --rm -t \ -e GITHUB_ACCESS_TOKEN= \ - -e AZURE_HOSTNAME= \ + -e AZURE_PROTOCOL= \ + -e AZURE_HOSTNAME= \ + -e AZURE_PORT= \ + -e AZURE_VIRTUAL_DIRECTORY= \ -e AZURE_ACCESS_TOKEN= \ -e AZURE_ORGANIZATION= \ -e AZURE_PROJECT= \ @@ -32,7 +35,7 @@ docker run --rm -t \ tingle/dependabot-azure-devops:0.4.0 ``` -An example: +An example, for Azure DevOps Services: ```bash docker run --rm -t \ @@ -58,6 +61,35 @@ docker run --rm -t \ tingle/dependabot-azure-devops:0.4.0 ``` +An example, for Azure DevOps Server: + +```bash +docker run --rm -t \ + -e GITHUB_ACCESS_TOKEN=ijkl..mnop \ + -e AZURE_PROTOCOL=http \ + -e AZURE_HOSTNAME=my-devops.com \ + -e AZURE_PORT=8080 \ + -e AZURE_VIRTUAL_DIRECTORY=tfs \ + -e AZURE_ACCESS_TOKEN=abcd..efgh \ + -e AZURE_ORGANIZATION=tinglesoftware \ + -e AZURE_PROJECT=oss \ + -e AZURE_REPOSITORY=dependabot-azure-devops \ + -e DEPENDABOT_PACKAGE_MANAGER=nuget \ + -e DEPENDABOT_DIRECTORY=/ \ + -e DEPENDABOT_TARGET_BRANCH=main \ + -e DEPENDABOT_VERSIONING_STRATEGY=auto \ + -e DEPENDABOT_OPEN_PULL_REQUESTS_LIMIT=10 \ + -e DEPENDABOT_EXTRA_CREDENTIALS='[{\"type\":\"npm_registry\",\"token\":\"\",\"registry\":\"npm.fontawesome.com\"}]' \ + -e DEPENDABOT_ALLOW='[{\"name\":"django*",\"type\":\"direct\"}]' \ + -e DEPENDABOT_IGNORE='[{\"name\":\"express\",\"versions\":[\"4.x\",\"5.x\"]}]' \ + -e AZURE_WORK_ITEM_ID=123 \ + -e AZURE_SET_AUTO_COMPLETE=true \ + -e AZURE_AUTO_APPROVE_PR=true \ + -e AZURE_AUTO_APPROVE_USER_EMAIL=supervisor@contoso.com \ + -e AZURE_AUTO_APPROVE_USER_TOKEN=ijkl..mnop \ + tingle/dependabot-azure-devops:0.4.0 +``` + ## Environment Variables To run the script, some environment variables are required. @@ -65,7 +97,10 @@ To run the script, some environment variables are required. |Variable Name|Description| |--|--| |GITHUB_ACCESS_TOKEN|**_Optional_**. The GitHub token for authenticating requests against GitHub public repositories. This is useful to avoid rate limiting errors. The token must include permissions to read public repositories. See the [documentation](https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/creating-a-personal-access-token) for more on Personal Access Tokens.| -|AZURE_HOSTNAME|**_Optional_**. The hostname of the where the organization is hosted. Defaults to `dev.azure.com` but for older organizations this may have the format `xxx.visualstudio.com`. Check the url on the browser. For Azure DevOps Server, this may be the unexposed one e.g. `localhost:8080` or one that you have exposed publicly via DNS.| +|AZURE_PROTOCOL|**_Optional_**. The transport protocol (`http` or `https`) used by your Azure DevOps installation. Defaults to `https`.| +|AZURE_HOSTNAME|**_Optional_**. The hostname of the where the organization is hosted. Defaults to `dev.azure.com` but for older organizations this may have the format `xxx.visualstudio.com`. Check the url on the browser. For Azure DevOps Server, this may be the unexposed one e.g. `localhost` or one that you have exposed publicly via DNS.| +|AZURE_PORT|**_Optional_**. The TCP port used by your Azure DevOps installation. Defaults to `80` or `443`, depending on the indicated protocol.| +|AZURE_VIRTUAL_DIRECTORY|**_Optional_**. Some Azure DevOps Server installations are hosted in an IIS virtual directory, traditionally named tfs. This variable can be used to define the name of that virtual directory. By default, this is not set.| |AZURE_ACCESS_TOKEN|**_Required_**. The Personal Access in Azure DevOps for accessing the repository and creating pull requests. The required permissions are:
- Code (Full)
- Pull Requests Threads (Read & Write).
See the [documentation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=preview-page#create-a-pat) to know more about creating a Personal Access Token| |AZURE_ORGANIZATION|**_Required_**. The name of the Azure DevOps Organization. This is can be extracted from the URL of the home page. https://dev.azure.com/{organization}/| |AZURE_PROJECT|**_Required_**. The name of the Azure DevOps Project within the above organization. This can be extracted them the URL too. https://dev.azure.com/{organization}/{project}/| diff --git a/src/script/update-script.rb b/src/script/update-script.rb index ef6eeb84..fecc6ac5 100644 --- a/src/script/update-script.rb +++ b/src/script/update-script.rb @@ -89,12 +89,34 @@ # https://github.com/wemake-services/kira-dependencies/pull/210 excluded_requirements = ENV['DEPENDABOT_EXCLUDE_REQUIREMENTS_TO_UNLOCK']&.split(" ")&.map(&:to_sym) || [] +################################# +# Setup the protocol to be used # +################################# +protocol = ENV["AZURE_PROTOCOL"] +protocol = "https" if protocol.nil? || protocol.empty? +puts "Using '#{protocol}' as protocol" + ################################# # Setup the hostname to be used # ################################# -azure_hostname = ENV["AZURE_HOSTNAME"] || "dev.azure.com" +azure_hostname = ENV["AZURE_HOSTNAME"] +azure_hostname = "dev.azure.com" if azure_hostname.nil? || azure_hostname.empty? puts "Using '#{azure_hostname}' as hostname" +################################# +# Setup the port to be used # +################################# +port = ENV["AZURE_PORT"] +port = (protocol == "http" ? "80" : "443") if port.nil? || port.empty? +puts "Using '#{port}' as port" + +################################# +# Setup the port to be used # +################################# +virtual_directory = ENV["AZURE_VIRTUAL_DIRECTORY"] +virtual_directory = "" if virtual_directory.nil? +puts "Using '#{virtual_directory}' as virtual directory" + ##################################### # Setup credentials for source code # ##################################### @@ -154,10 +176,13 @@ ignore_options = JSON.parse(ignore_options_json) end +api_endpoint = "#{protocol}://#{azure_hostname}:#{port}/" +api_endpoint = api_endpoint + "#{virtual_directory}/" if !virtual_directory.empty? + source = Dependabot::Source.new( provider: "azure", hostname: azure_hostname, - api_endpoint: "https://#{azure_hostname}/", + api_endpoint: api_endpoint, repo: repo_name, directory: directory, branch: branch,