@form8ion/codecov 7.5.0 → 7.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/lib/index.js +6 -5
  2. package/lib/index.js.map +1 -1
  3. package/package.json +4 -4
  4. package/src/badge/index.js +1 -0
  5. package/src/badge/repository-details-fetcher.js +10 -0
  6. package/src/badge/repository-details-fetcher.test.js +33 -0
  7. package/src/badge/scaffolder.js +21 -0
  8. package/src/badge/scaffolder.test.js +53 -0
  9. package/src/config/index.js +1 -0
  10. package/src/config/scaffolder.js +10 -0
  11. package/src/config/scaffolder.test.js +23 -0
  12. package/src/index.js +4 -0
  13. package/src/lifter.js +15 -0
  14. package/src/lifter.test.js +33 -0
  15. package/src/predicates.js +3 -0
  16. package/src/predicates.test.js +31 -0
  17. package/src/remover.js +9 -0
  18. package/src/remover.test.js +27 -0
  19. package/src/reporter/ci-providers/github-workflows/action/constants.js +1 -0
  20. package/src/reporter/ci-providers/github-workflows/action/index.js +4 -0
  21. package/src/reporter/ci-providers/github-workflows/action/lifter.js +12 -0
  22. package/src/reporter/ci-providers/github-workflows/action/lifter.test.js +21 -0
  23. package/src/reporter/ci-providers/github-workflows/action/remover.js +6 -0
  24. package/src/reporter/ci-providers/github-workflows/action/remover.test.js +22 -0
  25. package/src/reporter/ci-providers/github-workflows/action/scaffolder.js +14 -0
  26. package/src/reporter/ci-providers/github-workflows/action/scaffolder.test.js +19 -0
  27. package/src/reporter/ci-providers/github-workflows/action/tester.js +9 -0
  28. package/src/reporter/ci-providers/github-workflows/action/tester.test.js +23 -0
  29. package/src/reporter/ci-providers/github-workflows/index.js +3 -0
  30. package/src/reporter/ci-providers/github-workflows/lifter.js +25 -0
  31. package/src/reporter/ci-providers/github-workflows/lifter.test.js +47 -0
  32. package/src/reporter/ci-providers/github-workflows/predicate.js +5 -0
  33. package/src/reporter/ci-providers/github-workflows/predicate.test.js +20 -0
  34. package/src/reporter/ci-providers/github-workflows/remover.js +9 -0
  35. package/src/reporter/ci-providers/github-workflows/remover.test.js +30 -0
  36. package/src/reporter/ci-providers/github-workflows/steps/index.js +2 -0
  37. package/src/reporter/ci-providers/github-workflows/steps/lifter.js +16 -0
  38. package/src/reporter/ci-providers/github-workflows/steps/lifter.test.js +48 -0
  39. package/src/reporter/ci-providers/github-workflows/steps/tester.js +5 -0
  40. package/src/reporter/ci-providers/github-workflows/steps/tester.test.js +25 -0
  41. package/src/reporter/ci-providers/index.js +1 -0
  42. package/src/reporter/index.js +1 -0
  43. package/src/reporter/lifter.js +38 -0
  44. package/src/reporter/lifter.test.js +70 -0
  45. package/src/scaffolder.js +7 -0
  46. package/src/scaffolder.test.js +18 -0
  47. package/src/tester.js +5 -0
  48. package/src/tester.test.js +25 -0
package/lib/index.js CHANGED
@@ -56,10 +56,6 @@ async function scaffold({vcs, apiAccessToken}) {
56
56
 
57
57
  const ACTION_NAME = 'codecov/codecov-action';
58
58
 
59
- function removeCodecovActionFrom(jobs) {
60
- return removeActionFromJobs(jobs, ACTION_NAME);
61
- }
62
-
63
59
  function scaffoldAction() {
64
60
  return {
65
61
  name: 'Upload unit test coverage to Codecov',
@@ -94,6 +90,10 @@ function liftAction(action) {
94
90
  };
95
91
  }
96
92
 
93
+ function removeCodecovActionFrom(jobs) {
94
+ return removeActionFromJobs(jobs, ACTION_NAME);
95
+ }
96
+
97
97
  function codecovActionExistsInSteps(steps) {
98
98
  return !!steps.find(step => stepIsCodecovAction(step));
99
99
  }
@@ -181,7 +181,8 @@ async function liftReporter({projectRoot, packageManager}) {
181
181
  async function lift({projectRoot, packageManager, vcs}) {
182
182
  const [reportingResults, badgeResults] = await Promise.all([
183
183
  liftReporter({projectRoot, packageManager}),
184
- scaffold({vcs})
184
+ scaffold({vcs}),
185
+ scaffoldConfig({projectRoot})
185
186
  ]);
186
187
 
187
188
  return deepmerge.all([reportingResults, badgeResults]);
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/config/scaffolder.js","../src/scaffolder.js","../src/tester.js","../src/badge/repository-details-fetcher.js","../src/badge/scaffolder.js","../src/reporter/ci-providers/github-workflows/codecov-action.js","../src/reporter/ci-providers/github-workflows/action/scaffolder.js","../src/reporter/ci-providers/github-workflows/action/tester.js","../src/reporter/ci-providers/github-workflows/action/lifter.js","../src/reporter/ci-providers/github-workflows/steps/tester.js","../src/reporter/ci-providers/github-workflows/steps/lifter.js","../src/reporter/ci-providers/github-workflows/lifter.js","../src/reporter/ci-providers/github-workflows/remover.js","../src/reporter/ci-providers/github-workflows/predicate.js","../src/reporter/lifter.js","../src/lifter.js","../src/remover.js"],"sourcesContent":["import {fileTypes, writeConfigFile} from '@form8ion/core';\n\nexport default async function scaffoldConfig({projectRoot}) {\n await writeConfigFile({\n format: fileTypes.YAML,\n path: projectRoot,\n name: '.codecov',\n config: {comment: {layout: 'reach,diff,flags,tree'}}\n });\n}\n","import {scaffold as scaffoldConfig} from './config/index.js';\n\nexport async function scaffold({projectRoot}) {\n await scaffoldConfig({projectRoot});\n\n return {};\n}\n","import {fileExists} from '@form8ion/core';\n\nexport default async function codecovInUse({projectRoot}) {\n return fileExists(`${projectRoot}/.codecov.yml`);\n}\n","import got from 'got';\n\nexport default async function fetchRepositoryDetails({vcs, apiAccessToken}) {\n const {body: {repo}} = await got(\n `https://codecov.io/api/gh/${vcs.owner}/${vcs.name}`,\n {headers: {Authorization: apiAccessToken}, responseType: 'json'}\n );\n\n return repo;\n}\n","import fetchRepositoryDetails from './repository-details-fetcher.js';\n\nexport async function scaffold({vcs, apiAccessToken}) {\n return {\n ...['github', 'gitlab', 'bitbucket'].includes(vcs?.host) && {\n badges: {\n status: {\n coverage: {\n img: `https://img.shields.io/codecov/c/${vcs.host}/${vcs.owner}/${vcs.name}?logo=codecov${\n apiAccessToken\n ? `&token=${(await fetchRepositoryDetails({vcs, apiAccessToken})).image_token}`\n : ''\n }`,\n link: `https://codecov.io/${vcs.host}/${vcs.owner}/${vcs.name}`,\n text: 'Codecov'\n }\n }\n }\n }\n };\n}\n","import {removeActionFromJobs} from '@form8ion/github-workflows-core';\n\nexport const ACTION_NAME = 'codecov/codecov-action';\n\nexport function removeCodecovActionFrom(jobs) {\n return removeActionFromJobs(jobs, ACTION_NAME);\n}\n","import {ACTION_NAME} from '../codecov-action.js';\n\nexport default function scaffoldAction() {\n return {\n name: 'Upload unit test coverage to Codecov',\n uses: `${ACTION_NAME}@v5.5.2`,\n with: {\n // eslint-disable-next-line no-template-curly-in-string\n token: '${{ secrets.CODECOV_TOKEN }}',\n flags: 'unit',\n report_type: 'coverage'\n }\n };\n}\n","import {ACTION_NAME} from '../codecov-action.js';\n\nexport default function stepIsCodecovAction(step) {\n if (!step.uses) return false;\n\n const [actionName] = step.uses.split('@');\n\n return ACTION_NAME === actionName;\n}\n","export default function liftAction(action) {\n return {\n name: 'Upload unit test coverage to Codecov',\n ...action,\n with: {\n // eslint-disable-next-line no-template-curly-in-string\n token: '${{ secrets.CODECOV_TOKEN }}',\n flags: 'unit',\n report_type: 'coverage'\n }\n };\n}\n","import {test as stepIsCodecovAction} from '../action/index.js';\n\nexport default function codecovActionExistsInSteps(steps) {\n return !!steps.find(step => stepIsCodecovAction(step));\n}\n","import {scaffold as scaffoldAction, lift as liftAction, test as stepIsCodecovAction} from '../action/index.js';\nimport codecovActionExistsInSteps from './tester.js';\n\nexport default function liftSteps(steps) {\n if (!codecovActionExistsInSteps(steps)) {\n const stepsWithLegacyReportingRemoved = steps.filter(({run}) => 'npm run coverage:report' !== run);\n\n return [...stepsWithLegacyReportingRemoved, scaffoldAction()];\n }\n\n return steps.map(step => {\n if (stepIsCodecovAction(step)) return liftAction(step);\n\n return step;\n });\n}\n","import {loadWorkflowFile, writeWorkflowFile} from '@form8ion/github-workflows-core';\n\nimport {lift as liftSteps} from './steps/index.js';\n\nexport async function lift({projectRoot}) {\n const ciWorkflowName = 'node-ci';\n\n const workflowDetails = await loadWorkflowFile({projectRoot, name: ciWorkflowName});\n const {jobs: {verify: {steps}}} = workflowDetails;\n\n await writeWorkflowFile({\n projectRoot,\n name: ciWorkflowName,\n config: {\n ...workflowDetails,\n jobs: {\n ...workflowDetails.jobs,\n verify: {\n ...workflowDetails.jobs.verify,\n steps: liftSteps(steps)\n }\n }\n }\n });\n}\n","import {loadWorkflowFile, writeWorkflowFile} from '@form8ion/github-workflows-core';\nimport {removeCodecovActionFrom} from './codecov-action.js';\n\nexport default async function removeCodecovAction({projectRoot}) {\n const existingConfig = await loadWorkflowFile({projectRoot, name: 'node-ci'});\n existingConfig.jobs = removeCodecovActionFrom(existingConfig.jobs);\n\n await writeWorkflowFile({projectRoot, name: 'node-ci', config: existingConfig});\n}\n","import {workflowFileExists} from '@form8ion/github-workflows-core';\n\nexport default function ciWorkflowExists({projectRoot}) {\n return workflowFileExists({projectRoot, name: 'node-ci'});\n}\n","import {promises as fs} from 'node:fs';\nimport {writePackageJson} from '@form8ion/javascript-core';\n\nimport {execa} from 'execa';\nimport {lift as liftCiProvider, test as ciProviderIsLiftable} from './ci-providers/index.js';\n\nexport default async function liftReporter({projectRoot, packageManager}) {\n const pathToPackageJson = `${projectRoot}/package.json`;\n\n const [ciProviderCanBeLifted, existingPackageContents] = await Promise.all([\n ciProviderIsLiftable({projectRoot}),\n fs.readFile(pathToPackageJson, 'utf-8')\n ]);\n const parsedPackageContents = JSON.parse(existingPackageContents);\n const {scripts} = parsedPackageContents;\n const {'coverage:report': reportCoverageScript, ...otherScripts} = scripts;\n\n if (ciProviderCanBeLifted) await liftCiProvider({projectRoot});\n\n if (scripts['coverage:report']) {\n parsedPackageContents.scripts = otherScripts;\n await writePackageJson({projectRoot, config: parsedPackageContents});\n\n await execa(packageManager, ['remove', 'codecov']);\n\n return {\n ...!ciProviderCanBeLifted && {\n nextSteps: [{\n summary: 'Configure modern reporting to Codecov on your CI service',\n description: 'Configure the [Codecov Uploader](https://docs.codecov.com/docs/codecov-uploader) appropriately'\n + ' for your CI Provider. If available for your provider, prefer one of the dedicated wrappers.'\n }]\n }\n };\n }\n\n return {};\n}\n","import deepmerge from 'deepmerge';\n\nimport {scaffold as scaffoldBadge} from './badge/index.js';\nimport {lift as liftReporting} from './reporter/index.js';\n\nexport async function lift({projectRoot, packageManager, vcs}) {\n const [reportingResults, badgeResults] = await Promise.all([\n liftReporting({projectRoot, packageManager}),\n scaffoldBadge({vcs})\n ]);\n\n return deepmerge.all([reportingResults, badgeResults]);\n}\n","import {remove as removeAction, test as githubWorkflowExists} from './reporter/ci-providers/github-workflows/index.js';\n\nexport default async function removeCodecov({projectRoot}) {\n if (await githubWorkflowExists({projectRoot})) {\n await removeAction({projectRoot});\n }\n\n return {};\n}\n"],"names":["scaffold","lift","ciProviderIsLiftable","fs","liftCiProvider","liftReporting","scaffoldBadge","githubWorkflowExists","removeAction"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/config/scaffolder.js","../src/scaffolder.js","../src/tester.js","../src/badge/repository-details-fetcher.js","../src/badge/scaffolder.js","../src/reporter/ci-providers/github-workflows/action/constants.js","../src/reporter/ci-providers/github-workflows/action/scaffolder.js","../src/reporter/ci-providers/github-workflows/action/tester.js","../src/reporter/ci-providers/github-workflows/action/lifter.js","../src/reporter/ci-providers/github-workflows/action/remover.js","../src/reporter/ci-providers/github-workflows/steps/tester.js","../src/reporter/ci-providers/github-workflows/steps/lifter.js","../src/reporter/ci-providers/github-workflows/lifter.js","../src/reporter/ci-providers/github-workflows/remover.js","../src/reporter/ci-providers/github-workflows/predicate.js","../src/reporter/lifter.js","../src/lifter.js","../src/remover.js"],"sourcesContent":["import {fileTypes, writeConfigFile} from '@form8ion/core';\n\nexport default async function scaffoldConfig({projectRoot}) {\n await writeConfigFile({\n format: fileTypes.YAML,\n path: projectRoot,\n name: '.codecov',\n config: {comment: {layout: 'reach,diff,flags,tree'}}\n });\n}\n","import {scaffold as scaffoldConfig} from './config/index.js';\n\nexport async function scaffold({projectRoot}) {\n await scaffoldConfig({projectRoot});\n\n return {};\n}\n","import {fileExists} from '@form8ion/core';\n\nexport default async function codecovInUse({projectRoot}) {\n return fileExists(`${projectRoot}/.codecov.yml`);\n}\n","import got from 'got';\n\nexport default async function fetchRepositoryDetails({vcs, apiAccessToken}) {\n const {body: {repo}} = await got(\n `https://codecov.io/api/gh/${vcs.owner}/${vcs.name}`,\n {headers: {Authorization: apiAccessToken}, responseType: 'json'}\n );\n\n return repo;\n}\n","import fetchRepositoryDetails from './repository-details-fetcher.js';\n\nexport async function scaffold({vcs, apiAccessToken}) {\n return {\n ...['github', 'gitlab', 'bitbucket'].includes(vcs?.host) && {\n badges: {\n status: {\n coverage: {\n img: `https://img.shields.io/codecov/c/${vcs.host}/${vcs.owner}/${vcs.name}?logo=codecov${\n apiAccessToken\n ? `&token=${(await fetchRepositoryDetails({vcs, apiAccessToken})).image_token}`\n : ''\n }`,\n link: `https://codecov.io/${vcs.host}/${vcs.owner}/${vcs.name}`,\n text: 'Codecov'\n }\n }\n }\n }\n };\n}\n","export const ACTION_NAME = 'codecov/codecov-action';\n","import {ACTION_NAME} from './constants.js';\n\nexport default function scaffoldAction() {\n return {\n name: 'Upload unit test coverage to Codecov',\n uses: `${ACTION_NAME}@v5.5.2`,\n with: {\n // eslint-disable-next-line no-template-curly-in-string\n token: '${{ secrets.CODECOV_TOKEN }}',\n flags: 'unit',\n report_type: 'coverage'\n }\n };\n}\n","import {ACTION_NAME} from './constants.js';\n\nexport default function stepIsCodecovAction(step) {\n if (!step.uses) return false;\n\n const [actionName] = step.uses.split('@');\n\n return ACTION_NAME === actionName;\n}\n","export default function liftAction(action) {\n return {\n name: 'Upload unit test coverage to Codecov',\n ...action,\n with: {\n // eslint-disable-next-line no-template-curly-in-string\n token: '${{ secrets.CODECOV_TOKEN }}',\n flags: 'unit',\n report_type: 'coverage'\n }\n };\n}\n","import {removeActionFromJobs} from '@form8ion/github-workflows-core';\nimport {ACTION_NAME} from './constants.js';\n\nexport default function removeCodecovActionFrom(jobs) {\n return removeActionFromJobs(jobs, ACTION_NAME);\n}\n","import {test as stepIsCodecovAction} from '../action/index.js';\n\nexport default function codecovActionExistsInSteps(steps) {\n return !!steps.find(step => stepIsCodecovAction(step));\n}\n","import {scaffold as scaffoldAction, lift as liftAction, test as stepIsCodecovAction} from '../action/index.js';\nimport codecovActionExistsInSteps from './tester.js';\n\nexport default function liftSteps(steps) {\n if (!codecovActionExistsInSteps(steps)) {\n const stepsWithLegacyReportingRemoved = steps.filter(({run}) => 'npm run coverage:report' !== run);\n\n return [...stepsWithLegacyReportingRemoved, scaffoldAction()];\n }\n\n return steps.map(step => {\n if (stepIsCodecovAction(step)) return liftAction(step);\n\n return step;\n });\n}\n","import {loadWorkflowFile, writeWorkflowFile} from '@form8ion/github-workflows-core';\n\nimport {lift as liftSteps} from './steps/index.js';\n\nexport async function lift({projectRoot}) {\n const ciWorkflowName = 'node-ci';\n\n const workflowDetails = await loadWorkflowFile({projectRoot, name: ciWorkflowName});\n const {jobs: {verify: {steps}}} = workflowDetails;\n\n await writeWorkflowFile({\n projectRoot,\n name: ciWorkflowName,\n config: {\n ...workflowDetails,\n jobs: {\n ...workflowDetails.jobs,\n verify: {\n ...workflowDetails.jobs.verify,\n steps: liftSteps(steps)\n }\n }\n }\n });\n}\n","import {loadWorkflowFile, writeWorkflowFile} from '@form8ion/github-workflows-core';\nimport {remove as removeCodecovActionFrom} from './action/index.js';\n\nexport default async function removeCodecovAction({projectRoot}) {\n const existingConfig = await loadWorkflowFile({projectRoot, name: 'node-ci'});\n existingConfig.jobs = removeCodecovActionFrom(existingConfig.jobs);\n\n await writeWorkflowFile({projectRoot, name: 'node-ci', config: existingConfig});\n}\n","import {workflowFileExists} from '@form8ion/github-workflows-core';\n\nexport default function ciWorkflowExists({projectRoot}) {\n return workflowFileExists({projectRoot, name: 'node-ci'});\n}\n","import {promises as fs} from 'node:fs';\nimport {writePackageJson} from '@form8ion/javascript-core';\n\nimport {execa} from 'execa';\nimport {lift as liftCiProvider, test as ciProviderIsLiftable} from './ci-providers/index.js';\n\nexport default async function liftReporter({projectRoot, packageManager}) {\n const pathToPackageJson = `${projectRoot}/package.json`;\n\n const [ciProviderCanBeLifted, existingPackageContents] = await Promise.all([\n ciProviderIsLiftable({projectRoot}),\n fs.readFile(pathToPackageJson, 'utf-8')\n ]);\n const parsedPackageContents = JSON.parse(existingPackageContents);\n const {scripts} = parsedPackageContents;\n const {'coverage:report': reportCoverageScript, ...otherScripts} = scripts;\n\n if (ciProviderCanBeLifted) await liftCiProvider({projectRoot});\n\n if (scripts['coverage:report']) {\n parsedPackageContents.scripts = otherScripts;\n await writePackageJson({projectRoot, config: parsedPackageContents});\n\n await execa(packageManager, ['remove', 'codecov']);\n\n return {\n ...!ciProviderCanBeLifted && {\n nextSteps: [{\n summary: 'Configure modern reporting to Codecov on your CI service',\n description: 'Configure the [Codecov Uploader](https://docs.codecov.com/docs/codecov-uploader) appropriately'\n + ' for your CI Provider. If available for your provider, prefer one of the dedicated wrappers.'\n }]\n }\n };\n }\n\n return {};\n}\n","import deepmerge from 'deepmerge';\n\nimport {scaffold as scaffoldConfig} from './config/index.js';\nimport {scaffold as scaffoldBadge} from './badge/index.js';\nimport {lift as liftReporting} from './reporter/index.js';\n\nexport async function lift({projectRoot, packageManager, vcs}) {\n const [reportingResults, badgeResults] = await Promise.all([\n liftReporting({projectRoot, packageManager}),\n scaffoldBadge({vcs}),\n scaffoldConfig({projectRoot})\n ]);\n\n return deepmerge.all([reportingResults, badgeResults]);\n}\n","import {remove as removeAction, test as githubWorkflowExists} from './reporter/ci-providers/github-workflows/index.js';\n\nexport default async function removeCodecov({projectRoot}) {\n if (await githubWorkflowExists({projectRoot})) {\n await removeAction({projectRoot});\n }\n\n return {};\n}\n"],"names":["scaffold","lift","ciProviderIsLiftable","fs","liftCiProvider","liftReporting","scaffoldBadge","githubWorkflowExists","removeAction"],"mappings":"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"}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@form8ion/codecov",
3
3
  "description": "code coverage service plugin for form8ion",
4
4
  "license": "MIT",
5
- "version": "7.5.0",
5
+ "version": "7.6.1",
6
6
  "type": "module",
7
7
  "engines": {
8
8
  "node": "^20.19.0 || >=22.14.0"
@@ -27,7 +27,7 @@
27
27
  "lint:peer": "npm ls >/dev/null",
28
28
  "lint:publish": "publint --strict",
29
29
  "test:unit": "run-s 'test:unit:base -- --coverage'",
30
- "test:unit:base": "DEBUG=any vitest run",
30
+ "test:unit:base": "NODE_ENV=test DEBUG=any vitest run src/",
31
31
  "test:integration": "run-s 'test:integration:base -- --profile noWip'",
32
32
  "pretest:integration:base": "run-s build",
33
33
  "test:integration:base": "NODE_OPTIONS=--enable-source-maps DEBUG=any cucumber-js test/integration",
@@ -47,7 +47,8 @@
47
47
  },
48
48
  "files": [
49
49
  "example.js",
50
- "lib/"
50
+ "lib/",
51
+ "src/"
51
52
  ],
52
53
  "publishConfig": {
53
54
  "access": "public",
@@ -73,7 +74,6 @@
73
74
  "@travi/any": "3.1.3",
74
75
  "@vitest/coverage-v8": "4.1.0",
75
76
  "chai": "6.2.2",
76
- "cross-env": "10.1.0",
77
77
  "cz-conventional-changelog": "3.3.0",
78
78
  "gherkin-lint": "4.2.4",
79
79
  "http-status-codes": "2.3.0",
@@ -0,0 +1 @@
1
+ export {scaffold} from './scaffolder.js';
@@ -0,0 +1,10 @@
1
+ import got from 'got';
2
+
3
+ export default async function fetchRepositoryDetails({vcs, apiAccessToken}) {
4
+ const {body: {repo}} = await got(
5
+ `https://codecov.io/api/gh/${vcs.owner}/${vcs.name}`,
6
+ {headers: {Authorization: apiAccessToken}, responseType: 'json'}
7
+ );
8
+
9
+ return repo;
10
+ }
@@ -0,0 +1,33 @@
1
+ import got from 'got';
2
+
3
+ import {expect, describe, it, vi} from 'vitest';
4
+ import {when} from 'vitest-when';
5
+ import any from '@travi/any';
6
+
7
+ import fetchRepositoryDetails from './repository-details-fetcher.js';
8
+
9
+ vi.mock('got');
10
+
11
+ describe('repository-details-fetcher', () => {
12
+ it('should fetch repository details from the codecov api', async () => {
13
+ const apiAccessToken = any.string();
14
+ const vcsHost = any.word();
15
+ const vcsOwner = any.word();
16
+ const vcsName = any.word();
17
+ const vcs = {
18
+ ...any.simpleObject(),
19
+ host: vcsHost,
20
+ owner: vcsOwner,
21
+ name: vcsName
22
+ };
23
+ const repoDetails = any.simpleObject();
24
+ when(got)
25
+ .calledWith(
26
+ `https://codecov.io/api/gh/${vcsOwner}/${vcsName}`,
27
+ {headers: {Authorization: apiAccessToken}, responseType: 'json'}
28
+ )
29
+ .thenResolve({body: {repo: repoDetails}});
30
+
31
+ expect(await fetchRepositoryDetails({vcs, apiAccessToken})).toEqual(repoDetails);
32
+ });
33
+ });
@@ -0,0 +1,21 @@
1
+ import fetchRepositoryDetails from './repository-details-fetcher.js';
2
+
3
+ export async function scaffold({vcs, apiAccessToken}) {
4
+ return {
5
+ ...['github', 'gitlab', 'bitbucket'].includes(vcs?.host) && {
6
+ badges: {
7
+ status: {
8
+ coverage: {
9
+ img: `https://img.shields.io/codecov/c/${vcs.host}/${vcs.owner}/${vcs.name}?logo=codecov${
10
+ apiAccessToken
11
+ ? `&token=${(await fetchRepositoryDetails({vcs, apiAccessToken})).image_token}`
12
+ : ''
13
+ }`,
14
+ link: `https://codecov.io/${vcs.host}/${vcs.owner}/${vcs.name}`,
15
+ text: 'Codecov'
16
+ }
17
+ }
18
+ }
19
+ }
20
+ };
21
+ }
@@ -0,0 +1,53 @@
1
+ import {it, vi, describe, expect} from 'vitest';
2
+ import {when} from 'vitest-when';
3
+ import any from '@travi/any';
4
+
5
+ import fetchRepositoryDetails from './repository-details-fetcher.js';
6
+ import {scaffold} from './scaffolder.js';
7
+
8
+ vi.mock('./repository-details-fetcher.js');
9
+
10
+ describe('badge scaffolder', () => {
11
+ const vcsHost = any.fromList(['github', 'gitlab', 'bitbucket']);
12
+ const vcsOwner = any.word();
13
+ const vcsName = any.word();
14
+ const vcs = {
15
+ ...any.simpleObject(),
16
+ host: vcsHost,
17
+ owner: vcsOwner,
18
+ name: vcsName
19
+ };
20
+
21
+ it('should scaffold badge details for supported vcs hosts', async () => {
22
+ const {badges} = await scaffold({vcs});
23
+
24
+ expect(badges.status.coverage).toEqual({
25
+ img: `https://img.shields.io/codecov/c/${vcsHost}/${vcsOwner}/${vcsName}?logo=codecov`,
26
+ link: `https://codecov.io/${vcsHost}/${vcsOwner}/${vcsName}`,
27
+ text: 'Codecov'
28
+ });
29
+ });
30
+
31
+ it('should include the image token in the img url', async () => {
32
+ const apiAccessToken = any.string();
33
+ const token = any.word();
34
+ when(fetchRepositoryDetails).calledWith({vcs, apiAccessToken}).thenResolve({image_token: token});
35
+
36
+ const {badges} = await scaffold({vcs, apiAccessToken});
37
+
38
+ expect(badges.status.coverage.img)
39
+ .toEqual(`https://img.shields.io/codecov/c/${vcsHost}/${vcsOwner}/${vcsName}?logo=codecov&token=${token}`);
40
+ });
41
+
42
+ it('should not define the badge if shields.io badge does not support the host', async () => {
43
+ const {badges} = await scaffold({vcs: {host: any.word()}});
44
+
45
+ expect(badges).toBe(undefined);
46
+ });
47
+
48
+ it('should not define the badge if vcs details are not defined', async () => {
49
+ const {badges} = await scaffold({});
50
+
51
+ expect(badges).toBe(undefined);
52
+ });
53
+ });
@@ -0,0 +1 @@
1
+ export {default as scaffold} from './scaffolder.js';
@@ -0,0 +1,10 @@
1
+ import {fileTypes, writeConfigFile} from '@form8ion/core';
2
+
3
+ export default async function scaffoldConfig({projectRoot}) {
4
+ await writeConfigFile({
5
+ format: fileTypes.YAML,
6
+ path: projectRoot,
7
+ name: '.codecov',
8
+ config: {comment: {layout: 'reach,diff,flags,tree'}}
9
+ });
10
+ }
@@ -0,0 +1,23 @@
1
+ import {fileTypes, writeConfigFile} from '@form8ion/core';
2
+
3
+ import {describe, it, expect, vi} from 'vitest';
4
+ import any from '@travi/any';
5
+
6
+ import scaffoldConfig from './scaffolder.js';
7
+
8
+ vi.mock('@form8ion/core');
9
+
10
+ describe('config scaffolder', () => {
11
+ it('should create the config file', async () => {
12
+ const projectRoot = any.string();
13
+
14
+ await scaffoldConfig({projectRoot});
15
+
16
+ expect(writeConfigFile).toHaveBeenCalledWith({
17
+ format: fileTypes.YAML,
18
+ path: projectRoot,
19
+ name: '.codecov',
20
+ config: {comment: {layout: 'reach,diff,flags,tree'}}
21
+ });
22
+ });
23
+ });
package/src/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export {scaffold} from './scaffolder.js';
2
+ export {default as test} from './tester.js';
3
+ export {lift} from './lifter.js';
4
+ export {default as remove} from './remover.js';
package/src/lifter.js ADDED
@@ -0,0 +1,15 @@
1
+ import deepmerge from 'deepmerge';
2
+
3
+ import {scaffold as scaffoldConfig} from './config/index.js';
4
+ import {scaffold as scaffoldBadge} from './badge/index.js';
5
+ import {lift as liftReporting} from './reporter/index.js';
6
+
7
+ export async function lift({projectRoot, packageManager, vcs}) {
8
+ const [reportingResults, badgeResults] = await Promise.all([
9
+ liftReporting({projectRoot, packageManager}),
10
+ scaffoldBadge({vcs}),
11
+ scaffoldConfig({projectRoot})
12
+ ]);
13
+
14
+ return deepmerge.all([reportingResults, badgeResults]);
15
+ }
@@ -0,0 +1,33 @@
1
+ import deepmerge from 'deepmerge';
2
+
3
+ import {expect, it, vi, describe} from 'vitest';
4
+ import {when} from 'vitest-when';
5
+ import any from '@travi/any';
6
+
7
+ import {scaffold as scaffoldConfig} from './config/index.js';
8
+ import {scaffold as scaffoldBadge} from './badge/index.js';
9
+ import {lift as liftReporting} from './reporter/index.js';
10
+ import {lift} from './lifter.js';
11
+
12
+ vi.mock('deepmerge');
13
+ vi.mock('./config/index.js');
14
+ vi.mock('./badge/index.js');
15
+ vi.mock('./reporter/index.js');
16
+
17
+ describe('lifter', () => {
18
+ it('should lift the reporting process', async () => {
19
+ const projectRoot = any.string();
20
+ const packageManager = any.word();
21
+ const vcs = any.simpleObject();
22
+ const reportingResults = any.simpleObject();
23
+ const badgeResults = any.simpleObject();
24
+ const mergedResults = any.simpleObject();
25
+ when(liftReporting).calledWith({projectRoot, packageManager}).thenResolve(reportingResults);
26
+ when(scaffoldBadge).calledWith({vcs}).thenResolve(badgeResults);
27
+ when(deepmerge.all).calledWith([reportingResults, badgeResults]).thenReturn(mergedResults);
28
+
29
+ expect(await lift({projectRoot, packageManager, vcs})).toEqual(mergedResults);
30
+
31
+ expect(scaffoldConfig).toHaveBeenCalledWith({projectRoot});
32
+ });
33
+ });
@@ -0,0 +1,3 @@
1
+ export function coverageShouldBeReportedToCodecov({vcs, visibility, apiAccessToken}) {
2
+ return !!('Public' === visibility || (apiAccessToken && 'github' === vcs.host));
3
+ }
@@ -0,0 +1,31 @@
1
+ import {expect, it, describe} from 'vitest';
2
+ import any from '@travi/any';
3
+
4
+ import {coverageShouldBeReportedToCodecov} from './predicates.js';
5
+
6
+ describe('predicates', () => {
7
+ it('should determine that coverage should be reported when the project is public', () => {
8
+ expect(coverageShouldBeReportedToCodecov({visibility: 'Public'})).toBe(true);
9
+ });
10
+
11
+ it(
12
+ 'should determine that coverage should be reported when an API token is provided and GitHub is the VCS host',
13
+ async () => {
14
+ expect(coverageShouldBeReportedToCodecov({apiAccessToken: any.word(), vcs: {host: 'github'}})).toBe(true);
15
+ }
16
+ );
17
+
18
+ it(
19
+ 'should determine that coverage should not be reported when the project is not public and no API token is provided',
20
+ async () => {
21
+ expect(coverageShouldBeReportedToCodecov({})).toBe(false);
22
+ }
23
+ );
24
+
25
+ it(
26
+ "should determine that coverage should not be reported when an API token is provided but the VCS host isn't GitHub",
27
+ async () => {
28
+ expect(coverageShouldBeReportedToCodecov({apiAccessToken: any.word(), vcs: {host: any.word()}})).toBe(false);
29
+ }
30
+ );
31
+ });
package/src/remover.js ADDED
@@ -0,0 +1,9 @@
1
+ import {remove as removeAction, test as githubWorkflowExists} from './reporter/ci-providers/github-workflows/index.js';
2
+
3
+ export default async function removeCodecov({projectRoot}) {
4
+ if (await githubWorkflowExists({projectRoot})) {
5
+ await removeAction({projectRoot});
6
+ }
7
+
8
+ return {};
9
+ }
@@ -0,0 +1,27 @@
1
+ import {describe, expect, it, vi} from 'vitest';
2
+ import {when} from 'vitest-when';
3
+ import any from '@travi/any';
4
+
5
+ import {remove as removeAction, test as githubWorkflowExists} from './reporter/ci-providers/github-workflows/index.js';
6
+ import remove from './remover.js';
7
+
8
+ vi.mock(('./reporter/ci-providers/github-workflows/index.js'));
9
+
10
+ describe('remover', () => {
11
+ const projectRoot = any.string();
12
+
13
+ it('should remove the various parts', async () => {
14
+ when(githubWorkflowExists).calledWith({projectRoot}).thenResolve(true);
15
+
16
+ expect(await remove({projectRoot})).toEqual({});
17
+ expect(removeAction).toHaveBeenCalledWith({projectRoot});
18
+ });
19
+
20
+ it('should not remove the action if there is no GitHub Actions workflow', async () => {
21
+ when(githubWorkflowExists).calledWith({projectRoot}).thenResolve(false);
22
+
23
+ await remove({projectRoot});
24
+
25
+ expect(removeAction).not.toHaveBeenCalled();
26
+ });
27
+ });
@@ -0,0 +1 @@
1
+ export const ACTION_NAME = 'codecov/codecov-action';
@@ -0,0 +1,4 @@
1
+ export {default as scaffold} from './scaffolder.js';
2
+ export {default as test} from './tester.js';
3
+ export {default as lift} from './lifter.js';
4
+ export {default as remove} from './remover.js';
@@ -0,0 +1,12 @@
1
+ export default function liftAction(action) {
2
+ return {
3
+ name: 'Upload unit test coverage to Codecov',
4
+ ...action,
5
+ with: {
6
+ // eslint-disable-next-line no-template-curly-in-string
7
+ token: '${{ secrets.CODECOV_TOKEN }}',
8
+ flags: 'unit',
9
+ report_type: 'coverage'
10
+ }
11
+ };
12
+ }
@@ -0,0 +1,21 @@
1
+ import {describe, it, expect} from 'vitest';
2
+ import any from '@travi/any';
3
+
4
+ import liftAction from './lifter.js';
5
+
6
+ describe('action lifter', () => {
7
+ it('should expose the token secret to the action', async () => {
8
+ const existingAction = any.simpleObject();
9
+
10
+ expect(liftAction(existingAction)).toEqual({
11
+ name: 'Upload unit test coverage to Codecov',
12
+ ...existingAction,
13
+ with: {
14
+ // eslint-disable-next-line no-template-curly-in-string
15
+ token: '${{ secrets.CODECOV_TOKEN }}',
16
+ flags: 'unit',
17
+ report_type: 'coverage'
18
+ }
19
+ });
20
+ });
21
+ });
@@ -0,0 +1,6 @@
1
+ import {removeActionFromJobs} from '@form8ion/github-workflows-core';
2
+ import {ACTION_NAME} from './constants.js';
3
+
4
+ export default function removeCodecovActionFrom(jobs) {
5
+ return removeActionFromJobs(jobs, ACTION_NAME);
6
+ }
@@ -0,0 +1,22 @@
1
+ import {removeActionFromJobs} from '@form8ion/github-workflows-core';
2
+
3
+ import {describe, expect, it, vi} from 'vitest';
4
+ import {when} from 'vitest-when';
5
+ import any from '@travi/any';
6
+
7
+ import removeCodecovActionFrom from './remover.js';
8
+ import {ACTION_NAME} from './constants.js';
9
+
10
+ vi.mock('@form8ion/github-workflows-core');
11
+
12
+ describe('codecov action', () => {
13
+ describe('remove from jobs', () => {
14
+ it('should remove the codecov action from the provided jobs', async () => {
15
+ const jobs = any.listOf(any.simpleObject);
16
+ const updatedJobs = any.listOf(any.simpleObject);
17
+ when(removeActionFromJobs).calledWith(jobs, ACTION_NAME).thenReturn(updatedJobs);
18
+
19
+ expect(removeCodecovActionFrom(jobs)).toEqual(updatedJobs);
20
+ });
21
+ });
22
+ });
@@ -0,0 +1,14 @@
1
+ import {ACTION_NAME} from './constants.js';
2
+
3
+ export default function scaffoldAction() {
4
+ return {
5
+ name: 'Upload unit test coverage to Codecov',
6
+ uses: `${ACTION_NAME}@v5.5.2`,
7
+ with: {
8
+ // eslint-disable-next-line no-template-curly-in-string
9
+ token: '${{ secrets.CODECOV_TOKEN }}',
10
+ flags: 'unit',
11
+ report_type: 'coverage'
12
+ }
13
+ };
14
+ }
@@ -0,0 +1,19 @@
1
+ import {describe, it, expect} from 'vitest';
2
+
3
+ import scaffoldAction from './scaffolder.js';
4
+ import {ACTION_NAME} from './constants.js';
5
+
6
+ describe('codecov action scaffolder', () => {
7
+ it('should scaffold the codecov action', async () => {
8
+ expect(scaffoldAction()).toEqual({
9
+ name: 'Upload unit test coverage to Codecov',
10
+ uses: `${ACTION_NAME}@v5.5.2`,
11
+ with: {
12
+ // eslint-disable-next-line no-template-curly-in-string
13
+ token: '${{ secrets.CODECOV_TOKEN }}',
14
+ flags: 'unit',
15
+ report_type: 'coverage'
16
+ }
17
+ });
18
+ });
19
+ });
@@ -0,0 +1,9 @@
1
+ import {ACTION_NAME} from './constants.js';
2
+
3
+ export default function stepIsCodecovAction(step) {
4
+ if (!step.uses) return false;
5
+
6
+ const [actionName] = step.uses.split('@');
7
+
8
+ return ACTION_NAME === actionName;
9
+ }
@@ -0,0 +1,23 @@
1
+ import {describe, it, expect} from 'vitest';
2
+ import any from '@travi/any';
3
+
4
+ import stepIsCodecovAction from './tester.js';
5
+ import {ACTION_NAME} from './constants.js';
6
+
7
+ describe('action tester', () => {
8
+ it('should return `false` if the step does not use an action', async () => {
9
+ expect(stepIsCodecovAction(any.simpleObject())).toBe(false);
10
+ });
11
+
12
+ it('should return `false` if the step does not use the CodeCov action', async () => {
13
+ const otherAction = {...any.simpleObject(), uses: 'something-else@v1.2.3'};
14
+
15
+ expect(stepIsCodecovAction(otherAction)).toBe(false);
16
+ });
17
+
18
+ it('should return `true` if the step uses the CodeCov action', async () => {
19
+ const codecovAction = {...any.simpleObject(), uses: `${ACTION_NAME}@v5.5.2`};
20
+
21
+ expect(stepIsCodecovAction(codecovAction)).toBe(true);
22
+ });
23
+ });
@@ -0,0 +1,3 @@
1
+ export {lift} from './lifter.js';
2
+ export {default as remove} from './remover.js';
3
+ export {default as test} from './predicate.js';
@@ -0,0 +1,25 @@
1
+ import {loadWorkflowFile, writeWorkflowFile} from '@form8ion/github-workflows-core';
2
+
3
+ import {lift as liftSteps} from './steps/index.js';
4
+
5
+ export async function lift({projectRoot}) {
6
+ const ciWorkflowName = 'node-ci';
7
+
8
+ const workflowDetails = await loadWorkflowFile({projectRoot, name: ciWorkflowName});
9
+ const {jobs: {verify: {steps}}} = workflowDetails;
10
+
11
+ await writeWorkflowFile({
12
+ projectRoot,
13
+ name: ciWorkflowName,
14
+ config: {
15
+ ...workflowDetails,
16
+ jobs: {
17
+ ...workflowDetails.jobs,
18
+ verify: {
19
+ ...workflowDetails.jobs.verify,
20
+ steps: liftSteps(steps)
21
+ }
22
+ }
23
+ }
24
+ });
25
+ }
@@ -0,0 +1,47 @@
1
+ import {loadWorkflowFile, writeWorkflowFile} from '@form8ion/github-workflows-core';
2
+
3
+ import {describe, expect, it, vi} from 'vitest';
4
+ import {when} from 'vitest-when';
5
+ import any from '@travi/any';
6
+
7
+ import {lift as liftSteps} from './steps/index.js';
8
+ import {lift as configureGithubWorkflow} from './lifter.js';
9
+
10
+ vi.mock('@form8ion/github-workflows-core');
11
+ vi.mock('./steps/index.js');
12
+
13
+ describe('github workflow lifter', () => {
14
+ const projectRoot = any.string();
15
+ const ciWorkflowName = 'node-ci';
16
+ const liftedSteps = any.listOf(any.simpleObject);
17
+
18
+ it('should add the codecov action to the verify job', async () => {
19
+ const otherTopLevelProperties = any.simpleObject();
20
+ const otherJobs = any.simpleObject();
21
+ const otherVerifyProperties = any.simpleObject();
22
+ const existingVerifySteps = any.listOf(any.simpleObject);
23
+ const existingWorkflowContents = {
24
+ ...otherTopLevelProperties,
25
+ jobs: {...otherJobs, verify: {...otherVerifyProperties, steps: existingVerifySteps}}
26
+ };
27
+ when(loadWorkflowFile).calledWith({projectRoot, name: ciWorkflowName}).thenResolve(existingWorkflowContents);
28
+ when(liftSteps).calledWith(existingVerifySteps).thenReturn(liftedSteps);
29
+
30
+ await configureGithubWorkflow({projectRoot});
31
+
32
+ expect(writeWorkflowFile).toHaveBeenCalledWith({
33
+ projectRoot,
34
+ name: ciWorkflowName,
35
+ config: {
36
+ ...otherTopLevelProperties,
37
+ jobs: {
38
+ ...otherJobs,
39
+ verify: {
40
+ ...otherVerifyProperties,
41
+ steps: liftedSteps
42
+ }
43
+ }
44
+ }
45
+ });
46
+ });
47
+ });
@@ -0,0 +1,5 @@
1
+ import {workflowFileExists} from '@form8ion/github-workflows-core';
2
+
3
+ export default function ciWorkflowExists({projectRoot}) {
4
+ return workflowFileExists({projectRoot, name: 'node-ci'});
5
+ }
@@ -0,0 +1,20 @@
1
+ import {workflowFileExists} from '@form8ion/github-workflows-core';
2
+
3
+ import {expect, describe, it, vi} from 'vitest';
4
+ import {when} from 'vitest-when';
5
+ import any from '@travi/any';
6
+
7
+ import ciWorkflowExists from './predicate.js';
8
+
9
+ vi.mock('@form8ion/github-workflows-core');
10
+
11
+ describe('github workflows predicate', () => {
12
+ const projectRoot = any.string();
13
+
14
+ it('should determine whether the verification workflow exists', async () => {
15
+ const workflowExists = any.boolean();
16
+ when(workflowFileExists).calledWith({projectRoot, name: 'node-ci'}).thenResolve(workflowExists);
17
+
18
+ expect(await ciWorkflowExists({projectRoot})).toEqual(workflowExists);
19
+ });
20
+ });
@@ -0,0 +1,9 @@
1
+ import {loadWorkflowFile, writeWorkflowFile} from '@form8ion/github-workflows-core';
2
+ import {remove as removeCodecovActionFrom} from './action/index.js';
3
+
4
+ export default async function removeCodecovAction({projectRoot}) {
5
+ const existingConfig = await loadWorkflowFile({projectRoot, name: 'node-ci'});
6
+ existingConfig.jobs = removeCodecovActionFrom(existingConfig.jobs);
7
+
8
+ await writeWorkflowFile({projectRoot, name: 'node-ci', config: existingConfig});
9
+ }
@@ -0,0 +1,30 @@
1
+ import {loadWorkflowFile, writeWorkflowFile} from '@form8ion/github-workflows-core';
2
+
3
+ import {describe, expect, it, vi} from 'vitest';
4
+ import {when} from 'vitest-when';
5
+ import any from '@travi/any';
6
+
7
+ import {remove as removeCodecovActionFrom} from './action/index.js';
8
+ import remove from './remover.js';
9
+
10
+ vi.mock('@form8ion/github-workflows-core');
11
+ vi.mock('./action/index.js');
12
+
13
+ describe('action remover', () => {
14
+ it('should remove the action from the workflow', async () => {
15
+ const projectRoot = any.string();
16
+ const updatedJobs = any.simpleObject();
17
+ const ciWorkflowName = 'node-ci';
18
+ const existingWorkflowDefinition = {...any.simpleObject(), jobs: any.simpleObject()};
19
+ when(loadWorkflowFile).calledWith({projectRoot, name: ciWorkflowName}).thenResolve(existingWorkflowDefinition);
20
+ when(removeCodecovActionFrom).calledWith(existingWorkflowDefinition.jobs).thenReturn(updatedJobs);
21
+
22
+ await remove({projectRoot});
23
+
24
+ expect(writeWorkflowFile).toHaveBeenCalledWith({
25
+ projectRoot,
26
+ name: ciWorkflowName,
27
+ config: {...existingWorkflowDefinition, jobs: updatedJobs}
28
+ });
29
+ });
30
+ });
@@ -0,0 +1,2 @@
1
+ export {default as test} from './tester.js';
2
+ export {default as lift} from './lifter.js';
@@ -0,0 +1,16 @@
1
+ import {scaffold as scaffoldAction, lift as liftAction, test as stepIsCodecovAction} from '../action/index.js';
2
+ import codecovActionExistsInSteps from './tester.js';
3
+
4
+ export default function liftSteps(steps) {
5
+ if (!codecovActionExistsInSteps(steps)) {
6
+ const stepsWithLegacyReportingRemoved = steps.filter(({run}) => 'npm run coverage:report' !== run);
7
+
8
+ return [...stepsWithLegacyReportingRemoved, scaffoldAction()];
9
+ }
10
+
11
+ return steps.map(step => {
12
+ if (stepIsCodecovAction(step)) return liftAction(step);
13
+
14
+ return step;
15
+ });
16
+ }
@@ -0,0 +1,48 @@
1
+ import {describe, it, expect, vi} from 'vitest';
2
+ import any from '@travi/any';
3
+ import {when} from 'vitest-when';
4
+
5
+ import {scaffold as scaffoldAction, lift as liftAction, test as stepIsCodecovAction} from '../action/index.js';
6
+ import codecovActionExistsInSteps from './tester.js';
7
+ import liftSteps from './lifter.js';
8
+
9
+ vi.mock('../action/index.js');
10
+ vi.mock('./tester.js');
11
+
12
+ describe('steps lifter', () => {
13
+ const codecovAction = any.simpleObject();
14
+
15
+ it('should append the CodeCov step if it doesnt already exist', async () => {
16
+ const steps = any.listOf(any.simpleObject);
17
+ when(codecovActionExistsInSteps).calledWith(steps).thenReturn(false);
18
+ when(scaffoldAction).calledWith().thenReturn(codecovAction);
19
+
20
+ expect(liftSteps(steps)).toEqual([...steps, codecovAction]);
21
+ });
22
+
23
+ it('should remove the legacy reporting step, if present', async () => {
24
+ const stepsBeforeLegacy = any.listOf(any.simpleObject);
25
+ const stepsAfterLegacy = any.listOf(any.simpleObject);
26
+ const steps = [
27
+ ...stepsBeforeLegacy,
28
+ {...any.simpleObject(), run: 'npm run coverage:report'},
29
+ ...stepsAfterLegacy
30
+ ];
31
+ when(codecovActionExistsInSteps).calledWith(steps).thenReturn(false);
32
+ when(scaffoldAction).calledWith().thenReturn(codecovAction);
33
+
34
+ expect(liftSteps(steps)).toEqual([...stepsBeforeLegacy, ...stepsAfterLegacy, codecovAction]);
35
+ });
36
+
37
+ it('should lift the existing action, if present', async () => {
38
+ const stepsBeforeExisting = any.listOf(any.simpleObject);
39
+ const stepsAfterExisting = any.listOf(any.simpleObject);
40
+ const existingAction = any.simpleObject();
41
+ const steps = [...stepsBeforeExisting, existingAction, ...stepsAfterExisting];
42
+ when(codecovActionExistsInSteps).calledWith(steps).thenReturn(true);
43
+ when(stepIsCodecovAction).calledWith(existingAction).thenReturn(true);
44
+ when(liftAction).calledWith(existingAction).thenReturn(codecovAction);
45
+
46
+ expect(liftSteps(steps)).toEqual([...stepsBeforeExisting, codecovAction, ...stepsAfterExisting]);
47
+ });
48
+ });
@@ -0,0 +1,5 @@
1
+ import {test as stepIsCodecovAction} from '../action/index.js';
2
+
3
+ export default function codecovActionExistsInSteps(steps) {
4
+ return !!steps.find(step => stepIsCodecovAction(step));
5
+ }
@@ -0,0 +1,25 @@
1
+ import {describe, expect, it, vi} from 'vitest';
2
+ import {when} from 'vitest-when';
3
+ import any from '@travi/any';
4
+
5
+ import {test as stepIsCodecovAction} from '../action/index.js';
6
+ import codecovActionExistsInSteps from './tester.js';
7
+
8
+ vi.mock('../action/index.js');
9
+
10
+ describe('codecov action tester', () => {
11
+ it('should return `true` if the codecov action is found in the list of provided steps', async () => {
12
+ const codecovAction = any.simpleObject();
13
+ when(stepIsCodecovAction).calledWith(codecovAction).thenReturn(true);
14
+
15
+ expect(codecovActionExistsInSteps([
16
+ ...any.listOf(any.simpleObject),
17
+ codecovAction,
18
+ ...any.listOf(any.simpleObject)
19
+ ])).toBe(true);
20
+ });
21
+
22
+ it('should return `false` if no codecov action is found in the list of provided steps', async () => {
23
+ expect(codecovActionExistsInSteps(any.listOf(any.simpleObject))).toBe(false);
24
+ });
25
+ });
@@ -0,0 +1 @@
1
+ export {lift, test} from './github-workflows/index.js';
@@ -0,0 +1 @@
1
+ export {default as lift} from './lifter.js';
@@ -0,0 +1,38 @@
1
+ import {promises as fs} from 'node:fs';
2
+ import {writePackageJson} from '@form8ion/javascript-core';
3
+
4
+ import {execa} from 'execa';
5
+ import {lift as liftCiProvider, test as ciProviderIsLiftable} from './ci-providers/index.js';
6
+
7
+ export default async function liftReporter({projectRoot, packageManager}) {
8
+ const pathToPackageJson = `${projectRoot}/package.json`;
9
+
10
+ const [ciProviderCanBeLifted, existingPackageContents] = await Promise.all([
11
+ ciProviderIsLiftable({projectRoot}),
12
+ fs.readFile(pathToPackageJson, 'utf-8')
13
+ ]);
14
+ const parsedPackageContents = JSON.parse(existingPackageContents);
15
+ const {scripts} = parsedPackageContents;
16
+ const {'coverage:report': reportCoverageScript, ...otherScripts} = scripts;
17
+
18
+ if (ciProviderCanBeLifted) await liftCiProvider({projectRoot});
19
+
20
+ if (scripts['coverage:report']) {
21
+ parsedPackageContents.scripts = otherScripts;
22
+ await writePackageJson({projectRoot, config: parsedPackageContents});
23
+
24
+ await execa(packageManager, ['remove', 'codecov']);
25
+
26
+ return {
27
+ ...!ciProviderCanBeLifted && {
28
+ nextSteps: [{
29
+ summary: 'Configure modern reporting to Codecov on your CI service',
30
+ description: 'Configure the [Codecov Uploader](https://docs.codecov.com/docs/codecov-uploader) appropriately'
31
+ + ' for your CI Provider. If available for your provider, prefer one of the dedicated wrappers.'
32
+ }]
33
+ }
34
+ };
35
+ }
36
+
37
+ return {};
38
+ }
@@ -0,0 +1,70 @@
1
+ import {promises as fs} from 'node:fs';
2
+ import {execa} from 'execa';
3
+ import {writePackageJson} from '@form8ion/javascript-core';
4
+
5
+ import {it, describe, vi, expect} from 'vitest';
6
+ import {when} from 'vitest-when';
7
+ import any from '@travi/any';
8
+
9
+ import {lift as liftCiProvider, test as ciProviderIsLiftable} from './ci-providers/index.js';
10
+ import liftReporting from './lifter.js';
11
+
12
+ vi.mock('node:fs');
13
+ vi.mock('execa');
14
+ vi.mock('@form8ion/javascript-core');
15
+ vi.mock('./ci-providers/index.js');
16
+
17
+ describe('reporting lifter', () => {
18
+ const projectRoot = any.string();
19
+ const packageManager = any.word();
20
+ const pathToPackageJson = `${projectRoot}/package.json`;
21
+
22
+ it('should remove the legacy node reporter', async () => {
23
+ const otherScripts = any.simpleObject();
24
+ const otherTopLevelProperties = any.simpleObject();
25
+ const existingPackageContents = {
26
+ ...otherTopLevelProperties,
27
+ scripts: {...otherScripts, 'coverage:report': any.string()}
28
+ };
29
+ when(fs.readFile).calledWith(pathToPackageJson, 'utf-8').thenResolve(JSON.stringify(existingPackageContents));
30
+ when(ciProviderIsLiftable).calledWith({projectRoot}).thenResolve(false);
31
+
32
+ const {nextSteps} = await liftReporting({projectRoot, packageManager});
33
+
34
+ expect(nextSteps).toEqual([{
35
+ summary: 'Configure modern reporting to Codecov on your CI service',
36
+ description: 'Configure the [Codecov Uploader](https://docs.codecov.com/docs/codecov-uploader) appropriately'
37
+ + ' for your CI Provider. If available for your provider, prefer one of the dedicated wrappers.'
38
+ }]);
39
+
40
+ expect(execa).toHaveBeenCalledWith(packageManager, ['remove', 'codecov']);
41
+ expect(writePackageJson).toHaveBeenCalledWith({
42
+ projectRoot,
43
+ config: {...otherTopLevelProperties, scripts: otherScripts}
44
+ });
45
+ expect(liftCiProvider).not.toHaveBeenCalled();
46
+ });
47
+
48
+ it('should lift the ci provider when supported', async () => {
49
+ when(fs.readFile)
50
+ .calledWith(pathToPackageJson, 'utf-8')
51
+ .thenResolve(JSON.stringify({
52
+ ...any.simpleObject(),
53
+ scripts: {...any.simpleObject(), 'coverage:report': any.string()}
54
+ }));
55
+ when(ciProviderIsLiftable).calledWith({projectRoot}).thenResolve(true);
56
+
57
+ const {nextSteps} = await liftReporting({projectRoot, packageManager});
58
+
59
+ expect(liftCiProvider).toHaveBeenCalledWith({projectRoot});
60
+ expect(nextSteps).toBeUndefined();
61
+ });
62
+
63
+ it('should not update the `package.json` if it did not contain a `coverage:report` script', async () => {
64
+ const existingPackageContents = {...any.simpleObject(), scripts: any.simpleObject()};
65
+ when(fs.readFile).calledWith(pathToPackageJson, 'utf-8').thenResolve(JSON.stringify(existingPackageContents));
66
+
67
+ expect(await liftReporting({projectRoot})).toEqual({});
68
+ expect(writePackageJson).not.toHaveBeenCalled();
69
+ });
70
+ });
@@ -0,0 +1,7 @@
1
+ import {scaffold as scaffoldConfig} from './config/index.js';
2
+
3
+ export async function scaffold({projectRoot}) {
4
+ await scaffoldConfig({projectRoot});
5
+
6
+ return {};
7
+ }
@@ -0,0 +1,18 @@
1
+ import {describe, expect, it, vi} from 'vitest';
2
+ import any from '@travi/any';
3
+
4
+ import {scaffold as scaffoldConfig} from './config/index.js';
5
+ import {scaffold} from './scaffolder.js';
6
+
7
+ vi.mock('./config/index.js');
8
+
9
+ describe('scaffolder', () => {
10
+ it('should simply return empty results', async () => {
11
+ const projectRoot = any.string();
12
+
13
+ const results = await scaffold({projectRoot});
14
+
15
+ expect(results).toEqual({});
16
+ expect(scaffoldConfig).toHaveBeenCalledWith({projectRoot});
17
+ });
18
+ });
package/src/tester.js ADDED
@@ -0,0 +1,5 @@
1
+ import {fileExists} from '@form8ion/core';
2
+
3
+ export default async function codecovInUse({projectRoot}) {
4
+ return fileExists(`${projectRoot}/.codecov.yml`);
5
+ }
@@ -0,0 +1,25 @@
1
+ import {fileExists} from '@form8ion/core';
2
+
3
+ import {describe, expect, it, vi} from 'vitest';
4
+ import {when} from 'vitest-when';
5
+ import any from '@travi/any';
6
+
7
+ import codecovInUse from './tester.js';
8
+
9
+ vi.mock('@form8ion/core');
10
+
11
+ describe('codecov predicate', () => {
12
+ const projectRoot = any.string();
13
+
14
+ it('should return `true` if the config file exists', async () => {
15
+ when(fileExists).calledWith(`${projectRoot}/.codecov.yml`).thenResolve(true);
16
+
17
+ expect(await codecovInUse({projectRoot})).toBe(true);
18
+ });
19
+
20
+ it('should return `false` if the config file exists', async () => {
21
+ when(fileExists).calledWith(`${projectRoot}/.codecov.yml`).thenResolve(false);
22
+
23
+ expect(await codecovInUse({projectRoot})).toBe(false);
24
+ });
25
+ });