From 765c515ff31dac8c6c6eebcb5da2f9b55820f12a Mon Sep 17 00:00:00 2001 From: ghe Date: Fri, 16 Dec 2022 18:33:48 +0000 Subject: [PATCH] feat: function to import single target for sync --- src/scripts/sync/import-target.ts | 39 ++++++++++++ test/scripts/sync/import-target.spec.ts | 83 +++++++++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 src/scripts/sync/import-target.ts create mode 100644 test/scripts/sync/import-target.spec.ts diff --git a/src/scripts/sync/import-target.ts b/src/scripts/sync/import-target.ts new file mode 100644 index 00000000..b658105f --- /dev/null +++ b/src/scripts/sync/import-target.ts @@ -0,0 +1,39 @@ +import type { requestsManager } from 'snyk-request-manager'; +import * as debugLib from 'debug'; +import { defaultExclusionGlobs } from '../../common'; +import { importTarget, listIntegrations, pollImportUrls } from '../../lib'; +import type { + Project, + SupportedIntegrationTypesUpdateProject, + Target, +} from '../../lib/types'; + +const debug = debugLib('snyk:import-single-target'); + +export async function importSingleTarget( + requestManager: requestsManager, + orgId: string, + integrationType: SupportedIntegrationTypesUpdateProject, + target: Target, + filesToImport: string[] = [], + excludeFolders?: string, + loggingPath?: string, +): Promise<{ projects: Project[] }> { + const integrationsData = await listIntegrations(requestManager, orgId); + const integrationId = integrationsData[integrationType]; + const files = filesToImport.map((f) => ({ path: f })); + const { pollingUrl } = await importTarget( + requestManager, + orgId, + integrationId, + target, + files, + `${excludeFolders}, ${defaultExclusionGlobs.join(',')}`, + loggingPath, + ); + + debug(`Polling for updates`); + const res = await pollImportUrls(requestManager, [pollingUrl]); + debug(`Finished polling, discovered ${res.projects?.length} projects`); + return res; +} diff --git a/test/scripts/sync/import-target.spec.ts b/test/scripts/sync/import-target.spec.ts new file mode 100644 index 00000000..3d8127a9 --- /dev/null +++ b/test/scripts/sync/import-target.spec.ts @@ -0,0 +1,83 @@ +import * as fs from 'fs'; +import { requestsManager } from 'snyk-request-manager'; +import { importSingleTarget } from '../../../src/scripts/sync/import-target'; +import { SupportedIntegrationTypesUpdateProject } from '../../../src/lib/types'; +import type { Project } from '../../../src/lib/types'; +import { deleteFiles } from '../../delete-files'; +import { deleteTestProjects } from '../../delete-test-projects'; +import { generateLogsPaths } from '../../generate-log-file-names'; + +const ORG_ID = process.env.TEST_ORG_ID as string; +const SNYK_API_TEST = process.env.SNYK_API_TEST as string; + +jest.unmock('snyk-request-manager'); +jest.requireActual('snyk-request-manager'); + +describe('Import projects script', () => { + const discoveredProjects: Project[] = []; + let logs: string[]; + const OLD_ENV = process.env; + process.env.SNYK_API = SNYK_API_TEST; + process.env.SNYK_TOKEN = process.env.SNYK_TOKEN_TEST; + + afterAll(async () => { + await deleteTestProjects(ORG_ID, discoveredProjects); + await deleteFiles(logs); + process.env = { ...OLD_ENV }; + }, 10000); + + const requestManager = new requestsManager({ + userAgentPrefix: 'snyk-api-import:tests', + }); + + it('succeeds to import a single target', async () => { + const logFiles = generateLogsPaths(__dirname, ORG_ID); + logs = Object.values(logFiles); + + const target = { + name: 'ruby-with-versions', + owner: 'api-import-circle-test', + branch: 'master', + }; + + const { projects } = await importSingleTarget( + requestManager, + ORG_ID, + SupportedIntegrationTypesUpdateProject.GHE, + target, + ); + expect(projects).not.toBe([]); + expect(projects.length).toEqual(1); + expect(projects[0]).toMatchObject({ + projectUrl: expect.any(String), + success: true, + targetFile: expect.any(String), + }); + const logFile = fs.readFileSync(logFiles.importLogPath, 'utf8'); + expect(logFile).toMatch( + `"target":{"name":"ruby-with-versions","owner":"api-import-circle-test","branch":"master"}`, + ); + discoveredProjects.push(...projects); + }, 2400000); + it('exclusions propagate to API and apply as expected', async () => { + const logFiles = generateLogsPaths(__dirname, ORG_ID); + logs = Object.values(logFiles); + + const target = { + name: 'ruby-with-versions', + owner: 'api-import-circle-test', + branch: 'master', + }; + + const { projects } = await importSingleTarget( + requestManager, + ORG_ID, + SupportedIntegrationTypesUpdateProject.GHE, + target, + undefined, + 'ruby-2.5.3-exactly', + ); + expect(projects).toHaveLength(0); + }, 2400000); + it.todo('imports an individual file only if asked'); +});