Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added formatted proxy URL #834

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions node/docs/proxy.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface ProxyConfiguration {
proxyUsername?: string;
proxyPassword?: string;
proxyBypassHosts?: string[];
proxyFormattedUrl: string;
}
```

Expand Down Expand Up @@ -61,6 +62,24 @@ async function run() {
run();
```

For some external applications executed from the shell, you might need to set an environment variable that contains a formatted URL
in the following format: protocol://user:password@hostname:port
You can retrieve such configuration directly from task-lib:
```typescript
import tl = require('azure-pipelines-task-lib/task');

async function run() {
let proxy = tl.getProxyConfiguration()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: const


process.env['http_proxy'] = proxy.proxyFormattedUrl;
process.env['https_proxy'] = proxy.proxyFormattedUrl;
const gitPath: string = tl.which('git');
const gitPull = tl.tool(gitPath);
await gitPull.exec()
}

run();
```
#### PowerShell Lib

Method for retrieve proxy settings in PowerShell lib
Expand Down
2 changes: 1 addition & 1 deletion node/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion node/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "azure-pipelines-task-lib",
"version": "3.2.1",
"version": "3.3.0",
"description": "Azure Pipelines Task SDK",
"main": "./task.js",
"typings": "./task.d.ts",
Expand Down
26 changes: 25 additions & 1 deletion node/task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1839,11 +1839,33 @@ export function findMatch(defaultRoot: string, patterns: string[] | string, find

export interface ProxyConfiguration {
proxyUrl: string;
/**
* Proxy URI formated as: protocol://username:password@hostname:port
*
* For tools that require setting proxy configuration in the single environment variable
*/
proxyFormattedUrl: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does proxyFormattedUrl mean - what is the format/purpose/how to use it? Could it make sense to add JSDoc comments here?
Please update docs as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JSDoc added
Docs updated

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This field is not orthogonal to the other fields, so it could be error-prone in future (it depends on values of the fields like proxyUrl/proxyUsername, so if they will be changed - we would need to change it as well).
Could it make sense to just add some function which return formatted url - instead of adding new field to avoid such issue?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved per offline discussion - since we considering that this is intended to be read-only object (containing current proxy settings) - it should be good to keep in a separate field

proxyUsername?: string;
proxyPassword?: string;
proxyBypassHosts?: string[];
}

/**
* Build Proxy URL in the following format: protocol://username:password@hostname:port
* @param proxyUrl Url address of the proxy server (eg: http://example.com)
* @param proxyUsername Proxy username (optional)
* @param proxyPassword Proxy password (optional)
* @returns string
*/
function getProxyFormattedUrl(proxyUrl: string, proxyUsername: string | undefined, proxyPassword: string | undefined): string {
kirill-ivlev marked this conversation as resolved.
Show resolved Hide resolved
const parsedUrl: URL = new URL(proxyUrl);
let proxyAddress: string = `${parsedUrl.protocol}//${parsedUrl.host}`;
if (proxyUsername) {
proxyAddress = `${parsedUrl.protocol}//${proxyUsername}:${proxyPassword}@${parsedUrl.host}`;
}
return proxyAddress;
}

/**
* Gets http proxy configuration used by Build/Release agent
*
Expand All @@ -1869,11 +1891,13 @@ export function getHttpProxyConfiguration(requestUrl?: string): ProxyConfigurati
return null;
}
else {
const proxyAddress = getProxyFormattedUrl(proxyUrl, proxyUsername, proxyPassword)
return {
proxyUrl: proxyUrl,
proxyUsername: proxyUsername,
proxyPassword: proxyPassword,
proxyBypassHosts: proxyBypassHosts
proxyBypassHosts: proxyBypassHosts,
proxyFormattedUrl: proxyAddress
};
}
}
Expand Down
56 changes: 56 additions & 0 deletions node/test/gethttpproxytests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import * as assert from 'assert';
import * as tl from '../_build/task';

enum ProxyEnvironmentEnum {
proxyUrl = 'AGENT_PROXYURL',
proxyUsername = 'AGENT_PROXYUSERNAME',
proxyPassword = 'AGENT_PROXYPASSWORD',
proxyBypass = 'AGENT_PROXYBYPASSLIST'
}

describe('GetHttpProxyConfiguration Tests', () => {
const proxyHost: string = 'proxy.example.com';
const proxyPort: number = 8888;
const proxyUrl: string = `http://${proxyHost}:${proxyPort}`;
const proxyUsername: string = 'proxyUser';
const proxyPassword: string = 'proxyPassword';
const proxyByPass: string[] = ['http://bypass.example.com'];
const formatedUrlWithoutCrednetials = proxyUrl;
const fortmatedUrlWithCredentials = `http://${proxyUsername}:${proxyPassword}@${proxyHost}:${proxyPort}`;

it('returns a valid proxy configuration if no credentials set', () => {
process.env[ProxyEnvironmentEnum.proxyUrl] = proxyUrl;
process.env[ProxyEnvironmentEnum.proxyBypass] = JSON.stringify(proxyByPass);
const expected: tl.ProxyConfiguration = {
proxyUrl: proxyUrl,
proxyBypassHosts: proxyByPass,
proxyUsername: undefined,
proxyPassword: undefined,
proxyFormattedUrl: formatedUrlWithoutCrednetials
}
const result = tl.getHttpProxyConfiguration();
assert.deepStrictEqual(result, expected, 'it should have valid configuration');
});

it('returns valid proxy configuration if credentials set', () => {
process.env[ProxyEnvironmentEnum.proxyUrl] = proxyUrl;
process.env[ProxyEnvironmentEnum.proxyUsername] = proxyUsername;
process.env[ProxyEnvironmentEnum.proxyPassword] = proxyPassword;
process.env[ProxyEnvironmentEnum.proxyBypass] = JSON.stringify(proxyByPass);
const expected: tl.ProxyConfiguration = {
proxyUrl: proxyUrl,
proxyBypassHosts: proxyByPass,
proxyFormattedUrl: fortmatedUrlWithCredentials,
proxyPassword: proxyPassword,
proxyUsername: proxyUsername
}
const result = tl.getHttpProxyConfiguration();
assert.deepStrictEqual(result, expected, 'it should have credentials in formatted url');
});

it('returns null if host should be bypassed', () => {
process.env[ProxyEnvironmentEnum.proxyUrl] = proxyUrl;
const result = tl.getHttpProxyConfiguration(proxyByPass[0]);
assert.strictEqual(result, null, 'result should be null');
});
})
3 changes: 2 additions & 1 deletion node/test/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"findmatchtests.ts",
"mocktests.ts",
"retrytests.ts",
"isuncpathtests.ts"
"isuncpathtests.ts",
"gethttpproxytests.ts"
]
}