diff --git a/src/ci_providers/index.js b/src/ci_providers/index.js index 6287aa7e1..fa1e656d7 100644 --- a/src/ci_providers/index.js +++ b/src/ci_providers/index.js @@ -1,4 +1,5 @@ const providerAppveyorci = require('./provider_appveyorci') +const providerAzurepipelines = require('./provider_azurepipelines') const providerCircleci = require('./provider_circleci') const providerGitHubactions = require('./provider_githubactions') const providerGitLabci = require('./provider_gitlabci') @@ -9,6 +10,7 @@ const providerTravisci = require('./provider_travisci') // Please make sure provider_local is last const providers = [ providerAppveyorci, + providerAzurepipelines, providerCircleci, providerGitHubactions, providerGitLabci, diff --git a/src/ci_providers/provider_azurepipelines.js b/src/ci_providers/provider_azurepipelines.js new file mode 100644 index 000000000..6f152e6d5 --- /dev/null +++ b/src/ci_providers/provider_azurepipelines.js @@ -0,0 +1,105 @@ +var childProcess = require('child_process') +var { log } = require('../helpers/logger') + +function detect (envs) { + return !!envs.SYSTEM_TEAMFOUNDATIONSERVERURI +} + +function _getBuild (inputs) { + const { args, envs } = inputs + return args.build || envs.BUILD_BUILDNUMBER || '' +} + +function _getBuildURL (inputs) { + const { args, envs } = inputs + if (envs.SYSTEM_TEAMPROJECT && envs.BUILD_BUILDID) { + return encodeURIComponent(`${envs.SYSTEM_TEAMFOUNDATIONSERVERURI}${envs.SYSTEM_TEAMPROJECT}/_build/results?buildId=${envs.BUILD_BUILDID}`) + } + return '' +} + +function _getBranch (inputs) { + const { args, envs } = inputs + let branch = '' + if (envs.BUILD_SOURCEBRANCH) { + branch = envs.BUILD_SOURCEBRANCH.replace('refs/heads/', '') + } + return args.branch || branch +} + +function _getJob (envs) { + return envs.BUILD_BUILDID || '' +} + +function _getPR (inputs) { + const { args, envs } = inputs + return args.pr || envs.SYSTEM_PULLREQUEST_PULLREQUESTNUMBER || envs.SYSTEM_PULLREQUEST_PULLREQUESTID || '' +} + +function _getService () { + return 'azure_pipelines' +} + +function getServiceName () { + return 'Azure Pipelines' +} + +function _getSHA (inputs) { + const { args, envs } = inputs + let commit = envs.BUILD_SOURCEVERSION + + if (_getPR(inputs)) { + const mergeCommitRegex = /^[a-z0-9]{40} [a-z0-9]{40}$/ + const mergeCommitMessage = childProcess.execSync( + `git show --no-patch --format="%P"` + ) + if (mergeCommitRegex.exec(mergeCommitMessage)) { + const mergeCommit = mergeCommitMessage.split(" ")[1] + log(` Fixing merge commit SHA ${commit} -> ${mergeCommit}`) + commit = mergeCommit + } + } + + return args.sha || commit || '' +} + +function _getProject (inputs) { + const { envs } = inputs + return envs.SYSTEM_TEAMPROJECT || '' +} + +function _getServerURI (inputs) { + const { envs } = inputs + return envs.SYSTEM_TEAMFOUNDATIONSERVERURI +} + +function _getSlug (inputs) { + const { args } = inputs + return args.slug || '' +} +/** + * Generates and return the serviceParams object + * + * @param {args: {}, envs: {}} inputs an object of arguments and enviromental variable key/value pairs + * @returns { branch: String, build: String, buildURL: String, commit: String, job: String, pr: String, service: String, slug: String} + */ +function getServiceParams (inputs) { + return { + branch: _getBranch(inputs), + build: _getBuild(inputs), + buildURL: _getBuildURL(inputs), + commit: _getSHA(inputs), + job: _getJob(inputs.envs), + pr: _getPR(inputs), + project: _getProject(inputs), + server_uri: _getServerURI(inputs), + service: _getService(), + slug: _getSlug(inputs) + } +} + +module.exports = { + detect, + getServiceName, + getServiceParams +} diff --git a/test/helpers/validate.test.js b/test/helpers/validate.test.js index 08b1190f6..88f0dad75 100644 --- a/test/helpers/validate.test.js +++ b/test/helpers/validate.test.js @@ -10,6 +10,18 @@ describe('Input Validators', function () { }) }) + describe('URLs', function () { + it('Returns true with a valid URL', function () { + expect(validate.validateURL('https://codecov.io')).toBe(true) + }) + it('Returns false with an invalid URL', function () { + expect(validate.validateURL('not.a.URL.com')).toBe(false) + }) + it('Returns false with an empty URL', function () { + expect(validate.validateURL('')).toBe(false) + }) + }) + describe('Flags', function () { it('Should pass without a dash', function () { expect(validate.validateFlags('moo')).toBe(true) @@ -23,15 +35,19 @@ describe('Input Validators', function () { }) }) - describe('URLs', function () { - it('Returns true with a valid URL', function () { - expect(validate.validateURL('https://codecov.io')).toBe(true) + describe('FileNamePath', function () { + it('Should pass with an absolute path', function () { + expect(validate.validateFileNamePath('/path/to/file/1.txt')).toBe(true) }) - it('Returns false with an invalid URL', function () { - expect(validate.validateURL('not.a.URL.com')).toBe(false) + it('Should pass with a relative path', function () { + expect(validate.validateFileNamePath('./path/to/file/1.txt')).toBe(true) }) - it('Returns false with an empty URL', function () { - expect(validate.validateURL('')).toBe(false) + + it('Should fail with spaces', function () { + expect(validate.validateFileNamePath('/path to/file')).toBe(false) + }) + it('Should fail with other characters', function () { + expect(validate.validateFileNamePath('/path{}to/file')).toBe(false) }) }) }) diff --git a/test/providers/index.test.js b/test/providers/index.test.js index 612aac846..39d090107 100644 --- a/test/providers/index.test.js +++ b/test/providers/index.test.js @@ -24,6 +24,7 @@ describe('CI Providers', () => { GITLAB_CI: true, JENKINS_URL: 'https://example.com', SHIPPABLE: true, + SYSTEM_TEAMFOUNDATIONSERVERURI: 'https://example.azure.com', TRAVIS: true, TRAVIS_REPO_SLUG: 'testOrg/testRepo', } diff --git a/test/providers/provider_azurepipelines.test.js b/test/providers/provider_azurepipelines.test.js new file mode 100644 index 000000000..9385a50e3 --- /dev/null +++ b/test/providers/provider_azurepipelines.test.js @@ -0,0 +1,143 @@ +const td = require('testdouble') +const childProcess = require('child_process') + +const providerAzurepipelines = require('../../src/ci_providers//provider_azurepipelines') + +describe('Jenkins CI Params', () => { + afterEach(function () { + td.reset() + }) + + it('does not run without AzurePipelines env variable', () => { + const inputs = { + args: {}, + envs: {} + } + detected = providerAzurepipelines.detect(inputs.envs) + expect(detected).toBeFalsy() + }) + + it('gets correct params on pr number', () => { + const inputs = { + args: {}, + envs: { + BUILD_BUILDNUMBER: 1, + BUILD_BUILDID: 2, + BUILD_SOURCEBRANCH: 'refs/heads/main', + BUILD_SOURCEVERSION: 'testingsha', + SYSTEM_BUILD_BUILDID: 1, + SYSTEM_PULLREQUEST_PULLREQUESTNUMBER: 3, + SYSTEM_TEAMFOUNDATIONSERVERURI: 'https://example.azure.com', + SYSTEM_TEAMPROJECT: 'testOrg', + } + } + const expected = { + branch: 'main', + build: 1, + buildURL: 'https%3A%2F%2Fexample.azure.comtestOrg%2F_build%2Fresults%3FbuildId%3D2', + commit: 'testingsha', + job: 2, + pr: 3, + project: 'testOrg', + server_uri: 'https://example.azure.com', + service: 'azure_pipelines', + slug: '' + } + const params = providerAzurepipelines.getServiceParams(inputs) + expect(params).toMatchObject(expected) + }) + + it('gets correct params on pr id', () => { + const inputs = { + args: {}, + envs: { + BUILD_BUILDNUMBER: 1, + BUILD_BUILDID: 2, + BUILD_SOURCEBRANCH: 'refs/heads/main', + BUILD_SOURCEVERSION: 'testingsha', + SYSTEM_BUILD_BUILDID: 1, + SYSTEM_PULLREQUEST_PULLREQUESTID: 3, + SYSTEM_TEAMFOUNDATIONSERVERURI: 'https://example.azure.com', + SYSTEM_TEAMPROJECT: 'testOrg', + } + } + const expected = { + branch: 'main', + build: 1, + buildURL: 'https%3A%2F%2Fexample.azure.comtestOrg%2F_build%2Fresults%3FbuildId%3D2', + commit: 'testingsha', + job: 2, + pr: 3, + project: 'testOrg', + server_uri: 'https://example.azure.com', + service: 'azure_pipelines', + slug: '' + } + const params = providerAzurepipelines.getServiceParams(inputs) + expect(params).toMatchObject(expected) + }) + + it('gets correct params on merge', () => { + const inputs = { + args: {}, + envs: { + BUILD_BUILDNUMBER: 1, + BUILD_BUILDID: 2, + BUILD_SOURCEBRANCH: 'refs/heads/main', + BUILD_SOURCEVERSION: 'testingsha', + SYSTEM_BUILD_BUILDID: 1, + SYSTEM_PULLREQUEST_PULLREQUESTID: 3, + SYSTEM_TEAMFOUNDATIONSERVERURI: 'https://example.azure.com', + SYSTEM_TEAMPROJECT: 'testOrg', + } + } + const expected = { + branch: 'main', + build: 1, + buildURL: 'https%3A%2F%2Fexample.azure.comtestOrg%2F_build%2Fresults%3FbuildId%3D2', + commit: 'testingmergecommitsha2345678901234567890', + job: 2, + pr: 3, + project: 'testOrg', + server_uri: 'https://example.azure.com', + service: 'azure_pipelines', + slug: '' + } + const execSync = td.replace(childProcess, 'execSync') + td.when(execSync( + `git show --no-patch --format="%P"` + )).thenReturn("testingsha123456789012345678901234567890 testingmergecommitsha2345678901234567890") + const params = providerAzurepipelines.getServiceParams(inputs) + expect(params).toMatchObject(expected) + }) + + it('gets correct params for overrides', () => { + const inputs = { + args: { + branch: 'branch', + build: 3, + pr: '2', + sha: 'testsha', + slug: 'testOrg/testRepo' + }, + envs: { + SYSTEM_TEAMFOUNDATIONSERVERURI: 'https://example.azure.com', + } + } + const expected = { + branch: 'branch', + build: 3, + buildURL: '', + commit: 'testsha', + job: '', + pr: '2', + project: '', + server_uri: 'https://example.azure.com', + service: 'azure_pipelines', + slug: 'testOrg/testRepo' + } + + const params = providerAzurepipelines.getServiceParams(inputs) + expect(params).toMatchObject(expected) + }) +}) diff --git a/test/providers/provider_gitlabci.test.js b/test/providers/provider_gitlabci.test.js index 7a8162ef0..5d716a4db 100644 --- a/test/providers/provider_gitlabci.test.js +++ b/test/providers/provider_gitlabci.test.js @@ -131,6 +131,17 @@ describe('GitLabCI Params', () => { const params = providerGitLabci.getServiceParams(inputs) expect(params.slug).toBe('') }) + + it('can handle no remote origin url', () => { + inputs.envs['CI_BUILD_REPO'] = '' + const execSync = td.replace(childProcess, 'execSync') + td.when(execSync( + `git config --get remote.origin.url || hg paths default || echo ''` + )).thenReturn("") + + const params = providerGitLabci.getServiceParams(inputs) + expect(params.slug).toBe('') + }) }) it('gets correct params for overrides', () => {